From 7d4319dbf1f2d07ee877739e47028b9261afc193 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 16:27:33 +0200 Subject: [PATCH 01/57] Bump futures from 0.3.26 to 0.3.27 (#2359) Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.26 to 0.3.27. - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.26...0.3.27) --- updated-dependencies: - dependency-name: futures 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: Sebastian Kunert --- Cargo.lock | 36 +++++++++---------- client/consensus/aura/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/relay-chain/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/pov-recovery/Cargo.toml | 2 +- .../Cargo.toml | 2 +- client/relay-chain-interface/Cargo.toml | 2 +- client/relay-chain-minimal-node/Cargo.toml | 2 +- client/relay-chain-rpc-interface/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- polkadot-parachain/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- test/service/Cargo.toml | 2 +- 14 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dcd1e85fcc..04cd05245aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3661,9 +3661,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" dependencies = [ "futures-channel", "futures-core", @@ -3676,9 +3676,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" dependencies = [ "futures-core", "futures-sink", @@ -3686,15 +3686,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" [[package]] name = "futures-executor" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" +checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" dependencies = [ "futures-core", "futures-task", @@ -3704,9 +3704,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" [[package]] name = "futures-lite" @@ -3725,9 +3725,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" dependencies = [ "proc-macro2", "quote", @@ -3747,15 +3747,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" [[package]] name = "futures-timer" @@ -3765,9 +3765,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" dependencies = [ "futures-channel", "futures-core", diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index 4428c94c210..b7a65523cf5 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] async-trait = "0.1.68" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } -futures = "0.3.26" +futures = "0.3.27" tracing = "0.1.37" # Substrate diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index a588d02e741..84f3adaca1e 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" async-trait = "0.1.68" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } dyn-clone = "1.0.11" -futures = "0.3.26" +futures = "0.3.27" log = "0.4.17" tracing = "0.1.37" diff --git a/client/consensus/relay-chain/Cargo.toml b/client/consensus/relay-chain/Cargo.toml index 9b7d8dff3ff..b3cd2eea7b0 100644 --- a/client/consensus/relay-chain/Cargo.toml +++ b/client/consensus/relay-chain/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] async-trait = "0.1.68" -futures = "0.3.26" +futures = "0.3.27" parking_lot = "0.12.1" tracing = "0.1.37" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 96dc43a5f52..130ab98b754 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] async-trait = "0.1.68" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } -futures = "0.3.26" +futures = "0.3.27" futures-timer = "3.0.2" parking_lot = "0.12.1" tracing = "0.1.37" diff --git a/client/pov-recovery/Cargo.toml b/client/pov-recovery/Cargo.toml index 6b379fd89d6..5ab23ec7791 100644 --- a/client/pov-recovery/Cargo.toml +++ b/client/pov-recovery/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } -futures = "0.3.26" +futures = "0.3.27" futures-timer = "3.0.2" rand = "0.8.5" tracing = "0.1.37" diff --git a/client/relay-chain-inprocess-interface/Cargo.toml b/client/relay-chain-inprocess-interface/Cargo.toml index 059d6f198db..1959a7d163a 100644 --- a/client/relay-chain-inprocess-interface/Cargo.toml +++ b/client/relay-chain-inprocess-interface/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] async-trait = "0.1.68" -futures = "0.3.26" +futures = "0.3.27" futures-timer = "3.0.2" # Substrate diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index c4b413906e2..9583d78b613 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -14,7 +14,7 @@ sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "mas sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -futures = "0.3.26" +futures = "0.3.27" async-trait = "0.1.68" thiserror = "1.0.38" jsonrpsee-core = "0.16.2" diff --git a/client/relay-chain-minimal-node/Cargo.toml b/client/relay-chain-minimal-node/Cargo.toml index dc7cad4bd76..7c1c8621d36 100644 --- a/client/relay-chain-minimal-node/Cargo.toml +++ b/client/relay-chain-minimal-node/Cargo.toml @@ -36,5 +36,5 @@ array-bytes = "6.0" lru = "0.9" tracing = "0.1.37" async-trait = "0.1.68" -futures = "0.3.26" +futures = "0.3.27" tokio = { version = "1.26.0", features = ["macros"] } diff --git a/client/relay-chain-rpc-interface/Cargo.toml b/client/relay-chain-rpc-interface/Cargo.toml index b51997b666b..91afe09910e 100644 --- a/client/relay-chain-rpc-interface/Cargo.toml +++ b/client/relay-chain-rpc-interface/Cargo.toml @@ -23,7 +23,7 @@ sc-service = { git = "https://github.com/paritytech/substrate", branch = "master tokio = { version = "1.26.0", features = ["sync"] } -futures = "0.3.26" +futures = "0.3.27" futures-timer = "3.0.2" parity-scale-codec = "3.4.0" jsonrpsee = { version = "0.16.2", features = ["ws-client"] } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index ade6e7e8067..e17809158a9 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2021" [dependencies] -futures = "0.3.26" +futures = "0.3.27" # Substrate sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index 80de13097f2..32b1e1cabec 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -14,7 +14,7 @@ path = "src/main.rs" async-trait = "0.1.68" clap = { version = "4.1.11", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.26" +futures = "0.3.27" hex-literal = "0.3.4" log = "0.4.17" serde = { version = "1.0.156", features = ["derive"] } diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 418b79d30c0..79fcaa535f6 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -7,7 +7,7 @@ description = "Provides timestamp related functionality for parachains." [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } -futures = "0.3.26" +futures = "0.3.27" # Substrate sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index 3c0cec570fa..639aa369fef 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -72,7 +72,7 @@ cumulus-relay-chain-minimal-node = { path = "../../client/relay-chain-minimal-no cumulus-client-pov-recovery = { path = "../../client/pov-recovery" } [dev-dependencies] -futures = "0.3.26" +futures = "0.3.27" portpicker = "0.1.1" # Polkadot dependencies From ea6598c3fa5ffe793f73bffd0f369b08f51722f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 22:08:11 +0000 Subject: [PATCH 02/57] Bump clap from 4.1.11 to 4.1.13 (#2388) Bumps [clap](https://github.com/clap-rs/clap) from 4.1.11 to 4.1.13. - [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.1.11...v4.1.13) --- updated-dependencies: - dependency-name: clap 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 | 77 ++++++++++++++---------------- client/cli/Cargo.toml | 2 +- parachain-template/node/Cargo.toml | 2 +- polkadot-parachain/Cargo.toml | 2 +- test/service/Cargo.toml | 2 +- 5 files changed, 39 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04cd05245aa..b1eafbf02b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -550,7 +550,7 @@ version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cexpr", "clang-sys", "lazy_static", @@ -569,12 +569,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitflags" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" - [[package]] name = "bitvec" version = "1.0.1" @@ -1196,7 +1190,7 @@ version = "3.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" dependencies = [ - "bitflags 1.3.2", + "bitflags", "clap_lex 0.2.2", "indexmap", "textwrap", @@ -1204,11 +1198,11 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.11" +version = "4.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42dfd32784433290c51d92c438bb72ea5063797fc3cc9a21a8c4346bebbb2098" +checksum = "3c911b090850d79fc64fe9ea01e28e465f65e821e08813ced95bced72f7a8a9b" dependencies = [ - "bitflags 2.0.2", + "bitflags", "clap_derive", "clap_lex 0.3.0", "is-terminal", @@ -1219,15 +1213,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.1.9" +version = "4.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fddf67631444a3a3e3e5ac51c36a5e01335302de677bd78759eaa90ab1f46644" +checksum = "9a932373bab67b984c790ddf2c9ca295d8e3af3b7ef92de5a5bacdccdee4b09b" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.9", ] [[package]] @@ -1818,7 +1811,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.1.11", + "clap 4.1.13", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -2456,7 +2449,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.1.11", + "clap 4.1.13", "criterion", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -3384,7 +3377,7 @@ dependencies = [ "Inflector", "array-bytes 4.2.0", "chrono", - "clap 4.1.11", + "clap 4.1.13", "comfy-table", "frame-benchmarking", "frame-support", @@ -3501,7 +3494,7 @@ name = "frame-support" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" dependencies = [ - "bitflags 1.3.2", + "bitflags", "environmental", "frame-metadata", "frame-support-procedural", @@ -5714,7 +5707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" dependencies = [ "anyhow", - "bitflags 1.3.2", + "bitflags", "byteorder", "libc", "netlink-packet-core", @@ -5767,7 +5760,7 @@ version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if", "libc", "memoffset 0.6.5", @@ -5779,7 +5772,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if", "libc", "memoffset 0.7.1", @@ -6305,7 +6298,7 @@ name = "pallet-contracts" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" dependencies = [ - "bitflags 1.3.2", + "bitflags", "environmental", "frame-benchmarking", "frame-support", @@ -6335,7 +6328,7 @@ name = "pallet-contracts-primitives" version = "7.0.0" source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" dependencies = [ - "bitflags 1.3.2", + "bitflags", "parity-scale-codec", "scale-info", "sp-runtime", @@ -7198,7 +7191,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.1.11", + "clap 4.1.13", "cumulus-client-cli", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", @@ -7784,7 +7777,7 @@ name = "polkadot-cli" version = "0.9.39" source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" dependencies = [ - "clap 4.1.11", + "clap 4.1.13", "frame-benchmarking-cli", "futures", "log", @@ -8456,7 +8449,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", - "clap 4.1.11", + "clap 4.1.13", "collectives-polkadot-runtime", "contracts-rococo-runtime", "cumulus-client-cli", @@ -8772,7 +8765,7 @@ name = "polkadot-runtime-parachains" version = "0.9.39" source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" dependencies = [ - "bitflags 1.3.2", + "bitflags", "bitvec", "derive_more", "frame-benchmarking", @@ -9574,7 +9567,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] [[package]] @@ -9664,7 +9657,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" dependencies = [ - "bitflags 1.3.2", + "bitflags", "libc", "mach", "winapi", @@ -9975,7 +9968,7 @@ version = "0.35.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes 0.7.5", "libc", @@ -9989,7 +9982,7 @@ version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" dependencies = [ - "bitflags 1.3.2", + "bitflags", "errno", "io-lifetimes 1.0.2", "libc", @@ -10207,7 +10200,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c4 dependencies = [ "array-bytes 4.2.0", "chrono", - "clap 4.1.11", + "clap 4.1.13", "fdlimit", "futures", "libp2p", @@ -10727,7 +10720,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c4 dependencies = [ "array-bytes 4.2.0", "async-trait", - "bitflags 1.3.2", + "bitflags", "bytes", "futures", "futures-timer", @@ -11068,7 +11061,7 @@ name = "sc-storage-monitor" version = "0.1.0" source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" dependencies = [ - "clap 4.1.11", + "clap 4.1.13", "fs4", "futures", "log", @@ -11404,7 +11397,7 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -12004,7 +11997,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c4 dependencies = [ "array-bytes 4.2.0", "base58", - "bitflags 1.3.2", + "bitflags", "blake2", "bounded-collections", "dyn-clonable", @@ -12704,7 +12697,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg_aliases", "libc", "parking_lot 0.11.2", @@ -12989,7 +12982,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "system-configuration-sys", ] @@ -13367,7 +13360,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" dependencies = [ - "bitflags 1.3.2", + "bitflags", "bytes", "futures-core", "futures-util", @@ -13582,7 +13575,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" dependencies = [ "async-trait", - "clap 4.1.11", + "clap 4.1.13", "frame-remote-externalities", "frame-try-runtime", "hex", @@ -14481,7 +14474,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93f1db1727772c05cf7a2cfece52c3aca8045ca1e176cd517d323489aa3c6d87" dependencies = [ "async-trait", - "bitflags 1.3.2", + "bitflags", "bytes", "cc", "ipnet", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index e8aa942907c..a363cabc02d 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2021" [dependencies] -clap = { version = "4.1.11", features = ["derive"] } +clap = { version = "4.1.13", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.3.1" diff --git a/parachain-template/node/Cargo.toml b/parachain-template/node/Cargo.toml index e3c9b1825ad..38fe7b2ba86 100644 --- a/parachain-template/node/Cargo.toml +++ b/parachain-template/node/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" build = "build.rs" [dependencies] -clap = { version = "4.1.11", features = ["derive"] } +clap = { version = "4.1.13", features = ["derive"] } log = "0.4.17" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.156", features = ["derive"] } diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index 32b1e1cabec..83920372198 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -12,7 +12,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.68" -clap = { version = "4.1.11", features = ["derive"] } +clap = { version = "4.1.13", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.27" hex-literal = "0.3.4" diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index 639aa369fef..566655e28d2 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -10,7 +10,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.68" -clap = { version = "4.1.11", features = ["derive"] } +clap = { version = "4.1.13", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.4.0", features = [ "async_tokio" ] } jsonrpsee = { version = "0.16.2", features = ["server"] } From 35d79f3b218f0b44f89ec0b56cf0f4a9c4f63da8 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 28 Mar 2023 09:37:58 +0200 Subject: [PATCH 03/57] Remove HeaderBackend from RelayChainRPCClient (#2385) * Remove HeaderBackend from RelayChainRPCClient * update lockfile for {"substrate", "polkadot"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 520 +++++++++--------- .../src/blockchain_rpc_client.rs | 78 +-- client/relay-chain-minimal-node/src/lib.rs | 22 +- .../relay-chain-minimal-node/src/network.rs | 31 +- 4 files changed, 288 insertions(+), 363 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b1eafbf02b8..fee1e2f3fc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -529,7 +529,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "hash-db", "log", @@ -3324,7 +3324,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", ] @@ -3347,7 +3347,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-support-procedural", @@ -3372,7 +3372,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -3419,7 +3419,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3430,7 +3430,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3447,7 +3447,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -3476,7 +3476,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "log", @@ -3492,7 +3492,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "bitflags", "environmental", @@ -3525,7 +3525,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "Inflector", "cfg-expr", @@ -3540,7 +3540,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3552,7 +3552,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro2", "quote", @@ -3562,7 +3562,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "log", @@ -3580,7 +3580,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -3595,7 +3595,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "sp-api", @@ -3604,7 +3604,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "parity-scale-codec", @@ -4567,7 +4567,7 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "frame-benchmarking", @@ -4665,7 +4665,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "frame-support", "polkadot-primitives", @@ -5507,7 +5507,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "log", @@ -5526,7 +5526,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "anyhow", "jsonrpsee", @@ -5945,9 +5945,9 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "orchestra" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e7d5b6bb115db09390bed8842c94180893dd83df3dfce7354f2a2aa090a4ee" +checksum = "227585216d05ba65c7ab0a0450a3cf2cbd81a98862a54c4df8e14d5ac6adb015" dependencies = [ "async-trait", "dyn-clonable", @@ -5962,9 +5962,9 @@ dependencies = [ [[package]] name = "orchestra-proc-macro" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2af4dabb2286b0be0e9711d2d24e25f6217048b71210cffd3daddc3b5c84e1f" +checksum = "2871aadd82a2c216ee68a69837a526dfe788ecbe74c4c5038a6acdbff6653066" dependencies = [ "expander 0.0.6", "itertools", @@ -6015,7 +6015,7 @@ dependencies = [ [[package]] name = "pallet-alliance" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -6036,7 +6036,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6054,7 +6054,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6069,7 +6069,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6085,7 +6085,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6101,7 +6101,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6115,7 +6115,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6139,7 +6139,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6159,7 +6159,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6174,7 +6174,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6193,7 +6193,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6217,7 +6217,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6235,7 +6235,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6279,7 +6279,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6296,7 +6296,7 @@ dependencies = [ [[package]] name = "pallet-contracts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "bitflags", "environmental", @@ -6326,7 +6326,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "bitflags", "parity-scale-codec", @@ -6339,7 +6339,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro2", "quote", @@ -6349,7 +6349,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6366,7 +6366,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6384,7 +6384,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6407,7 +6407,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6420,7 +6420,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6438,7 +6438,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6456,7 +6456,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6479,7 +6479,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6495,7 +6495,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6515,7 +6515,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6532,7 +6532,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6546,7 +6546,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6563,7 +6563,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6580,7 +6580,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6596,7 +6596,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6614,7 +6614,7 @@ dependencies = [ [[package]] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "pallet-nfts", @@ -6625,7 +6625,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6641,7 +6641,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6658,7 +6658,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6678,7 +6678,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6689,7 +6689,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6706,7 +6706,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6730,7 +6730,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6747,7 +6747,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6762,7 +6762,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6780,7 +6780,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6795,7 +6795,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6814,7 +6814,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6831,7 +6831,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6852,7 +6852,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6868,7 +6868,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6882,7 +6882,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6905,7 +6905,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6916,7 +6916,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "log", "sp-arithmetic", @@ -6925,7 +6925,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "sp-api", @@ -6934,7 +6934,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6951,7 +6951,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -6980,7 +6980,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -6998,7 +6998,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -7017,7 +7017,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-support", "frame-system", @@ -7033,7 +7033,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7049,7 +7049,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7061,7 +7061,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -7078,7 +7078,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -7093,7 +7093,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -7109,7 +7109,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -7124,7 +7124,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-benchmarking", "frame-support", @@ -7139,7 +7139,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7160,7 +7160,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "frame-benchmarking", "frame-support", @@ -7702,7 +7702,7 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "polkadot-node-metrics", @@ -7717,7 +7717,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7731,7 +7731,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "derive_more", "fatality", @@ -7754,7 +7754,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "fatality", "futures", @@ -7775,7 +7775,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "clap 4.1.13", "frame-benchmarking-cli", @@ -7803,7 +7803,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "frame-benchmarking", @@ -7846,7 +7846,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "always-assert", "bitvec", @@ -7868,7 +7868,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "parity-scale-codec", "scale-info", @@ -7880,7 +7880,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "derive_more", "fatality", @@ -7905,7 +7905,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7919,7 +7919,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "futures-timer", @@ -7939,7 +7939,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "always-assert", "async-trait", @@ -7962,7 +7962,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "parity-scale-codec", @@ -7980,7 +7980,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "derive_more", @@ -8009,7 +8009,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "futures", @@ -8030,7 +8030,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "fatality", @@ -8049,7 +8049,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8064,7 +8064,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "futures", @@ -8084,7 +8084,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "polkadot-node-metrics", @@ -8099,7 +8099,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "futures-timer", @@ -8116,7 +8116,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "fatality", "futures", @@ -8135,7 +8135,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "futures", @@ -8152,7 +8152,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "fatality", @@ -8170,7 +8170,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "always-assert", "assert_matches", @@ -8206,7 +8206,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "polkadot-node-primitives", @@ -8222,7 +8222,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "futures", "lru 0.9.0", @@ -8237,7 +8237,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "lazy_static", "log", @@ -8255,7 +8255,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bs58", "futures", @@ -8274,7 +8274,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "derive_more", @@ -8296,7 +8296,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bounded-vec", "futures", @@ -8319,7 +8319,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8329,7 +8329,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "futures", @@ -8347,7 +8347,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "derive_more", @@ -8370,7 +8370,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "derive_more", @@ -8403,7 +8403,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "futures", @@ -8426,7 +8426,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bounded-collections", "derive_more", @@ -8523,7 +8523,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -8539,7 +8539,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "hex-literal", @@ -8565,7 +8565,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8597,7 +8597,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "frame-benchmarking", @@ -8691,7 +8691,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "frame-benchmarking", @@ -8737,7 +8737,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "frame-support", "polkadot-primitives", @@ -8751,7 +8751,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bs58", "parity-scale-codec", @@ -8763,7 +8763,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitflags", "bitvec", @@ -8807,7 +8807,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "async-trait", "frame-benchmarking-cli", @@ -8917,7 +8917,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -8938,7 +8938,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -8948,7 +8948,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -8973,7 +8973,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "frame-election-provider-support", @@ -9034,7 +9034,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "frame-benchmarking", "frame-system", @@ -9770,7 +9770,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9856,7 +9856,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "frame-support", "polkadot-primitives", @@ -10089,7 +10089,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "log", "sp-core", @@ -10100,7 +10100,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "futures", @@ -10128,7 +10128,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "futures-timer", @@ -10151,7 +10151,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10166,7 +10166,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10185,7 +10185,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10196,7 +10196,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -10236,7 +10236,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "fnv", "futures", @@ -10262,7 +10262,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "hash-db", "kvdb", @@ -10288,7 +10288,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "futures", @@ -10313,7 +10313,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "futures", @@ -10342,7 +10342,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "fork-tree", @@ -10381,7 +10381,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "jsonrpsee", @@ -10403,7 +10403,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10438,7 +10438,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "jsonrpsee", @@ -10457,7 +10457,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10470,7 +10470,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "ahash 0.8.2", "array-bytes 4.2.0", @@ -10510,7 +10510,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "finality-grandpa", "futures", @@ -10530,7 +10530,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "futures", @@ -10553,7 +10553,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10577,7 +10577,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10590,7 +10590,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "log", "sc-allocator", @@ -10603,7 +10603,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "anyhow", "cfg-if", @@ -10621,7 +10621,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "ansi_term", "futures", @@ -10637,7 +10637,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10652,7 +10652,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10696,7 +10696,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "cid", "futures", @@ -10716,7 +10716,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10744,7 +10744,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "ahash 0.8.2", "futures", @@ -10763,7 +10763,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10785,7 +10785,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10819,7 +10819,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10839,7 +10839,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10870,7 +10870,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "libp2p", @@ -10883,7 +10883,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10892,7 +10892,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "jsonrpsee", @@ -10922,7 +10922,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10941,7 +10941,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "http", "jsonrpsee", @@ -10956,7 +10956,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10982,7 +10982,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "directories", @@ -11048,7 +11048,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "log", "parity-scale-codec", @@ -11059,7 +11059,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "clap 4.1.13", "fs4", @@ -11075,7 +11075,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11094,7 +11094,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "libc", @@ -11113,7 +11113,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "chrono", "futures", @@ -11132,7 +11132,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "ansi_term", "atty", @@ -11163,7 +11163,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11174,7 +11174,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "futures", @@ -11201,7 +11201,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "futures", @@ -11215,7 +11215,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-channel", "futures", @@ -11696,7 +11696,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "enumn", "parity-scale-codec", @@ -11773,7 +11773,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "hash-db", "log", @@ -11791,7 +11791,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "Inflector", "blake2", @@ -11805,7 +11805,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "scale-info", @@ -11818,7 +11818,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "integer-sqrt", "num-traits", @@ -11832,7 +11832,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "scale-info", @@ -11845,7 +11845,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "sp-api", @@ -11857,7 +11857,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "log", @@ -11875,7 +11875,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "futures", @@ -11890,7 +11890,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "parity-scale-codec", @@ -11908,7 +11908,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "merlin", @@ -11931,7 +11931,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11950,7 +11950,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "finality-grandpa", "log", @@ -11968,7 +11968,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "scale-info", @@ -11980,7 +11980,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "scale-info", @@ -11993,7 +11993,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "base58", @@ -12036,7 +12036,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "blake2b_simd", "byteorder", @@ -12050,7 +12050,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro2", "quote", @@ -12061,7 +12061,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12070,7 +12070,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro2", "quote", @@ -12080,7 +12080,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "environmental", "parity-scale-codec", @@ -12091,7 +12091,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12106,7 +12106,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "bytes", "ed25519", @@ -12131,7 +12131,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "lazy_static", "sp-core", @@ -12142,7 +12142,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "merlin", @@ -12158,7 +12158,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "thiserror", "zstd", @@ -12167,7 +12167,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12185,7 +12185,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "scale-info", @@ -12199,7 +12199,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "sp-api", "sp-core", @@ -12209,7 +12209,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "backtrace", "lazy_static", @@ -12219,7 +12219,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "rustc-hash", "serde", @@ -12229,7 +12229,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "either", "hash256-std-hasher", @@ -12251,7 +12251,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12269,7 +12269,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "Inflector", "proc-macro-crate", @@ -12281,7 +12281,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "serde", "serde_json", @@ -12290,7 +12290,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "scale-info", @@ -12304,7 +12304,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "scale-info", @@ -12316,7 +12316,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "hash-db", "log", @@ -12336,12 +12336,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12354,7 +12354,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "futures-timer", @@ -12369,7 +12369,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "sp-std", @@ -12381,7 +12381,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "sp-api", "sp-runtime", @@ -12390,7 +12390,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "log", @@ -12406,7 +12406,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "ahash 0.8.2", "hash-db", @@ -12429,7 +12429,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12446,7 +12446,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12457,7 +12457,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12471,7 +12471,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "parity-scale-codec", "scale-info", @@ -12795,7 +12795,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "platforms", ] @@ -12803,7 +12803,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12822,7 +12822,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "hyper", "log", @@ -12834,7 +12834,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "jsonrpsee", @@ -12847,7 +12847,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "jsonrpsee", "log", @@ -12866,7 +12866,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -12892,7 +12892,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12902,7 +12902,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12913,7 +12913,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "ansi_term", "build-helper", @@ -13040,7 +13040,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "frame-support", "polkadot-primitives", @@ -13431,7 +13431,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13442,7 +13442,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -13572,7 +13572,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bf395c8308c481a9774373e0b0b14bd7a2e4b8d2" +source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" dependencies = [ "async-trait", "clap 4.1.13", @@ -14500,7 +14500,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bitvec", "frame-benchmarking", @@ -14592,7 +14592,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "frame-support", "polkadot-primitives", @@ -15028,7 +15028,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "bounded-collections", "derivative", @@ -15044,7 +15044,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "frame-support", "frame-system", @@ -15065,7 +15065,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "environmental", "frame-benchmarking", @@ -15085,7 +15085,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#27ddd270c3979fd2a5e2ac6fb3c9d474962c9260" +source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" dependencies = [ "Inflector", "proc-macro2", diff --git a/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs b/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs index 67f402ad432..b8939df5fd5 100644 --- a/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs +++ b/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs @@ -18,13 +18,11 @@ use std::pin::Pin; use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult}; use cumulus_relay_chain_rpc_interface::RelayChainRpcClient; -use futures::{Future, Stream, StreamExt}; +use futures::{Stream, StreamExt}; use polkadot_core_primitives::{Block, BlockNumber, Hash, Header}; use polkadot_overseer::RuntimeApiSubsystemClient; -use sc_authority_discovery::AuthorityDiscovery; +use sc_authority_discovery::{AuthorityDiscovery, Error as AuthorityDiscoveryError}; use sp_api::{ApiError, RuntimeApiInfo}; -use sp_blockchain::{HeaderBackend, Info}; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; #[derive(Clone)] pub struct BlockChainRpcClient { @@ -312,6 +310,14 @@ impl AuthorityDiscovery for BlockChainRpcClient { let result = self.rpc_client.authority_discovery_authorities(at).await?; Ok(result) } + + async fn best_hash(&self) -> std::result::Result { + self.block_get_hash(None) + .await + .ok() + .flatten() + .ok_or_else(|| AuthorityDiscoveryError::BestBlockFetchingError) + } } impl BlockChainRpcClient { @@ -327,67 +333,3 @@ impl BlockChainRpcClient { Ok(self.rpc_client.get_finalized_heads_stream()?.boxed()) } } - -fn block_local(fut: impl Future) -> T { - let tokio_handle = tokio::runtime::Handle::current(); - tokio::task::block_in_place(|| tokio_handle.block_on(fut)) -} - -impl HeaderBackend for BlockChainRpcClient { - fn header( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result::Header>> { - Ok(block_local(self.rpc_client.chain_get_header(Some(hash)))?) - } - - fn info(&self) -> Info { - let best_header = block_local(self.rpc_client.chain_get_header(None)) - .expect("Unable to get header from relay chain.") - .unwrap(); - let genesis_hash = block_local(self.rpc_client.chain_get_head(Some(0))) - .expect("Unable to get header from relay chain."); - let finalized_head = block_local(self.rpc_client.chain_get_finalized_head()) - .expect("Unable to get finalized head from relay chain."); - let finalized_header = block_local(self.rpc_client.chain_get_header(Some(finalized_head))) - .expect("Unable to get finalized header from relay chain.") - .unwrap(); - Info { - best_hash: best_header.hash(), - best_number: best_header.number, - genesis_hash, - finalized_hash: finalized_head, - finalized_number: finalized_header.number, - finalized_state: None, - number_leaves: 1, - block_gap: None, - } - } - - fn status( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result { - if self.header(hash)?.is_some() { - Ok(sc_client_api::blockchain::BlockStatus::InChain) - } else { - Ok(sc_client_api::blockchain::BlockStatus::Unknown) - } - } - - fn number( - &self, - hash: ::Hash, - ) -> sp_blockchain::Result::Header as HeaderT>::Number>> { - let result = block_local(self.rpc_client.chain_get_header(Some(hash)))? - .map(|maybe_header| maybe_header.number); - Ok(result) - } - - fn hash( - &self, - number: NumberFor, - ) -> sp_blockchain::Result::Hash>> { - Ok(block_local(self.rpc_client.chain_get_block_hash(number.into()))?) - } -} diff --git a/client/relay-chain-minimal-node/src/lib.rs b/client/relay-chain-minimal-node/src/lib.rs index c5c2c2fd6e9..c47f6d08d22 100644 --- a/client/relay-chain-minimal-node/src/lib.rs +++ b/client/relay-chain-minimal-node/src/lib.rs @@ -18,6 +18,7 @@ use collator_overseer::{CollatorOverseerGenArgs, NewMinimalNode}; use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; use cumulus_relay_chain_rpc_interface::{RelayChainRpcInterface, Url}; +use network::build_collator_network; use polkadot_network_bridge::{peer_sets_info, IsAuthority}; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, @@ -149,14 +150,12 @@ async fn new_minimal_relay_chain( let (collation_req_receiver, available_data_req_receiver) = build_request_response_protocol_receivers(&request_protocol_names, &mut config); + let best_header = relay_chain_rpc_client.chain_get_header(None).await?.ok_or_else(|| { + RelayChainError::RpcCallError("Unable to fetch best header".to_string().into()) + })?; let (network, network_starter, sync_oracle) = - network::build_collator_network(network::BuildCollatorNetworkParams { - config: &config, - client: relay_chain_rpc_client.clone(), - spawn_handle: task_manager.spawn_handle(), - genesis_hash, - }) - .map_err(|e| RelayChainError::Application(Box::new(e) as Box<_>))?; + build_collator_network(&config, task_manager.spawn_handle(), genesis_hash, best_header) + .map_err(|e| RelayChainError::Application(Box::new(e) as Box<_>))?; let authority_discovery_service = build_authority_discovery_service( &task_manager, @@ -180,12 +179,9 @@ async fn new_minimal_relay_chain( peer_set_protocol_names, }; - let overseer_handle = collator_overseer::spawn_overseer( - overseer_args, - &task_manager, - relay_chain_rpc_client.clone(), - ) - .map_err(|e| RelayChainError::Application(Box::new(e) as Box<_>))?; + let overseer_handle = + collator_overseer::spawn_overseer(overseer_args, &task_manager, relay_chain_rpc_client) + .map_err(|e| RelayChainError::Application(Box::new(e) as Box<_>))?; network_starter.start_network(); diff --git a/client/relay-chain-minimal-node/src/network.rs b/client/relay-chain-minimal-node/src/network.rs index 0a4ace78ca5..4dff55a65de 100644 --- a/client/relay-chain-minimal-node/src/network.rs +++ b/client/relay-chain-minimal-node/src/network.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use polkadot_core_primitives::{Block, Hash}; +use polkadot_core_primitives::{Block, Hash, Header}; use sp_runtime::traits::{Block as BlockT, NumberFor}; use sc_network::{ @@ -24,45 +24,32 @@ use sc_network::{ NetworkService, }; -use sc_client_api::HeaderBackend; use sc_network_common::{role::Roles, sync::message::BlockAnnouncesHandshake}; use sc_service::{error::Error, Configuration, NetworkStarter, SpawnTaskHandle}; use std::{iter, sync::Arc}; -use crate::BlockChainRpcClient; - -pub(crate) struct BuildCollatorNetworkParams<'a> { - /// The service configuration. - pub config: &'a Configuration, - /// A shared client returned by `new_full_parts`. - pub client: Arc, - /// A handle for spawning tasks. - pub spawn_handle: SpawnTaskHandle, - /// Genesis hash - pub genesis_hash: Hash, -} - /// Build the network service, the network status sinks and an RPC sender. pub(crate) fn build_collator_network( - params: BuildCollatorNetworkParams, + config: &Configuration, + spawn_handle: SpawnTaskHandle, + genesis_hash: Hash, + best_header: Header, ) -> Result< (Arc>, NetworkStarter, Box), Error, > { - let BuildCollatorNetworkParams { config, client, spawn_handle, genesis_hash } = params; - let protocol_id = config.protocol_id(); let block_announce_config = get_block_announce_proto_config::( protocol_id.clone(), &None, Roles::from(&config.role), - client.info().best_number, - client.info().best_hash, + best_header.number, + best_header.hash(), genesis_hash, ); - let network_params = sc_network::config::Params { + let network_params = sc_network::config::Params:: { role: config.role.clone(), executor: { let spawn_handle = Clone::clone(&spawn_handle); @@ -72,7 +59,7 @@ pub(crate) fn build_collator_network( }, fork_id: None, network_config: config.network.clone(), - chain: client.clone(), + genesis_hash, protocol_id, metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, From 0ef1444c48b33e175f12c9f6893f47a1f3cee1c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Mar 2023 11:08:38 +0200 Subject: [PATCH 04/57] Bump scale-info from 2.3.1 to 2.4.0 (#2386) Bumps [scale-info](https://github.com/paritytech/scale-info) from 2.3.1 to 2.4.0. - [Release notes](https://github.com/paritytech/scale-info/releases) - [Changelog](https://github.com/paritytech/scale-info/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/scale-info/compare/v2.3.1...v2.4.0) --- updated-dependencies: - dependency-name: scale-info 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 | 8 ++++---- pallets/aura-ext/Cargo.toml | 2 +- pallets/collator-selection/Cargo.toml | 2 +- pallets/dmp-queue/Cargo.toml | 2 +- pallets/parachain-system/Cargo.toml | 2 +- pallets/solo-to-para/Cargo.toml | 2 +- pallets/xcm/Cargo.toml | 2 +- pallets/xcmp-queue/Cargo.toml | 2 +- parachain-template/runtime/Cargo.toml | 2 +- parachains/common/Cargo.toml | 2 +- parachains/pallets/parachain-info/Cargo.toml | 2 +- parachains/pallets/ping/Cargo.toml | 2 +- parachains/runtimes/assets/statemine/Cargo.toml | 2 +- parachains/runtimes/assets/statemint/Cargo.toml | 2 +- parachains/runtimes/assets/westmint/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 +- parachains/runtimes/contracts/contracts-rococo/Cargo.toml | 2 +- parachains/runtimes/starters/seedling/Cargo.toml | 2 +- parachains/runtimes/starters/shell/Cargo.toml | 2 +- parachains/runtimes/testing/penpal/Cargo.toml | 2 +- parachains/runtimes/testing/rococo-parachain/Cargo.toml | 2 +- primitives/parachain-inherent/Cargo.toml | 2 +- test/runtime/Cargo.toml | 2 +- 26 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fee1e2f3fc4..ba9fbd564c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11229,9 +11229,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "001cf62ece89779fd16105b5f515ad0e5cedcd5440d3dd806bb067978e7c3608" +checksum = "61471dff9096de1d8b2319efed7162081e96793f5ebb147e50db10d50d648a4d" dependencies = [ "bitvec", "cfg-if", @@ -11243,9 +11243,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "303959cf613a6f6efd19ed4b4ad5bf79966a13352716299ad532cfb115f4205c" +checksum = "219580e803a66b3f05761fd06f1f879a872444e49ce23f73694d26e5a954c7e6" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/pallets/aura-ext/Cargo.toml b/pallets/aura-ext/Cargo.toml index 21a558348a7..6eaf27c96ed 100644 --- a/pallets/aura-ext/Cargo.toml +++ b/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.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/collator-selection/Cargo.toml b/pallets/collator-selection/Cargo.toml index 5d7f0aae3f6..9629c7de5cf 100644 --- a/pallets/collator-selection/Cargo.toml +++ b/pallets/collator-selection/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = { version = "0.4.17", 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.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/pallets/dmp-queue/Cargo.toml b/pallets/dmp-queue/Cargo.toml index 313c53dd859..bbf19ad62be 100644 --- a/pallets/dmp-queue/Cargo.toml +++ b/pallets/dmp-queue/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/parachain-system/Cargo.toml b/pallets/parachain-system/Cargo.toml index a1018cf65bf..e793ddc4c19 100644 --- a/pallets/parachain-system/Cargo.toml +++ b/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.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/solo-to-para/Cargo.toml b/pallets/solo-to-para/Cargo.toml index 4d5f8771c0d..ddc2ca56a3b 100644 --- a/pallets/solo-to-para/Cargo.toml +++ b/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.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/xcm/Cargo.toml b/pallets/xcm/Cargo.toml index f207fc37085..e9404b3500d 100644 --- a/pallets/xcm/Cargo.toml +++ b/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.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/xcmp-queue/Cargo.toml b/pallets/xcmp-queue/Cargo.toml index 48ebde53311..acd440f5818 100644 --- a/pallets/xcmp-queue/Cargo.toml +++ b/pallets/xcmp-queue/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } log = { version = "0.4.17", default-features = false } rand_chacha = { version = "0.3.0", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachain-template/runtime/Cargo.toml b/parachain-template/runtime/Cargo.toml index 704c9ea39c3..3724596ceb7 100644 --- a/parachain-template/runtime/Cargo.toml +++ b/parachain-template/runtime/Cargo.toml @@ -18,7 +18,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Local diff --git a/parachains/common/Cargo.toml b/parachains/common/Cargo.toml index 4b525c4525d..f89544d8241 100644 --- a/parachains/common/Cargo.toml +++ b/parachains/common/Cargo.toml @@ -10,7 +10,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.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } diff --git a/parachains/pallets/parachain-info/Cargo.toml b/parachains/pallets/parachain-info/Cargo.toml index ee453bc1846..270cc869a19 100644 --- a/parachains/pallets/parachain-info/Cargo.toml +++ b/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.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachains/pallets/ping/Cargo.toml b/parachains/pallets/ping/Cargo.toml index 0e9a1af8693..fbfcc703644 100644 --- a/parachains/pallets/ping/Cargo.toml +++ b/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.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachains/runtimes/assets/statemine/Cargo.toml b/parachains/runtimes/assets/statemine/Cargo.toml index 31f34516a5c..694f19a274b 100644 --- a/parachains/runtimes/assets/statemine/Cargo.toml +++ b/parachains/runtimes/assets/statemine/Cargo.toml @@ -9,7 +9,7 @@ description = "Kusama variant of Statemint parachain runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.3.4" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/assets/statemint/Cargo.toml b/parachains/runtimes/assets/statemint/Cargo.toml index a8de1be1994..cee4c46dbb2 100644 --- a/parachains/runtimes/assets/statemint/Cargo.toml +++ b/parachains/runtimes/assets/statemint/Cargo.toml @@ -9,7 +9,7 @@ description = "Statemint parachain runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/assets/westmint/Cargo.toml b/parachains/runtimes/assets/westmint/Cargo.toml index c08d432ec33..dc2574e8b8a 100644 --- a/parachains/runtimes/assets/westmint/Cargo.toml +++ b/parachains/runtimes/assets/westmint/Cargo.toml @@ -9,7 +9,7 @@ description = "Westend variant of Statemint parachain runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml index 4dbbd829c88..5428dc08a43 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } serde = { version = "1.0.156", optional = true, features = ["derive"] } smallvec = "1.8.1" diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml index 692345116b4..51765638c7f 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } serde = { version = "1.0.156", optional = true, features = ["derive"] } smallvec = "1.8.1" diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 4512d45d505..43d9484658d 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } serde = { version = "1.0.156", optional = true, features = ["derive"] } smallvec = "1.8.1" diff --git a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 77c08d63c6f..04609ca594c 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/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.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index a43fce8e1ca..fcca53c1695 100644 --- a/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -14,7 +14,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/starters/seedling/Cargo.toml b/parachains/runtimes/starters/seedling/Cargo.toml index 7bf6b85dd3f..f26906da461 100644 --- a/parachains/runtimes/starters/seedling/Cargo.toml +++ b/parachains/runtimes/starters/seedling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachains/runtimes/starters/shell/Cargo.toml b/parachains/runtimes/starters/shell/Cargo.toml index e36d5a30393..22efd8f8bef 100644 --- a/parachains/runtimes/starters/shell/Cargo.toml +++ b/parachains/runtimes/starters/shell/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachains/runtimes/testing/penpal/Cargo.toml b/parachains/runtimes/testing/penpal/Cargo.toml index 3e2af43ce63..85d115f06ac 100644 --- a/parachains/runtimes/testing/penpal/Cargo.toml +++ b/parachains/runtimes/testing/penpal/Cargo.toml @@ -18,7 +18,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.16", default-features = false } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 65cd4bafeaa..14ea9a04292 100644 --- a/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -7,7 +7,7 @@ description = "Simple runtime used by the rococo parachain(s)" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { git = "https://github.com/paritytech/substrate", optional = true, default-features = false, branch = "master" } diff --git a/primitives/parachain-inherent/Cargo.toml b/primitives/parachain-inherent/Cargo.toml index 361d0e328ba..7fec7149975 100644 --- a/primitives/parachain-inherent/Cargo.toml +++ b/primitives/parachain-inherent/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] async-trait = { version = "0.1.68", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } tracing = { version = "0.1.37", optional = true } # Substrate diff --git a/test/runtime/Cargo.toml b/test/runtime/Cargo.toml index c4e350b20b3..be7c531f57f 100644 --- a/test/runtime/Cargo.toml +++ b/test/runtime/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.3.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } From 066db6b95f6f83d38893d5151946866bb401b4f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Mar 2023 13:24:31 +0200 Subject: [PATCH 05/57] Bump serde_json from 1.0.94 to 1.0.95 (#2387) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.94 to 1.0.95. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.94...v1.0.95) --- updated-dependencies: - dependency-name: serde_json 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 | 4 ++-- client/relay-chain-rpc-interface/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba9fbd564c0..5d5750dbdda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11498,9 +11498,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa 1.0.4", "ryu", diff --git a/client/relay-chain-rpc-interface/Cargo.toml b/client/relay-chain-rpc-interface/Cargo.toml index 91afe09910e..3f2195e300a 100644 --- a/client/relay-chain-rpc-interface/Cargo.toml +++ b/client/relay-chain-rpc-interface/Cargo.toml @@ -30,6 +30,6 @@ jsonrpsee = { version = "0.16.2", features = ["ws-client"] } tracing = "0.1.37" async-trait = "0.1.68" url = "2.3.1" -serde_json = "1.0.94" +serde_json = "1.0.95" serde = "1.0.156" lru = "0.9.0" From 1d8208b184eb70bc76cac60628630729c3002f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Wed, 29 Mar 2023 12:37:13 +0200 Subject: [PATCH 06/57] Companion: wasm-builder support stable Rust (#2393) * Companion: wasm-builder support stable Rust * update lockfile for {"polkadot", "substrate"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 517 +++++++++++++++++++++++++++-------------------------- 1 file changed, 259 insertions(+), 258 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d5750dbdda..99f929afc36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -529,7 +529,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "hash-db", "log", @@ -3324,7 +3324,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", ] @@ -3347,7 +3347,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-support-procedural", @@ -3372,7 +3372,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -3419,7 +3419,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3430,7 +3430,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3447,7 +3447,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -3476,7 +3476,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "log", @@ -3492,7 +3492,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "bitflags", "environmental", @@ -3525,7 +3525,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "Inflector", "cfg-expr", @@ -3540,7 +3540,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3552,7 +3552,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro2", "quote", @@ -3562,7 +3562,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "log", @@ -3580,7 +3580,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -3595,7 +3595,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "sp-api", @@ -3604,7 +3604,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "parity-scale-codec", @@ -4567,7 +4567,7 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "frame-benchmarking", @@ -4665,7 +4665,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "frame-support", "polkadot-primitives", @@ -5507,7 +5507,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "log", @@ -5526,7 +5526,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "anyhow", "jsonrpsee", @@ -6015,7 +6015,7 @@ dependencies = [ [[package]] name = "pallet-alliance" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -6036,7 +6036,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6054,7 +6054,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6069,7 +6069,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6085,7 +6085,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6101,7 +6101,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6115,7 +6115,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6139,7 +6139,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6159,7 +6159,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6174,7 +6174,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6193,7 +6193,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6217,7 +6217,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6235,7 +6235,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6279,7 +6279,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6296,7 +6296,7 @@ dependencies = [ [[package]] name = "pallet-contracts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "bitflags", "environmental", @@ -6326,7 +6326,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "bitflags", "parity-scale-codec", @@ -6339,7 +6339,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro2", "quote", @@ -6349,7 +6349,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6366,7 +6366,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6384,7 +6384,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6407,7 +6407,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6420,7 +6420,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6438,7 +6438,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6456,7 +6456,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6479,7 +6479,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6495,7 +6495,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6515,7 +6515,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6532,7 +6532,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6546,7 +6546,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6563,7 +6563,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6580,7 +6580,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6596,7 +6596,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6614,7 +6614,7 @@ dependencies = [ [[package]] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "pallet-nfts", @@ -6625,7 +6625,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6641,7 +6641,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6658,7 +6658,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6678,7 +6678,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6689,7 +6689,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6706,7 +6706,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6730,7 +6730,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6747,7 +6747,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6762,7 +6762,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6780,7 +6780,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6795,7 +6795,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6814,7 +6814,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6831,7 +6831,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6852,7 +6852,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6868,7 +6868,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6882,7 +6882,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6905,7 +6905,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6916,7 +6916,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "log", "sp-arithmetic", @@ -6925,7 +6925,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "sp-api", @@ -6934,7 +6934,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6951,7 +6951,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -6980,7 +6980,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -6998,7 +6998,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -7017,7 +7017,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-support", "frame-system", @@ -7033,7 +7033,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7049,7 +7049,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7061,7 +7061,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -7078,7 +7078,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -7093,7 +7093,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -7109,7 +7109,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -7124,7 +7124,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-benchmarking", "frame-support", @@ -7139,7 +7139,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7160,7 +7160,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "frame-benchmarking", "frame-support", @@ -7702,7 +7702,7 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "polkadot-node-metrics", @@ -7717,7 +7717,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7731,7 +7731,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "derive_more", "fatality", @@ -7754,7 +7754,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "fatality", "futures", @@ -7775,7 +7775,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "clap 4.1.13", "frame-benchmarking-cli", @@ -7803,7 +7803,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "frame-benchmarking", @@ -7846,7 +7846,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "always-assert", "bitvec", @@ -7868,7 +7868,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "parity-scale-codec", "scale-info", @@ -7880,7 +7880,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "derive_more", "fatality", @@ -7905,7 +7905,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7919,7 +7919,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "futures-timer", @@ -7939,7 +7939,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "always-assert", "async-trait", @@ -7962,7 +7962,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "parity-scale-codec", @@ -7980,7 +7980,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "derive_more", @@ -8009,7 +8009,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "futures", @@ -8030,7 +8030,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "fatality", @@ -8049,7 +8049,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8064,7 +8064,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "futures", @@ -8084,7 +8084,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "polkadot-node-metrics", @@ -8099,7 +8099,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "futures-timer", @@ -8116,7 +8116,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "fatality", "futures", @@ -8135,7 +8135,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "futures", @@ -8152,7 +8152,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "fatality", @@ -8170,7 +8170,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "always-assert", "assert_matches", @@ -8206,7 +8206,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "polkadot-node-primitives", @@ -8222,7 +8222,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "futures", "lru 0.9.0", @@ -8237,7 +8237,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "lazy_static", "log", @@ -8255,7 +8255,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bs58", "futures", @@ -8274,7 +8274,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "derive_more", @@ -8296,7 +8296,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bounded-vec", "futures", @@ -8319,7 +8319,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8329,7 +8329,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "futures", @@ -8347,7 +8347,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "derive_more", @@ -8370,7 +8370,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "derive_more", @@ -8403,7 +8403,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "futures", @@ -8426,7 +8426,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bounded-collections", "derive_more", @@ -8523,7 +8523,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -8539,7 +8539,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "hex-literal", @@ -8565,7 +8565,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8597,7 +8597,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "frame-benchmarking", @@ -8691,7 +8691,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "frame-benchmarking", @@ -8737,7 +8737,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "frame-support", "polkadot-primitives", @@ -8751,7 +8751,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bs58", "parity-scale-codec", @@ -8763,7 +8763,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitflags", "bitvec", @@ -8807,7 +8807,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "async-trait", "frame-benchmarking-cli", @@ -8917,7 +8917,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -8938,7 +8938,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -8948,7 +8948,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -8973,7 +8973,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "frame-election-provider-support", @@ -9034,7 +9034,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "frame-benchmarking", "frame-system", @@ -9770,7 +9770,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9856,7 +9856,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "frame-support", "polkadot-primitives", @@ -10038,9 +10038,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.5" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "rw-stream-sink" @@ -10089,7 +10089,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "log", "sp-core", @@ -10100,7 +10100,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "futures", @@ -10128,7 +10128,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "futures-timer", @@ -10151,7 +10151,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10166,7 +10166,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10185,7 +10185,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10196,7 +10196,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -10236,7 +10236,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "fnv", "futures", @@ -10262,7 +10262,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "hash-db", "kvdb", @@ -10288,7 +10288,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "futures", @@ -10313,7 +10313,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "futures", @@ -10342,7 +10342,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "fork-tree", @@ -10381,7 +10381,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "jsonrpsee", @@ -10403,7 +10403,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10438,7 +10438,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "jsonrpsee", @@ -10457,7 +10457,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10470,7 +10470,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "ahash 0.8.2", "array-bytes 4.2.0", @@ -10510,7 +10510,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "finality-grandpa", "futures", @@ -10530,7 +10530,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "futures", @@ -10553,7 +10553,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10577,7 +10577,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10590,7 +10590,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "log", "sc-allocator", @@ -10603,7 +10603,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "anyhow", "cfg-if", @@ -10621,7 +10621,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "ansi_term", "futures", @@ -10637,7 +10637,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10652,7 +10652,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10696,7 +10696,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "cid", "futures", @@ -10716,7 +10716,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10744,7 +10744,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "ahash 0.8.2", "futures", @@ -10763,7 +10763,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10785,7 +10785,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10819,7 +10819,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10839,7 +10839,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10870,7 +10870,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "libp2p", @@ -10883,7 +10883,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10892,7 +10892,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "jsonrpsee", @@ -10922,7 +10922,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10941,7 +10941,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "http", "jsonrpsee", @@ -10956,7 +10956,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10982,7 +10982,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "directories", @@ -11048,7 +11048,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "log", "parity-scale-codec", @@ -11059,7 +11059,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "clap 4.1.13", "fs4", @@ -11075,7 +11075,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11094,7 +11094,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "libc", @@ -11113,7 +11113,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "chrono", "futures", @@ -11132,7 +11132,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "ansi_term", "atty", @@ -11163,7 +11163,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11174,7 +11174,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "futures", @@ -11201,7 +11201,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "futures", @@ -11215,7 +11215,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-channel", "futures", @@ -11696,7 +11696,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "enumn", "parity-scale-codec", @@ -11773,7 +11773,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "hash-db", "log", @@ -11791,7 +11791,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "Inflector", "blake2", @@ -11805,7 +11805,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11818,7 +11818,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "integer-sqrt", "num-traits", @@ -11832,7 +11832,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11845,7 +11845,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "sp-api", @@ -11857,7 +11857,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "log", @@ -11875,7 +11875,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "futures", @@ -11890,7 +11890,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "parity-scale-codec", @@ -11908,7 +11908,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "merlin", @@ -11931,7 +11931,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11950,7 +11950,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "finality-grandpa", "log", @@ -11968,7 +11968,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11980,7 +11980,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "scale-info", @@ -11993,7 +11993,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "base58", @@ -12036,7 +12036,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "blake2b_simd", "byteorder", @@ -12050,7 +12050,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro2", "quote", @@ -12061,7 +12061,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12070,7 +12070,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro2", "quote", @@ -12080,7 +12080,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "environmental", "parity-scale-codec", @@ -12091,7 +12091,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12106,7 +12106,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "bytes", "ed25519", @@ -12115,6 +12115,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", + "rustversion", "secp256k1", "sp-core", "sp-externalities", @@ -12131,7 +12132,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "lazy_static", "sp-core", @@ -12142,7 +12143,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "merlin", @@ -12158,7 +12159,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "thiserror", "zstd", @@ -12167,7 +12168,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12185,7 +12186,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "scale-info", @@ -12199,7 +12200,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "sp-api", "sp-core", @@ -12209,7 +12210,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "backtrace", "lazy_static", @@ -12219,7 +12220,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "rustc-hash", "serde", @@ -12229,7 +12230,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "either", "hash256-std-hasher", @@ -12251,7 +12252,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12269,7 +12270,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "Inflector", "proc-macro-crate", @@ -12281,7 +12282,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "serde", "serde_json", @@ -12290,7 +12291,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "scale-info", @@ -12304,7 +12305,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "scale-info", @@ -12316,7 +12317,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "hash-db", "log", @@ -12336,12 +12337,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12354,7 +12355,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "futures-timer", @@ -12369,7 +12370,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "sp-std", @@ -12381,7 +12382,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "sp-api", "sp-runtime", @@ -12390,7 +12391,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "log", @@ -12406,7 +12407,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "ahash 0.8.2", "hash-db", @@ -12429,7 +12430,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12446,7 +12447,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12457,7 +12458,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12471,7 +12472,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "parity-scale-codec", "scale-info", @@ -12795,7 +12796,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "platforms", ] @@ -12803,7 +12804,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12822,7 +12823,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "hyper", "log", @@ -12834,7 +12835,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "jsonrpsee", @@ -12847,7 +12848,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "jsonrpsee", "log", @@ -12866,7 +12867,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -12892,7 +12893,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12902,7 +12903,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12913,7 +12914,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "ansi_term", "build-helper", @@ -13040,7 +13041,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "frame-support", "polkadot-primitives", @@ -13431,7 +13432,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13442,7 +13443,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -13572,7 +13573,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#9b43d8f891b1e53be2aa55687632ac6b17800cf8" +source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" dependencies = [ "async-trait", "clap 4.1.13", @@ -14500,7 +14501,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bitvec", "frame-benchmarking", @@ -14592,7 +14593,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "frame-support", "polkadot-primitives", @@ -15028,7 +15029,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "bounded-collections", "derivative", @@ -15044,7 +15045,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "frame-support", "frame-system", @@ -15065,7 +15066,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "environmental", "frame-benchmarking", @@ -15085,7 +15086,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#bebd1a788ecccfa1a6adc61004e4f700988f40d4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" dependencies = [ "Inflector", "proc-macro2", From 559f3caa2b621dcba57b4806fe50f1ec095338a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 13:50:40 +0000 Subject: [PATCH 07/57] Bump thiserror from 1.0.38 to 1.0.40 (#2396) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.38 to 1.0.40. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.38...1.0.40) --- 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> --- Cargo.lock | 10 +++++----- client/relay-chain-interface/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99f929afc36..f22e30f4171 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13060,22 +13060,22 @@ checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.9", ] [[package]] diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index 9583d78b613..11d0f6d96a6 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -16,6 +16,6 @@ sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "mas futures = "0.3.27" async-trait = "0.1.68" -thiserror = "1.0.38" +thiserror = "1.0.40" jsonrpsee-core = "0.16.2" parity-scale-codec = "3.4.0" From 69dd6ae5f7c4b36146b684a27810fd8434e76b58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 21:50:17 +0200 Subject: [PATCH 08/57] Bump syn from 1.0.109 to 2.0.9 (#2397) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.109 to 2.0.9. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.109...2.0.9) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 2 +- pallets/parachain-system/proc-macro/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f22e30f4171..0acb8c0c188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2098,7 +2098,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.9", ] [[package]] diff --git a/pallets/parachain-system/proc-macro/Cargo.toml b/pallets/parachain-system/proc-macro/Cargo.toml index fa975eb0b84..e3f9487d8c1 100644 --- a/pallets/parachain-system/proc-macro/Cargo.toml +++ b/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 = "1.0.109" +syn = "2.0.9" proc-macro2 = "1.0.52" quote = "1.0.26" proc-macro-crate = "1.3.1" From 247e843011c03e9837849e811b47e66630625ef0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 21:50:45 +0200 Subject: [PATCH 09/57] Bump serde from 1.0.156 to 1.0.159 (#2395) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.156 to 1.0.159. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.156...v1.0.159) --- updated-dependencies: - dependency-name: serde 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 | 10 +++++----- client/relay-chain-rpc-interface/Cargo.toml | 2 +- parachain-template/node/Cargo.toml | 2 +- .../runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-polkadot/Cargo.toml | 2 +- .../runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- polkadot-parachain/Cargo.toml | 2 +- test/service/Cargo.toml | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0acb8c0c188..4084da626bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11478,22 +11478,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.156" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.156" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.9", ] [[package]] diff --git a/client/relay-chain-rpc-interface/Cargo.toml b/client/relay-chain-rpc-interface/Cargo.toml index 3f2195e300a..34458a4510e 100644 --- a/client/relay-chain-rpc-interface/Cargo.toml +++ b/client/relay-chain-rpc-interface/Cargo.toml @@ -31,5 +31,5 @@ tracing = "0.1.37" async-trait = "0.1.68" url = "2.3.1" serde_json = "1.0.95" -serde = "1.0.156" +serde = "1.0.159" lru = "0.9.0" diff --git a/parachain-template/node/Cargo.toml b/parachain-template/node/Cargo.toml index 38fe7b2ba86..ba828fae060 100644 --- a/parachain-template/node/Cargo.toml +++ b/parachain-template/node/Cargo.toml @@ -13,7 +13,7 @@ build = "build.rs" clap = { version = "4.1.13", features = ["derive"] } log = "0.4.17" codec = { package = "parity-scale-codec", version = "3.0.0" } -serde = { version = "1.0.156", features = ["derive"] } +serde = { version = "1.0.159", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } # Local diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml index 5428dc08a43..4b2cf6a5737 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/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.3.4" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.156", optional = true, features = ["derive"] } +serde = { version = "1.0.159", optional = true, features = ["derive"] } smallvec = "1.8.1" # Substrate diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml index 51765638c7f..9526bd8e3b9 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/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.3.4" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.156", optional = true, features = ["derive"] } +serde = { version = "1.0.159", optional = true, features = ["derive"] } smallvec = "1.8.1" # Substrate diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 43d9484658d..5599231c678 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/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.3.4" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.156", optional = true, features = ["derive"] } +serde = { version = "1.0.159", optional = true, features = ["derive"] } smallvec = "1.8.1" # Substrate diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index 83920372198..0f6ebbd9a3a 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.27" hex-literal = "0.3.4" log = "0.4.17" -serde = { version = "1.0.156", features = ["derive"] } +serde = { version = "1.0.159", features = ["derive"] } # Local rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index 566655e28d2..ff88ae5b84f 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -15,7 +15,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.4.0", features = [ "async_tokio" ] } jsonrpsee = { version = "0.16.2", features = ["server"] } rand = "0.8.5" -serde = { version = "1.0.156", features = ["derive"] } +serde = { version = "1.0.159", features = ["derive"] } tokio = { version = "1.26.0", features = ["macros"] } tracing = "0.1.37" url = "2.3.1" From 2ce882fff03353f1479dc7890631b017732f1224 Mon Sep 17 00:00:00 2001 From: Aaro Altonen <48052676+altonen@users.noreply.github.com> Date: Thu, 30 Mar 2023 15:33:14 +0300 Subject: [PATCH 10/57] Companion for https://github.com/paritytech/substrate/pull/13725 (#2401) * Companion for https://github.com/paritytech/substrate/pull/13725 * Add comment * update lockfile for {"substrate", "polkadot"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 522 +++++++++--------- client/relay-chain-minimal-node/Cargo.toml | 1 + .../relay-chain-minimal-node/src/network.rs | 4 + 3 files changed, 264 insertions(+), 263 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4084da626bd..098e5450813 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -499,12 +499,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base58" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" - [[package]] name = "base64" version = "0.13.0" @@ -529,7 +523,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "hash-db", "log", @@ -2324,6 +2318,7 @@ dependencies = [ "sc-network-common", "sc-service", "sc-tracing", + "sc-utils", "sp-api", "sp-blockchain", "sp-consensus", @@ -3324,7 +3319,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", ] @@ -3347,7 +3342,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-support-procedural", @@ -3372,7 +3367,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -3419,7 +3414,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3430,7 +3425,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3447,7 +3442,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -3476,7 +3471,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "log", @@ -3492,7 +3487,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "bitflags", "environmental", @@ -3525,7 +3520,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "Inflector", "cfg-expr", @@ -3540,7 +3535,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3552,7 +3547,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro2", "quote", @@ -3562,7 +3557,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "log", @@ -3580,7 +3575,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -3595,7 +3590,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "sp-api", @@ -3604,7 +3599,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "parity-scale-codec", @@ -4567,7 +4562,7 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "frame-benchmarking", @@ -4665,7 +4660,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "frame-support", "polkadot-primitives", @@ -5507,7 +5502,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "log", @@ -5526,7 +5521,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "anyhow", "jsonrpsee", @@ -6015,7 +6010,7 @@ dependencies = [ [[package]] name = "pallet-alliance" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -6036,7 +6031,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6054,7 +6049,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6069,7 +6064,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6085,7 +6080,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6101,7 +6096,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6115,7 +6110,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6139,7 +6134,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6159,7 +6154,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6174,7 +6169,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6193,7 +6188,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6217,7 +6212,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6235,7 +6230,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6279,7 +6274,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6296,7 +6291,7 @@ dependencies = [ [[package]] name = "pallet-contracts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "bitflags", "environmental", @@ -6326,7 +6321,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "bitflags", "parity-scale-codec", @@ -6339,7 +6334,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro2", "quote", @@ -6349,7 +6344,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6366,7 +6361,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6384,7 +6379,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6407,7 +6402,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6420,7 +6415,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6438,7 +6433,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6456,7 +6451,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6479,7 +6474,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6495,7 +6490,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6515,7 +6510,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6532,7 +6527,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6546,7 +6541,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6563,7 +6558,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6580,7 +6575,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6596,7 +6591,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6614,7 +6609,7 @@ dependencies = [ [[package]] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "pallet-nfts", @@ -6625,7 +6620,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6641,7 +6636,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6658,7 +6653,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6678,7 +6673,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6689,7 +6684,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6706,7 +6701,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6730,7 +6725,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6747,7 +6742,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6762,7 +6757,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6780,7 +6775,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6795,7 +6790,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6814,7 +6809,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6831,7 +6826,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6852,7 +6847,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6868,7 +6863,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6882,7 +6877,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6905,7 +6900,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6916,7 +6911,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "log", "sp-arithmetic", @@ -6925,7 +6920,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "sp-api", @@ -6934,7 +6929,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6951,7 +6946,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -6980,7 +6975,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6998,7 +6993,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7017,7 +7012,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-support", "frame-system", @@ -7033,7 +7028,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7049,7 +7044,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7061,7 +7056,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7078,7 +7073,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7093,7 +7088,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7109,7 +7104,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7124,7 +7119,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7139,7 +7134,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7160,7 +7155,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "frame-benchmarking", "frame-support", @@ -7702,7 +7697,7 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "polkadot-node-metrics", @@ -7717,7 +7712,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7731,7 +7726,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "derive_more", "fatality", @@ -7754,7 +7749,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "fatality", "futures", @@ -7775,7 +7770,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "clap 4.1.13", "frame-benchmarking-cli", @@ -7803,7 +7798,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "frame-benchmarking", @@ -7846,7 +7841,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "always-assert", "bitvec", @@ -7868,7 +7863,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "parity-scale-codec", "scale-info", @@ -7880,7 +7875,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "derive_more", "fatality", @@ -7905,7 +7900,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7919,7 +7914,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "futures-timer", @@ -7939,7 +7934,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "always-assert", "async-trait", @@ -7962,7 +7957,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "parity-scale-codec", @@ -7980,7 +7975,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "derive_more", @@ -8009,7 +8004,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "futures", @@ -8030,7 +8025,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "fatality", @@ -8049,7 +8044,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8064,7 +8059,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "futures", @@ -8084,7 +8079,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "polkadot-node-metrics", @@ -8099,7 +8094,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "futures-timer", @@ -8116,7 +8111,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "fatality", "futures", @@ -8135,7 +8130,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "futures", @@ -8152,7 +8147,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "fatality", @@ -8170,7 +8165,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "always-assert", "assert_matches", @@ -8197,6 +8192,7 @@ dependencies = [ "sp-maybe-compressed-blob", "sp-tracing", "sp-wasm-interface", + "substrate-build-script-utils", "tempfile", "tikv-jemalloc-ctl", "tokio", @@ -8206,7 +8202,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "polkadot-node-primitives", @@ -8222,7 +8218,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "futures", "lru 0.9.0", @@ -8237,7 +8233,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "lazy_static", "log", @@ -8255,7 +8251,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bs58", "futures", @@ -8274,7 +8270,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "derive_more", @@ -8296,7 +8292,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bounded-vec", "futures", @@ -8319,7 +8315,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8329,7 +8325,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "futures", @@ -8347,7 +8343,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "derive_more", @@ -8370,7 +8366,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "derive_more", @@ -8403,7 +8399,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "futures", @@ -8426,7 +8422,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bounded-collections", "derive_more", @@ -8523,7 +8519,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -8539,7 +8535,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "hex-literal", @@ -8565,7 +8561,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8597,7 +8593,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "frame-benchmarking", @@ -8691,7 +8687,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "frame-benchmarking", @@ -8737,7 +8733,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "frame-support", "polkadot-primitives", @@ -8751,7 +8747,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bs58", "parity-scale-codec", @@ -8763,7 +8759,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitflags", "bitvec", @@ -8807,7 +8803,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "async-trait", "frame-benchmarking-cli", @@ -8917,7 +8913,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -8938,7 +8934,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -8948,7 +8944,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -8973,7 +8969,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "frame-election-provider-support", @@ -9034,7 +9030,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "frame-benchmarking", "frame-system", @@ -9770,7 +9766,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9856,7 +9852,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "frame-support", "polkadot-primitives", @@ -10089,7 +10085,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "log", "sp-core", @@ -10100,7 +10096,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "futures", @@ -10128,7 +10124,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "futures-timer", @@ -10151,7 +10147,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10166,7 +10162,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10185,7 +10181,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10196,7 +10192,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -10236,7 +10232,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "fnv", "futures", @@ -10262,7 +10258,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "hash-db", "kvdb", @@ -10288,7 +10284,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "futures", @@ -10313,7 +10309,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "futures", @@ -10342,7 +10338,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "fork-tree", @@ -10381,7 +10377,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "jsonrpsee", @@ -10403,7 +10399,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10438,7 +10434,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "jsonrpsee", @@ -10457,7 +10453,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10470,7 +10466,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "ahash 0.8.2", "array-bytes 4.2.0", @@ -10510,7 +10506,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "finality-grandpa", "futures", @@ -10530,7 +10526,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "futures", @@ -10553,7 +10549,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10577,7 +10573,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10590,7 +10586,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "log", "sc-allocator", @@ -10603,7 +10599,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "anyhow", "cfg-if", @@ -10621,7 +10617,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "ansi_term", "futures", @@ -10637,7 +10633,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10652,7 +10648,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10696,7 +10692,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "cid", "futures", @@ -10716,7 +10712,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10744,7 +10740,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "ahash 0.8.2", "futures", @@ -10763,7 +10759,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10785,7 +10781,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10819,7 +10815,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10839,7 +10835,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10870,7 +10866,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "libp2p", @@ -10883,7 +10879,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10892,7 +10888,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "jsonrpsee", @@ -10922,7 +10918,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10941,7 +10937,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "http", "jsonrpsee", @@ -10956,7 +10952,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10982,7 +10978,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "directories", @@ -11048,7 +11044,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "log", "parity-scale-codec", @@ -11059,7 +11055,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "clap 4.1.13", "fs4", @@ -11075,7 +11071,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11094,7 +11090,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "libc", @@ -11113,7 +11109,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "chrono", "futures", @@ -11132,7 +11128,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "ansi_term", "atty", @@ -11163,7 +11159,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11174,7 +11170,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "futures", @@ -11201,7 +11197,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "futures", @@ -11215,7 +11211,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-channel", "futures", @@ -11696,7 +11692,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "enumn", "parity-scale-codec", @@ -11773,7 +11769,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "hash-db", "log", @@ -11791,7 +11787,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "Inflector", "blake2", @@ -11805,7 +11801,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "scale-info", @@ -11818,7 +11814,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "integer-sqrt", "num-traits", @@ -11832,7 +11828,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "scale-info", @@ -11845,7 +11841,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "sp-api", @@ -11857,7 +11853,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "log", @@ -11875,7 +11871,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "futures", @@ -11890,7 +11886,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "parity-scale-codec", @@ -11908,7 +11904,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "merlin", @@ -11931,7 +11927,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11950,7 +11946,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "finality-grandpa", "log", @@ -11968,7 +11964,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "scale-info", @@ -11980,7 +11976,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "scale-info", @@ -11993,13 +11989,13 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", - "base58", "bitflags", "blake2", "bounded-collections", + "bs58", "dyn-clonable", "ed25519-zebra", "futures", @@ -12036,7 +12032,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "blake2b_simd", "byteorder", @@ -12050,7 +12046,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro2", "quote", @@ -12061,7 +12057,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12070,7 +12066,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro2", "quote", @@ -12080,7 +12076,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "environmental", "parity-scale-codec", @@ -12091,7 +12087,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12106,7 +12102,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "bytes", "ed25519", @@ -12132,7 +12128,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "lazy_static", "sp-core", @@ -12143,7 +12139,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "merlin", @@ -12159,7 +12155,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "thiserror", "zstd", @@ -12168,7 +12164,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12186,7 +12182,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12200,7 +12196,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "sp-api", "sp-core", @@ -12210,7 +12206,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "backtrace", "lazy_static", @@ -12220,7 +12216,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "rustc-hash", "serde", @@ -12230,7 +12226,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "either", "hash256-std-hasher", @@ -12252,7 +12248,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12270,7 +12266,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "Inflector", "proc-macro-crate", @@ -12282,7 +12278,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "serde", "serde_json", @@ -12291,7 +12287,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12305,7 +12301,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12317,7 +12313,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "hash-db", "log", @@ -12337,12 +12333,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12355,7 +12351,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "futures-timer", @@ -12370,7 +12366,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "sp-std", @@ -12382,7 +12378,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "sp-api", "sp-runtime", @@ -12391,7 +12387,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "log", @@ -12407,7 +12403,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "ahash 0.8.2", "hash-db", @@ -12430,7 +12426,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12447,7 +12443,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12458,7 +12454,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12472,7 +12468,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12796,7 +12792,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "platforms", ] @@ -12804,7 +12800,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12823,7 +12819,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "hyper", "log", @@ -12835,7 +12831,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "jsonrpsee", @@ -12848,7 +12844,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "jsonrpsee", "log", @@ -12867,7 +12863,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -12893,7 +12889,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12903,7 +12899,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12914,7 +12910,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "ansi_term", "build-helper", @@ -13041,7 +13037,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "frame-support", "polkadot-primitives", @@ -13432,7 +13428,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13443,7 +13439,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -13573,7 +13569,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#f40ba0d09785159a31a43b16b47ddb5ae8e62e1d" +source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" dependencies = [ "async-trait", "clap 4.1.13", @@ -14501,7 +14497,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bitvec", "frame-benchmarking", @@ -14593,7 +14589,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "frame-support", "polkadot-primitives", @@ -15029,7 +15025,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "bounded-collections", "derivative", @@ -15045,7 +15041,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "frame-support", "frame-system", @@ -15066,7 +15062,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "environmental", "frame-benchmarking", @@ -15086,7 +15082,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21298c8a0f3bfdaedc757d2f46d29c3aa242f128" +source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" dependencies = [ "Inflector", "proc-macro2", diff --git a/client/relay-chain-minimal-node/Cargo.toml b/client/relay-chain-minimal-node/Cargo.toml index 7c1c8621d36..11918a4c958 100644 --- a/client/relay-chain-minimal-node/Cargo.toml +++ b/client/relay-chain-minimal-node/Cargo.toml @@ -21,6 +21,7 @@ sc-network = { git = "https://github.com/paritytech/substrate", branch = "master sc-network-common = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/client/relay-chain-minimal-node/src/network.rs b/client/relay-chain-minimal-node/src/network.rs index 4dff55a65de..5225fa053cc 100644 --- a/client/relay-chain-minimal-node/src/network.rs +++ b/client/relay-chain-minimal-node/src/network.rs @@ -26,6 +26,7 @@ use sc_network::{ 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}; @@ -49,6 +50,8 @@ pub(crate) fn build_collator_network( genesis_hash, ); + // 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: { @@ -64,6 +67,7 @@ pub(crate) fn build_collator_network( metrics_registry: config.prometheus_config.as_ref().map(|config| config.registry.clone()), block_announce_config, request_response_protocol_configs: Vec::new(), + tx, }; let network_worker = sc_network::NetworkWorker::new(network_params)?; From 3ce4e830880d300731625eccf019ed992495a113 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Mar 2023 13:02:34 +0000 Subject: [PATCH 11/57] Bump syn from 2.0.9 to 2.0.11 (#2405) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.9 to 2.0.11. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.9...2.0.11) --- updated-dependencies: - dependency-name: syn 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 | 14 +++++++------- pallets/parachain-system/proc-macro/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 098e5450813..33e59ef310e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,7 +427,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.11", ] [[package]] @@ -1214,7 +1214,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.11", ] [[package]] @@ -2092,7 +2092,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.11", ] [[package]] @@ -11489,7 +11489,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.11", ] [[package]] @@ -12952,9 +12952,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.9" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da4a3c17e109f700685ec577c0f85efd9b19bcf15c913985f14dc1ac01775aa" +checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" dependencies = [ "proc-macro2", "quote", @@ -13071,7 +13071,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.9", + "syn 2.0.11", ] [[package]] diff --git a/pallets/parachain-system/proc-macro/Cargo.toml b/pallets/parachain-system/proc-macro/Cargo.toml index e3f9487d8c1..bcb8c800cf1 100644 --- a/pallets/parachain-system/proc-macro/Cargo.toml +++ b/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.9" +syn = "2.0.11" proc-macro2 = "1.0.52" quote = "1.0.26" proc-macro-crate = "1.3.1" From 693e97336de278fc1e6e91373e437f17c9698ce9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Mar 2023 16:06:58 +0200 Subject: [PATCH 12/57] Bump scale-info from 2.4.0 to 2.5.0 (#2404) Bumps [scale-info](https://github.com/paritytech/scale-info) from 2.4.0 to 2.5.0. - [Release notes](https://github.com/paritytech/scale-info/releases) - [Changelog](https://github.com/paritytech/scale-info/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/scale-info/compare/v2.4.0...v2.5.0) --- updated-dependencies: - dependency-name: scale-info 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 | 8 ++++---- pallets/aura-ext/Cargo.toml | 2 +- pallets/collator-selection/Cargo.toml | 2 +- pallets/dmp-queue/Cargo.toml | 2 +- pallets/parachain-system/Cargo.toml | 2 +- pallets/solo-to-para/Cargo.toml | 2 +- pallets/xcm/Cargo.toml | 2 +- pallets/xcmp-queue/Cargo.toml | 2 +- parachain-template/runtime/Cargo.toml | 2 +- parachains/common/Cargo.toml | 2 +- parachains/pallets/parachain-info/Cargo.toml | 2 +- parachains/pallets/ping/Cargo.toml | 2 +- parachains/runtimes/assets/statemine/Cargo.toml | 2 +- parachains/runtimes/assets/statemint/Cargo.toml | 2 +- parachains/runtimes/assets/westmint/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 +- parachains/runtimes/contracts/contracts-rococo/Cargo.toml | 2 +- parachains/runtimes/starters/seedling/Cargo.toml | 2 +- parachains/runtimes/starters/shell/Cargo.toml | 2 +- parachains/runtimes/testing/penpal/Cargo.toml | 2 +- parachains/runtimes/testing/rococo-parachain/Cargo.toml | 2 +- primitives/parachain-inherent/Cargo.toml | 2 +- test/runtime/Cargo.toml | 2 +- 26 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33e59ef310e..89ce007ab33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11225,9 +11225,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61471dff9096de1d8b2319efed7162081e96793f5ebb147e50db10d50d648a4d" +checksum = "0cfdffd972d76b22f3d7f81c8be34b2296afd3a25e0a547bd9abe340a4dbbe97" dependencies = [ "bitvec", "cfg-if", @@ -11239,9 +11239,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219580e803a66b3f05761fd06f1f879a872444e49ce23f73694d26e5a954c7e6" +checksum = "61fa974aea2d63dd18a4ec3a49d59af9f34178c73a4f56d2f18205628d00681e" dependencies = [ "proc-macro-crate", "proc-macro2", diff --git a/pallets/aura-ext/Cargo.toml b/pallets/aura-ext/Cargo.toml index 6eaf27c96ed..1db43697511 100644 --- a/pallets/aura-ext/Cargo.toml +++ b/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.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/collator-selection/Cargo.toml b/pallets/collator-selection/Cargo.toml index 9629c7de5cf..17bb6fe5579 100644 --- a/pallets/collator-selection/Cargo.toml +++ b/pallets/collator-selection/Cargo.toml @@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"] log = { version = "0.4.17", 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.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-std = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/pallets/dmp-queue/Cargo.toml b/pallets/dmp-queue/Cargo.toml index bbf19ad62be..6d072adaede 100644 --- a/pallets/dmp-queue/Cargo.toml +++ b/pallets/dmp-queue/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/parachain-system/Cargo.toml b/pallets/parachain-system/Cargo.toml index e793ddc4c19..b7eef00712e 100644 --- a/pallets/parachain-system/Cargo.toml +++ b/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.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/solo-to-para/Cargo.toml b/pallets/solo-to-para/Cargo.toml index ddc2ca56a3b..d092fac6ea7 100644 --- a/pallets/solo-to-para/Cargo.toml +++ b/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.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/xcm/Cargo.toml b/pallets/xcm/Cargo.toml index e9404b3500d..59a751dde09 100644 --- a/pallets/xcm/Cargo.toml +++ b/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.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/pallets/xcmp-queue/Cargo.toml b/pallets/xcmp-queue/Cargo.toml index acd440f5818..ed5f199e1fe 100644 --- a/pallets/xcmp-queue/Cargo.toml +++ b/pallets/xcmp-queue/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ], default-features = false } log = { version = "0.4.17", default-features = false } rand_chacha = { version = "0.3.0", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachain-template/runtime/Cargo.toml b/parachain-template/runtime/Cargo.toml index 3724596ceb7..fe15f82af0e 100644 --- a/parachain-template/runtime/Cargo.toml +++ b/parachain-template/runtime/Cargo.toml @@ -18,7 +18,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Local diff --git a/parachains/common/Cargo.toml b/parachains/common/Cargo.toml index f89544d8241..5898ae3d9ba 100644 --- a/parachains/common/Cargo.toml +++ b/parachains/common/Cargo.toml @@ -10,7 +10,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.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "master" } diff --git a/parachains/pallets/parachain-info/Cargo.toml b/parachains/pallets/parachain-info/Cargo.toml index 270cc869a19..3d706e35e8e 100644 --- a/parachains/pallets/parachain-info/Cargo.toml +++ b/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.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachains/pallets/ping/Cargo.toml b/parachains/pallets/ping/Cargo.toml index fbfcc703644..1dd218ccc79 100644 --- a/parachains/pallets/ping/Cargo.toml +++ b/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.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachains/runtimes/assets/statemine/Cargo.toml b/parachains/runtimes/assets/statemine/Cargo.toml index 694f19a274b..704a49a0a55 100644 --- a/parachains/runtimes/assets/statemine/Cargo.toml +++ b/parachains/runtimes/assets/statemine/Cargo.toml @@ -9,7 +9,7 @@ description = "Kusama variant of Statemint parachain runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.3.4" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/assets/statemint/Cargo.toml b/parachains/runtimes/assets/statemint/Cargo.toml index cee4c46dbb2..bd482fd2a06 100644 --- a/parachains/runtimes/assets/statemint/Cargo.toml +++ b/parachains/runtimes/assets/statemint/Cargo.toml @@ -9,7 +9,7 @@ description = "Statemint parachain runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/assets/westmint/Cargo.toml b/parachains/runtimes/assets/westmint/Cargo.toml index dc2574e8b8a..d98db24e185 100644 --- a/parachains/runtimes/assets/westmint/Cargo.toml +++ b/parachains/runtimes/assets/westmint/Cargo.toml @@ -9,7 +9,7 @@ description = "Westend variant of Statemint parachain runtime" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml index 4b2cf6a5737..f0392c7716b 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } smallvec = "1.8.1" diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml index 9526bd8e3b9..8f29167a24f 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } smallvec = "1.8.1" diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 5599231c678..30e3cad3e21 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4" } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } smallvec = "1.8.1" diff --git a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index 04609ca594c..ba3b9ece735 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/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.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index fcca53c1695..b667bbf8a98 100644 --- a/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -14,7 +14,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/starters/seedling/Cargo.toml b/parachains/runtimes/starters/seedling/Cargo.toml index f26906da461..96ec9544009 100644 --- a/parachains/runtimes/starters/seedling/Cargo.toml +++ b/parachains/runtimes/starters/seedling/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachains/runtimes/starters/shell/Cargo.toml b/parachains/runtimes/starters/shell/Cargo.toml index 22efd8f8bef..a176e73906a 100644 --- a/parachains/runtimes/starters/shell/Cargo.toml +++ b/parachains/runtimes/starters/shell/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/parachains/runtimes/testing/penpal/Cargo.toml b/parachains/runtimes/testing/penpal/Cargo.toml index 85d115f06ac..e1ff15b0e02 100644 --- a/parachains/runtimes/testing/penpal/Cargo.toml +++ b/parachains/runtimes/testing/penpal/Cargo.toml @@ -18,7 +18,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } hex-literal = { version = "0.3.4", optional = true } log = { version = "0.4.16", default-features = false } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" # Substrate diff --git a/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/parachains/runtimes/testing/rococo-parachain/Cargo.toml index 14ea9a04292..ecf6acda9e3 100644 --- a/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -7,7 +7,7 @@ description = "Simple runtime used by the rococo parachain(s)" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-benchmarking = { git = "https://github.com/paritytech/substrate", optional = true, default-features = false, branch = "master" } diff --git a/primitives/parachain-inherent/Cargo.toml b/primitives/parachain-inherent/Cargo.toml index 7fec7149975..2135802592b 100644 --- a/primitives/parachain-inherent/Cargo.toml +++ b/primitives/parachain-inherent/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] async-trait = { version = "0.1.68", optional = true } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } tracing = { version = "0.1.37", optional = true } # Substrate diff --git a/test/runtime/Cargo.toml b/test/runtime/Cargo.toml index be7c531f57f..619d01fce8d 100644 --- a/test/runtime/Cargo.toml +++ b/test/runtime/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-info = { version = "2.4.0", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate frame-executive = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } From f5340e7faa06d6a34b2afa80e7838281334f1b31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Mar 2023 15:17:47 +0000 Subject: [PATCH 13/57] Bump tempfile from 3.4.0 to 3.5.0 (#2406) Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.4.0 to 3.5.0. - [Release notes](https://github.com/Stebalien/tempfile/releases) - [Changelog](https://github.com/Stebalien/tempfile/blob/master/NEWS) - [Commits](https://github.com/Stebalien/tempfile/commits) --- updated-dependencies: - dependency-name: tempfile 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: parity-processbot <> --- Cargo.lock | 62 ++++++++++++++++++++++++++++------- polkadot-parachain/Cargo.toml | 2 +- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 89ce007ab33..cb9e1990039 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3094,6 +3094,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "errno-dragonfly" version = "0.1.2" @@ -3250,7 +3261,7 @@ checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.10", "winapi", ] @@ -5263,6 +5274,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" +[[package]] +name = "linux-raw-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd550e73688e6d578f0ac2119e32b797a327631a42f9433e59d02e139c8df60d" + [[package]] name = "lock_api" version = "0.4.6" @@ -7412,7 +7429,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.10", "smallvec", "winapi", ] @@ -7425,7 +7442,7 @@ checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.10", "smallvec", "windows-sys 0.32.0", ] @@ -9566,6 +9583,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.0" @@ -9573,7 +9599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom 0.2.8", - "redox_syscall", + "redox_syscall 0.2.10", ] [[package]] @@ -9965,7 +9991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" dependencies = [ "bitflags", - "errno", + "errno 0.2.8", "io-lifetimes 0.7.5", "libc", "linux-raw-sys 0.0.46", @@ -9979,13 +10005,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" dependencies = [ "bitflags", - "errno", + "errno 0.2.8", "io-lifetimes 1.0.2", "libc", "linux-raw-sys 0.1.3", "windows-sys 0.42.0", ] +[[package]] +name = "rustix" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b24138615de35e32031d041a09032ef3487a616d901ca4db224e7d557efae2" +dependencies = [ + "bitflags", + "errno 0.3.0", + "io-lifetimes 1.0.2", + "libc", + "linux-raw-sys 0.3.0", + "windows-sys 0.45.0", +] + [[package]] name = "rustls" version = "0.19.1" @@ -13008,15 +13048,15 @@ checksum = "9410d0f6853b1d94f0e519fb95df60f29d2c1eff2d921ffdf01a4c8a3b54f12d" [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", - "rustix 0.36.7", - "windows-sys 0.42.0", + "redox_syscall 0.3.5", + "rustix 0.37.3", + "windows-sys 0.45.0", ] [[package]] diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index 0f6ebbd9a3a..b285df93d71 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -94,7 +94,7 @@ substrate-build-script-utils = { git = "https://github.com/paritytech/substrate" [dev-dependencies] assert_cmd = "2.0" nix = { version = "0.26.1", features = ["signal"] } -tempfile = "3.4.0" +tempfile = "3.5.0" tokio = { version = "1.26.0", features = ["macros", "time", "parking_lot"] } wait-timeout = "0.2" # purge_chain_works works with rococo-local and needs to allow this From 337bd17c382a73d9e9a53ccbd07714f0d388f0d4 Mon Sep 17 00:00:00 2001 From: Javier Viola Date: Thu, 30 Mar 2023 16:49:51 -0300 Subject: [PATCH 14/57] bump zombienet version (#2411) --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 63e195808fe..449d32a993a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -29,7 +29,7 @@ variables: CI_IMAGE: "paritytech/ci-linux:production" DOCKER_OS: "debian:stretch" ARCH: "x86_64" - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.40" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.43" .common-before-script: before_script: From 826e1aab2a5e07af0c761588fdbd76712d84ce59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Mar 2023 09:29:41 +0200 Subject: [PATCH 15/57] Bump tokio from 1.26.0 to 1.27.0 (#2413) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.26.0 to 1.27.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.26.0...tokio-1.27.0) --- updated-dependencies: - dependency-name: tokio 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 | 15 +++++++-------- client/network/Cargo.toml | 2 +- client/pov-recovery/Cargo.toml | 2 +- client/relay-chain-minimal-node/Cargo.toml | 2 +- client/relay-chain-rpc-interface/Cargo.toml | 2 +- polkadot-parachain/Cargo.toml | 2 +- test/service/Cargo.toml | 2 +- 7 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cb9e1990039..d44670fa562 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11781,9 +11781,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.4" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -13257,14 +13257,13 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.26.0" +version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "parking_lot 0.12.1", @@ -13277,13 +13276,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.7.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.11", ] [[package]] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 130ab98b754..c6578d546f3 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -31,7 +31,7 @@ cumulus-relay-chain-interface = { path = "../relay-chain-interface" } [dev-dependencies] portpicker = "0.1.1" -tokio = { version = "1.26.0", features = ["macros"] } +tokio = { version = "1.27.0", features = ["macros"] } url = "2.3.1" # Substrate diff --git a/client/pov-recovery/Cargo.toml b/client/pov-recovery/Cargo.toml index 5ab23ec7791..68990975936 100644 --- a/client/pov-recovery/Cargo.toml +++ b/client/pov-recovery/Cargo.toml @@ -31,7 +31,7 @@ cumulus-relay-chain-interface = {path = "../relay-chain-interface"} async-trait = "0.1.68" [dev-dependencies] -tokio = { version = "1.26.0", features = ["macros"] } +tokio = { version = "1.27.0", features = ["macros"] } portpicker = "0.1.1" # Cumulus diff --git a/client/relay-chain-minimal-node/Cargo.toml b/client/relay-chain-minimal-node/Cargo.toml index 11918a4c958..f5d462ba826 100644 --- a/client/relay-chain-minimal-node/Cargo.toml +++ b/client/relay-chain-minimal-node/Cargo.toml @@ -38,4 +38,4 @@ lru = "0.9" tracing = "0.1.37" async-trait = "0.1.68" futures = "0.3.27" -tokio = { version = "1.26.0", features = ["macros"] } +tokio = { version = "1.27.0", features = ["macros"] } diff --git a/client/relay-chain-rpc-interface/Cargo.toml b/client/relay-chain-rpc-interface/Cargo.toml index 34458a4510e..904426da4aa 100644 --- a/client/relay-chain-rpc-interface/Cargo.toml +++ b/client/relay-chain-rpc-interface/Cargo.toml @@ -21,7 +21,7 @@ sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "mas sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } -tokio = { version = "1.26.0", features = ["sync"] } +tokio = { version = "1.27.0", features = ["sync"] } futures = "0.3.27" futures-timer = "3.0.2" diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index b285df93d71..c273c2e9acb 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -95,7 +95,7 @@ substrate-build-script-utils = { git = "https://github.com/paritytech/substrate" assert_cmd = "2.0" nix = { version = "0.26.1", features = ["signal"] } tempfile = "3.5.0" -tokio = { version = "1.26.0", features = ["macros", "time", "parking_lot"] } +tokio = { version = "1.27.0", features = ["macros", "time", "parking_lot"] } wait-timeout = "0.2" # purge_chain_works works with rococo-local and needs to allow this polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master", features = ["rococo-native"] } diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index ff88ae5b84f..f7efd1d0d49 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -16,7 +16,7 @@ criterion = { version = "0.4.0", features = [ "async_tokio" ] } jsonrpsee = { version = "0.16.2", features = ["server"] } rand = "0.8.5" serde = { version = "1.0.159", features = ["derive"] } -tokio = { version = "1.26.0", features = ["macros"] } +tokio = { version = "1.27.0", features = ["macros"] } tracing = "0.1.37" url = "2.3.1" From 93d9b6afa21085bd2e54505b6bb961524dc59c2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Mar 2023 10:17:38 +0000 Subject: [PATCH 16/57] Bump syn from 2.0.11 to 2.0.12 (#2414) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.11 to 2.0.12. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.11...2.0.12) --- updated-dependencies: - dependency-name: syn 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 | 16 ++++++++-------- pallets/parachain-system/proc-macro/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d44670fa562..53b14f659bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,7 +427,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.12", ] [[package]] @@ -1214,7 +1214,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.12", ] [[package]] @@ -2092,7 +2092,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.12", ] [[package]] @@ -11529,7 +11529,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.12", ] [[package]] @@ -12992,9 +12992,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" +checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" dependencies = [ "proc-macro2", "quote", @@ -13111,7 +13111,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.12", ] [[package]] @@ -13282,7 +13282,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.12", ] [[package]] diff --git a/pallets/parachain-system/proc-macro/Cargo.toml b/pallets/parachain-system/proc-macro/Cargo.toml index bcb8c800cf1..d9938c3b1e0 100644 --- a/pallets/parachain-system/proc-macro/Cargo.toml +++ b/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.11" +syn = "2.0.12" proc-macro2 = "1.0.52" quote = "1.0.26" proc-macro-crate = "1.3.1" From b1cd3d5df949e8df07d594885acc685e8bdf3b41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 31 Mar 2023 11:09:14 +0000 Subject: [PATCH 17/57] Bump proc-macro2 from 1.0.52 to 1.0.54 (#2415) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.52 to 1.0.54. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.52...1.0.54) --- updated-dependencies: - dependency-name: proc-macro2 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 | 4 ++-- pallets/parachain-system/proc-macro/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53b14f659bc..1e6123727cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9266,9 +9266,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] diff --git a/pallets/parachain-system/proc-macro/Cargo.toml b/pallets/parachain-system/proc-macro/Cargo.toml index d9938c3b1e0..e42d076c77e 100644 --- a/pallets/parachain-system/proc-macro/Cargo.toml +++ b/pallets/parachain-system/proc-macro/Cargo.toml @@ -10,7 +10,7 @@ proc-macro = true [dependencies] syn = "2.0.12" -proc-macro2 = "1.0.52" +proc-macro2 = "1.0.54" quote = "1.0.26" proc-macro-crate = "1.3.1" From 9106fa8621db4b67a690efc998a692602bc35fdc Mon Sep 17 00:00:00 2001 From: PG Herveou Date: Fri, 31 Mar 2023 13:29:44 +0200 Subject: [PATCH 18/57] Companion PR for contract deletion updates (#2409) * Companion PR for contract deletion updates see https://github.com/paritytech/substrate/pull/13702 * Revert "Companion PR for contract deletion updates" This reverts commit 4fb2ca53a1bdfbd7dc0d35be52525da99547c76c. * fix lint * update lockfile for {"polkadot", "substrate"} --------- Co-authored-by: parity-processbot <> --- Cargo.lock | 512 +++++++++--------- .../contracts-rococo/src/contracts.rs | 17 +- 2 files changed, 258 insertions(+), 271 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e6123727cc..0753cbdf387 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -523,7 +523,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "hash-db", "log", @@ -3330,7 +3330,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", ] @@ -3353,7 +3353,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-support-procedural", @@ -3378,7 +3378,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -3425,7 +3425,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3436,7 +3436,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3453,7 +3453,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -3482,7 +3482,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "log", @@ -3498,7 +3498,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "bitflags", "environmental", @@ -3531,7 +3531,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "Inflector", "cfg-expr", @@ -3546,7 +3546,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3558,7 +3558,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro2", "quote", @@ -3568,7 +3568,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "log", @@ -3586,7 +3586,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -3601,7 +3601,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "sp-api", @@ -3610,7 +3610,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "parity-scale-codec", @@ -4573,7 +4573,7 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "frame-benchmarking", @@ -4671,7 +4671,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "frame-support", "polkadot-primitives", @@ -5519,7 +5519,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "log", @@ -5538,7 +5538,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "anyhow", "jsonrpsee", @@ -6027,7 +6027,7 @@ dependencies = [ [[package]] name = "pallet-alliance" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -6048,7 +6048,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6066,7 +6066,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6081,7 +6081,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6097,7 +6097,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6113,7 +6113,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6127,7 +6127,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6151,7 +6151,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6171,7 +6171,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6186,7 +6186,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6205,7 +6205,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6229,7 +6229,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6247,7 +6247,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6291,7 +6291,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6308,7 +6308,7 @@ dependencies = [ [[package]] name = "pallet-contracts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "bitflags", "environmental", @@ -6338,7 +6338,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "bitflags", "parity-scale-codec", @@ -6351,7 +6351,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro2", "quote", @@ -6361,7 +6361,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6378,7 +6378,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6396,7 +6396,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6419,7 +6419,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6432,7 +6432,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6450,7 +6450,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6468,7 +6468,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6491,7 +6491,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6507,7 +6507,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6527,7 +6527,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6544,7 +6544,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6558,7 +6558,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6575,7 +6575,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6592,7 +6592,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6608,7 +6608,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6626,7 +6626,7 @@ dependencies = [ [[package]] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "pallet-nfts", @@ -6637,7 +6637,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6653,7 +6653,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6670,7 +6670,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6690,7 +6690,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6701,7 +6701,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6718,7 +6718,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6742,7 +6742,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6759,7 +6759,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6774,7 +6774,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6792,7 +6792,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6807,7 +6807,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6826,7 +6826,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6843,7 +6843,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6864,7 +6864,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6880,7 +6880,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6894,7 +6894,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6917,7 +6917,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6928,7 +6928,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "log", "sp-arithmetic", @@ -6937,7 +6937,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "sp-api", @@ -6946,7 +6946,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -6963,7 +6963,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -6992,7 +6992,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -7010,7 +7010,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -7029,7 +7029,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-support", "frame-system", @@ -7045,7 +7045,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7061,7 +7061,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7073,7 +7073,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -7090,7 +7090,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -7105,7 +7105,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -7121,7 +7121,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -7136,7 +7136,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-benchmarking", "frame-support", @@ -7151,7 +7151,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7172,7 +7172,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "frame-benchmarking", "frame-support", @@ -7714,7 +7714,7 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "polkadot-node-metrics", @@ -7729,7 +7729,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7743,7 +7743,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "derive_more", "fatality", @@ -7766,7 +7766,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "fatality", "futures", @@ -7787,7 +7787,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "clap 4.1.13", "frame-benchmarking-cli", @@ -7815,7 +7815,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "frame-benchmarking", @@ -7858,7 +7858,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "always-assert", "bitvec", @@ -7880,7 +7880,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "parity-scale-codec", "scale-info", @@ -7892,7 +7892,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "derive_more", "fatality", @@ -7917,7 +7917,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7931,7 +7931,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "futures-timer", @@ -7951,7 +7951,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "always-assert", "async-trait", @@ -7974,7 +7974,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "parity-scale-codec", @@ -7992,7 +7992,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "derive_more", @@ -8021,7 +8021,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "futures", @@ -8042,7 +8042,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "fatality", @@ -8061,7 +8061,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8076,7 +8076,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "futures", @@ -8096,7 +8096,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "polkadot-node-metrics", @@ -8111,7 +8111,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "futures-timer", @@ -8128,7 +8128,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "fatality", "futures", @@ -8147,7 +8147,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "futures", @@ -8164,7 +8164,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "fatality", @@ -8182,7 +8182,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "always-assert", "assert_matches", @@ -8219,7 +8219,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "polkadot-node-primitives", @@ -8235,7 +8235,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "futures", "lru 0.9.0", @@ -8250,7 +8250,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "lazy_static", "log", @@ -8268,7 +8268,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bs58", "futures", @@ -8287,7 +8287,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "derive_more", @@ -8309,7 +8309,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bounded-vec", "futures", @@ -8332,7 +8332,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8342,7 +8342,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "futures", @@ -8360,7 +8360,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "derive_more", @@ -8383,7 +8383,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "derive_more", @@ -8416,7 +8416,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "futures", @@ -8439,7 +8439,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bounded-collections", "derive_more", @@ -8536,7 +8536,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -8552,7 +8552,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "hex-literal", @@ -8578,7 +8578,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8610,7 +8610,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "frame-benchmarking", @@ -8704,7 +8704,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "frame-benchmarking", @@ -8750,7 +8750,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "frame-support", "polkadot-primitives", @@ -8764,7 +8764,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bs58", "parity-scale-codec", @@ -8776,7 +8776,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitflags", "bitvec", @@ -8820,7 +8820,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "async-trait", "frame-benchmarking-cli", @@ -8930,7 +8930,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -8951,7 +8951,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -8961,7 +8961,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -8986,7 +8986,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "frame-election-provider-support", @@ -9047,7 +9047,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "frame-benchmarking", "frame-system", @@ -9792,7 +9792,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9878,7 +9878,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "frame-support", "polkadot-primitives", @@ -10125,7 +10125,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "log", "sp-core", @@ -10136,7 +10136,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "futures", @@ -10164,7 +10164,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "futures-timer", @@ -10187,7 +10187,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10202,7 +10202,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10221,7 +10221,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10232,7 +10232,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -10272,7 +10272,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "fnv", "futures", @@ -10298,7 +10298,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "hash-db", "kvdb", @@ -10324,7 +10324,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "futures", @@ -10349,7 +10349,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "futures", @@ -10378,7 +10378,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "fork-tree", @@ -10417,7 +10417,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "jsonrpsee", @@ -10439,7 +10439,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10474,7 +10474,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "jsonrpsee", @@ -10493,7 +10493,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10506,7 +10506,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "ahash 0.8.2", "array-bytes 4.2.0", @@ -10546,7 +10546,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "finality-grandpa", "futures", @@ -10566,7 +10566,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "futures", @@ -10589,7 +10589,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10613,7 +10613,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10626,7 +10626,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "log", "sc-allocator", @@ -10639,7 +10639,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "anyhow", "cfg-if", @@ -10657,7 +10657,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "ansi_term", "futures", @@ -10673,7 +10673,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10688,7 +10688,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10732,7 +10732,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "cid", "futures", @@ -10752,7 +10752,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10780,7 +10780,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "ahash 0.8.2", "futures", @@ -10799,7 +10799,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10821,7 +10821,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10855,7 +10855,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10875,7 +10875,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10906,7 +10906,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "libp2p", @@ -10919,7 +10919,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10928,7 +10928,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "jsonrpsee", @@ -10958,7 +10958,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -10977,7 +10977,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "http", "jsonrpsee", @@ -10992,7 +10992,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "futures", @@ -11018,7 +11018,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "directories", @@ -11084,7 +11084,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "log", "parity-scale-codec", @@ -11095,7 +11095,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "clap 4.1.13", "fs4", @@ -11111,7 +11111,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11130,7 +11130,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "libc", @@ -11149,7 +11149,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "chrono", "futures", @@ -11168,7 +11168,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "ansi_term", "atty", @@ -11199,7 +11199,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11210,7 +11210,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "futures", @@ -11237,7 +11237,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "futures", @@ -11251,7 +11251,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-channel", "futures", @@ -11732,7 +11732,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "enumn", "parity-scale-codec", @@ -11809,7 +11809,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "hash-db", "log", @@ -11827,7 +11827,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "Inflector", "blake2", @@ -11841,7 +11841,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "scale-info", @@ -11854,7 +11854,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "integer-sqrt", "num-traits", @@ -11868,7 +11868,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "scale-info", @@ -11881,7 +11881,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "sp-api", @@ -11893,7 +11893,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "log", @@ -11911,7 +11911,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "futures", @@ -11926,7 +11926,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "parity-scale-codec", @@ -11944,7 +11944,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "merlin", @@ -11967,7 +11967,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "lazy_static", "parity-scale-codec", @@ -11986,7 +11986,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "finality-grandpa", "log", @@ -12004,7 +12004,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "scale-info", @@ -12016,7 +12016,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "scale-info", @@ -12029,7 +12029,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "bitflags", @@ -12072,7 +12072,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "blake2b_simd", "byteorder", @@ -12086,7 +12086,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro2", "quote", @@ -12097,7 +12097,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12106,7 +12106,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro2", "quote", @@ -12116,7 +12116,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "environmental", "parity-scale-codec", @@ -12127,7 +12127,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12142,7 +12142,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "bytes", "ed25519", @@ -12168,7 +12168,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "lazy_static", "sp-core", @@ -12179,7 +12179,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "merlin", @@ -12195,7 +12195,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "thiserror", "zstd", @@ -12204,7 +12204,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12222,7 +12222,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "scale-info", @@ -12236,7 +12236,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "sp-api", "sp-core", @@ -12246,7 +12246,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "backtrace", "lazy_static", @@ -12256,7 +12256,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "rustc-hash", "serde", @@ -12266,7 +12266,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "either", "hash256-std-hasher", @@ -12288,7 +12288,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12306,7 +12306,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "Inflector", "proc-macro-crate", @@ -12318,7 +12318,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "serde", "serde_json", @@ -12327,7 +12327,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "scale-info", @@ -12341,7 +12341,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "scale-info", @@ -12353,7 +12353,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "hash-db", "log", @@ -12373,12 +12373,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12391,7 +12391,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "futures-timer", @@ -12406,7 +12406,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "sp-std", @@ -12418,7 +12418,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "sp-api", "sp-runtime", @@ -12427,7 +12427,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "log", @@ -12443,7 +12443,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "ahash 0.8.2", "hash-db", @@ -12466,7 +12466,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12483,7 +12483,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12494,7 +12494,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12508,7 +12508,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "parity-scale-codec", "scale-info", @@ -12832,7 +12832,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "platforms", ] @@ -12840,7 +12840,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12859,7 +12859,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "hyper", "log", @@ -12871,7 +12871,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "jsonrpsee", @@ -12884,7 +12884,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "jsonrpsee", "log", @@ -12903,7 +12903,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -12929,7 +12929,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12939,7 +12939,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12950,7 +12950,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "ansi_term", "build-helper", @@ -13077,7 +13077,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "frame-support", "polkadot-primitives", @@ -13467,7 +13467,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13478,7 +13478,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -13608,7 +13608,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#44998291834b3a36a11c8dede63ce60362f1a3a5" +source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", "clap 4.1.13", @@ -14536,7 +14536,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bitvec", "frame-benchmarking", @@ -14628,7 +14628,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "frame-support", "polkadot-primitives", @@ -15064,7 +15064,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "bounded-collections", "derivative", @@ -15080,7 +15080,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "frame-support", "frame-system", @@ -15101,7 +15101,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "environmental", "frame-benchmarking", @@ -15121,7 +15121,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#1fe1702508f24b96b136f696fc180d6b27145c8b" +source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ "Inflector", "proc-macro2", diff --git a/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs b/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs index 7c19677603c..27a16a6357e 100644 --- a/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -1,15 +1,13 @@ use crate::{ constants::currency::deposit, Balance, Balances, RandomnessCollectiveFlip, Runtime, - RuntimeBlockWeights, RuntimeCall, RuntimeEvent, Timestamp, + RuntimeCall, RuntimeEvent, Timestamp, }; use frame_support::{ parameter_types, traits::{ConstBool, ConstU32, Nothing}, - weights::Weight, }; use pallet_contracts::{ - weights::{SubstrateWeight, WeightInfo}, - Config, DefaultAddressGenerator, Frame, Schedule, + weights::SubstrateWeight, Config, DefaultAddressGenerator, Frame, Schedule, }; pub use parachains_common::AVERAGE_ON_INITIALIZE_RATIO; @@ -20,15 +18,6 @@ pub const CONTRACTS_DEBUG_OUTPUT: bool = true; parameter_types! { pub const DepositPerItem: Balance = deposit(1, 0); pub const DepositPerByte: Balance = deposit(0, 1); - // The lazy deletion runs inside on_initialize. - pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO * - RuntimeBlockWeights::get().max_block; - // The weight needed for decoding the queue should be less or equal than a fifth - // of the overall weight dedicated to the lazy deletion. - pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get().ref_time() / ( - ::WeightInfo::on_initialize_per_queue_item(1).ref_time() - - ::WeightInfo::on_initialize_per_queue_item(0).ref_time() - )) / 5) as u32; pub MySchedule: Schedule = Default::default(); } @@ -50,8 +39,6 @@ impl Config for Runtime { type WeightPrice = pallet_transaction_payment::Pallet; type WeightInfo = SubstrateWeight; type ChainExtension = (); - type DeletionQueueDepth = DeletionQueueDepth; - type DeletionWeightLimit = DeletionWeightLimit; type Schedule = MySchedule; type CallStack = [Frame; 5]; type AddressGenerator = DefaultAddressGenerator; From e5035c8279c4d7552039cc539a3d344d551260fc Mon Sep 17 00:00:00 2001 From: tmpolaczyk <44604217+tmpolaczyk@users.noreply.github.com> Date: Fri, 31 Mar 2023 17:08:07 +0200 Subject: [PATCH 19/57] Allow arbitrary key-values in RelayStateSproofBuilder (#2407) --- test/relay-sproof-builder/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/relay-sproof-builder/src/lib.rs b/test/relay-sproof-builder/src/lib.rs index 93da853c8d1..decc6ee3aa0 100644 --- a/test/relay-sproof-builder/src/lib.rs +++ b/test/relay-sproof-builder/src/lib.rs @@ -45,6 +45,7 @@ pub struct RelayStateSproofBuilder { pub current_slot: relay_chain::Slot, pub current_epoch: u64, pub randomness: relay_chain::Hash, + pub additional_key_values: Vec<(Vec, Vec)>, } impl Default for RelayStateSproofBuilder { @@ -71,6 +72,7 @@ impl Default for RelayStateSproofBuilder { current_slot: 0.into(), current_epoch: 0u64, randomness: relay_chain::Hash::default(), + additional_key_values: vec![], } } } @@ -163,6 +165,10 @@ impl RelayStateSproofBuilder { self.randomness.encode(), ); insert(relay_chain::well_known_keys::CURRENT_SLOT.to_vec(), self.current_slot.encode()); + + for (key, value) in self.additional_key_values { + insert(key, value); + } } let root = backend.root().clone(); From e5d994b0c3471bd556235eaed07e27cedd28a0c8 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Sat, 1 Apr 2023 16:44:32 +0200 Subject: [PATCH 20/57] help text examples + clean up (#2418) --- Cargo.lock | 23 +++++++++++++++++++ .../src/collator_overseer.rs | 8 +++---- client/relay-chain-minimal-node/src/lib.rs | 9 ++++---- .../src/reconnecting_ws_client.rs | 2 +- parachain-template/node/Cargo.toml | 3 ++- parachain-template/node/src/cli.rs | 13 +++++++++++ polkadot-parachain/Cargo.toml | 1 + polkadot-parachain/src/cli.rs | 10 ++++++++ 8 files changed, 59 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0753cbdf387..31021e2b8b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1324,6 +1324,27 @@ dependencies = [ "xcm-executor", ] +[[package]] +name = "color-print" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0" +dependencies = [ + "color-print-proc-macro", +] + +[[package]] +name = "color-print-proc-macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" +dependencies = [ + "nom", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "comfy-table" version = "6.0.0" @@ -7204,6 +7225,7 @@ name = "parachain-template-node" version = "0.1.0" dependencies = [ "clap 4.1.13", + "color-print", "cumulus-client-cli", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", @@ -8464,6 +8486,7 @@ dependencies = [ "bridge-hub-rococo-runtime", "clap 4.1.13", "collectives-polkadot-runtime", + "color-print", "contracts-rococo-runtime", "cumulus-client-cli", "cumulus-client-consensus-aura", diff --git a/client/relay-chain-minimal-node/src/collator_overseer.rs b/client/relay-chain-minimal-node/src/collator_overseer.rs index dce68e3b1f6..9bcbc2a67a8 100644 --- a/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -114,7 +114,7 @@ fn build_overseer<'a>( .collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?)) .collator_protocol({ let side = ProtocolSide::Collator( - network_service.local_peer_id().clone(), + network_service.local_peer_id(), collator_pair, collation_req_receiver, Metrics::register(registry)?, @@ -129,8 +129,8 @@ fn build_overseer<'a>( peer_set_protocol_names.clone(), )) .network_bridge_tx(NetworkBridgeTxSubsystem::new( - network_service.clone(), - authority_discovery_service.clone(), + network_service, + authority_discovery_service, network_bridge_metrics, req_protocol_names, peer_set_protocol_names, @@ -170,7 +170,7 @@ pub(crate) fn spawn_overseer( e })?; - let overseer_handle = Handle::new(overseer_handle.clone()); + let overseer_handle = Handle::new(overseer_handle); { let handle = overseer_handle.clone(); task_manager.spawn_essential_handle().spawn_blocking( diff --git a/client/relay-chain-minimal-node/src/lib.rs b/client/relay-chain-minimal-node/src/lib.rs index c47f6d08d22..90afd31b8b6 100644 --- a/client/relay-chain-minimal-node/src/lib.rs +++ b/client/relay-chain-minimal-node/src/lib.rs @@ -69,7 +69,7 @@ fn build_authority_discovery_service( network.clone(), Box::pin(dht_event_stream), authority_discovery_role, - prometheus_registry.clone(), + prometheus_registry, ); task_manager.spawn_handle().spawn( @@ -150,9 +150,10 @@ async fn new_minimal_relay_chain( let (collation_req_receiver, available_data_req_receiver) = build_request_response_protocol_receivers(&request_protocol_names, &mut config); - let best_header = relay_chain_rpc_client.chain_get_header(None).await?.ok_or_else(|| { - RelayChainError::RpcCallError("Unable to fetch best header".to_string().into()) - })?; + let best_header = relay_chain_rpc_client + .chain_get_header(None) + .await? + .ok_or_else(|| RelayChainError::RpcCallError("Unable to fetch best header".to_string()))?; let (network, network_starter, sync_oracle) = build_collator_network(&config, task_manager.spawn_handle(), genesis_hash, best_header) .map_err(|e| RelayChainError::Application(Box::new(e) as Box<_>))?; diff --git a/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs b/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs index 05d1c23bb7a..e03525226bc 100644 --- a/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs +++ b/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs @@ -381,7 +381,7 @@ impl ReconnectingWebsocketWorker { } if client_manager.connect_to_new_rpc_server().await.is_err() { - return Err(format!("Unable to find valid external RPC server, shutting down.")) + return Err("Unable to find valid external RPC server, shutting down.".to_string()) }; for item in requests_to_retry.into_iter() { diff --git a/parachain-template/node/Cargo.toml b/parachain-template/node/Cargo.toml index ba828fae060..29dfabe7e5f 100644 --- a/parachain-template/node/Cargo.toml +++ b/parachain-template/node/Cargo.toml @@ -52,7 +52,7 @@ substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate try-runtime-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } # Polkadot -polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master", features = ["rococo-native"] } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" } @@ -64,6 +64,7 @@ cumulus-client-service = { path = "../../client/service" } cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } cumulus-relay-chain-interface = { path = "../../client/relay-chain-interface" } +color-print = "0.3.4" [build-dependencies] substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/parachain-template/node/src/cli.rs b/parachain-template/node/src/cli.rs index 1da49b3b168..2e64a53e96a 100644 --- a/parachain-template/node/src/cli.rs +++ b/parachain-template/node/src/cli.rs @@ -44,12 +44,25 @@ pub enum Subcommand { TryRuntime, } +const AFTER_HELP_EXAMPLE: &str = color_print::cstr!( + r#"Examples: + parachain-template-node build-spec --disable-default-bootnode > plain-parachain-chainspec.json + Export a chainspec for a local testnet in json format. + parachain-template-node --chain plain-parachain-chainspec.json --tmp -- --chain rococo-local + Launch a full node with chain specification loaded from plain-parachain-chainspec.json. + parachain-template-node + Launch a full node with default parachain local-testnet and relay chain rococo-local. + parachain-template-node --collator + Launch a collator with default parachain local-testnet and relay chain rococo-local. + "# +); #[derive(Debug, clap::Parser)] #[command( propagate_version = true, args_conflicts_with_subcommands = true, subcommand_negates_reqs = true )] +#[clap(after_help = AFTER_HELP_EXAMPLE)] pub struct Cli { #[command(subcommand)] pub subcommand: Option, diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index c273c2e9acb..f4bee0a272e 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -87,6 +87,7 @@ cumulus-client-service = { path = "../client/service" } cumulus-primitives-core = { path = "../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../primitives/parachain-inherent" } cumulus-relay-chain-interface = { path = "../client/relay-chain-interface" } +color-print = "0.3.4" [build-dependencies] substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/polkadot-parachain/src/cli.rs b/polkadot-parachain/src/cli.rs index 90460095a6c..682911abf75 100644 --- a/polkadot-parachain/src/cli.rs +++ b/polkadot-parachain/src/cli.rs @@ -64,12 +64,22 @@ pub enum Subcommand { TryRuntime, } +const AFTER_HELP_EXAMPLE: &str = color_print::cstr!( + r#"Examples: + polkadot-parachain --chain statemint --sync warp -- --chain polkadot --sync warp + Launch a warp-syncing full node of the statemint parachain on the polkadot relay chain. + polkadot-parachain --chain statemint --sync warp --relay-chain-rpc-url ws://rpc.example.com -- --chain polkadot + Launch a warp-syncing full node of the statemint parachain on the polkadot relay chain. + Uses ws://rpc.example.com as remote relay chain node. + "# +); #[derive(Debug, clap::Parser)] #[command( propagate_version = true, args_conflicts_with_subcommands = true, subcommand_negates_reqs = true )] +#[clap(after_help = AFTER_HELP_EXAMPLE)] pub struct Cli { #[command(subcommand)] pub subcommand: Option, From e67094e551adf03379ad0886c1a0a66a451448cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 22:27:24 +0200 Subject: [PATCH 21/57] Bump futures from 0.3.27 to 0.3.28 (#2420) Bumps [futures](https://github.com/rust-lang/futures-rs) from 0.3.27 to 0.3.28. - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.27...0.3.28) --- updated-dependencies: - dependency-name: futures 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 | 38 +++++++++---------- client/consensus/aura/Cargo.toml | 2 +- client/consensus/common/Cargo.toml | 2 +- client/consensus/relay-chain/Cargo.toml | 2 +- client/network/Cargo.toml | 2 +- client/pov-recovery/Cargo.toml | 2 +- .../Cargo.toml | 2 +- client/relay-chain-interface/Cargo.toml | 2 +- client/relay-chain-minimal-node/Cargo.toml | 2 +- client/relay-chain-rpc-interface/Cargo.toml | 2 +- client/service/Cargo.toml | 2 +- polkadot-parachain/Cargo.toml | 2 +- primitives/timestamp/Cargo.toml | 2 +- test/service/Cargo.toml | 2 +- 14 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31021e2b8b4..a00e83ce6dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3681,9 +3681,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -3696,9 +3696,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -3706,15 +3706,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -3724,9 +3724,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-lite" @@ -3745,13 +3745,13 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.12", ] [[package]] @@ -3767,15 +3767,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-timer" @@ -3785,9 +3785,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", diff --git a/client/consensus/aura/Cargo.toml b/client/consensus/aura/Cargo.toml index b7a65523cf5..f284391494f 100644 --- a/client/consensus/aura/Cargo.toml +++ b/client/consensus/aura/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] async-trait = "0.1.68" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } -futures = "0.3.27" +futures = "0.3.28" tracing = "0.1.37" # Substrate diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 84f3adaca1e..d0bc28171fb 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" async-trait = "0.1.68" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } dyn-clone = "1.0.11" -futures = "0.3.27" +futures = "0.3.28" log = "0.4.17" tracing = "0.1.37" diff --git a/client/consensus/relay-chain/Cargo.toml b/client/consensus/relay-chain/Cargo.toml index b3cd2eea7b0..98331588ac1 100644 --- a/client/consensus/relay-chain/Cargo.toml +++ b/client/consensus/relay-chain/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] async-trait = "0.1.68" -futures = "0.3.27" +futures = "0.3.28" parking_lot = "0.12.1" tracing = "0.1.37" diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index c6578d546f3..4b7793d0cc4 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] async-trait = "0.1.68" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } -futures = "0.3.27" +futures = "0.3.28" futures-timer = "3.0.2" parking_lot = "0.12.1" tracing = "0.1.37" diff --git a/client/pov-recovery/Cargo.toml b/client/pov-recovery/Cargo.toml index 68990975936..542c79d3d78 100644 --- a/client/pov-recovery/Cargo.toml +++ b/client/pov-recovery/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } -futures = "0.3.27" +futures = "0.3.28" futures-timer = "3.0.2" rand = "0.8.5" tracing = "0.1.37" diff --git a/client/relay-chain-inprocess-interface/Cargo.toml b/client/relay-chain-inprocess-interface/Cargo.toml index 1959a7d163a..a3bc7de0eb1 100644 --- a/client/relay-chain-inprocess-interface/Cargo.toml +++ b/client/relay-chain-inprocess-interface/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] async-trait = "0.1.68" -futures = "0.3.27" +futures = "0.3.28" futures-timer = "3.0.2" # Substrate diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index 11d0f6d96a6..421c9c9aa9c 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -14,7 +14,7 @@ sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "mas sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -futures = "0.3.27" +futures = "0.3.28" async-trait = "0.1.68" thiserror = "1.0.40" jsonrpsee-core = "0.16.2" diff --git a/client/relay-chain-minimal-node/Cargo.toml b/client/relay-chain-minimal-node/Cargo.toml index f5d462ba826..737445c30c1 100644 --- a/client/relay-chain-minimal-node/Cargo.toml +++ b/client/relay-chain-minimal-node/Cargo.toml @@ -37,5 +37,5 @@ array-bytes = "6.0" lru = "0.9" tracing = "0.1.37" async-trait = "0.1.68" -futures = "0.3.27" +futures = "0.3.28" tokio = { version = "1.27.0", features = ["macros"] } diff --git a/client/relay-chain-rpc-interface/Cargo.toml b/client/relay-chain-rpc-interface/Cargo.toml index 904426da4aa..85f78b199e9 100644 --- a/client/relay-chain-rpc-interface/Cargo.toml +++ b/client/relay-chain-rpc-interface/Cargo.toml @@ -23,7 +23,7 @@ sc-service = { git = "https://github.com/paritytech/substrate", branch = "master tokio = { version = "1.27.0", features = ["sync"] } -futures = "0.3.27" +futures = "0.3.28" futures-timer = "3.0.2" parity-scale-codec = "3.4.0" jsonrpsee = { version = "0.16.2", features = ["ws-client"] } diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e17809158a9..52ab82a1127 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2021" [dependencies] -futures = "0.3.27" +futures = "0.3.28" # Substrate sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index f4bee0a272e..8f42c1ee1f1 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -14,7 +14,7 @@ path = "src/main.rs" async-trait = "0.1.68" clap = { version = "4.1.13", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } -futures = "0.3.27" +futures = "0.3.28" hex-literal = "0.3.4" log = "0.4.17" serde = { version = "1.0.159", features = ["derive"] } diff --git a/primitives/timestamp/Cargo.toml b/primitives/timestamp/Cargo.toml index 79fcaa535f6..254ab578b95 100644 --- a/primitives/timestamp/Cargo.toml +++ b/primitives/timestamp/Cargo.toml @@ -7,7 +7,7 @@ description = "Provides timestamp related functionality for parachains." [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } -futures = "0.3.27" +futures = "0.3.28" # Substrate sp-inherents = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index f7efd1d0d49..ea2c5c3fc13 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -72,7 +72,7 @@ cumulus-relay-chain-minimal-node = { path = "../../client/relay-chain-minimal-no cumulus-client-pov-recovery = { path = "../../client/pov-recovery" } [dev-dependencies] -futures = "0.3.27" +futures = "0.3.28" portpicker = "0.1.1" # Polkadot dependencies From 6bdcf1f792a1e136657287c1d4dbc6782b866996 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Apr 2023 20:58:34 +0000 Subject: [PATCH 22/57] Bump clap from 4.1.13 to 4.1.14 (#2421) Bumps [clap](https://github.com/clap-rs/clap) from 4.1.13 to 4.1.14. - [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.1.13...v4.1.14) --- updated-dependencies: - dependency-name: clap 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 | 48 +++++++++++++++++------------- client/cli/Cargo.toml | 2 +- parachain-template/node/Cargo.toml | 2 +- polkadot-parachain/Cargo.toml | 2 +- test/service/Cargo.toml | 2 +- 5 files changed, 31 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a00e83ce6dc..06a1ea811aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1192,24 +1192,33 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.13" +version = "4.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c911b090850d79fc64fe9ea01e28e465f65e821e08813ced95bced72f7a8a9b" +checksum = "906f7fe1da4185b7a282b2bc90172a496f9def1aca4545fe7526810741591e14" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex 0.3.0", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351f9ad9688141ed83dfd8f5fb998a06225ef444b48ff4dc43de6d409b7fd10b" +dependencies = [ + "bitflags", + "clap_lex 0.4.1", + "is-terminal", "strsim", "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.12" +version = "4.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a932373bab67b984c790ddf2c9ca295d8e3af3b7ef92de5a5bacdccdee4b09b" +checksum = "81d7dc0031c3a59a04fc2ba395c8e2dd463cba1859275f065d225f6122221b45" dependencies = [ "heck", "proc-macro2", @@ -1228,12 +1237,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "coarsetime" @@ -1826,7 +1832,7 @@ dependencies = [ name = "cumulus-client-cli" version = "0.1.0" dependencies = [ - "clap 4.1.13", + "clap 4.1.14", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -2465,7 +2471,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.1.13", + "clap 4.1.14", "criterion", "cumulus-client-cli", "cumulus-client-consensus-common", @@ -3404,7 +3410,7 @@ dependencies = [ "Inflector", "array-bytes 4.2.0", "chrono", - "clap 4.1.13", + "clap 4.1.14", "comfy-table", "frame-benchmarking", "frame-support", @@ -7224,7 +7230,7 @@ dependencies = [ name = "parachain-template-node" version = "0.1.0" dependencies = [ - "clap 4.1.13", + "clap 4.1.14", "color-print", "cumulus-client-cli", "cumulus-client-consensus-aura", @@ -7811,7 +7817,7 @@ name = "polkadot-cli" version = "0.9.39" source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" dependencies = [ - "clap 4.1.13", + "clap 4.1.14", "frame-benchmarking-cli", "futures", "log", @@ -8484,7 +8490,7 @@ dependencies = [ "bridge-hub-kusama-runtime", "bridge-hub-polkadot-runtime", "bridge-hub-rococo-runtime", - "clap 4.1.13", + "clap 4.1.14", "collectives-polkadot-runtime", "color-print", "contracts-rococo-runtime", @@ -10259,7 +10265,7 @@ source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da dependencies = [ "array-bytes 4.2.0", "chrono", - "clap 4.1.13", + "clap 4.1.14", "fdlimit", "futures", "libp2p", @@ -11120,7 +11126,7 @@ name = "sc-storage-monitor" version = "0.1.0" source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ - "clap 4.1.13", + "clap 4.1.14", "fs4", "futures", "log", @@ -13634,7 +13640,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" dependencies = [ "async-trait", - "clap 4.1.13", + "clap 4.1.14", "frame-remote-externalities", "frame-try-runtime", "hex", diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index a363cabc02d..68f8b472cf2 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Parity Technologies "] edition = "2021" [dependencies] -clap = { version = "4.1.13", features = ["derive"] } +clap = { version = "4.1.14", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } url = "2.3.1" diff --git a/parachain-template/node/Cargo.toml b/parachain-template/node/Cargo.toml index 29dfabe7e5f..5bdeffa1541 100644 --- a/parachain-template/node/Cargo.toml +++ b/parachain-template/node/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" build = "build.rs" [dependencies] -clap = { version = "4.1.13", features = ["derive"] } +clap = { version = "4.1.14", features = ["derive"] } log = "0.4.17" codec = { package = "parity-scale-codec", version = "3.0.0" } serde = { version = "1.0.159", features = ["derive"] } diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index 8f42c1ee1f1..dca3d1edf66 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -12,7 +12,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.68" -clap = { version = "4.1.13", features = ["derive"] } +clap = { version = "4.1.14", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.3.4" diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index ea2c5c3fc13..5388b83e23e 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -10,7 +10,7 @@ path = "src/main.rs" [dependencies] async-trait = "0.1.68" -clap = { version = "4.1.13", features = ["derive"] } +clap = { version = "4.1.14", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.4.0", features = [ "async_tokio" ] } jsonrpsee = { version = "0.16.2", features = ["server"] } From 66bfb2c7b4740c1624171faef19b3f382d02da47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20K=C3=B6cher?= Date: Mon, 3 Apr 2023 12:55:29 +0200 Subject: [PATCH 23/57] Update Substrate & Polkadot (#2422) --- Cargo.lock | 565 ++++++++++++++++++++++++++++------------------------- 1 file changed, 298 insertions(+), 267 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06a1ea811aa..85a361e944b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -523,7 +523,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "hash-db", "log", @@ -2558,13 +2558,14 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.1" +version = "4.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4033478fbf70d6acf2655ac70da91ee65852d69daf7a67bf7a2f518fb47aafcf" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.6.4", + "cfg-if", + "fiat-crypto", + "packed_simd_2", + "platforms 3.0.2", "subtle", "zeroize", ] @@ -3270,6 +3271,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "file-per-thread-logger" version = "0.1.4" @@ -3357,7 +3364,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", ] @@ -3380,7 +3387,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-support-procedural", @@ -3405,7 +3412,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -3452,7 +3459,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3463,7 +3470,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3480,7 +3487,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -3509,7 +3516,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "log", @@ -3525,7 +3532,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "bitflags", "environmental", @@ -3558,7 +3565,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "Inflector", "cfg-expr", @@ -3573,7 +3580,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3585,7 +3592,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro2", "quote", @@ -3595,7 +3602,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "log", @@ -3613,7 +3620,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -3628,7 +3635,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "sp-api", @@ -3637,7 +3644,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "parity-scale-codec", @@ -4600,7 +4607,7 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "frame-benchmarking", @@ -4698,7 +4705,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "frame-support", "polkadot-primitives", @@ -4770,6 +4777,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + [[package]] name = "libm" version = "0.2.1" @@ -5546,7 +5559,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "log", @@ -5565,7 +5578,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "anyhow", "jsonrpsee", @@ -6051,10 +6064,20 @@ dependencies = [ "sha2 0.10.2", ] +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm 0.1.4", +] + [[package]] name = "pallet-alliance" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -6075,7 +6098,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6093,7 +6116,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6108,7 +6131,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6124,7 +6147,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6140,7 +6163,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6154,7 +6177,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6178,7 +6201,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6198,7 +6221,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6213,7 +6236,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6232,7 +6255,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6256,7 +6279,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6274,7 +6297,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6318,7 +6341,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6335,7 +6358,7 @@ dependencies = [ [[package]] name = "pallet-contracts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "bitflags", "environmental", @@ -6365,7 +6388,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "bitflags", "parity-scale-codec", @@ -6378,7 +6401,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro2", "quote", @@ -6388,7 +6411,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6405,7 +6428,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6423,7 +6446,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6446,7 +6469,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6459,7 +6482,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6477,7 +6500,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6495,7 +6518,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6518,7 +6541,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6534,7 +6557,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6554,7 +6577,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6571,7 +6594,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6585,7 +6608,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6602,7 +6625,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6619,7 +6642,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6635,7 +6658,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6653,7 +6676,7 @@ dependencies = [ [[package]] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "pallet-nfts", @@ -6664,7 +6687,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6680,7 +6703,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6697,7 +6720,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6717,7 +6740,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6728,7 +6751,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6745,7 +6768,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6769,7 +6792,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6786,7 +6809,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6801,7 +6824,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6819,7 +6842,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6834,7 +6857,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6853,7 +6876,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6870,7 +6893,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6891,7 +6914,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6907,7 +6930,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -6921,7 +6944,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6944,7 +6967,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6955,7 +6978,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "log", "sp-arithmetic", @@ -6964,7 +6987,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "sp-api", @@ -6973,7 +6996,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -6990,7 +7013,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -7019,7 +7042,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -7037,7 +7060,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -7056,7 +7079,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-support", "frame-system", @@ -7072,7 +7095,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7088,7 +7111,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7100,7 +7123,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -7117,7 +7140,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -7132,7 +7155,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -7148,7 +7171,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -7163,7 +7186,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-benchmarking", "frame-support", @@ -7178,7 +7201,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7199,7 +7222,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "frame-benchmarking", "frame-support", @@ -7711,6 +7734,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "plotters" version = "0.3.1" @@ -7742,9 +7771,10 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", + "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7757,7 +7787,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7771,7 +7801,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "derive_more", "fatality", @@ -7794,7 +7824,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "fatality", "futures", @@ -7815,7 +7845,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "clap 4.1.14", "frame-benchmarking-cli", @@ -7843,7 +7873,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "frame-benchmarking", @@ -7886,7 +7916,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "always-assert", "bitvec", @@ -7908,7 +7938,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "parity-scale-codec", "scale-info", @@ -7920,7 +7950,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "derive_more", "fatality", @@ -7945,7 +7975,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7959,7 +7989,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", "futures-timer", @@ -7979,7 +8009,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "always-assert", "async-trait", @@ -8002,7 +8032,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", "parity-scale-codec", @@ -8020,7 +8050,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "derive_more", @@ -8049,7 +8079,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "futures", @@ -8070,7 +8100,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "fatality", @@ -8089,7 +8119,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8104,7 +8134,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "futures", @@ -8124,7 +8154,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", "polkadot-node-metrics", @@ -8139,7 +8169,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", "futures-timer", @@ -8156,7 +8186,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "fatality", "futures", @@ -8175,7 +8205,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "futures", @@ -8192,7 +8222,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "fatality", @@ -8210,7 +8240,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "always-assert", "assert_matches", @@ -8247,7 +8277,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", "polkadot-node-primitives", @@ -8263,7 +8293,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "futures", "lru 0.9.0", @@ -8278,7 +8308,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "lazy_static", "log", @@ -8296,7 +8326,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bs58", "futures", @@ -8315,7 +8345,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "derive_more", @@ -8337,7 +8367,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bounded-vec", "futures", @@ -8360,7 +8390,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8370,7 +8400,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "futures", @@ -8388,7 +8418,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "derive_more", @@ -8411,7 +8441,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "derive_more", @@ -8444,7 +8474,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "futures", @@ -8467,7 +8497,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bounded-collections", "derive_more", @@ -8565,7 +8595,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -8581,7 +8611,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "hex-literal", @@ -8607,7 +8637,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8639,7 +8669,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "frame-benchmarking", @@ -8733,7 +8763,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "frame-benchmarking", @@ -8779,7 +8809,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "frame-support", "polkadot-primitives", @@ -8793,7 +8823,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bs58", "parity-scale-codec", @@ -8805,7 +8835,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitflags", "bitvec", @@ -8849,7 +8879,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "async-trait", "frame-benchmarking-cli", @@ -8959,7 +8989,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -8980,7 +9010,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -8990,7 +9020,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -9015,7 +9045,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "frame-election-provider-support", @@ -9076,7 +9106,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "frame-benchmarking", "frame-system", @@ -9821,7 +9851,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9907,7 +9937,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "frame-support", "polkadot-primitives", @@ -10154,7 +10184,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "log", "sp-core", @@ -10165,7 +10195,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "futures", @@ -10193,7 +10223,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "futures-timer", @@ -10216,7 +10246,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10231,7 +10261,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10250,7 +10280,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10261,7 +10291,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -10301,7 +10331,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "fnv", "futures", @@ -10327,7 +10357,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "hash-db", "kvdb", @@ -10353,7 +10383,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "futures", @@ -10378,7 +10408,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "futures", @@ -10407,7 +10437,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "fork-tree", @@ -10446,7 +10476,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "jsonrpsee", @@ -10468,7 +10498,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10503,7 +10533,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "jsonrpsee", @@ -10522,7 +10552,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10535,7 +10565,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "ahash 0.8.2", "array-bytes 4.2.0", @@ -10575,7 +10605,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "finality-grandpa", "futures", @@ -10595,7 +10625,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "futures", @@ -10618,7 +10648,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10642,7 +10672,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10655,7 +10685,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "log", "sc-allocator", @@ -10668,7 +10698,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "anyhow", "cfg-if", @@ -10686,7 +10716,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "ansi_term", "futures", @@ -10702,7 +10732,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10717,7 +10747,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10747,6 +10777,7 @@ dependencies = [ "serde", "serde_json", "smallvec", + "snow", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -10761,7 +10792,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "cid", "futures", @@ -10781,7 +10812,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10809,7 +10840,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "ahash 0.8.2", "futures", @@ -10828,7 +10859,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10850,7 +10881,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10884,7 +10915,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10904,7 +10935,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10935,7 +10966,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "libp2p", @@ -10948,7 +10979,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10957,7 +10988,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "jsonrpsee", @@ -10987,7 +11018,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11006,7 +11037,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "http", "jsonrpsee", @@ -11021,7 +11052,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "futures", @@ -11047,7 +11078,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "directories", @@ -11113,7 +11144,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "log", "parity-scale-codec", @@ -11124,7 +11155,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "clap 4.1.14", "fs4", @@ -11140,7 +11171,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11159,7 +11190,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "libc", @@ -11178,7 +11209,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "chrono", "futures", @@ -11197,7 +11228,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "ansi_term", "atty", @@ -11228,7 +11259,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11239,7 +11270,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "futures", @@ -11266,7 +11297,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "futures", @@ -11280,7 +11311,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-channel", "futures", @@ -11761,7 +11792,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "enumn", "parity-scale-codec", @@ -11793,14 +11824,14 @@ checksum = "45456094d1983e2ee2a18fdfebce3189fa451699d0502cb8e3b49dba5ba41451" [[package]] name = "snow" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774d05a3edae07ce6d68ea6984f3c05e9bba8927e3dd591e3b479e5b03213d0d" +checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" dependencies = [ "aes-gcm 0.9.4", "blake2", "chacha20poly1305", - "curve25519-dalek 4.0.0-pre.1", + "curve25519-dalek 4.0.0-rc.1", "rand_core 0.6.4", "ring", "rustc_version 0.4.0", @@ -11838,7 +11869,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "hash-db", "log", @@ -11856,7 +11887,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "Inflector", "blake2", @@ -11870,7 +11901,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "scale-info", @@ -11883,7 +11914,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "integer-sqrt", "num-traits", @@ -11897,7 +11928,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "scale-info", @@ -11910,7 +11941,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "sp-api", @@ -11922,7 +11953,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "log", @@ -11940,7 +11971,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "futures", @@ -11955,7 +11986,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "parity-scale-codec", @@ -11973,7 +12004,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "merlin", @@ -11996,7 +12027,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "lazy_static", "parity-scale-codec", @@ -12015,7 +12046,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "finality-grandpa", "log", @@ -12033,7 +12064,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "scale-info", @@ -12045,7 +12076,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "scale-info", @@ -12058,7 +12089,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "bitflags", @@ -12101,7 +12132,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "blake2b_simd", "byteorder", @@ -12115,7 +12146,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro2", "quote", @@ -12126,7 +12157,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12135,7 +12166,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro2", "quote", @@ -12145,7 +12176,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "environmental", "parity-scale-codec", @@ -12156,7 +12187,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12171,7 +12202,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "bytes", "ed25519", @@ -12197,7 +12228,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "lazy_static", "sp-core", @@ -12208,7 +12239,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "merlin", @@ -12224,7 +12255,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "thiserror", "zstd", @@ -12233,7 +12264,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12251,7 +12282,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "scale-info", @@ -12265,7 +12296,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "sp-api", "sp-core", @@ -12275,7 +12306,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "backtrace", "lazy_static", @@ -12285,7 +12316,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "rustc-hash", "serde", @@ -12295,7 +12326,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "either", "hash256-std-hasher", @@ -12317,7 +12348,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12335,7 +12366,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "Inflector", "proc-macro-crate", @@ -12347,7 +12378,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "serde", "serde_json", @@ -12356,7 +12387,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "scale-info", @@ -12370,7 +12401,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "scale-info", @@ -12382,7 +12413,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "hash-db", "log", @@ -12402,12 +12433,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12420,7 +12451,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "futures-timer", @@ -12435,7 +12466,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "sp-std", @@ -12447,7 +12478,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "sp-api", "sp-runtime", @@ -12456,7 +12487,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "log", @@ -12472,7 +12503,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "ahash 0.8.2", "hash-db", @@ -12495,7 +12526,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12512,7 +12543,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12523,7 +12554,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12537,7 +12568,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "parity-scale-codec", "scale-info", @@ -12861,15 +12892,15 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ - "platforms", + "platforms 2.0.0", ] [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12888,7 +12919,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "hyper", "log", @@ -12900,7 +12931,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "jsonrpsee", @@ -12913,7 +12944,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "jsonrpsee", "log", @@ -12932,7 +12963,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -12958,7 +12989,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "futures", "substrate-test-utils-derive", @@ -12968,7 +12999,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -12979,7 +13010,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "ansi_term", "build-helper", @@ -13106,7 +13137,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "frame-support", "polkadot-primitives", @@ -13496,7 +13527,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13507,7 +13538,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -13637,7 +13668,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#de4cca40b5da41e76c111c66229521f1052ea298" +source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" dependencies = [ "async-trait", "clap 4.1.14", @@ -14085,7 +14116,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" dependencies = [ "downcast-rs", - "libm", + "libm 0.2.1", "memory_units", "num-rational", "num-traits", @@ -14099,7 +14130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" dependencies = [ "downcast-rs", - "libm", + "libm 0.2.1", "num-traits", "paste", ] @@ -14565,7 +14596,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", "frame-benchmarking", @@ -14657,7 +14688,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "frame-support", "polkadot-primitives", @@ -15093,7 +15124,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bounded-collections", "derivative", @@ -15109,7 +15140,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "frame-support", "frame-system", @@ -15130,7 +15161,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "environmental", "frame-benchmarking", @@ -15150,7 +15181,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2708cf111392e3d9a02471c1b50b6079c278d2f4" +source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "Inflector", "proc-macro2", From d12c6d03c94bb93b071595d1a93e8e4dfdd65e10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 21:51:47 +0000 Subject: [PATCH 24/57] Bump syn from 2.0.12 to 2.0.13 (#2428) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.12 to 2.0.13. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.12...2.0.13) --- updated-dependencies: - dependency-name: syn 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 | 22 +++++++++---------- .../parachain-system/proc-macro/Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85a361e944b..83cf774daea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,7 +427,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -1223,7 +1223,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -2119,7 +2119,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -3764,7 +3764,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -9325,9 +9325,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -11589,7 +11589,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -13052,9 +13052,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.12" +version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" dependencies = [ "proc-macro2", "quote", @@ -13171,7 +13171,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] @@ -13342,7 +13342,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.12", + "syn 2.0.13", ] [[package]] diff --git a/pallets/parachain-system/proc-macro/Cargo.toml b/pallets/parachain-system/proc-macro/Cargo.toml index e42d076c77e..170372eb2b1 100644 --- a/pallets/parachain-system/proc-macro/Cargo.toml +++ b/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.12" +syn = "2.0.13" proc-macro2 = "1.0.54" quote = "1.0.26" proc-macro-crate = "1.3.1" From 697f0cd1d8900153e4bd4f7bc91c547d6f476362 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 21:53:58 +0000 Subject: [PATCH 25/57] Bump hex-literal from 0.3.4 to 0.4.0 (#2426) Bumps [hex-literal](https://github.com/RustCrypto/utils) from 0.3.4 to 0.4.0. - [Release notes](https://github.com/RustCrypto/utils/releases) - [Commits](https://github.com/RustCrypto/utils/compare/hex-literal-v0.3.4...hex-literal-v0.4.0) --- 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> --- Cargo.lock | 44 +++++++++++-------- pallets/parachain-system/Cargo.toml | 2 +- parachain-template/runtime/Cargo.toml | 2 +- .../runtimes/assets/statemine/Cargo.toml | 2 +- .../runtimes/assets/statemint/Cargo.toml | 4 +- .../runtimes/assets/westmint/Cargo.toml | 4 +- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 2 +- .../bridge-hub-polkadot/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- .../collectives-polkadot/Cargo.toml | 4 +- .../contracts/contracts-rococo/Cargo.toml | 2 +- parachains/runtimes/testing/penpal/Cargo.toml | 2 +- polkadot-parachain/Cargo.toml | 2 +- 13 files changed, 40 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 83cf774daea..a9cf1112cb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,7 +342,7 @@ dependencies = [ "cumulus-test-relay-sproof-builder", "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.3.4", "pallet-assets", "pallet-balances", "pallet-collator-selection", @@ -716,7 +716,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "kusama-runtime-constants", "log", "pallet-aura", @@ -779,7 +779,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "log", "pallet-aura", "pallet-authorship", @@ -842,7 +842,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "log", "pallet-aura", "pallet-authorship", @@ -1283,7 +1283,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "log", "pallet-alliance", "pallet-aura", @@ -1418,7 +1418,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "kusama-runtime-constants", "log", "pallet-aura", @@ -2090,7 +2090,7 @@ dependencies = [ "environmental", "frame-support", "frame-system", - "hex-literal", + "hex-literal 0.4.0", "impl-trait-for-tuples", "lazy_static", "log", @@ -4061,6 +4061,12 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +[[package]] +name = "hex-literal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcb5b3e439c92a7191df2f9bbe733de8de55c3f86368cdb1c63f8be7e9e328e" + [[package]] name = "hkdf" version = "0.12.3" @@ -4618,7 +4624,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "kusama-runtime-constants", "log", "pallet-authority-discovery", @@ -7323,7 +7329,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "log", "pallet-aura", "pallet-authorship", @@ -7566,7 +7572,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "log", "pallet-asset-tx-payment", "pallet-assets", @@ -8535,7 +8541,7 @@ dependencies = [ "frame-benchmarking", "frame-benchmarking-cli", "futures", - "hex-literal", + "hex-literal 0.4.0", "jsonrpsee", "log", "nix 0.26.2", @@ -8614,7 +8620,7 @@ version = "0.9.39" source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" dependencies = [ "bitvec", - "hex-literal", + "hex-literal 0.3.4", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", @@ -8680,7 +8686,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", @@ -8886,7 +8892,7 @@ dependencies = [ "frame-support", "frame-system-rpc-runtime-api", "futures", - "hex-literal", + "hex-literal 0.3.4", "kusama-runtime", "kvdb", "kvdb-rocksdb", @@ -9861,7 +9867,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", @@ -12655,7 +12661,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "kusama-runtime-constants", "log", "pallet-asset-tx-payment", @@ -12725,7 +12731,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "log", "pallet-asset-tx-payment", "pallet-assets", @@ -14607,7 +14613,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", @@ -14721,7 +14727,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.4.0", "log", "pallet-asset-tx-payment", "pallet-assets", diff --git a/pallets/parachain-system/Cargo.toml b/pallets/parachain-system/Cargo.toml index b7eef00712e..c4aa4ffa1e3 100644 --- a/pallets/parachain-system/Cargo.toml +++ b/pallets/parachain-system/Cargo.toml @@ -36,7 +36,7 @@ cumulus-primitives-core = { path = "../../primitives/core", default-features = f cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent", default-features = false } [dev-dependencies] -hex-literal = "0.3.4" +hex-literal = "0.4.0" lazy_static = "1.4" # Substrate diff --git a/parachain-template/runtime/Cargo.toml b/parachain-template/runtime/Cargo.toml index fe15f82af0e..0fa6948d58b 100644 --- a/parachain-template/runtime/Cargo.toml +++ b/parachain-template/runtime/Cargo.toml @@ -16,7 +16,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.3.4", optional = true } +hex-literal = { version = "0.4.0", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" diff --git a/parachains/runtimes/assets/statemine/Cargo.toml b/parachains/runtimes/assets/statemine/Cargo.toml index 704a49a0a55..3fdac10c637 100644 --- a/parachains/runtimes/assets/statemine/Cargo.toml +++ b/parachains/runtimes/assets/statemine/Cargo.toml @@ -7,7 +7,7 @@ description = "Kusama variant of Statemint parachain runtime" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = "0.3.4" } +hex-literal = { version = "0.4.0" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" diff --git a/parachains/runtimes/assets/statemint/Cargo.toml b/parachains/runtimes/assets/statemint/Cargo.toml index bd482fd2a06..273c3ff5c2c 100644 --- a/parachains/runtimes/assets/statemint/Cargo.toml +++ b/parachains/runtimes/assets/statemint/Cargo.toml @@ -7,7 +7,7 @@ description = "Statemint parachain runtime" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = "0.3.4", optional = true } +hex-literal = { version = "0.4.0", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" @@ -73,7 +73,7 @@ parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } [dev-dependencies] -hex-literal = "0.3.4" +hex-literal = "0.4.0" asset-test-utils = { path = "../test-utils"} [build-dependencies] diff --git a/parachains/runtimes/assets/westmint/Cargo.toml b/parachains/runtimes/assets/westmint/Cargo.toml index d98db24e185..89b59b7def4 100644 --- a/parachains/runtimes/assets/westmint/Cargo.toml +++ b/parachains/runtimes/assets/westmint/Cargo.toml @@ -7,7 +7,7 @@ description = "Westend variant of Statemint parachain runtime" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "max-encoded-len"] } -hex-literal = { version = "0.3.4", optional = true } +hex-literal = { version = "0.4.0", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" @@ -74,7 +74,7 @@ parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } [dev-dependencies] -hex-literal = "0.3.4" +hex-literal = "0.4.0" asset-test-utils = { path = "../test-utils"} [build-dependencies] diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml index f0392c7716b..9d8703a6ab8 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -10,7 +10,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.3.4" } +hex-literal = { version = "0.4.0" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml index 8f29167a24f..2d00cd9fce3 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -10,7 +10,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.3.4" } +hex-literal = { version = "0.4.0" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 30e3cad3e21..8cc54ac2672 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -10,7 +10,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.3.4" } +hex-literal = { version = "0.4.0" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } diff --git a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index ba3b9ece735..c0659ffb825 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -7,7 +7,7 @@ description = "Polkadot 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.3.4", optional = true } +hex-literal = { version = "0.4.0", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" @@ -74,7 +74,7 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features = parachains-common = { path = "../../../common", default-features = false } [dev-dependencies] -hex-literal = "0.3.4" +hex-literal = "0.4.0" [build-dependencies] substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } diff --git a/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index b667bbf8a98..9b5809b3d38 100644 --- a/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.3.4", optional = true } +hex-literal = { version = "0.4.0", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" diff --git a/parachains/runtimes/testing/penpal/Cargo.toml b/parachains/runtimes/testing/penpal/Cargo.toml index e1ff15b0e02..105f5f8072a 100644 --- a/parachains/runtimes/testing/penpal/Cargo.toml +++ b/parachains/runtimes/testing/penpal/Cargo.toml @@ -16,7 +16,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.3.4", optional = true } +hex-literal = { version = "0.4.0", optional = true } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index dca3d1edf66..9b1e0e10484 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -15,7 +15,7 @@ async-trait = "0.1.68" clap = { version = "4.1.14", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" -hex-literal = "0.3.4" +hex-literal = "0.4.0" log = "0.4.17" serde = { version = "1.0.159", features = ["derive"] } From 2b4467cf6c20a5ce62ec908167f8463d34225eda Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 27 Mar 2023 11:49:26 +0200 Subject: [PATCH 26/57] Updated scripts for transfer assets --- parachains/runtimes/bridge-hubs/README.md | 17 + scripts/bridges_rococo_wococo.sh | 531 +++++++++------------ scripts/generate_hex_encoded_call/index.js | 64 ++- 3 files changed, 291 insertions(+), 321 deletions(-) diff --git a/parachains/runtimes/bridge-hubs/README.md b/parachains/runtimes/bridge-hubs/README.md index c7f8378ad04..788e767f0fc 100644 --- a/parachains/runtimes/bridge-hubs/README.md +++ b/parachains/runtimes/bridge-hubs/README.md @@ -169,6 +169,23 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ ### Send messages (Rococo, Wococo) +#### Transfer assets via bridge + +1. allow bridge transfer on statemine/westmint (governance-like): + ``` + ./scripts/bridges_rococo_wococo.sh allow-transfers-local + ``` + +2. do transfer from statemine to westmint + ``` + ./scripts/bridges_rococo_wococo.sh transfer-asset-from-statemine-local + ``` + +#### Ping via bridge +``` +./scripts/bridges_rococo_wococo.sh allow-transfers-local +./scripts/bridges_rococo_wococo.sh ping-via-bridge-from-statemine-local +``` #### Local Rococo:Statemine -> Wococo:Westmint - check that relayers are up and running (see above) diff --git a/scripts/bridges_rococo_wococo.sh b/scripts/bridges_rococo_wococo.sh index a9375b8150d..e5c19d3004e 100755 --- a/scripts/bridges_rococo_wococo.sh +++ b/scripts/bridges_rococo_wococo.sh @@ -74,65 +74,70 @@ function generate_hex_encoded_call_data() { return $retVal } -STATEMINE_ACCOUNT_SEED_FOR_LOCAL="//Alice" -ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO="scatter feed race company oxygen trip extra elbow slot bundle auto canoe" - -function send_xcm_transact_remark_from_statemine() { - local url=$1 +function transfer_balance() { + local runtime_para_endpoint=$1 local seed=$2 - local bridge_hub_para_id=$3 - local target_network=$4 - local target_network_para_id=$5 - local target_network_para_endpoint=$6 - echo " calling send_xcm_transact_remark_from_statemine:" - echo " url: ${url}" + local target_account=$3 + local amount=$4 + echo " calling transfer_balance:" + echo " runtime_para_endpoint: ${runtime_para_endpoint}" echo " seed: ${seed}" - echo " bridge_hub_para_id: ${bridge_hub_para_id}" - echo " target_network: ${target_network}" - echo " target_network_para_id: ${target_network_para_id}" - echo " target_network_para_endpoint: ${target_network_para_endpoint}" - echo " params:" + echo " target_account: ${target_account}" + echo " amount: ${amount}" + echo "--------------------------------------------------" + + polkadot-js-api \ + --ws "${runtime_para_endpoint}" \ + --seed "${seed?}" \ + tx.balances.transfer \ + "${target_account}" \ + "${amount}" +} - # generate data for Transact on the other side (Westmint) - local tmp_file=$(mktemp) - generate_hex_encoded_call_data "remark-with-event" "${target_network_para_endpoint}" "${tmp_file}" - local hex_encoded_data=$(cat $tmp_file) +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 bridge_hub_para_id "$bridge_hub_para_id" \ - '{ "V3": { "parents": 1, "interior": { "X1": { "Parachain": $bridge_hub_para_id } } } }') + --arg para_id "$para_id" \ + '{ "V3": { "parents": 0, "interior": { "X1": { "Parachain": $para_id } } } }') local message=$(jq --null-input \ - --arg target_network "$target_network" \ - --arg target_network_para_id "$target_network_para_id" \ --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": [ - { - "ExportMessage": { - "network": $target_network, - "destination": { - "X1": { - "Parachain": $target_network_para_id - } - }, - "xcm": [ + { + "UnpaidExecution": { + "weight_limit": "Unlimited" + } + }, { "Transact": { - "origin_kind": "SovereignAccount", + "origin_kind": "Superuser", "require_weight_at_most": { - "ref_time": 1000000000, - "proof_size": 0, + "ref_time": $require_weight_at_most_ref_time, + "proof_size": $require_weight_at_most_proof_size, }, "call": { "encoded": $hex_encoded_data } } } - ] - } - } ] } ') @@ -147,13 +152,17 @@ function send_xcm_transact_remark_from_statemine() { echo "--------------------------------------------------" polkadot-js-api \ - --ws "${url?}" \ - --seed "${seed?}" \ - tx.polkadotXcm.send \ + --ws "${relay_url?}" \ + --seed "${relay_chain_seed?}" \ + --sudo \ + tx.xcmPallet.send \ "${dest}" \ "${message}" } +STATEMINE_ACCOUNT_SEED_FOR_LOCAL="//Alice" +ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO="scatter feed race company oxygen trip extra elbow slot bundle auto canoe" + function send_xcm_trap_from_statemine() { local url=$1 local seed=$2 @@ -212,30 +221,29 @@ function send_xcm_trap_from_statemine() { "${message}" } -function allow_assets_transfer_from_statemine() { +function allow_assets_transfer_send() { local relay_url=$1 local relay_chain_seed=$2 - local statemine_para_id=$3 - local statemine_para_endpoint=$4 + local runtime_para_id=$3 + local runtime_para_endpoint=$4 local bridge_hub_para_id=$5 - local statemint_para_network=$6 - local statemint_para_para_id=$7 - echo " calling allow_assets_transfer_from_statemine:" + 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 " statemine_para_id: ${statemine_para_id}" - echo " statemine_para_endpoint: ${statemine_para_endpoint}" + echo " runtime_para_id: ${runtime_para_id}" + echo " runtime_para_endpoint: ${runtime_para_endpoint}" echo " bridge_hub_para_id: ${bridge_hub_para_id}" - echo " statemint_para_network: ${statemint_para_network}" - echo " statemint_para_para_id: ${statemint_para_para_id}" + echo " bridged_para_network: ${bridged_para_network}" + echo " bridged_para_para_id: ${bridged_para_para_id}" echo " params:" - # generate data for Transact on Statemine + # 1. generate data for Transact (add_exporter_config) local bridge_config=$(jq --null-input \ - --arg statemint_para_network "$statemint_para_network" \ --arg bridge_hub_para_id "$bridge_hub_para_id" \ - --arg statemint_para_network "$statemint_para_network" \ - --arg statemint_para_para_id "$statemint_para_para_id" \ + --arg bridged_para_network "$bridged_para_network" \ + --arg bridged_para_para_id "$bridged_para_para_id" \ ' { "bridgeLocation": { @@ -249,133 +257,149 @@ function allow_assets_transfer_from_statemine() { "interior": { "X2": [ { - "GlobalConsensus": $statemint_para_network, + "GlobalConsensus": $bridged_para_network, }, { - "Parachain": $statemint_para_para_id + "Parachain": $bridged_para_para_id } ] } + }, + "targetLocationFee": { + "id": { + "Concrete": { + "parents": 1, + "interior": "Here" + } + }, + "fun": { + "Fungible": 50000000000 + } } } ' ) local tmp_output_file=$(mktemp) - generate_hex_encoded_call_data "add-bridge-config" "${statemine_para_endpoint}" "${tmp_output_file}" $statemint_para_network "$bridge_config" + 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) - local dest=$(jq --null-input \ - --arg statemine_para_id "$statemine_para_id" \ - '{ "V3": { "parents": 0, "interior": { "X1": { "Parachain": $statemine_para_id } } } }') + send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 +} - local message=$(jq --null-input \ - --argjson hex_encoded_data $hex_encoded_data \ - ' - { - "V3": [ - { - "UnpaidExecution": { - "weight_limit": "Unlimited" - } - }, - { - "Transact": { - "origin_kind": "Superuser", - "require_weight_at_most": { - "ref_time": 1000000000, - "proof_size": 0, - }, - "call": { - "encoded": $hex_encoded_data - } - } - } - ] - } - ') +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 global_consensus=$5 + local asset_owner_account_id=$6 + 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 " global_consensus: ${global_consensus}" + echo " asset_owner_account_id: ${asset_owner_account_id}" + echo " params:" - echo "" - echo " dest:" - echo "${dest}" - echo "" - echo " message:" - echo "${message}" - echo "" - echo "--------------------------------------------------" + # 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) - polkadot-js-api \ - --ws "${relay_url?}" \ - --seed "${relay_chain_seed?}" \ - --sudo \ - tx.xcmPallet.send \ - "${dest}" \ - "${message}" + send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 } -function remove_assets_transfer_from_statemine() { +function allow_assets_transfer_receive() { local relay_url=$1 local relay_chain_seed=$2 - local statemine_para_id=$3 - local statemine_para_endpoint=$4 - local statemint_para_network=$5 - echo " calling remove_assets_transfer_from_statemine:" + 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:" echo " relay_url: ${relay_url}" echo " relay_chain_seed: ${relay_chain_seed}" - echo " statemine_para_id: ${statemine_para_id}" - echo " statemine_para_endpoint: ${statemine_para_endpoint}" - echo " statemint_para_network: ${statemint_para_network}" + 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 " 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 "remove-bridge-config" "${statemine_para_endpoint}" "${tmp_output_file}" $statemint_para_network + generate_hex_encoded_call_data "add-universal-alias" "${runtime_para_endpoint}" "${tmp_output_file}" "$location" "$junction" local hex_encoded_data=$(cat $tmp_output_file) - local dest=$(jq --null-input \ - --arg statemine_para_id "$statemine_para_id" \ - '{ "V3": { "parents": 0, "interior": { "X1": { "Parachain": $statemine_para_id } } } }') - - local message=$(jq --null-input \ - --argjson hex_encoded_data $hex_encoded_data \ - ' - { - "V3": [ - { - "UnpaidExecution": { - "weight_limit": "Unlimited" - } - }, - { - "Transact": { - "origin_kind": "Superuser", - "require_weight_at_most": { - "ref_time": 1000000000, - "proof_size": 0, - }, - "call": { - "encoded": $hex_encoded_data - } + 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 } - } - ] - } - ') + ] + } + } }') - echo "" - echo " dest:" - echo "${dest}" - echo "" - echo " message:" - echo "${message}" - echo "" - echo "--------------------------------------------------" + local tmp_output_file=$(mktemp) + generate_hex_encoded_call_data "add-reserve-location" "${runtime_para_endpoint}" "${tmp_output_file}" "$reserve_location" + local hex_encoded_data=$(cat $tmp_output_file) - polkadot-js-api \ - --ws "${relay_url?}" \ - --seed "${relay_chain_seed?}" \ - --sudo \ - tx.xcmPallet.send \ - "${dest}" \ - "${message}" + send_governance_transact "${relay_url}" "${relay_chain_seed}" "${runtime_para_id}" "${hex_encoded_data}" 200000000 12000 +} + +function remove_assets_transfer_send() { + 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:" + 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 " params:" + + local tmp_output_file=$(mktemp) + generate_hex_encoded_call_data "remove-exporter-config" "${runtime_para_endpoint}" "${tmp_output_file}" $bridged_network + local hex_encoded_data=$(cat $tmp_output_file) + + 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 @@ -411,7 +435,9 @@ function transfer_asset_via_bridge() { ) -## TODO: decode some account to bytes: "id": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" +## // TODO:check-parameter - find dynamic way to decode some account to bytes: "id": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" +## AccountId32::from_str("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY").unwrap().0` -> [u8; 32] +## [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] local destination=$(jq --null-input \ ' @@ -428,7 +454,7 @@ function transfer_asset_via_bridge() { }, { "AccountId32": { - "id": [28, 189, 45, 67, 83, 10, 68, 112, 90, 208, 136, 175, 49, 62, 24, 248, 11, 83, 239, 22, 179, 97, 119, 205, 75, 119, 184, 70, 242, 165, 240, 124] + "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] } } ] @@ -447,65 +473,14 @@ function transfer_asset_via_bridge() { echo "" echo "--------------------------------------------------" -# local tmp_output_file=$(mktemp) -# generate_hex_encoded_call_data "transfer-asset-via-bridge" "${url}" "${tmp_output_file}" "$assets" "$destination" -# local hex_encoded_data=$(cat $tmp_output_file) - polkadot-js-api \ --ws "${url?}" \ --seed "${seed?}" \ - tx.bridgeAssetsTransfer.transferAssetViaBridge \ + tx.bridgeTransfer.transferAssetViaBridge \ "${assets}" \ "${destination}" } -function register_parachain() { - local PORT=$1 - local PARA_ID=$2 - local GENESIS_FILE=$3 - local GENESIS_WASM_FILE=$4 - - echo "" - echo "" - echo " Please, register parachain: https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A${PORT}#/sudo" - echo " parasSudoWrapper.sudoScheduleParaInitialize:" - echo " ParaId: $PARA_ID" - echo " Genesis (file): $GENESIS_FILE" - echo " Genesis wasm (file): $GENESIS_WASM_FILE" - echo " Parachain: Yes" - echo "" - echo "" - - # TODO: find the way to do it automatically -} - -function show_node_log_file() { - local NAME=$1 - local WS_PORT=$2 - local FILE_PATH=$3 - - echo "" - echo "" - echo " Node(${NAME}): ws-port: ${WS_PORT}" - echo " Logs: ${FILE_PATH}" - echo "" - echo "" -} - -function check_parachain_collator() { - local PORT=$1 - local PALLET=$2 - - echo "" - echo "" - echo " Once relayers work, check parachain: https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A${PORT}#/chainstate" - echo " Pallet: ${PALLET}" - echo " Keys:" - echo " bestFinalized()" - echo "" - echo "" -} - function init_ro_wo() { ensure_relayer @@ -563,95 +538,11 @@ function run_relay() { } case "$1" in - start-rococo) - ensure_binaries - - # TODO: change to generate: ./bin/polkadot key generate-node-key - VALIDATOR_KEY_ALICE=(12D3KooWRD6kEQuKDn7BCsMfW71U8AEFDYTc7N2dFQthRsjSR8J5 aa5dc9a97f82f9af38d1f16fbc9c72e915577c3ca654f7d33601645ca5b9a8a5) - VALIDATOR_KEY_BOB=(12D3KooWELR4gpc8unmH8WiauK133v397KoMfkkjESWJrzg7Y3Pq 556a36beaeeb95225eb84ae2633bd8135e5ace22f03291853654f07bc5da20ae) - VALIDATOR_KEY_CHARLIE=(12D3KooWRatYNHCRpyzhjPqfSPHYsUTi1zX4452kxSWg8ek99Vun 56e6593340685021d27509c0f48836c1dcb84c5aeba730ada68f54a9ae242e67) - COLLATOR_KEY_ALICE=(12D3KooWAU51GKCfPBfhaKK8gr6XmHNVXd4e96BYL9v2QkWtDrAm 15642c2e078ddfaacd1e68afcc8bab6dd8085b72b3038b799ddfb46bec18696c) - COLLATOR_KEY_BOB=(12D3KooWPg8SEatSi9HvdPJVYBNxeNAvyPTo3Rd4WPdzLRcM8gaS ac651cd6b9a2c7768bca92369ecd4807b54059c33775257e6ba5f72ae91a136d) - - # Start Rococo relay - ~/local_bridge_testing/bin/polkadot build-spec --chain rococo-local --disable-default-bootnode --raw > ~/local_bridge_testing/rococo-local-cfde.json - ~/local_bridge_testing/bin/polkadot --chain ~/local_bridge_testing/rococo-local-cfde.json --alice --tmp --port 30332 --rpc-port 9932 --ws-port 9942 --no-mdns --node-key ${VALIDATOR_KEY_ALICE[1]} --bootnodes=/ip4/127.0.0.1/tcp/30333/p2p/${VALIDATOR_KEY_BOB[0]} &> ~/local_bridge_testing/logs/rococo_relay_alice.log & - ~/local_bridge_testing/bin/polkadot --chain ~/local_bridge_testing/rococo-local-cfde.json --bob --tmp --port 30333 --rpc-port 9933 --ws-port 9943 --no-mdns --node-key ${VALIDATOR_KEY_BOB[1]} --bootnodes=/ip4/127.0.0.1/tcp/30332/p2p/${VALIDATOR_KEY_ALICE[0]} &> ~/local_bridge_testing/logs/rococo_relay_bob.log & - ~/local_bridge_testing/bin/polkadot --chain ~/local_bridge_testing/rococo-local-cfde.json --charlie --tmp --port 30334 --rpc-port 9934 --ws-port 9944 --no-mdns ${VALIDATOR_KEY_CHARLIE[1]} --bootnodes=/ip4/127.0.0.1/tcp/30332/p2p/${VALIDATOR_KEY_ALICE[0]} &> ~/local_bridge_testing/logs/rococo_relay_charlie.log & - sleep 2 - - # Prepare Rococo parachain - rm ~/local_bridge_testing/bridge-hub-rococo-local-raw.json - ~/local_bridge_testing/bin/polkadot-parachain build-spec --chain bridge-hub-rococo-local --raw --disable-default-bootnode > ~/local_bridge_testing/bridge-hub-rococo-local-raw.json - ~/local_bridge_testing/bin/polkadot-parachain export-genesis-state --chain ~/local_bridge_testing/bridge-hub-rococo-local-raw.json > ~/local_bridge_testing/bridge-hub-rococo-local-genesis - ~/local_bridge_testing/bin/polkadot-parachain export-genesis-wasm --chain ~/local_bridge_testing/bridge-hub-rococo-local-raw.json > ~/local_bridge_testing/bridge-hub-rococo-local-genesis-wasm - - # Rococo - ~/local_bridge_testing/bin/polkadot-parachain --chain ~/local_bridge_testing/bridge-hub-rococo-local-raw.json --collator --alice --force-authoring --tmp --port 40333 --rpc-port 8933 --ws-port 8943 --no-mdns --node-key ${COLLATOR_KEY_ALICE[1]} --bootnodes=/ip4/127.0.0.1/tcp/40334/p2p/${COLLATOR_KEY_BOB[0]} -- --execution wasm --chain ~/local_bridge_testing/rococo-local-cfde.json --port 41333 --rpc-port 48933 --ws-port 48943 --no-mdns --node-key ${COLLATOR_KEY_ALICE[1]} --bootnodes=/ip4/127.0.0.1/tcp/30332/p2p/${VALIDATOR_KEY_ALICE[0]} &> ~/local_bridge_testing/logs/rococo_para_alice.log & - show_node_log_file alice 8943 ~/local_bridge_testing/logs/rococo_para_alice.log - ~/local_bridge_testing/bin/polkadot-parachain --chain ~/local_bridge_testing/bridge-hub-rococo-local-raw.json --collator --bob --force-authoring --tmp --port 40334 --rpc-port 8934 --ws-port 8944 --no-mdns --node-key ${COLLATOR_KEY_BOB[1]} --bootnodes=/ip4/127.0.0.1/tcp/40333/p2p/${COLLATOR_KEY_ALICE[0]} -- --execution wasm --chain ~/local_bridge_testing/rococo-local-cfde.json --port 41334 --rpc-port 48934 --ws-port 48944 --no-mdns --node-key ${COLLATOR_KEY_BOB[1]} --bootnodes=/ip4/127.0.0.1/tcp/30333/p2p/${VALIDATOR_KEY_BOB[0]} &> ~/local_bridge_testing/logs/rococo_para_bob.log & - show_node_log_file bob 8944 ~/local_bridge_testing/logs/rococo_para_bob.log - - register_parachain 9942 1013 ~/local_bridge_testing/bridge-hub-rococo-local-genesis ~/local_bridge_testing/bridge-hub-rococo-local-genesis-wasm - check_parachain_collator 8943 bridgeWococoGrandpa - ;; - start-wococo) - ensure_binaries - - # TODO: change to generate: ./bin/polkadot key generate-node-key - VALIDATOR_KEY_ALICE=(12D3KooWKB4SqNJAttmDHXEKtETLPr8Nixso8gUNzNKDS9b6HtYj 8c87694d3a3b3a0e201caceaae095aac66a76ba37545c439f7e0d986670da8e6) - VALIDATOR_KEY_BOB=(12D3KooWJq6xkfyV3LFxoNgsCskAwLv6VfLhL3cjHfW4UxDNwroF 9ebcd7371b427d63c087762fe3dc5a1d4b01875cb8611c263feda21364d4a329) - VALIDATOR_KEY_CHARLIE=(12D3KooW9yQQXz6xUJY2YgizKTFLS5fPaPi4KznQdMHEW4Hzt3NL 8bb1c50421a73082b8275ead6e3f150a774a0f8d6ad4a786df5d5b7688115cb1) - VALIDATOR_KEY_DAVE=(12D3KooWJP1R7XxqEuSryXSKYRVz9wdMRvd5LSqjRpdK4AvjnB12 e160d8b0ef4d66e02abf6663417b024f27f6cb2f826b746f3d267c58a32e9c05) - COLLATOR_KEY_ALICE=(12D3KooWNsQbEdW1eyC6TXAJCXxZ8qzkCJPWFqhWjco1SYYdaKPU 93ac8257255961b3d3ec0038747f0f9c7ddaa5dd352297daa352e098285965b7) - COLLATOR_KEY_BOB=(12D3KooWQ9yxdcf7kavoaKNWmt92tkCGQ8C4sq2JNBgCjvGtvvFg 7e396f01a8a74ecf2010ab2d57ca9fc6c5d673914d97ad6a066fe724e60c3412) - - # Start Wococo relay - ~/local_bridge_testing/bin/polkadot build-spec --chain wococo-local --disable-default-bootnode --raw > ~/local_bridge_testing/wococo-local-cfde.json - ~/local_bridge_testing/bin/polkadot --chain ~/local_bridge_testing/wococo-local-cfde.json --alice --tmp --port 30335 --rpc-port 9935 --ws-port 9945 --no-mdns --node-key ${VALIDATOR_KEY_ALICE[1]} --bootnodes=/ip4/127.0.0.1/tcp/30336/p2p/${VALIDATOR_KEY_BOB[0]} &> ~/local_bridge_testing/logs/wococo_relay_alice.log & - ~/local_bridge_testing/bin/polkadot --chain ~/local_bridge_testing/wococo-local-cfde.json --bob --tmp --port 30336 --rpc-port 9936 --ws-port 9946 --no-mdns --node-key ${VALIDATOR_KEY_BOB[1]} --bootnodes=/ip4/127.0.0.1/tcp/30335/p2p/${VALIDATOR_KEY_ALICE[0]} &> ~/local_bridge_testing/logs/wococo_relay_bob.log & - ~/local_bridge_testing/bin/polkadot --chain ~/local_bridge_testing/wococo-local-cfde.json --charlie --tmp --port 30337 --rpc-port 9937 --ws-port 9947 --no-mdns --node-key ${VALIDATOR_KEY_CHARLIE[1]} --bootnodes=/ip4/127.0.0.1/tcp/30335/p2p/${VALIDATOR_KEY_ALICE[0]} &> ~/local_bridge_testing/logs/wococo_relay_charlie.log & - ~/local_bridge_testing/bin/polkadot --chain ~/local_bridge_testing/wococo-local-cfde.json --dave --tmp --port 30338 --rpc-port 9938 --ws-port 9948 --no-mdns --node-key ${VALIDATOR_KEY_DAVE[1]} --bootnodes=/ip4/127.0.0.1/tcp/30336/p2p/${VALIDATOR_KEY_BOB[0]} &> ~/local_bridge_testing/logs/wococo_relay_dave.log & - sleep 2 - - # Prepare Wococo parachain - rm ~/local_bridge_testing/bridge-hub-wococo-local-raw.json - ~/local_bridge_testing/bin/polkadot-parachain build-spec --chain bridge-hub-wococo-local --raw --disable-default-bootnode > ~/local_bridge_testing/bridge-hub-wococo-local-raw.json - ~/local_bridge_testing/bin/polkadot-parachain export-genesis-state --chain ~/local_bridge_testing/bridge-hub-wococo-local-raw.json > ~/local_bridge_testing/bridge-hub-wococo-local-genesis - ~/local_bridge_testing/bin/polkadot-parachain export-genesis-wasm --chain ~/local_bridge_testing/bridge-hub-wococo-local-raw.json > ~/local_bridge_testing/bridge-hub-wococo-local-genesis-wasm - - # Wococo - ~/local_bridge_testing/bin/polkadot-parachain --chain ~/local_bridge_testing/bridge-hub-wococo-local-raw.json --collator --alice --force-authoring --tmp --port 40335 --rpc-port 8935 --ws-port 8945 --no-mdns --node-key ${COLLATOR_KEY_ALICE[1]} --bootnodes=/ip4/127.0.0.1/tcp/40336/p2p/${COLLATOR_KEY_BOB[0]} -- --execution wasm --chain ~/local_bridge_testing/wococo-local-cfde.json --port 41335 --rpc-port 48935 --ws-port 48945 --no-mdns --node-key ${COLLATOR_KEY_ALICE[1]} --bootnodes=/ip4/127.0.0.1/tcp/30335/p2p/${VALIDATOR_KEY_ALICE[0]} &> ~/local_bridge_testing/logs/wococo_para_alice.log & - show_node_log_file alice 8945 ~/local_bridge_testing/logs/wococo_para_alice.log - ~/local_bridge_testing/bin/polkadot-parachain --chain ~/local_bridge_testing/bridge-hub-wococo-local-raw.json --collator --bob --force-authoring --tmp --port 40336 --rpc-port 8936 --ws-port 8946 --no-mdns --node-key ${COLLATOR_KEY_BOB[1]} --bootnodes=/ip4/127.0.0.1/tcp/40335/p2p/${COLLATOR_KEY_ALICE[0]} -- --execution wasm --chain ~/local_bridge_testing/wococo-local-cfde.json --port 41336 --rpc-port 48936 --ws-port 48946 --no-mdns --node-key ${COLLATOR_KEY_BOB[1]} --bootnodes=/ip4/127.0.0.1/tcp/30336/p2p/${VALIDATOR_KEY_BOB[0]} &> ~/local_bridge_testing/logs/wococo_para_bob.log & - show_node_log_file bob 8946 ~/local_bridge_testing/logs/wococo_para_bob.log - - register_parachain 9945 1013 ~/local_bridge_testing/bridge-hub-wococo-local-genesis ~/local_bridge_testing/bridge-hub-wococo-local-genesis-wasm - check_parachain_collator 8945 bridgeRococoGrandpa - ;; - init-ro-wo) - # Init bridge Rococo->Wococo - init_ro_wo - ;; - init-wo-ro) - # Init bridge Wococo->Rococo - init_wo_ro - ;; run-relay) init_ro_wo init_wo_ro run_relay ;; - send-remark-local) - ensure_polkadot_js_api - send_xcm_transact_remark_from_statemine \ - "ws://127.0.0.1:9910" \ - "${STATEMINE_ACCOUNT_SEED_FOR_LOCAL}" \ - 1013 \ - "Wococo" \ - 1000 \ - "ws://127.0.0.1:9010" - ;; send-trap-local) ensure_polkadot_js_api send_xcm_trap_from_statemine \ @@ -661,16 +552,6 @@ case "$1" in "Wococo" \ 1000 ;; - send-remark-rococo) - ensure_polkadot_js_api - send_xcm_transact_remark_from_statemine \ - "wss://ws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io" \ - "${ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO}" \ - 1013 \ - "Wococo" \ - 1000 \ - "wss://ws-wococo-wockmint-collator-node-0.parity-testnet.parity.io" - ;; send-trap-rococo) ensure_polkadot_js_api send_xcm_trap_from_statemine \ @@ -680,9 +561,15 @@ case "$1" in "Wococo" \ 1000 ;; + allow-transfers-local) + # this allows send transfers on statemine (by governance-like) + ./$0 "allow-transfer-on-statemine-local" + # this allows receive transfers on westmint (by governance-like) + ./$0 "allow-transfer-on-westmint-local" + ;; allow-transfer-on-statemine-local) ensure_polkadot_js_api - allow_assets_transfer_from_statemine \ + allow_assets_transfer_send \ "ws://127.0.0.1:9942" \ "//Alice" \ 1000 \ @@ -690,24 +577,56 @@ case "$1" in 1013 \ "Wococo" 1000 ;; + allow-transfer-on-westmint-local) + ensure_polkadot_js_api + allow_assets_transfer_receive \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9010" \ + 1014 \ + "Rococo" \ + 1000 + # drip SovereignAccount for `MultiLocation { parents: 2, interior: X2(GlobalConsensus(Rococo), Parachain(1000)) }` + transfer_balance \ + "ws://127.0.0.1:9010" \ + "//Alice" \ + "5DHZvp523gmJWxg9UcLVbofyu5nZkPvATeP1ciYncpFpXtiG" \ + $((1000000000 + 50000000000 * 20)) # ExistentialDeposit + targetLocationFee * 20 + # create foreign assets for native Statemine token (yes, Kusama, because we are using Statemine runtime on rococo) + force_create_foreign_asset \ + "ws://127.0.0.1:9945" \ + "//Alice" \ + 1000 \ + "ws://127.0.0.1:9010" \ + "Kusama" \ + "5DHZvp523gmJWxg9UcLVbofyu5nZkPvATeP1ciYncpFpXtiG" + ;; remove-assets-transfer-from-statemine-local) ensure_polkadot_js_api - remove_assets_transfer_from_statemine \ + remove_assets_transfer_send \ "ws://127.0.0.1:9942" \ "//Alice" \ 1000 \ "ws://127.0.0.1:9910" \ "Wococo" ;; - transfer-asset) + transfer-asset-from-statemine-local) ensure_polkadot_js_api transfer_asset_via_bridge \ "ws://127.0.0.1:9910" \ "//Alice" ;; + drip) + transfer_balance \ + "ws://127.0.0.1:9010" \ + "//Alice" \ + "5DHZvp523gmJWxg9UcLVbofyu5nZkPvATeP1ciYncpFpXtiG" \ + $((1000000000 + 50000000000 * 20)) + ;; stop) pkill -f polkadot pkill -f parachain ;; - *) echo "A command is require. Supported commands: run-relay, send-trap-rococo/send-trap-local, send-remark-local/send-remark-rococo, allow-transfer-on-statemine-local/remove-assets-transfer-from-statemine-local, transfer-asset"; exit 1;; + *) echo "A command is require. Supported commands: run-relay, send-trap-rococo/send-trap-local, send-remark-local/send-remark-rococo, allow-transfers-local/allow-transfer-on-statemine-local/remove-assets-transfer-from-statemine-local, allow-transfer-on-westmint-local, transfer-asset-from-statemine-local"; exit 1;; esac diff --git a/scripts/generate_hex_encoded_call/index.js b/scripts/generate_hex_encoded_call/index.js index 167a292bb26..b135622c335 100644 --- a/scripts/generate_hex_encoded_call/index.js +++ b/scripts/generate_hex_encoded_call/index.js @@ -34,11 +34,11 @@ function remarkWithEvent(endpoint, outputFile) { }); } -function addBridgeConfig(endpoint, outputFile, bridgedNetwork, bridgeConfig) { - console.log(`Generating addBridgeConfig from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on bridgedNetwork: ${bridgedNetwork}, bridgeConfig: ${bridgeConfig}`); +function addExporterConfig(endpoint, outputFile, bridgedNetwork, bridgeConfig) { + console.log(`Generating addExporterConfig from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on bridgedNetwork: ${bridgedNetwork}, bridgeConfig: ${bridgeConfig}`); connect(endpoint) .then((api) => { - const call = api.tx.bridgeAssetsTransfer.addBridgeConfig(bridgedNetwork, JSON.parse(bridgeConfig)); + const call = api.tx.bridgeTransfer.addExporterConfig(bridgedNetwork, JSON.parse(bridgeConfig)); writeHexEncodedBytesToOutput(call.method, outputFile); exit(0); }) @@ -48,11 +48,11 @@ function addBridgeConfig(endpoint, outputFile, bridgedNetwork, bridgeConfig) { }); } -function removeBridgeConfig(endpoint, outputFile, bridgedNetwork) { - console.log(`Generating removeBridgeConfig from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on bridgedNetwork: ${bridgedNetwork}`); +function addUniversalAlias(endpoint, outputFile, location, junction) { + console.log(`Generating addUniversalAlias from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on location: ${location}, junction: ${junction}`); connect(endpoint) .then((api) => { - const call = api.tx.bridgeAssetsTransfer.removeBridgeConfig(bridgedNetwork); + const call = api.tx.bridgeTransfer.addUniversalAlias(JSON.parse(location), JSON.parse(junction)); writeHexEncodedBytesToOutput(call.method, outputFile); exit(0); }) @@ -62,11 +62,39 @@ function removeBridgeConfig(endpoint, outputFile, bridgedNetwork) { }); } -function transferAssetViaBridge(endpoint, outputFile, assets, destination) { - console.log(`Generating transferAssetViaBridge from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on assets: ${assets}, destination: ${destination}`); +function addReserveLocation(endpoint, outputFile, reserve_location) { + console.log(`Generating addReserveLocation from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on reserve_location: ${reserve_location}`); connect(endpoint) .then((api) => { - const call = api.tx.bridgeAssetsTransfer.transferAssetViaBridge(JSON.parse(assets), JSON.parse(destination)); + const call = api.tx.bridgeTransfer.addReserveLocation(JSON.parse(reserve_location)); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +function removeExporterConfig(endpoint, outputFile, bridgedNetwork) { + console.log(`Generating removeExporterConfig from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on bridgedNetwork: ${bridgedNetwork}`); + connect(endpoint) + .then((api) => { + const call = api.tx.bridgeTransfer.removeExporterConfig(bridgedNetwork); + writeHexEncodedBytesToOutput(call.method, outputFile); + exit(0); + }) + .catch((e) => { + console.error(e); + exit(1); + }); +} + +function forceCreateAsset(endpoint, outputFile, assetId, assetOwnerAccountId, isSufficient, minBalance) { + console.log(`Generating forceCreateAsset from RPC endpoint: ${endpoint} to outputFile: ${outputFile} based on assetId: ${assetId}, assetOwnerAccountId: ${assetOwnerAccountId}, isSufficient: ${isSufficient}, minBalance: ${minBalance}`); + connect(endpoint) + .then((api) => { + const call = api.tx.foreignAssets.forceCreate(JSON.parse(assetId), assetOwnerAccountId, isSufficient, minBalance); writeHexEncodedBytesToOutput(call.method, outputFile); exit(0); }) @@ -95,14 +123,20 @@ switch (type) { case 'remark-with-event': remarkWithEvent(rpcEnpoint, output); break; - case 'add-bridge-config': - addBridgeConfig(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + case 'add-exporter-config': + addExporterConfig(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + break; + case 'remove-exporter-config': + removeExporterConfig(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + break; + case 'add-universal-alias': + addUniversalAlias(rpcEnpoint, output, inputArgs[0], inputArgs[1]); break; - case 'remove-bridge-config': - removeBridgeConfig(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + case 'add-reserve-location': + addReserveLocation(rpcEnpoint, output, inputArgs[0]); break; - case 'transfer-asset-via-bridge': - transferAssetViaBridge(rpcEnpoint, output, inputArgs[0], inputArgs[1]); + case 'force-create-asset': + forceCreateAsset(rpcEnpoint, output, inputArgs[0], inputArgs[1], inputArgs[2], inputArgs[3]); break; case 'check': console.log(`Checking nodejs installation, if you see this everything is ready!`); From 53c6b8d71a3261f27d67cc8bd05d3646f6d332ac Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 4 Apr 2023 11:32:03 +0200 Subject: [PATCH 27/57] Companion for #6986 (#2416) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: apply substrate/pull/13610 * Added `origin` to config for `universal_origin` benchmark * update lockfile for {"polkadot", "substrate"} * Update --------- Co-authored-by: William Freudenberger Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher --- Cargo.lock | 512 +++++++++--------- parachains/common/src/xcm_config.rs | 4 +- .../runtimes/assets/statemine/src/lib.rs | 2 +- .../runtimes/assets/statemint/src/lib.rs | 2 +- .../runtimes/assets/westmint/src/lib.rs | 2 +- .../bridge-hubs/bridge-hub-kusama/src/lib.rs | 2 +- .../bridge-hub-polkadot/src/lib.rs | 2 +- .../bridge-hubs/bridge-hub-rococo/src/lib.rs | 2 +- 8 files changed, 264 insertions(+), 264 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9cf1112cb9..163917a1be1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -523,7 +523,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "hash-db", "log", @@ -3364,7 +3364,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", ] @@ -3387,7 +3387,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-support-procedural", @@ -3412,7 +3412,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -3459,7 +3459,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3470,7 +3470,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3487,7 +3487,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -3516,7 +3516,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "log", @@ -3532,7 +3532,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "bitflags", "environmental", @@ -3565,7 +3565,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "Inflector", "cfg-expr", @@ -3580,7 +3580,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3592,7 +3592,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro2", "quote", @@ -3602,7 +3602,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "log", @@ -3620,7 +3620,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -3635,7 +3635,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "sp-api", @@ -3644,7 +3644,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "parity-scale-codec", @@ -4613,7 +4613,7 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "frame-benchmarking", @@ -4711,7 +4711,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "frame-support", "polkadot-primitives", @@ -5565,7 +5565,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "log", @@ -5584,7 +5584,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "anyhow", "jsonrpsee", @@ -6083,7 +6083,7 @@ dependencies = [ [[package]] name = "pallet-alliance" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -6104,7 +6104,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6122,7 +6122,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6137,7 +6137,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6153,7 +6153,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6169,7 +6169,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6183,7 +6183,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6207,7 +6207,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6227,7 +6227,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6242,7 +6242,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6261,7 +6261,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6285,7 +6285,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6303,7 +6303,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6347,7 +6347,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6364,7 +6364,7 @@ dependencies = [ [[package]] name = "pallet-contracts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "bitflags", "environmental", @@ -6394,7 +6394,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "bitflags", "parity-scale-codec", @@ -6407,7 +6407,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro2", "quote", @@ -6417,7 +6417,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6434,7 +6434,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6452,7 +6452,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6475,7 +6475,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6488,7 +6488,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6506,7 +6506,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6524,7 +6524,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6547,7 +6547,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6563,7 +6563,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6583,7 +6583,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6600,7 +6600,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6614,7 +6614,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6631,7 +6631,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6648,7 +6648,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6664,7 +6664,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6682,7 +6682,7 @@ dependencies = [ [[package]] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "pallet-nfts", @@ -6693,7 +6693,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6709,7 +6709,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6726,7 +6726,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6746,7 +6746,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6757,7 +6757,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6774,7 +6774,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6798,7 +6798,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6815,7 +6815,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6830,7 +6830,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6848,7 +6848,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6863,7 +6863,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6882,7 +6882,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6899,7 +6899,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6920,7 +6920,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -6936,7 +6936,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -6950,7 +6950,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6973,7 +6973,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6984,7 +6984,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "log", "sp-arithmetic", @@ -6993,7 +6993,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "sp-api", @@ -7002,7 +7002,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7019,7 +7019,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -7048,7 +7048,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7066,7 +7066,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7085,7 +7085,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-support", "frame-system", @@ -7101,7 +7101,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7117,7 +7117,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7129,7 +7129,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7146,7 +7146,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7161,7 +7161,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7177,7 +7177,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7192,7 +7192,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-benchmarking", "frame-support", @@ -7207,7 +7207,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7228,7 +7228,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "frame-benchmarking", "frame-support", @@ -7777,7 +7777,7 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "polkadot-node-jaeger", @@ -7793,7 +7793,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7807,7 +7807,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "derive_more", "fatality", @@ -7830,7 +7830,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "fatality", "futures", @@ -7851,7 +7851,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "clap 4.1.14", "frame-benchmarking-cli", @@ -7879,7 +7879,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "frame-benchmarking", @@ -7922,7 +7922,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "always-assert", "bitvec", @@ -7944,7 +7944,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "parity-scale-codec", "scale-info", @@ -7956,7 +7956,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "derive_more", "fatality", @@ -7981,7 +7981,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7995,7 +7995,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "futures-timer", @@ -8015,7 +8015,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "always-assert", "async-trait", @@ -8038,7 +8038,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "parity-scale-codec", @@ -8056,7 +8056,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "derive_more", @@ -8085,7 +8085,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "futures", @@ -8106,7 +8106,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "fatality", @@ -8125,7 +8125,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8140,7 +8140,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "futures", @@ -8160,7 +8160,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "polkadot-node-metrics", @@ -8175,7 +8175,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "futures-timer", @@ -8192,7 +8192,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "fatality", "futures", @@ -8211,7 +8211,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "futures", @@ -8228,7 +8228,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "fatality", @@ -8246,7 +8246,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "always-assert", "assert_matches", @@ -8283,7 +8283,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "polkadot-node-primitives", @@ -8299,7 +8299,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "futures", "lru 0.9.0", @@ -8314,7 +8314,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "lazy_static", "log", @@ -8332,7 +8332,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bs58", "futures", @@ -8351,7 +8351,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "derive_more", @@ -8373,7 +8373,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bounded-vec", "futures", @@ -8396,7 +8396,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8406,7 +8406,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "futures", @@ -8424,7 +8424,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "derive_more", @@ -8447,7 +8447,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "derive_more", @@ -8480,7 +8480,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "futures", @@ -8503,7 +8503,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bounded-collections", "derive_more", @@ -8601,7 +8601,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -8617,7 +8617,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "hex-literal 0.3.4", @@ -8643,7 +8643,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8675,7 +8675,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "frame-benchmarking", @@ -8769,7 +8769,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "frame-benchmarking", @@ -8815,7 +8815,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "frame-support", "polkadot-primitives", @@ -8829,7 +8829,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bs58", "parity-scale-codec", @@ -8841,7 +8841,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitflags", "bitvec", @@ -8885,7 +8885,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "async-trait", "frame-benchmarking-cli", @@ -8995,7 +8995,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -9016,7 +9016,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -9026,7 +9026,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -9051,7 +9051,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "frame-election-provider-support", @@ -9112,7 +9112,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "frame-benchmarking", "frame-system", @@ -9857,7 +9857,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9943,7 +9943,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "frame-support", "polkadot-primitives", @@ -10190,7 +10190,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "log", "sp-core", @@ -10201,7 +10201,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "futures", @@ -10229,7 +10229,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "futures-timer", @@ -10252,7 +10252,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10267,7 +10267,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10286,7 +10286,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10297,7 +10297,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -10337,7 +10337,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "fnv", "futures", @@ -10363,7 +10363,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "hash-db", "kvdb", @@ -10389,7 +10389,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "futures", @@ -10414,7 +10414,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "futures", @@ -10443,7 +10443,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "fork-tree", @@ -10482,7 +10482,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "jsonrpsee", @@ -10504,7 +10504,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10539,7 +10539,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "jsonrpsee", @@ -10558,7 +10558,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10571,7 +10571,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "ahash 0.8.2", "array-bytes 4.2.0", @@ -10611,7 +10611,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "finality-grandpa", "futures", @@ -10631,7 +10631,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "futures", @@ -10654,7 +10654,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10678,7 +10678,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10691,7 +10691,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "log", "sc-allocator", @@ -10704,7 +10704,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "anyhow", "cfg-if", @@ -10722,7 +10722,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "ansi_term", "futures", @@ -10738,7 +10738,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10753,7 +10753,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10798,7 +10798,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "cid", "futures", @@ -10818,7 +10818,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10846,7 +10846,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "ahash 0.8.2", "futures", @@ -10865,7 +10865,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10887,7 +10887,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10921,7 +10921,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10941,7 +10941,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10972,7 +10972,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "libp2p", @@ -10985,7 +10985,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10994,7 +10994,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "jsonrpsee", @@ -11024,7 +11024,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11043,7 +11043,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "http", "jsonrpsee", @@ -11058,7 +11058,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "futures", @@ -11084,7 +11084,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "directories", @@ -11150,7 +11150,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "log", "parity-scale-codec", @@ -11161,7 +11161,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "clap 4.1.14", "fs4", @@ -11177,7 +11177,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11196,7 +11196,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "libc", @@ -11215,7 +11215,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "chrono", "futures", @@ -11234,7 +11234,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "ansi_term", "atty", @@ -11265,7 +11265,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11276,7 +11276,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "futures", @@ -11303,7 +11303,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "futures", @@ -11317,7 +11317,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-channel", "futures", @@ -11798,7 +11798,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "enumn", "parity-scale-codec", @@ -11875,7 +11875,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "hash-db", "log", @@ -11893,7 +11893,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "Inflector", "blake2", @@ -11907,7 +11907,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "scale-info", @@ -11920,7 +11920,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "integer-sqrt", "num-traits", @@ -11934,7 +11934,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "scale-info", @@ -11947,7 +11947,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "sp-api", @@ -11959,7 +11959,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "log", @@ -11977,7 +11977,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "futures", @@ -11992,7 +11992,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "parity-scale-codec", @@ -12010,7 +12010,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "merlin", @@ -12033,7 +12033,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "lazy_static", "parity-scale-codec", @@ -12052,7 +12052,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "finality-grandpa", "log", @@ -12070,7 +12070,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12082,7 +12082,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12095,7 +12095,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "bitflags", @@ -12138,7 +12138,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "blake2b_simd", "byteorder", @@ -12152,7 +12152,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro2", "quote", @@ -12163,7 +12163,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12172,7 +12172,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro2", "quote", @@ -12182,7 +12182,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "environmental", "parity-scale-codec", @@ -12193,7 +12193,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12208,7 +12208,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "bytes", "ed25519", @@ -12234,7 +12234,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "lazy_static", "sp-core", @@ -12245,7 +12245,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "merlin", @@ -12261,7 +12261,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "thiserror", "zstd", @@ -12270,7 +12270,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12288,7 +12288,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12302,7 +12302,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "sp-api", "sp-core", @@ -12312,7 +12312,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "backtrace", "lazy_static", @@ -12322,7 +12322,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "rustc-hash", "serde", @@ -12332,7 +12332,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "either", "hash256-std-hasher", @@ -12354,7 +12354,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12372,7 +12372,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "Inflector", "proc-macro-crate", @@ -12384,7 +12384,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "serde", "serde_json", @@ -12393,7 +12393,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12407,7 +12407,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12419,7 +12419,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "hash-db", "log", @@ -12439,12 +12439,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12457,7 +12457,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "futures-timer", @@ -12472,7 +12472,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "sp-std", @@ -12484,7 +12484,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "sp-api", "sp-runtime", @@ -12493,7 +12493,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "log", @@ -12509,7 +12509,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "ahash 0.8.2", "hash-db", @@ -12532,7 +12532,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12549,7 +12549,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12560,7 +12560,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12574,7 +12574,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "parity-scale-codec", "scale-info", @@ -12898,7 +12898,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "platforms 2.0.0", ] @@ -12906,7 +12906,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12925,7 +12925,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "hyper", "log", @@ -12937,7 +12937,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "jsonrpsee", @@ -12950,7 +12950,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "jsonrpsee", "log", @@ -12969,7 +12969,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -12995,7 +12995,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "futures", "substrate-test-utils-derive", @@ -13005,7 +13005,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -13016,7 +13016,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "ansi_term", "build-helper", @@ -13143,7 +13143,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "frame-support", "polkadot-primitives", @@ -13533,7 +13533,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13544,7 +13544,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -13674,7 +13674,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#be9fa62238fcfd7eb49218809a6b981f71c34eb3" +source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" dependencies = [ "async-trait", "clap 4.1.14", @@ -14602,7 +14602,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bitvec", "frame-benchmarking", @@ -14694,7 +14694,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "frame-support", "polkadot-primitives", @@ -15130,7 +15130,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "bounded-collections", "derivative", @@ -15146,7 +15146,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "frame-support", "frame-system", @@ -15167,7 +15167,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "environmental", "frame-benchmarking", @@ -15187,7 +15187,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#21c8734670b5392bfcddca4eb65c6585e6974640" +source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" dependencies = [ "Inflector", "proc-macro2", diff --git a/parachains/common/src/xcm_config.rs b/parachains/common/src/xcm_config.rs index 04f73c6b7e7..d367fd4d1a1 100644 --- a/parachains/common/src/xcm_config.rs +++ b/parachains/common/src/xcm_config.rs @@ -2,7 +2,7 @@ use crate::impls::AccountIdOf; use core::{marker::PhantomData, ops::ControlFlow}; use frame_support::{ log, - traits::{fungibles::Inspect, tokens::BalanceConversion, ContainsPair}, + traits::{fungibles::Inspect, tokens::ConversionToAssetBalance, ContainsPair}, weights::Weight, }; use sp_runtime::traits::Get; @@ -96,7 +96,7 @@ impl where Runtime: pallet_assets::Config, WeightToFee: frame_support::weights::WeightToFee, - BalanceConverter: BalanceConversion< + BalanceConverter: ConversionToAssetBalance< CurrencyBalance, >::AssetId, >::Balance, diff --git a/parachains/runtimes/assets/statemine/src/lib.rs b/parachains/runtimes/assets/statemine/src/lib.rs index 597f478eec8..6c332a11520 100644 --- a/parachains/runtimes/assets/statemine/src/lib.rs +++ b/parachains/runtimes/assets/statemine/src/lib.rs @@ -1113,7 +1113,7 @@ impl_runtime_apis! { Err(BenchmarkError::Skip) } - fn universal_alias() -> Result { + fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { Err(BenchmarkError::Skip) } diff --git a/parachains/runtimes/assets/statemint/src/lib.rs b/parachains/runtimes/assets/statemint/src/lib.rs index 02e43e27ac4..d62b19be844 100644 --- a/parachains/runtimes/assets/statemint/src/lib.rs +++ b/parachains/runtimes/assets/statemint/src/lib.rs @@ -1010,7 +1010,7 @@ impl_runtime_apis! { Err(BenchmarkError::Skip) } - fn universal_alias() -> Result { + fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { Err(BenchmarkError::Skip) } diff --git a/parachains/runtimes/assets/westmint/src/lib.rs b/parachains/runtimes/assets/westmint/src/lib.rs index 5994fdcabb5..45c0e9f27b2 100644 --- a/parachains/runtimes/assets/westmint/src/lib.rs +++ b/parachains/runtimes/assets/westmint/src/lib.rs @@ -1124,7 +1124,7 @@ impl_runtime_apis! { Err(BenchmarkError::Skip) } - fn universal_alias() -> Result { + fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { Err(BenchmarkError::Skip) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs index 0e9b1eeb45f..3c77d40086c 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs @@ -687,7 +687,7 @@ impl_runtime_apis! { Err(BenchmarkError::Skip) } - fn universal_alias() -> Result { + fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { Err(BenchmarkError::Skip) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs index 9ee28a5d77f..9c9c8ba1c58 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs @@ -687,7 +687,7 @@ impl_runtime_apis! { Err(BenchmarkError::Skip) } - fn universal_alias() -> Result { + fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { Err(BenchmarkError::Skip) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index e577dd364d5..9c52457d164 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -737,7 +737,7 @@ impl_runtime_apis! { Err(BenchmarkError::Skip) } - fn universal_alias() -> Result { + fn universal_alias() -> Result<(MultiLocation, Junction), BenchmarkError> { Err(BenchmarkError::Skip) } From 5ed3677723374ee3ba6133890b3175586d489393 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Tue, 4 Apr 2023 16:00:05 +0200 Subject: [PATCH 28/57] [backport] weights 9400 (#2425) * [benchmarks] pr with weights (#2373) Co-authored-by: paritytech-ci * [benchmarks] pr with weights (#2374) Co-authored-by: paritytech-ci * [benchmarks] pr with weights (#2375) Co-authored-by: paritytech-ci * Proof size in test wasn't sufficient (due to updated weights.) --------- Co-authored-by: Paritytech CI <52199148+paritytech-ci@users.noreply.github.com> Co-authored-by: paritytech-ci Co-authored-by: Giles Cope --- .../src/weights/cumulus_pallet_xcmp_queue.rs | 20 +- .../statemine/src/weights/frame_system.rs | 53 +- .../statemine/src/weights/pallet_assets.rs | 290 ++++----- .../statemine/src/weights/pallet_balances.rs | 74 +-- .../src/weights/pallet_collator_selection.rs | 78 +-- .../statemine/src/weights/pallet_multisig.rs | 104 +-- .../statemine/src/weights/pallet_nfts.rs | 615 +++++++++--------- .../statemine/src/weights/pallet_proxy.rs | 158 ++--- .../statemine/src/weights/pallet_session.rs | 20 +- .../statemine/src/weights/pallet_timestamp.rs | 16 +- .../statemine/src/weights/pallet_uniques.rs | 288 ++++---- .../statemine/src/weights/pallet_utility.rs | 36 +- .../statemine/src/weights/pallet_xcm.rs | 130 ++-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 61 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 169 +++-- .../src/weights/cumulus_pallet_xcmp_queue.rs | 20 +- .../statemint/src/weights/frame_system.rs | 49 +- .../statemint/src/weights/pallet_assets.rs | 294 ++++----- .../statemint/src/weights/pallet_balances.rs | 74 +-- .../src/weights/pallet_collator_selection.rs | 78 +-- .../statemint/src/weights/pallet_multisig.rs | 104 +-- .../statemint/src/weights/pallet_proxy.rs | 158 ++--- .../statemint/src/weights/pallet_session.rs | 20 +- .../statemint/src/weights/pallet_timestamp.rs | 16 +- .../statemint/src/weights/pallet_uniques.rs | 288 ++++---- .../statemint/src/weights/pallet_utility.rs | 36 +- .../statemint/src/weights/pallet_xcm.rs | 110 ++-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 49 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 137 ++-- .../assets/test-utils/src/test_cases.rs | 8 +- .../src/weights/cumulus_pallet_xcmp_queue.rs | 20 +- .../westmint/src/weights/frame_system.rs | 47 +- .../westmint/src/weights/pallet_assets.rs | 286 ++++---- .../westmint/src/weights/pallet_balances.rs | 74 +-- .../src/weights/pallet_collator_selection.rs | 78 +-- .../westmint/src/weights/pallet_multisig.rs | 106 +-- .../westmint/src/weights/pallet_nfts.rs | 607 +++++++++-------- .../westmint/src/weights/pallet_proxy.rs | 158 ++--- .../westmint/src/weights/pallet_session.rs | 20 +- .../westmint/src/weights/pallet_timestamp.rs | 16 +- .../westmint/src/weights/pallet_uniques.rs | 288 ++++---- .../westmint/src/weights/pallet_utility.rs | 36 +- .../assets/westmint/src/weights/pallet_xcm.rs | 112 ++-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 49 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 137 ++-- .../src/weights/cumulus_pallet_xcmp_queue.rs | 22 +- .../src/weights/frame_system.rs | 51 +- .../src/weights/pallet_balances.rs | 76 +-- .../src/weights/pallet_collator_selection.rs | 80 +-- .../src/weights/pallet_multisig.rs | 106 +-- .../src/weights/pallet_session.rs | 22 +- .../src/weights/pallet_timestamp.rs | 18 +- .../src/weights/pallet_utility.rs | 38 +- .../src/weights/pallet_xcm.rs | 106 +-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 46 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 137 ++-- .../src/weights/cumulus_pallet_xcmp_queue.rs | 22 +- .../src/weights/frame_system.rs | 51 +- .../src/weights/pallet_balances.rs | 76 +-- .../src/weights/pallet_collator_selection.rs | 80 +-- .../src/weights/pallet_multisig.rs | 106 +-- .../src/weights/pallet_session.rs | 22 +- .../src/weights/pallet_timestamp.rs | 18 +- .../src/weights/pallet_utility.rs | 38 +- .../src/weights/pallet_xcm.rs | 106 +-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 46 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 137 ++-- .../src/weights/cumulus_pallet_xcmp_queue.rs | 22 +- .../src/weights/frame_system.rs | 51 +- .../src/weights/pallet_balances.rs | 76 +-- .../src/weights/pallet_collator_selection.rs | 80 +-- .../src/weights/pallet_multisig.rs | 110 ++-- .../src/weights/pallet_session.rs | 22 +- .../src/weights/pallet_timestamp.rs | 18 +- .../src/weights/pallet_utility.rs | 38 +- .../src/weights/pallet_xcm.rs | 106 +-- .../xcm/pallet_xcm_benchmarks_fungible.rs | 46 +- .../xcm/pallet_xcm_benchmarks_generic.rs | 134 ++-- .../src/weights/cumulus_pallet_xcmp_queue.rs | 22 +- .../src/weights/frame_system.rs | 51 +- .../src/weights/pallet_alliance.rs | 282 ++++---- .../src/weights/pallet_balances.rs | 76 +-- .../src/weights/pallet_collator_selection.rs | 80 +-- .../src/weights/pallet_collective.rs | 188 +++--- .../src/weights/pallet_multisig.rs | 108 +-- .../src/weights/pallet_proxy.rs | 160 +++-- .../src/weights/pallet_session.rs | 22 +- .../src/weights/pallet_timestamp.rs | 18 +- .../src/weights/pallet_utility.rs | 38 +- .../src/weights/pallet_xcm.rs | 106 +-- 90 files changed, 4418 insertions(+), 4427 deletions(-) diff --git a/parachains/runtimes/assets/statemine/src/weights/cumulus_pallet_xcmp_queue.rs b/parachains/runtimes/assets/statemine/src/weights/cumulus_pallet_xcmp_queue.rs index 9730e2df7b6..5cad45cc0b0 100644 --- a/parachains/runtimes/assets/statemine/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/parachains/runtimes/assets/statemine/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -52,10 +52,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_956 nanoseconds. - Weight::from_parts(5_108_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_483_000 picoseconds. + Weight::from_parts(5_808_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,10 +64,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_weight() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_945 nanoseconds. - Weight::from_parts(5_080_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_773_000 picoseconds. + Weight::from_parts(5_913_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/parachains/runtimes/assets/statemine/src/weights/frame_system.rs b/parachains/runtimes/assets/statemine/src/weights/frame_system.rs index 11188b93267..4f0967e636d 100644 --- a/parachains/runtimes/assets/statemine/src/weights/frame_system.rs +++ b/parachains/runtimes/assets/statemine/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -52,22 +52,22 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_524 nanoseconds. - Weight::from_parts(1_612_000, 0) + // Minimum execution time: 2_146_000 picoseconds. + Weight::from_parts(2_194_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(413, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(368, 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_865 nanoseconds. - Weight::from_parts(6_939_000, 0) + // Minimum execution time: 7_732_000 picoseconds. + Weight::from_parts(8_001_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_762, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_403, 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) @@ -76,10 +76,10 @@ impl frame_system::WeightInfo for WeightInfo { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 3_490 nanoseconds. - Weight::from_parts(3_688_000, 0) - .saturating_add(Weight::from_parts(0, 495)) + // Estimated: `1485` + // Minimum execution time: 4_287_000 picoseconds. + Weight::from_parts(4_602_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,11 +90,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_683 nanoseconds. - Weight::from_parts(1_726_000, 0) + // Minimum execution time: 2_319_000 picoseconds. + Weight::from_parts(2_401_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_736 - .saturating_add(Weight::from_parts(582_823, 0).saturating_mul(i.into())) + // Standard Error: 1_933 + .saturating_add(Weight::from_parts(669_111, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -104,11 +104,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_711 nanoseconds. - Weight::from_parts(1_787_000, 0) + // Minimum execution time: 2_381_000 picoseconds. + Weight::from_parts(2_405_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 779 - .saturating_add(Weight::from_parts(445_878, 0).saturating_mul(i.into())) + .saturating_add(Weight::from_parts(492_780, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -116,13 +116,14 @@ impl frame_system::WeightInfo for WeightInfo { /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `81 + p * (69 ±0)` - // Estimated: `72 + p * (70 ±0)` - // Minimum execution time: 3_428 nanoseconds. - Weight::from_parts(3_492_000, 0) - .saturating_add(Weight::from_parts(0, 72)) - // Standard Error: 991 - .saturating_add(Weight::from_parts(953_258, 0).saturating_mul(p.into())) + // Measured: `84 + p * (69 ±0)` + // Estimated: `75 + p * (70 ±0)` + // Minimum execution time: 4_204_000 picoseconds. + Weight::from_parts(4_269_000, 0) + .saturating_add(Weight::from_parts(0, 75)) + // Standard Error: 1_101 + .saturating_add(Weight::from_parts(1_014_807, 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/parachains/runtimes/assets/statemine/src/weights/pallet_assets.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_assets.rs index 1ecec9b5e09..94957ff84fa 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_assets.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_assets.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_assets` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -53,11 +53,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `141` - // Estimated: `5288` - // Minimum execution time: 21_487 nanoseconds. - Weight::from_parts(21_977_000, 0) - .saturating_add(Weight::from_parts(0, 5288)) + // Measured: `109` + // Estimated: `7268` + // Minimum execution time: 24_493_000 picoseconds. + Weight::from_parts(24_993_000, 0) + .saturating_add(Weight::from_parts(0, 7268)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -66,10 +66,10 @@ impl pallet_assets::WeightInfo for WeightInfo { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `6` - // Estimated: `2685` - // Minimum execution time: 10_630 nanoseconds. - Weight::from_parts(10_963_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Estimated: `3675` + // Minimum execution time: 12_605_000 picoseconds. + Weight::from_parts(12_888_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -77,11 +77,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 13_627 nanoseconds. - Weight::from_parts(13_906_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 14_917_000 picoseconds. + Weight::from_parts(15_146_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -94,13 +94,13 @@ impl pallet_assets::WeightInfo for WeightInfo { /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + c * (240 ±0)` - // Estimated: `5262 + c * (5180 ±0)` - // Minimum execution time: 15_861 nanoseconds. - Weight::from_parts(16_079_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) - // Standard Error: 10_732 - .saturating_add(Weight::from_parts(14_192_928, 0).saturating_mul(c.into())) + // Measured: `0 + c * (208 ±0)` + // Estimated: `8232 + c * (5180 ±0)` + // Minimum execution time: 17_844_000 picoseconds. + Weight::from_parts(18_064_000, 0) + .saturating_add(Weight::from_parts(0, 8232)) + // Standard Error: 6_979 + .saturating_add(Weight::from_parts(12_064_749, 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)) @@ -114,13 +114,13 @@ impl pallet_assets::WeightInfo for WeightInfo { /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `446 + a * (86 ±0)` - // Estimated: `5308 + a * (2623 ±0)` - // Minimum execution time: 16_455 nanoseconds. - Weight::from_parts(16_720_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) - // Standard Error: 7_111 - .saturating_add(Weight::from_parts(13_717_750, 0).saturating_mul(a.into())) + // Measured: `414 + a * (86 ±0)` + // Estimated: `7288 + a * (2623 ±0)` + // Minimum execution time: 18_402_000 picoseconds. + Weight::from_parts(18_742_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) + // Standard Error: 5_332 + .saturating_add(Weight::from_parts(12_085_212, 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)) @@ -133,11 +133,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 12_819 nanoseconds. - Weight::from_parts(13_111_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 14_390_000 picoseconds. + Weight::from_parts(14_903_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -147,11 +147,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5262` - // Minimum execution time: 22_897 nanoseconds. - Weight::from_parts(23_386_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `243` + // Estimated: `7242` + // Minimum execution time: 26_171_000 picoseconds. + Weight::from_parts(26_478_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -161,11 +161,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 28_432 nanoseconds. - Weight::from_parts(28_903_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 31_291_000 picoseconds. + Weight::from_parts(31_810_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -177,11 +177,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `10442` - // Minimum execution time: 39_823 nanoseconds. - Weight::from_parts(40_380_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 42_608_000 picoseconds. + Weight::from_parts(43_553_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -193,11 +193,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `383` - // Estimated: `10442` - // Minimum execution time: 34_924 nanoseconds. - Weight::from_parts(35_584_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 37_541_000 picoseconds. + Weight::from_parts(38_166_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -209,11 +209,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `10442` - // Minimum execution time: 39_647 nanoseconds. - Weight::from_parts(40_611_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 42_931_000 picoseconds. + Weight::from_parts(43_458_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -223,11 +223,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 16_462 nanoseconds. - Weight::from_parts(16_821_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 17_652_000 picoseconds. + Weight::from_parts(18_018_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -237,11 +237,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 16_416 nanoseconds. - Weight::from_parts(16_758_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 17_510_000 picoseconds. + Weight::from_parts(17_911_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -249,11 +249,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 12_853 nanoseconds. - Weight::from_parts(13_257_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 13_954_000 picoseconds. + Weight::from_parts(14_284_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -261,11 +261,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 12_422 nanoseconds. - Weight::from_parts(12_763_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 14_216_000 picoseconds. + Weight::from_parts(14_459_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -275,11 +275,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 13_950 nanoseconds. - Weight::from_parts(14_242_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 15_550_000 picoseconds. + Weight::from_parts(16_001_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -287,11 +287,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `2685` - // Minimum execution time: 12_726 nanoseconds. - Weight::from_parts(13_072_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 14_389_000 picoseconds. + Weight::from_parts(14_677_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -301,15 +301,13 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(_n: u32, s: u32, ) -> Weight { + fn set_metadata(_n: u32, _s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 22_772 nanoseconds. - Weight::from_parts(24_026_274, 0) - .saturating_add(Weight::from_parts(0, 5300)) - // Standard Error: 1_231 - .saturating_add(Weight::from_parts(203, 0).saturating_mul(s.into())) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 25_401_000 picoseconds. + Weight::from_parts(27_056_833, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -319,11 +317,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `471` - // Estimated: `5300` - // Minimum execution time: 23_310 nanoseconds. - Weight::from_parts(23_724_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `407` + // Estimated: `7280` + // Minimum execution time: 26_001_000 picoseconds. + Weight::from_parts(26_493_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -333,17 +331,15 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(n: u32, s: u32, ) -> Weight { + fn force_set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `82` - // Estimated: `5300` - // Minimum execution time: 12_379 nanoseconds. - Weight::from_parts(12_903_065, 0) - .saturating_add(Weight::from_parts(0, 5300)) - // Standard Error: 330 - .saturating_add(Weight::from_parts(667, 0).saturating_mul(n.into())) - // Standard Error: 330 - .saturating_add(Weight::from_parts(2_891, 0).saturating_mul(s.into())) + // Estimated: `7280` + // Minimum execution time: 13_988_000 picoseconds. + Weight::from_parts(14_751_106, 0) + .saturating_add(Weight::from_parts(0, 7280)) + // Standard Error: 381 + .saturating_add(Weight::from_parts(2_884, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -353,11 +349,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `471` - // Estimated: `5300` - // Minimum execution time: 23_531 nanoseconds. - Weight::from_parts(23_845_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `407` + // Estimated: `7280` + // Minimum execution time: 25_837_000 picoseconds. + Weight::from_parts(26_110_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -365,11 +361,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `275` - // Estimated: `2685` - // Minimum execution time: 12_426 nanoseconds. - Weight::from_parts(12_888_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 13_423_000 picoseconds. + Weight::from_parts(13_565_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -379,11 +375,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `5308` - // Minimum execution time: 26_365 nanoseconds. - Weight::from_parts(26_700_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `277` + // Estimated: `7288` + // Minimum execution time: 29_285_000 picoseconds. + Weight::from_parts(29_727_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -397,11 +393,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `553` - // Estimated: `13065` - // Minimum execution time: 53_167 nanoseconds. - Weight::from_parts(53_564_000, 0) - .saturating_add(Weight::from_parts(0, 13065)) + // Measured: `521` + // Estimated: `17025` + // Minimum execution time: 58_369_000 picoseconds. + Weight::from_parts(58_844_000, 0) + .saturating_add(Weight::from_parts(0, 17025)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -411,11 +407,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `479` - // Estimated: `5308` - // Minimum execution time: 28_120 nanoseconds. - Weight::from_parts(28_540_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `447` + // Estimated: `7288` + // Minimum execution time: 31_073_000 picoseconds. + Weight::from_parts(31_536_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -425,11 +421,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `479` - // Estimated: `5308` - // Minimum execution time: 28_503 nanoseconds. - Weight::from_parts(28_988_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `447` + // Estimated: `7288` + // Minimum execution time: 32_182_000 picoseconds. + Weight::from_parts(32_625_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -437,12 +433,12 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `383` + // Measured: `243` // Estimated: `3675` - // Minimum execution time: 16_213 nanoseconds. - Weight::from_parts(16_575_000, 0) + // Minimum execution time: 14_610_000 picoseconds. + Weight::from_parts(14_895_000, 0) .saturating_add(Weight::from_parts(0, 3675)) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_balances.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_balances.rs index de0bba5f9fb..2d3be9da403 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_balances.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -51,11 +51,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1178` - // Estimated: `2603` - // Minimum execution time: 46_493 nanoseconds. - Weight::from_parts(47_804_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 34_132_000 picoseconds. + Weight::from_parts(34_669_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -63,11 +63,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1062` - // Estimated: `2603` - // Minimum execution time: 35_020 nanoseconds. - Weight::from_parts(35_462_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 25_052_000 picoseconds. + Weight::from_parts(25_681_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,11 +75,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1174` - // Estimated: `2603` - // Minimum execution time: 26_282 nanoseconds. - Weight::from_parts(26_915_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 15_072_000 picoseconds. + Weight::from_parts(15_451_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -87,11 +87,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1174` - // Estimated: `2603` - // Minimum execution time: 29_529 nanoseconds. - Weight::from_parts(30_135_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 18_416_000 picoseconds. + Weight::from_parts(18_742_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -99,11 +99,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1174` - // Estimated: `5206` - // Minimum execution time: 46_969 nanoseconds. - Weight::from_parts(47_657_000, 0) - .saturating_add(Weight::from_parts(0, 5206)) + // Measured: `103` + // Estimated: `6196` + // Minimum execution time: 36_626_000 picoseconds. + Weight::from_parts(37_176_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,11 +111,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1062` - // Estimated: `2603` - // Minimum execution time: 41_398 nanoseconds. - Weight::from_parts(42_012_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 31_008_000 picoseconds. + Weight::from_parts(31_562_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,11 +126,11 @@ impl pallet_balances::WeightInfo for WeightInfo { } fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1058` - // Estimated: `2603` - // Minimum execution time: 22_969 nanoseconds. - Weight::from_parts(23_548_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 14_214_000 picoseconds. + Weight::from_parts(14_535_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_collator_selection.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_collator_selection.rs index 4ad4a2ffce2..6165f030031 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_collator_selection.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -55,12 +55,12 @@ impl pallet_collator_selection::WeightInfo for WeightIn fn set_invulnerables(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178 + b * (78 ±0)` - // Estimated: `178 + b * (2554 ±0)` - // Minimum execution time: 14_234 nanoseconds. - Weight::from_parts(15_794_150, 0) - .saturating_add(Weight::from_parts(0, 178)) - // Standard Error: 4_000 - .saturating_add(Weight::from_parts(2_477_800, 0).saturating_mul(b.into())) + // Estimated: `1168 + b * (2554 ±0)` + // Minimum execution time: 15_415_000 picoseconds. + Weight::from_parts(15_521_960, 0) + .saturating_add(Weight::from_parts(0, 1168)) + // Standard Error: 3_294 + .saturating_add(Weight::from_parts(2_582_035, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 2554).saturating_mul(b.into())) @@ -71,8 +71,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_190 nanoseconds. - Weight::from_parts(7_441_000, 0) + // Minimum execution time: 7_363_000 picoseconds. + Weight::from_parts(7_715_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,8 +82,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_495 nanoseconds. - Weight::from_parts(7_666_000, 0) + // Minimum execution time: 7_516_000 picoseconds. + Weight::from_parts(7_860_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,13 +102,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 999]`. fn register_as_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1171 + c * (48 ±0)` - // Estimated: `56784 + c * (49 ±0)` - // Minimum execution time: 35_713 nanoseconds. - Weight::from_parts(27_978_009, 0) - .saturating_add(Weight::from_parts(0, 56784)) - // Standard Error: 1_293 - .saturating_add(Weight::from_parts(111_881, 0).saturating_mul(c.into())) + // Measured: `1108 + c * (48 ±0)` + // Estimated: `61671 + c * (49 ±0)` + // Minimum execution time: 38_063_000 picoseconds. + Weight::from_parts(30_924_306, 0) + .saturating_add(Weight::from_parts(0, 61671)) + // Standard Error: 1_232 + .saturating_add(Weight::from_parts(106_039, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 49).saturating_mul(c.into())) @@ -120,13 +120,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[6, 1000]`. fn leave_intent(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `536 + c * (48 ±0)` - // Estimated: `48497` - // Minimum execution time: 27_164 nanoseconds. - Weight::from_parts(16_901_858, 0) - .saturating_add(Weight::from_parts(0, 48497)) - // Standard Error: 1_312 - .saturating_add(Weight::from_parts(108_799, 0).saturating_mul(c.into())) + // Measured: `452 + c * (48 ±0)` + // Estimated: `49487` + // Minimum execution time: 29_598_000 picoseconds. + Weight::from_parts(19_372_924, 0) + .saturating_add(Weight::from_parts(0, 49487)) + // Standard Error: 1_253 + .saturating_add(Weight::from_parts(106_394, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -138,11 +138,11 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { // Proof Size summary in bytes: - // Measured: `135` - // Estimated: `5749` - // Minimum execution time: 26_007 nanoseconds. - Weight::from_parts(26_416_000, 0) - .saturating_add(Weight::from_parts(0, 5749)) + // Measured: `103` + // Estimated: `7729` + // Minimum execution time: 28_647_000 picoseconds. + Weight::from_parts(28_951_000, 0) + .saturating_add(Weight::from_parts(0, 7729)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -160,18 +160,18 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 1000]`. fn new_session(r: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `22784 + r * (148 ±0) + c * (97 ±0)` - // Estimated: `52737 + c * (2519 ±0) + r * (2602 ±0)` - // Minimum execution time: 16_056 nanoseconds. - Weight::from_parts(16_335_000, 0) - .saturating_add(Weight::from_parts(0, 52737)) - // Standard Error: 806_799 - .saturating_add(Weight::from_parts(29_195_677, 0).saturating_mul(c.into())) + // Measured: `22721 + r * (116 ±0) + c * (97 ±0)` + // Estimated: `56697 + c * (2520 ±0) + r * (2602 ±0)` + // Minimum execution time: 17_043_000 picoseconds. + Weight::from_parts(17_352_000, 0) + .saturating_add(Weight::from_parts(0, 56697)) + // Standard Error: 798_735 + .saturating_add(Weight::from_parts(28_961_284, 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, 2520).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 2602).saturating_mul(r.into())) } } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_multisig.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_multisig.rs index 37355802376..2e5f4b322f0 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_multisig.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -52,11 +52,11 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_185 nanoseconds. - Weight::from_parts(12_423_059, 0) + // Minimum execution time: 11_992_000 picoseconds. + Weight::from_parts(12_412_280, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(596, 0).saturating_mul(z.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(503, 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) @@ -64,15 +64,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 35_394 nanoseconds. - Weight::from_parts(28_339_222, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 525 - .saturating_add(Weight::from_parts(76_810, 0).saturating_mul(s.into())) + // Measured: `262 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 37_343_000 picoseconds. + Weight::from_parts(31_041_082, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 579 + .saturating_add(Weight::from_parts(68_564, 0).saturating_mul(s.into())) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_641, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_253, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,15 +82,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 26_605 nanoseconds. - Weight::from_parts(19_882_694, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 486 - .saturating_add(Weight::from_parts(73_686, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_615, 0).saturating_mul(z.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 27_702_000 picoseconds. + Weight::from_parts(22_324_758, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 382 + .saturating_add(Weight::from_parts(59_647, 0).saturating_mul(s.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(1_199, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,15 +102,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `448 + s * (33 ±0)` - // Estimated: `8424` - // Minimum execution time: 40_558 nanoseconds. - Weight::from_parts(31_782_538, 0) - .saturating_add(Weight::from_parts(0, 8424)) - // Standard Error: 587 - .saturating_add(Weight::from_parts(94_913, 0).saturating_mul(s.into())) + // Measured: `385 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 42_944_000 picoseconds. + Weight::from_parts(35_467_441, 0) + .saturating_add(Weight::from_parts(0, 10404)) + // Standard Error: 600 + .saturating_add(Weight::from_parts(80_406, 0).saturating_mul(s.into())) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_647, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_220, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -119,13 +119,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `318 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 24_889 nanoseconds. - Weight::from_parts(27_183_432, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 835 - .saturating_add(Weight::from_parts(79_518, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 27_997_000 picoseconds. + Weight::from_parts(30_250_714, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 709 + .saturating_add(Weight::from_parts(67_226, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -134,13 +134,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 17_143 nanoseconds. - Weight::from_parts(18_532_968, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 632 - .saturating_add(Weight::from_parts(75_565, 0).saturating_mul(s.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 19_821_000 picoseconds. + Weight::from_parts(20_670_152, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 470 + .saturating_add(Weight::from_parts(65_289, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,13 +149,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `517 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 26_917 nanoseconds. - Weight::from_parts(28_425_612, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 685 - .saturating_add(Weight::from_parts(81_581, 0).saturating_mul(s.into())) + // Measured: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 28_820_000 picoseconds. + Weight::from_parts(31_182_331, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 874 + .saturating_add(Weight::from_parts(68_617, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_nfts.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_nfts.rs index d4d05c7ce25..8c4425114b1 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_nfts.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_nfts.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,16 +17,16 @@ //! Autogenerated weights for `pallet_nfts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 // Executed Command: // ./artifacts/polkadot-parachain // benchmark // pallet -// --chain=westmint-dev +// --chain=statemine-dev // --execution=wasm // --wasm-execution=compiled // --pallet=pallet_nfts @@ -35,7 +35,7 @@ // --repeat=20 // --json // --header=./file_header.txt -// --output=./parachains/runtimes/assets/westmint/src/weights/pallet_nfts.rs +// --output=./parachains/runtimes/assets/statemine/src/weights/pallet_nfts.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,7 +50,7 @@ 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(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -59,18 +59,18 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `3054` - // Minimum execution time: 30_978 nanoseconds. - Weight::from_parts(31_489_000, 0) - .saturating_add(Weight::from_parts(0, 3054)) + // Measured: `145` + // Estimated: `5038` + // Minimum execution time: 34_100_000 picoseconds. + Weight::from_parts(34_649_000, 0) + .saturating_add(Weight::from_parts(0, 5038)) .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(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -80,62 +80,55 @@ impl pallet_nfts::WeightInfo for WeightInfo { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `3054` - // Minimum execution time: 20_101 nanoseconds. - Weight::from_parts(20_488_000, 0) - .saturating_add(Weight::from_parts(0, 3054)) + // Estimated: `5038` + // Minimum execution time: 22_415_000 picoseconds. + Weight::from_parts(22_808_000, 0) + .saturating_add(Weight::from_parts(0, 5038)) .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(80), added: 2555, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1001 w:1000) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1001 w:1000) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(219), added: 2694, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1001 w:1000) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(254), added: 2729, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 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(166), added: 2641, mode: MaxEncodedLen) + /// 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 ItemConfigOf (r:0 w:1000) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:1000) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, 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 `n` is `[0, 1000]`. /// 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(_n: u32, m: u32, a: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `172673 + m * (206 ±0) + a * (210 ±0)` - // Estimated: `3347314 + m * (2694 ±0) + a * (2729 ±0)` - // Minimum execution time: 23_505_821 nanoseconds. - Weight::from_parts(16_948_157_713, 0) - .saturating_add(Weight::from_parts(0, 3347314)) - // Standard Error: 20_494 - .saturating_add(Weight::from_parts(7_059_571, 0).saturating_mul(m.into())) - // Standard Error: 20_494 - .saturating_add(Weight::from_parts(8_471_367, 0).saturating_mul(a.into())) + fn destroy(m: u32, _c: u32, a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32170 + a * (366 ±0)` + // Estimated: `2538829 + a * (2954 ±0)` + // Minimum execution time: 978_514_000 picoseconds. + Weight::from_parts(915_478_956, 0) + .saturating_add(Weight::from_parts(0, 2538829)) + // Standard Error: 4_368 + .saturating_add(Weight::from_parts(3_621, 0).saturating_mul(m.into())) + // Standard Error: 4_368 + .saturating_add(Weight::from_parts(5_742_436, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004)) - .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(3005)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.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, 2694).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 2729).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(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -144,11 +137,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `13506` - // Minimum execution time: 39_850 nanoseconds. - Weight::from_parts(40_227_000, 0) - .saturating_add(Weight::from_parts(0, 13506)) + // Measured: `421` + // Estimated: `18460` + // Minimum execution time: 44_509_000 picoseconds. + Weight::from_parts(45_090_000, 0) + .saturating_add(Weight::from_parts(0, 18460)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -157,7 +150,7 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -166,24 +159,22 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `13506` - // Minimum execution time: 40_379 nanoseconds. - Weight::from_parts(41_110_000, 0) - .saturating_add(Weight::from_parts(0, 13506)) + // Measured: `421` + // Estimated: `18460` + // Minimum execution time: 43_761_000 picoseconds. + Weight::from_parts(44_304_000, 0) + .saturating_add(Weight::from_parts(0, 18460)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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 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:0) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(219), added: 2694, mode: MaxEncodedLen) + /// 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) @@ -194,26 +185,22 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `647` - // Estimated: `13652` - // Minimum execution time: 43_534 nanoseconds. - Weight::from_parts(43_846_000, 0) - .saturating_add(Weight::from_parts(0, 13652)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `530` + // Estimated: `15200` + // Minimum execution time: 45_215_000 picoseconds. + Weight::from_parts(46_367_000, 0) + .saturating_add(Weight::from_parts(0, 15200)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: 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) @@ -222,16 +209,16 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `811` - // Estimated: `16109` - // Minimum execution time: 49_184 nanoseconds. - Weight::from_parts(49_935_000, 0) - .saturating_add(Weight::from_parts(0, 16109)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `559` + // Estimated: `14926` + // Minimum execution time: 35_381_000 picoseconds. + Weight::from_parts(35_896_000, 0) + .saturating_add(Weight::from_parts(0, 14926)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -239,13 +226,13 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `756 + i * (140 ±0)` - // Estimated: `5103 + i * (3336 ±0)` - // Minimum execution time: 15_668 nanoseconds. - Weight::from_parts(15_762_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) - // Standard Error: 12_791 - .saturating_add(Weight::from_parts(12_224_567, 0).saturating_mul(i.into())) + // Measured: `729 + i * (108 ±0)` + // Estimated: `8077 + i * (3336 ±0)` + // Minimum execution time: 16_621_000 picoseconds. + Weight::from_parts(16_839_000, 0) + .saturating_add(Weight::from_parts(0, 8077)) + // Standard Error: 13_184 + .saturating_add(Weight::from_parts(13_274_447, 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()))) @@ -258,10 +245,10 @@ impl pallet_nfts::WeightInfo for WeightInfo { fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `5067` - // Minimum execution time: 18_861 nanoseconds. - Weight::from_parts(19_195_000, 0) - .saturating_add(Weight::from_parts(0, 5067)) + // Estimated: `7047` + // Minimum execution time: 20_314_000 picoseconds. + Weight::from_parts(20_726_000, 0) + .saturating_add(Weight::from_parts(0, 7047)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -272,145 +259,149 @@ impl pallet_nfts::WeightInfo for WeightInfo { fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `5067` - // Minimum execution time: 18_710 nanoseconds. - Weight::from_parts(18_971_000, 0) - .saturating_add(Weight::from_parts(0, 5067)) + // Estimated: `7047` + // Minimum execution time: 20_178_000 picoseconds. + Weight::from_parts(20_565_000, 0) + .saturating_add(Weight::from_parts(0, 7047)) .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 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: `289` - // Estimated: `5092` - // Minimum execution time: 17_067 nanoseconds. - Weight::from_parts(17_233_000, 0) - .saturating_add(Weight::from_parts(0, 5092)) + // Measured: `306` + // Estimated: `7087` + // Minimum execution time: 17_142_000 picoseconds. + Weight::from_parts(18_191_000, 0) + .saturating_add(Weight::from_parts(0, 7087)) .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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `381` - // Estimated: `5082` - // Minimum execution time: 21_203 nanoseconds. - Weight::from_parts(21_468_000, 0) - .saturating_add(Weight::from_parts(0, 5082)) + // Measured: `354` + // Estimated: `7066` + // Minimum execution time: 22_902_000 picoseconds. + Weight::from_parts(23_495_000, 0) + .saturating_add(Weight::from_parts(0, 7066)) .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(80), added: 2555, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:4) + /// 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: `362` - // Estimated: `2555` - // Minimum execution time: 24_304 nanoseconds. - Weight::from_parts(24_823_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `335` + // Estimated: `9627` + // Minimum execution time: 41_436_000 picoseconds. + Weight::from_parts(41_922_000, 0) + .saturating_add(Weight::from_parts(0, 9627)) + .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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `304` - // Estimated: `2555` - // Minimum execution time: 17_173 nanoseconds. - Weight::from_parts(17_448_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) + // Measured: `277` + // Estimated: `3549` + // Minimum execution time: 19_015_000 picoseconds. + Weight::from_parts(19_490_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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `2555` - // Minimum execution time: 13_697 nanoseconds. - Weight::from_parts(13_924_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) + // Estimated: `3549` + // Minimum execution time: 15_532_000 picoseconds. + Weight::from_parts(15_827_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 Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: - // Measured: `445` - // Estimated: `5078` - // Minimum execution time: 18_063 nanoseconds. - Weight::from_parts(18_438_000, 0) - .saturating_add(Weight::from_parts(0, 5078)) + // Measured: `401` + // Estimated: `7047` + // Minimum execution time: 21_022_000 picoseconds. + Weight::from_parts(21_289_000, 0) + .saturating_add(Weight::from_parts(0, 7047)) .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(80), added: 2555, mode: MaxEncodedLen) + /// 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(254), added: 2729, mode: MaxEncodedLen) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(479), added: 2954, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `10355` - // Minimum execution time: 37_582 nanoseconds. - Weight::from_parts(38_155_000, 0) - .saturating_add(Weight::from_parts(0, 10355)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `505` + // Estimated: `18078` + // Minimum execution time: 47_283_000 picoseconds. + Weight::from_parts(47_793_000, 0) + .saturating_add(Weight::from_parts(0, 18078)) + .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(80), added: 2555, mode: MaxEncodedLen) + /// 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(254), added: 2729, mode: MaxEncodedLen) + /// 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: `337` - // Estimated: `5284` - // Minimum execution time: 24_392 nanoseconds. - Weight::from_parts(24_787_000, 0) - .saturating_add(Weight::from_parts(0, 5284)) + // Measured: `310` + // Estimated: `7493` + // Minimum execution time: 27_462_000 picoseconds. + Weight::from_parts(27_798_000, 0) + .saturating_add(Weight::from_parts(0, 7493)) .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(254), added: 2729, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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: `724` - // Estimated: `7807` - // Minimum execution time: 34_564 nanoseconds. - Weight::from_parts(34_956_000, 0) - .saturating_add(Weight::from_parts(0, 7807)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `949` + // Estimated: `14540` + // Minimum execution time: 44_392_000 picoseconds. + Weight::from_parts(44_956_000, 0) + .saturating_add(Weight::from_parts(0, 14540)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: Nfts Item (r:1 w:0) @@ -419,11 +410,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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: `379` - // Estimated: `6812` - // Minimum execution time: 17_194 nanoseconds. - Weight::from_parts(17_467_000, 0) - .saturating_add(Weight::from_parts(0, 6812)) + // Measured: `347` + // Estimated: `8792` + // Minimum execution time: 18_619_000 picoseconds. + Weight::from_parts(18_970_000, 0) + .saturating_add(Weight::from_parts(0, 8792)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -432,133 +423,135 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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(254), added: 2729, mode: MaxEncodedLen) + /// 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: `828 + n * (204 ±0)` - // Estimated: `12144 + n * (2729 ±0)` - // Minimum execution time: 25_617 nanoseconds. - Weight::from_parts(25_917_000, 0) - .saturating_add(Weight::from_parts(0, 12144)) - // Standard Error: 5_524 - .saturating_add(Weight::from_parts(7_538_893, 0).saturating_mul(n.into())) + // Measured: `726 + n * (398 ±0)` + // Estimated: `16329 + n * (2954 ±0)` + // Minimum execution time: 28_293_000 picoseconds. + Weight::from_parts(28_502_000, 0) + .saturating_add(Weight::from_parts(0, 16329)) + // Standard Error: 4_215 + .saturating_add(Weight::from_parts(5_601_603, 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, 2729).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(80), added: 2555, mode: MaxEncodedLen) + /// 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(219), added: 2694, mode: MaxEncodedLen) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(347), added: 2822, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `10320` - // Minimum execution time: 32_053 nanoseconds. - Weight::from_parts(32_510_000, 0) - .saturating_add(Weight::from_parts(0, 10320)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `505` + // Estimated: `17946` + // Minimum execution time: 39_371_000 picoseconds. + Weight::from_parts(39_852_000, 0) + .saturating_add(Weight::from_parts(0, 17946)) + .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(219), added: 2694, mode: MaxEncodedLen) + /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `688` - // Estimated: `7772` - // Minimum execution time: 30_654 nanoseconds. - Weight::from_parts(31_113_000, 0) - .saturating_add(Weight::from_parts(0, 7772)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `815` + // Estimated: `14408` + // Minimum execution time: 37_535_000 picoseconds. + Weight::from_parts(38_894_000, 0) + .saturating_add(Weight::from_parts(0, 14408)) + .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(80), added: 2555, mode: MaxEncodedLen) + /// 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(166), added: 2641, mode: MaxEncodedLen) + /// 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: `333` - // Estimated: `7744` - // Minimum execution time: 27_700 nanoseconds. - Weight::from_parts(28_291_000, 0) - .saturating_add(Weight::from_parts(0, 7744)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `364` + // Estimated: `14380` + // Minimum execution time: 35_608_000 picoseconds. + Weight::from_parts(35_741_000, 0) + .saturating_add(Weight::from_parts(0, 14380)) + .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(80), added: 2555, mode: MaxEncodedLen) + /// 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(166), added: 2641, mode: MaxEncodedLen) + /// 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: `555` - // Estimated: `7744` - // Minimum execution time: 27_483 nanoseconds. - Weight::from_parts(27_830_000, 0) - .saturating_add(Weight::from_parts(0, 7744)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `682` + // Estimated: `14380` + // Minimum execution time: 33_234_000 picoseconds. + Weight::from_parts(33_617_000, 0) + .saturating_add(Weight::from_parts(0, 14380)) + .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) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `466` - // Estimated: `8428` - // Minimum execution time: 23_623 nanoseconds. - Weight::from_parts(24_282_000, 0) - .saturating_add(Weight::from_parts(0, 8428)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `376` + // Estimated: `7864` + // Minimum execution time: 22_900_000 picoseconds. + Weight::from_parts(23_351_000, 0) + .saturating_add(Weight::from_parts(0, 7864)) + .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) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `5880` - // Minimum execution time: 21_115 nanoseconds. - Weight::from_parts(22_036_000, 0) - .saturating_add(Weight::from_parts(0, 5880)) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `384` + // Estimated: `4326` + // Minimum execution time: 20_413_000 picoseconds. + Weight::from_parts(20_622_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) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `5880` - // Minimum execution time: 20_352 nanoseconds. - Weight::from_parts(20_627_000, 0) - .saturating_add(Weight::from_parts(0, 5880)) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `384` + // Estimated: `4326` + // Minimum execution time: 19_132_000 picoseconds. + Weight::from_parts(19_443_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) @@ -566,38 +559,38 @@ impl pallet_nfts::WeightInfo for WeightInfo { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2527` - // Minimum execution time: 14_427 nanoseconds. - Weight::from_parts(15_169_000, 0) - .saturating_add(Weight::from_parts(0, 2527)) + // Estimated: `3517` + // Minimum execution time: 16_661_000 picoseconds. + Weight::from_parts(16_925_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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `333` - // Estimated: `5103` - // Minimum execution time: 18_049 nanoseconds. - Weight::from_parts(18_431_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) + // Measured: `306` + // Estimated: `7087` + // Minimum execution time: 19_575_000 picoseconds. + Weight::from_parts(19_826_000, 0) + .saturating_add(Weight::from_parts(0, 7087)) .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(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `5103` - // Minimum execution time: 17_166 nanoseconds. - Weight::from_parts(17_511_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) + // Measured: `289` + // Estimated: `7072` + // Minimum execution time: 19_749_000 picoseconds. + Weight::from_parts(19_902_000, 0) + .saturating_add(Weight::from_parts(0, 7072)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -611,11 +604,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `516` - // Estimated: `8407` - // Minimum execution time: 22_556 nanoseconds. - Weight::from_parts(22_839_000, 0) - .saturating_add(Weight::from_parts(0, 8407)) + // Measured: `484` + // Estimated: `11377` + // Minimum execution time: 23_970_000 picoseconds. + Weight::from_parts(24_589_000, 0) + .saturating_add(Weight::from_parts(0, 11377)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -624,37 +617,35 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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: `897` - // Estimated: `16129` - // Minimum execution time: 53_554 nanoseconds. - Weight::from_parts(54_285_000, 0) - .saturating_add(Weight::from_parts(0, 16129)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `671` + // Estimated: `18480` + // Minimum execution time: 43_929_000 picoseconds. + Weight::from_parts(44_364_000, 0) + .saturating_add(Weight::from_parts(0, 18480)) + .saturating_add(T::DbWeight::get().reads(5)) + .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_031 nanoseconds. - Weight::from_parts(3_579_973, 0) + // Minimum execution time: 2_611_000 picoseconds. + Weight::from_parts(4_292_527, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 8_727 - .saturating_add(Weight::from_parts(3_165_511, 0).saturating_mul(n.into())) + // Standard Error: 9_304 + .saturating_add(Weight::from_parts(3_636_886, 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) @@ -662,11 +653,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn create_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `524` - // Estimated: `6672` - // Minimum execution time: 20_161 nanoseconds. - Weight::from_parts(20_487_000, 0) - .saturating_add(Weight::from_parts(0, 6672)) + // Measured: `460` + // Estimated: `7662` + // Minimum execution time: 22_643_000 picoseconds. + Weight::from_parts(22_957_000, 0) + .saturating_add(Weight::from_parts(0, 7662)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -676,11 +667,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `511` - // Estimated: `5882` - // Minimum execution time: 19_470 nanoseconds. - Weight::from_parts(19_832_000, 0) - .saturating_add(Weight::from_parts(0, 5882)) + // Measured: `479` + // Estimated: `7862` + // Minimum execution time: 21_037_000 picoseconds. + Weight::from_parts(21_359_000, 0) + .saturating_add(Weight::from_parts(0, 7862)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -689,85 +680,85 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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:2 w:0) /// 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 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: `1026` - // Estimated: `21970` - // Minimum execution time: 78_114 nanoseconds. - Weight::from_parts(79_459_000, 0) - .saturating_add(Weight::from_parts(0, 21970)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(11)) + // Measured: `800` + // Estimated: `24321` + // Minimum execution time: 72_434_000 picoseconds. + Weight::from_parts(73_184_000, 0) + .saturating_add(Weight::from_parts(0, 24321)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(10)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:2 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Nfts Attribute (r:10 w:10) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(254), added: 2729, mode: MaxEncodedLen) + /// 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(219), added: 2694, mode: MaxEncodedLen) + /// 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: `525` - // Estimated: `16259 + n * (2729 ±0)` - // Minimum execution time: 108_373 nanoseconds. - Weight::from_parts(112_094_892, 0) - .saturating_add(Weight::from_parts(0, 16259)) - // Standard Error: 27_186 - .saturating_add(Weight::from_parts(20_710_983, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `524` + // Estimated: `29399 + n * (2954 ±0)` + // Minimum execution time: 125_554_000 picoseconds. + Weight::from_parts(129_631_978, 0) + .saturating_add(Weight::from_parts(0, 29399)) + // Standard Error: 20_858 + .saturating_add(Weight::from_parts(26_871_088, 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, 2729).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(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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(446), added: 2921, mode: MaxEncodedLen) + /// 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: `716` - // Estimated: `14198 + n * (2921 ±0)` - // Minimum execution time: 84_153 nanoseconds. - Weight::from_parts(96_401_623, 0) - .saturating_add(Weight::from_parts(0, 14198)) - // Standard Error: 70_244 - .saturating_add(Weight::from_parts(26_866_222, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Measured: `554` + // Estimated: `20462 + n * (2954 ±0)` + // Minimum execution time: 76_170_000 picoseconds. + Weight::from_parts(85_697_599, 0) + .saturating_add(Weight::from_parts(0, 20462)) + // Standard Error: 51_480 + .saturating_add(Weight::from_parts(26_398_485, 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_u64)) + .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, 2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_proxy.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_proxy.rs index c4c259678fc..9e97e9e982d 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_proxy.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_proxy.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_proxy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -52,13 +52,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 15_168 nanoseconds. - Weight::from_parts(15_986_761, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 2_885 - .saturating_add(Weight::from_parts(12_185, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_846_000 picoseconds. + Weight::from_parts(17_545_125, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_168 + .saturating_add(Weight::from_parts(38_590, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -71,15 +71,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `550 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 32_310 nanoseconds. - Weight::from_parts(32_466_194, 0) - .saturating_add(Weight::from_parts(0, 11027)) - // Standard Error: 1_813 - .saturating_add(Weight::from_parts(120_725, 0).saturating_mul(a.into())) - // Standard Error: 1_873 - .saturating_add(Weight::from_parts(32_578, 0).saturating_mul(p.into())) + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 35_646_000 picoseconds. + Weight::from_parts(35_944_816, 0) + .saturating_add(Weight::from_parts(0, 13997)) + // Standard Error: 1_868 + .saturating_add(Weight::from_parts(137_815, 0).saturating_mul(a.into())) + // Standard Error: 1_930 + .saturating_add(Weight::from_parts(38_331, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -91,15 +91,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 20_363 nanoseconds. - Weight::from_parts(21_135_277, 0) - .saturating_add(Weight::from_parts(0, 7311)) - // Standard Error: 1_404 - .saturating_add(Weight::from_parts(120_045, 0).saturating_mul(a.into())) - // Standard Error: 1_450 - .saturating_add(Weight::from_parts(8_992, 0).saturating_mul(p.into())) + // Measured: `369 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_142_000 picoseconds. + Weight::from_parts(23_269_000, 0) + .saturating_add(Weight::from_parts(0, 9291)) + // Standard Error: 1_365 + .saturating_add(Weight::from_parts(140_747, 0).saturating_mul(a.into())) + // Standard Error: 1_411 + .saturating_add(Weight::from_parts(14_983, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,15 +111,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 20_086 nanoseconds. - Weight::from_parts(21_145_287, 0) - .saturating_add(Weight::from_parts(0, 7311)) - // Standard Error: 1_612 - .saturating_add(Weight::from_parts(113_598, 0).saturating_mul(a.into())) - // Standard Error: 1_666 - .saturating_add(Weight::from_parts(11_520, 0).saturating_mul(p.into())) + // Measured: `369 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_465_000 picoseconds. + Weight::from_parts(23_366_335, 0) + .saturating_add(Weight::from_parts(0, 9291)) + // Standard Error: 4_348 + .saturating_add(Weight::from_parts(149_266, 0).saturating_mul(a.into())) + // Standard Error: 4_492 + .saturating_add(Weight::from_parts(10_411, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -133,15 +133,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 27_819 nanoseconds. - Weight::from_parts(28_662_588, 0) - .saturating_add(Weight::from_parts(0, 11027)) - // Standard Error: 2_297 - .saturating_add(Weight::from_parts(128_485, 0).saturating_mul(a.into())) - // Standard Error: 2_373 - .saturating_add(Weight::from_parts(47_044, 0).saturating_mul(p.into())) + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 31_086_000 picoseconds. + Weight::from_parts(32_252_234, 0) + .saturating_add(Weight::from_parts(0, 13997)) + // Standard Error: 2_039 + .saturating_add(Weight::from_parts(131_541, 0).saturating_mul(a.into())) + // Standard Error: 2_107 + .saturating_add(Weight::from_parts(41_085, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -150,13 +150,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 21_187 nanoseconds. - Weight::from_parts(22_430_290, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 6_530 - .saturating_add(Weight::from_parts(43_133, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_040_000 picoseconds. + Weight::from_parts(24_914_869, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_025 + .saturating_add(Weight::from_parts(47_844, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,13 +165,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_985 nanoseconds. - Weight::from_parts(21_852_273, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_662 - .saturating_add(Weight::from_parts(66_644, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_495_000 picoseconds. + Weight::from_parts(24_788_899, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_911 + .saturating_add(Weight::from_parts(68_917, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -180,41 +180,41 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 16_958 nanoseconds. - Weight::from_parts(17_752_361, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_173 - .saturating_add(Weight::from_parts(25_691, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 19_269_000 picoseconds. + Weight::from_parts(20_040_655, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_327 + .saturating_add(Weight::from_parts(24_180, 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 { + fn create_pure(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `139` - // Estimated: `3716` - // Minimum execution time: 23_055 nanoseconds. - Weight::from_parts(23_892_965, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_390 - .saturating_add(Weight::from_parts(16_195, 0).saturating_mul(p.into())) + // Estimated: `4706` + // Minimum execution time: 25_926_000 picoseconds. + Weight::from_parts(26_963_808, 0) + .saturating_add(Weight::from_parts(0, 4706)) .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 { + fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `196 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 18_344 nanoseconds. - Weight::from_parts(20_533_110, 0) - .saturating_add(Weight::from_parts(0, 3716)) + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 19_961_000 picoseconds. + Weight::from_parts(20_928_300, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_576 + .saturating_add(Weight::from_parts(28_604, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_session.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_session.rs index 773068d7e10..06d41c6383a 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_session.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -54,10 +54,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `270` - // Estimated: `5490` - // Minimum execution time: 15_187 nanoseconds. - Weight::from_parts(15_459_000, 0) - .saturating_add(Weight::from_parts(0, 5490)) + // Estimated: `7470` + // Minimum execution time: 17_273_000 picoseconds. + Weight::from_parts(17_562_000, 0) + .saturating_add(Weight::from_parts(0, 7470)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `242` - // Estimated: `2959` - // Minimum execution time: 11_795 nanoseconds. - Weight::from_parts(11_994_000, 0) - .saturating_add(Weight::from_parts(0, 2959)) + // Estimated: `3949` + // Minimum execution time: 13_268_000 picoseconds. + Weight::from_parts(13_646_000, 0) + .saturating_add(Weight::from_parts(0, 3949)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_timestamp.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_timestamp.rs index 0802c0eb098..af27f018b00 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_timestamp.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -54,10 +54,10 @@ impl pallet_timestamp::WeightInfo for WeightInfo { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `86` - // Estimated: `1006` - // Minimum execution time: 8_408 nanoseconds. - Weight::from_parts(8_706_000, 0) - .saturating_add(Weight::from_parts(0, 1006)) + // Estimated: `2986` + // Minimum execution time: 9_234_000 picoseconds. + Weight::from_parts(9_578_000, 0) + .saturating_add(Weight::from_parts(0, 2986)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_timestamp::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `57` // Estimated: `0` - // Minimum execution time: 3_185 nanoseconds. - Weight::from_parts(3_282_000, 0) + // Minimum execution time: 3_193_000 picoseconds. + Weight::from_parts(3_306_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_uniques.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_uniques.rs index 5bd62a1fc8d..44846163ff0 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_uniques.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_uniques.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_uniques` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -53,11 +53,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `2653` - // Minimum execution time: 24_517 nanoseconds. - Weight::from_parts(24_884_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `145` + // Estimated: `3643` + // Minimum execution time: 25_977_000 picoseconds. + Weight::from_parts(27_109_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_uniques::WeightInfo for WeightInfo { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2653` - // Minimum execution time: 13_312 nanoseconds. - Weight::from_parts(13_652_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Estimated: `3643` + // Minimum execution time: 14_712_000 picoseconds. + Weight::from_parts(15_150_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -79,14 +79,14 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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 Attribute (r:0 w:1000) - /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, 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 InstanceMetadataOf (r:0 w:1000) - /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, 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) @@ -96,24 +96,28 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `289 + n * (108 ±0) + m * (56 ±0) + a * (107 ±0)` - // Estimated: `5250 + n * (2597 ±0)` - // Minimum execution time: 2_287_290 nanoseconds. - Weight::from_parts(2_319_526_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) - // Standard Error: 25_275 - .saturating_add(Weight::from_parts(8_587_226, 0).saturating_mul(n.into())) - // Standard Error: 25_275 - .saturating_add(Weight::from_parts(193_381, 0).saturating_mul(m.into())) - // Standard Error: 25_275 - .saturating_add(Weight::from_parts(296_151, 0).saturating_mul(a.into())) + // Measured: `257 + n * (76 ±0) + m * (56 ±0) + a * (107 ±0)` + // Estimated: `9210 + n * (2597 ±0) + a * (2647 ±0) + m * (2662 ±0)` + // Minimum execution time: 2_367_187_000 picoseconds. + Weight::from_parts(2_382_789_000, 0) + .saturating_add(Weight::from_parts(0, 9210)) + // Standard Error: 24_652 + .saturating_add(Weight::from_parts(6_204_090, 0).saturating_mul(n.into())) + // Standard Error: 24_652 + .saturating_add(Weight::from_parts(246_468, 0).saturating_mul(m.into())) + // Standard Error: 24_652 + .saturating_add(Weight::from_parts(346_915, 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, 2597).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2647).saturating_mul(a.into())) + .saturating_add(Weight::from_parts(0, 2662).saturating_mul(m.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -125,11 +129,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `7749` - // Minimum execution time: 29_225 nanoseconds. - Weight::from_parts(29_894_000, 0) - .saturating_add(Weight::from_parts(0, 7749)) + // Measured: `282` + // Estimated: `10719` + // Minimum execution time: 31_948_000 picoseconds. + Weight::from_parts(32_314_000, 0) + .saturating_add(Weight::from_parts(0, 10719)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -143,11 +147,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 30_673 nanoseconds. - Weight::from_parts(31_553_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 33_711_000 picoseconds. + Weight::from_parts(34_742_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -161,11 +165,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 24_944 nanoseconds. - Weight::from_parts(25_233_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 26_609_000 picoseconds. + Weight::from_parts(27_130_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -176,13 +180,13 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `770 + i * (108 ±0)` - // Estimated: `2653 + i * (2597 ±0)` - // Minimum execution time: 14_364 nanoseconds. - Weight::from_parts(14_520_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) - // Standard Error: 12_908 - .saturating_add(Weight::from_parts(12_176_880, 0).saturating_mul(i.into())) + // Measured: `738 + i * (76 ±0)` + // Estimated: `4633 + i * (2597 ±0)` + // Minimum execution time: 15_463_000 picoseconds. + Weight::from_parts(15_625_000, 0) + .saturating_add(Weight::from_parts(0, 4633)) + // Standard Error: 12_996 + .saturating_add(Weight::from_parts(13_104_503, 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)) @@ -195,11 +199,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 17_798 nanoseconds. - Weight::from_parts(18_009_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 18_897_000 picoseconds. + Weight::from_parts(19_276_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,11 +213,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 17_924 nanoseconds. - Weight::from_parts(18_168_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 18_883_000 picoseconds. + Weight::from_parts(19_526_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -221,11 +225,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 13_425 nanoseconds. - Weight::from_parts(13_846_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 14_519_000 picoseconds. + Weight::from_parts(14_887_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -233,11 +237,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 13_484 nanoseconds. - Weight::from_parts(13_715_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 14_172_000 picoseconds. + Weight::from_parts(14_395_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -249,11 +253,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `388` - // Estimated: `5180` - // Minimum execution time: 21_132 nanoseconds. - Weight::from_parts(21_421_000, 0) - .saturating_add(Weight::from_parts(0, 5180)) + // Measured: `356` + // Estimated: `7160` + // Minimum execution time: 22_131_000 picoseconds. + Weight::from_parts(22_540_000, 0) + .saturating_add(Weight::from_parts(0, 7160)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -261,11 +265,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 13_763 nanoseconds. - Weight::from_parts(14_136_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 15_582_000 picoseconds. + Weight::from_parts(15_907_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -275,11 +279,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `2653` - // Minimum execution time: 16_125 nanoseconds. - Weight::from_parts(16_516_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 17_915_000 picoseconds. + Weight::from_parts(18_190_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -291,11 +295,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `623` - // Estimated: `7962` - // Minimum execution time: 34_408 nanoseconds. - Weight::from_parts(34_820_000, 0) - .saturating_add(Weight::from_parts(0, 7962)) + // Measured: `559` + // Estimated: `10932` + // Minimum execution time: 37_851_000 picoseconds. + Weight::from_parts(38_554_000, 0) + .saturating_add(Weight::from_parts(0, 10932)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -307,11 +311,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `851` - // Estimated: `7962` - // Minimum execution time: 33_385 nanoseconds. - Weight::from_parts(34_088_000, 0) - .saturating_add(Weight::from_parts(0, 7962)) + // Measured: `756` + // Estimated: `10932` + // Minimum execution time: 37_289_000 picoseconds. + Weight::from_parts(37_807_000, 0) + .saturating_add(Weight::from_parts(0, 10932)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -321,11 +325,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `380` - // Estimated: `5315` - // Minimum execution time: 27_303 nanoseconds. - Weight::from_parts(27_692_000, 0) - .saturating_add(Weight::from_parts(0, 5315)) + // Measured: `348` + // Estimated: `7295` + // Minimum execution time: 28_825_000 picoseconds. + Weight::from_parts(29_277_000, 0) + .saturating_add(Weight::from_parts(0, 7295)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -335,11 +339,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `623` - // Estimated: `5315` - // Minimum execution time: 27_530 nanoseconds. - Weight::from_parts(28_122_000, 0) - .saturating_add(Weight::from_parts(0, 5315)) + // Measured: `559` + // Estimated: `7295` + // Minimum execution time: 29_274_000 picoseconds. + Weight::from_parts(29_941_000, 0) + .saturating_add(Weight::from_parts(0, 7295)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -349,11 +353,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `5295` - // Minimum execution time: 26_384 nanoseconds. - Weight::from_parts(27_285_000, 0) - .saturating_add(Weight::from_parts(0, 5295)) + // Measured: `282` + // Estimated: `7275` + // Minimum execution time: 28_196_000 picoseconds. + Weight::from_parts(28_563_000, 0) + .saturating_add(Weight::from_parts(0, 7275)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -363,11 +367,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `537` - // Estimated: `5295` - // Minimum execution time: 24_599 nanoseconds. - Weight::from_parts(24_992_000, 0) - .saturating_add(Weight::from_parts(0, 5295)) + // Measured: `473` + // Estimated: `7275` + // Minimum execution time: 26_657_000 picoseconds. + Weight::from_parts(27_189_000, 0) + .saturating_add(Weight::from_parts(0, 7275)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -377,11 +381,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 19_754 nanoseconds. - Weight::from_parts(20_071_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 21_135_000 picoseconds. + Weight::from_parts(21_445_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -391,11 +395,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `525` - // Estimated: `5250` - // Minimum execution time: 19_376 nanoseconds. - Weight::from_parts(19_716_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `461` + // Estimated: `7230` + // Minimum execution time: 20_803_000 picoseconds. + Weight::from_parts(21_249_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -404,10 +408,10 @@ impl pallet_uniques::WeightInfo for WeightInfo { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2527` - // Minimum execution time: 15_069 nanoseconds. - Weight::from_parts(15_273_000, 0) - .saturating_add(Weight::from_parts(0, 2527)) + // Estimated: `3517` + // Minimum execution time: 16_421_000 picoseconds. + Weight::from_parts(16_940_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -417,11 +421,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `5152` - // Minimum execution time: 15_900 nanoseconds. - Weight::from_parts(16_182_000, 0) - .saturating_add(Weight::from_parts(0, 5152)) + // Measured: `282` + // Estimated: `7132` + // Minimum execution time: 17_792_000 picoseconds. + Weight::from_parts(18_087_000, 0) + .saturating_add(Weight::from_parts(0, 7132)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -431,11 +435,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `291` - // Estimated: `2597` - // Minimum execution time: 15_789 nanoseconds. - Weight::from_parts(16_115_000, 0) - .saturating_add(Weight::from_parts(0, 2597)) + // Measured: `259` + // Estimated: `3587` + // Minimum execution time: 17_036_000 picoseconds. + Weight::from_parts(17_365_000, 0) + .saturating_add(Weight::from_parts(0, 3587)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -449,11 +453,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `636` - // Estimated: `7814` - // Minimum execution time: 34_557 nanoseconds. - Weight::from_parts(34_927_000, 0) - .saturating_add(Weight::from_parts(0, 7814)) + // Measured: `540` + // Estimated: `10784` + // Minimum execution time: 37_920_000 picoseconds. + Weight::from_parts(38_587_000, 0) + .saturating_add(Weight::from_parts(0, 10784)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_utility.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_utility.rs index f0823eb6f87..25a8f1375d0 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_utility.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -52,18 +52,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_416 nanoseconds. - Weight::from_parts(18_983_305, 0) + // Minimum execution time: 7_113_000 picoseconds. + Weight::from_parts(38_041_346, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_082 - .saturating_add(Weight::from_parts(4_175_368, 0).saturating_mul(c.into())) + // Standard Error: 4_785 + .saturating_add(Weight::from_parts(4_680_352, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_581 nanoseconds. - Weight::from_parts(4_767_000, 0) + // Minimum execution time: 5_441_000 picoseconds. + Weight::from_parts(5_594_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +71,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_279 nanoseconds. - Weight::from_parts(21_320_216, 0) + // Minimum execution time: 7_203_000 picoseconds. + Weight::from_parts(18_311_542, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_995 - .saturating_add(Weight::from_parts(4_376_040, 0).saturating_mul(c.into())) + // Standard Error: 2_281 + .saturating_add(Weight::from_parts(4_950_166, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_298 nanoseconds. - Weight::from_parts(8_522_000, 0) + // Minimum execution time: 9_631_000 picoseconds. + Weight::from_parts(9_881_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +90,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_311 nanoseconds. - Weight::from_parts(16_307_926, 0) + // Minimum execution time: 7_146_000 picoseconds. + Weight::from_parts(22_172_240, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_381 - .saturating_add(Weight::from_parts(4_172_851, 0).saturating_mul(c.into())) + // Standard Error: 3_023 + .saturating_add(Weight::from_parts(4_688_391, 0).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/assets/statemine/src/weights/pallet_xcm.rs b/parachains/runtimes/assets/statemine/src/weights/pallet_xcm.rs index 8863a425c01..832a9af5f5e 100644 --- a/parachains/runtimes/assets/statemine/src/weights/pallet_xcm.rs +++ b/parachains/runtimes/assets/statemine/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 @@ -59,11 +59,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) fn send() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `4645` - // Minimum execution time: 25_244 nanoseconds. - Weight::from_parts(25_671_000, 0) - .saturating_add(Weight::from_parts(0, 4645)) + // Measured: `75` + // Estimated: `9780` + // Minimum execution time: 28_004_000 picoseconds. + Weight::from_parts(28_341_000, 0) + .saturating_add(Weight::from_parts(0, 9780)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,10 +72,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `499` - // Minimum execution time: 25_183 nanoseconds. - Weight::from_parts(25_684_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 23_734_000 picoseconds. + Weight::from_parts(24_091_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: ParachainInfo ParachainId (r:1 w:0) @@ -83,10 +83,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `499` - // Minimum execution time: 18_819 nanoseconds. - Weight::from_parts(19_048_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 19_172_000 picoseconds. + Weight::from_parts(19_439_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Benchmark Override (r:0 w:0) @@ -95,7 +95,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -105,8 +105,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_636 nanoseconds. - Weight::from_parts(8_906_000, 0) + // Minimum execution time: 10_181_000 picoseconds. + Weight::from_parts(10_441_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -116,8 +116,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_486 nanoseconds. - Weight::from_parts(2_652_000, 0) + // Minimum execution time: 3_092_000 picoseconds. + Weight::from_parts(3_217_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -139,11 +139,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `7729` - // Minimum execution time: 29_811 nanoseconds. - Weight::from_parts(30_291_000, 0) - .saturating_add(Weight::from_parts(0, 7729)) + // Measured: `75` + // Estimated: `14955` + // Minimum execution time: 36_167_000 picoseconds. + Weight::from_parts(37_036_000, 0) + .saturating_add(Weight::from_parts(0, 14955)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -163,11 +163,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: - // Measured: `220` - // Estimated: `8470` - // Minimum execution time: 31_884 nanoseconds. - Weight::from_parts(32_567_000, 0) - .saturating_add(Weight::from_parts(0, 8470)) + // Measured: `257` + // Estimated: `14669` + // Minimum execution time: 39_341_000 picoseconds. + Weight::from_parts(40_254_000, 0) + .saturating_add(Weight::from_parts(0, 14669)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -175,11 +175,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: PolkadotXcm SupportedVersion (max_values: None, max_size: None, mode: Measured) fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `9995` - // Minimum execution time: 14_098 nanoseconds. - Weight::from_parts(14_349_000, 0) - .saturating_add(Weight::from_parts(0, 9995)) + // Measured: `129` + // Estimated: `11019` + // Minimum execution time: 20_159_000 picoseconds. + Weight::from_parts(20_621_000, 0) + .saturating_add(Weight::from_parts(0, 11019)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -187,11 +187,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: PolkadotXcm VersionNotifiers (max_values: None, max_size: None, mode: Measured) fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: - // Measured: `99` - // Estimated: `9999` - // Minimum execution time: 14_117 nanoseconds. - Weight::from_parts(14_383_000, 0) - .saturating_add(Weight::from_parts(0, 9999)) + // Measured: `133` + // Estimated: `11023` + // Minimum execution time: 20_095_000 picoseconds. + Weight::from_parts(20_335_000, 0) + .saturating_add(Weight::from_parts(0, 11023)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -199,11 +199,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) fn already_notified_target() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `12481` - // Minimum execution time: 15_353 nanoseconds. - Weight::from_parts(15_558_000, 0) - .saturating_add(Weight::from_parts(0, 12481)) + // Measured: `140` + // Estimated: `13505` + // Minimum execution time: 20_826_000 picoseconds. + Weight::from_parts(21_160_000, 0) + .saturating_add(Weight::from_parts(0, 13505)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) @@ -220,11 +220,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) fn notify_current_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `10041` - // Minimum execution time: 28_752 nanoseconds. - Weight::from_parts(29_435_000, 0) - .saturating_add(Weight::from_parts(0, 10041)) + // Measured: `142` + // Estimated: `16197` + // Minimum execution time: 38_595_000 picoseconds. + Weight::from_parts(39_178_000, 0) + .saturating_add(Weight::from_parts(0, 16197)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -232,22 +232,22 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: - // Measured: `136` - // Estimated: `7561` - // Minimum execution time: 7_143 nanoseconds. - Weight::from_parts(7_368_000, 0) - .saturating_add(Weight::from_parts(0, 7561)) + // Measured: `172` + // Estimated: `8587` + // Minimum execution time: 11_391_000 picoseconds. + Weight::from_parts(11_704_000, 0) + .saturating_add(Weight::from_parts(0, 8587)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) /// Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `10006` - // Minimum execution time: 14_381 nanoseconds. - Weight::from_parts(14_582_000, 0) - .saturating_add(Weight::from_parts(0, 10006)) + // Measured: `140` + // Estimated: `11030` + // Minimum execution time: 22_506_000 picoseconds. + Weight::from_parts(23_076_000, 0) + .saturating_add(Weight::from_parts(0, 11030)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,11 +265,11 @@ impl pallet_xcm::WeightInfo for WeightInfo { /// Proof Skipped: 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: `15027` - // Minimum execution time: 34_190 nanoseconds. - Weight::from_parts(34_889_000, 0) - .saturating_add(Weight::from_parts(0, 15027)) + // Measured: `146` + // Estimated: `21171` + // Minimum execution time: 47_662_000 picoseconds. + Weight::from_parts(48_167_000, 0) + .saturating_add(Weight::from_parts(0, 21171)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 8999d55df5b..d93dd65746b 100644 --- a/parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,27 +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-03-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, 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` +//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./templates/xcm-bench-template.hbs +// --chain=statemine-dev // --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_xcm_benchmarks::fungible -// --chain=statemine-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/assets/statemine/src/weights/xcm/ +// --output=./parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 22_457_000 picoseconds. - Weight::from_parts(22_952_000, 3593) + // Minimum execution time: 23_021_000 picoseconds. + Weight::from_parts(23_385_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 32_247_000 picoseconds. - Weight::from_parts(32_534_000, 6196) + // Minimum execution time: 33_451_000 picoseconds. + Weight::from_parts(33_779_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -87,10 +86,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn transfer_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `139` - // Estimated: `17785` - // Minimum execution time: 53_956_000 picoseconds. - Weight::from_parts(55_144_000, 17785) + // Measured: `176` + // Estimated: `17970` + // Minimum execution time: 56_145_000 picoseconds. + Weight::from_parts(56_830_000, 17970) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -98,8 +97,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_424_000 picoseconds. - Weight::from_parts(4_494_000, 0) + // Minimum execution time: 4_315_000 picoseconds. + Weight::from_parts(4_448_000, 0) } // Storage: System Account (r:1 w:1) // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -107,8 +106,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 25_243_000 picoseconds. - Weight::from_parts(25_666_000, 3593) + // Minimum execution time: 25_505_000 picoseconds. + Weight::from_parts(25_697_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -128,10 +127,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn deposit_reserve_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `14677` - // Minimum execution time: 47_487_000 picoseconds. - Weight::from_parts(80_083_000, 14677) + // Measured: `75` + // Estimated: `14862` + // Minimum execution time: 50_620_000 picoseconds. + Weight::from_parts(50_926_000, 14862) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -149,10 +148,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn initiate_teleport() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `11084` - // Minimum execution time: 31_674_000 picoseconds. - Weight::from_parts(45_575_000, 11084) + // Measured: `75` + // Estimated: `11269` + // Minimum execution time: 31_700_000 picoseconds. + Weight::from_parts(32_178_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 8424d5d64a9..058f23631dd 100644 --- a/parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,27 +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-03-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, 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` +//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemine-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./templates/xcm-bench-template.hbs +// --chain=statemine-dev // --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_xcm_benchmarks::generic -// --chain=statemine-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/assets/statemine/src/weights/xcm/ +// --output=./parachains/runtimes/assets/statemine/src/weights/xcm/pallet_xcm_benchmarks_generic.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -63,10 +62,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn report_holding() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `11084` - // Minimum execution time: 364_890_000 picoseconds. - Weight::from_parts(367_248_000, 11084) + // Measured: `75` + // Estimated: `11269` + // Minimum execution time: 367_337_000 picoseconds. + Weight::from_parts(368_530_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -74,67 +73,67 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_032_000 picoseconds. - Weight::from_parts(4_167_000, 0) + // Minimum execution time: 4_121_000 picoseconds. + Weight::from_parts(4_318_000, 0) } // Storage: PolkadotXcm Queries (r:1 w:0) // Proof Skipped: 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: 11_093_000 picoseconds. - Weight::from_parts(11_300_000, 3497) + // Measured: `69` + // Estimated: `3534` + // Minimum execution time: 11_951_000 picoseconds. + Weight::from_parts(12_171_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_672_000 picoseconds. - Weight::from_parts(13_829_000, 0) + // Minimum execution time: 13_626_000 picoseconds. + Weight::from_parts(13_891_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_451_000 picoseconds. - Weight::from_parts(4_581_000, 0) + // Minimum execution time: 4_276_000 picoseconds. + Weight::from_parts(4_444_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_053_000 picoseconds. - Weight::from_parts(3_148_000, 0) + // Minimum execution time: 2_969_000 picoseconds. + Weight::from_parts(3_090_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_733_000 picoseconds. - Weight::from_parts(4_784_000, 0) + // Minimum execution time: 3_148_000 picoseconds. + Weight::from_parts(3_252_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_002_000 picoseconds. - Weight::from_parts(3_072_000, 0) + // Minimum execution time: 3_027_000 picoseconds. + Weight::from_parts(3_081_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_959_000 picoseconds. - Weight::from_parts(4_036_000, 0) + // Minimum execution time: 3_863_000 picoseconds. + Weight::from_parts(3_934_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_974_000 picoseconds. - Weight::from_parts(3_052_000, 0) + // Minimum execution time: 3_013_000 picoseconds. + Weight::from_parts(3_115_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -150,10 +149,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn report_error() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `11084` - // Minimum execution time: 24_065_000 picoseconds. - Weight::from_parts(24_646_000, 11084) + // Measured: `75` + // Estimated: `11269` + // Minimum execution time: 25_963_000 picoseconds. + Weight::from_parts(26_428_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -161,10 +160,10 @@ impl WeightInfo { // Proof Skipped: 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: 15_036_000 picoseconds. - Weight::from_parts(15_419_000, 3555) + // Measured: `126` + // Estimated: `3591` + // Minimum execution time: 16_492_000 picoseconds. + Weight::from_parts(16_930_000, 3591) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -172,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_008_000 picoseconds. - Weight::from_parts(3_083_000, 0) + // Minimum execution time: 3_004_000 picoseconds. + Weight::from_parts(3_070_000, 0) } // Storage: PolkadotXcm VersionNotifyTargets (r:1 w:1) // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) @@ -189,10 +188,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn subscribe_version() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `13098` - // Minimum execution time: 44_824_000 picoseconds. - Weight::from_parts(45_183_000, 13098) + // Measured: `75` + // Estimated: `13320` + // Minimum execution time: 28_804_000 picoseconds. + Weight::from_parts(29_543_000, 13320) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -202,8 +201,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_969_000 picoseconds. - Weight::from_parts(5_198_000, 0) + // Minimum execution time: 5_140_000 picoseconds. + Weight::from_parts(5_343_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: ParachainInfo ParachainId (r:1 w:0) @@ -220,10 +219,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn initiate_reserve_withdraw() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `11084` - // Minimum execution time: 422_661_000 picoseconds. - Weight::from_parts(425_164_000, 11084) + // Measured: `75` + // Estimated: `11269` + // Minimum execution time: 410_533_000 picoseconds. + Weight::from_parts(412_507_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -231,36 +230,36 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 135_692_000 picoseconds. - Weight::from_parts(136_167_000, 0) + // Minimum execution time: 126_970_000 picoseconds. + Weight::from_parts(129_854_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_880_000 picoseconds. - Weight::from_parts(13_103_000, 0) + // Minimum execution time: 13_585_000 picoseconds. + Weight::from_parts(13_852_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_842_000 picoseconds. - Weight::from_parts(4_898_000, 0) + // Minimum execution time: 3_091_000 picoseconds. + Weight::from_parts(3_180_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_026_000 picoseconds. - Weight::from_parts(3_109_000, 0) + // Minimum execution time: 2_982_000 picoseconds. + Weight::from_parts(3_060_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_241_000 picoseconds. - Weight::from_parts(3_281_000, 0) + // Minimum execution time: 3_246_000 picoseconds. + Weight::from_parts(3_332_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -276,10 +275,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn query_pallet() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `11084` - // Minimum execution time: 27_818_000 picoseconds. - Weight::from_parts(28_080_000, 11084) + // Measured: `75` + // Estimated: `11269` + // Minimum execution time: 29_939_000 picoseconds. + Weight::from_parts(30_426_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -287,8 +286,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_410_000 picoseconds. - Weight::from_parts(5_514_000, 0) + // Minimum execution time: 5_477_000 picoseconds. + Weight::from_parts(5_585_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -304,10 +303,10 @@ impl WeightInfo { // Proof Skipped: ParachainSystem PendingUpwardMessages (max_values: Some(1), max_size: None, mode: Measured) pub fn report_transact_status() -> Weight { // Proof Size summary in bytes: - // Measured: `38` - // Estimated: `11084` - // Minimum execution time: 24_798_000 picoseconds. - Weight::from_parts(26_833_000, 11084) + // Measured: `75` + // Estimated: `11269` + // Minimum execution time: 26_349_000 picoseconds. + Weight::from_parts(26_957_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -315,35 +314,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_083_000 picoseconds. - Weight::from_parts(3_148_000, 0) + // Minimum execution time: 3_087_000 picoseconds. + Weight::from_parts(3_137_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_995_000 picoseconds. - Weight::from_parts(3_045_000, 0) + // Minimum execution time: 3_047_000 picoseconds. + Weight::from_parts(3_111_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_080_000 picoseconds. - Weight::from_parts(3_128_000, 0) + // Minimum execution time: 3_018_000 picoseconds. + Weight::from_parts(3_082_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_009_000 picoseconds. - Weight::from_parts(3_102_000, 0) + // Minimum execution time: 3_051_000 picoseconds. + Weight::from_parts(3_090_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_202_000 picoseconds. - Weight::from_parts(3_290_000, 0) + // Minimum execution time: 3_140_000 picoseconds. + Weight::from_parts(3_274_000, 0) } } diff --git a/parachains/runtimes/assets/statemint/src/weights/cumulus_pallet_xcmp_queue.rs b/parachains/runtimes/assets/statemint/src/weights/cumulus_pallet_xcmp_queue.rs index 746387e0796..02bedfa2d6a 100644 --- a/parachains/runtimes/assets/statemint/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/parachains/runtimes/assets/statemint/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -52,10 +52,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_717 nanoseconds. - Weight::from_parts(4_964_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_634_000 picoseconds. + Weight::from_parts(5_845_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,10 +64,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_weight() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_840 nanoseconds. - Weight::from_parts(5_074_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_684_000 picoseconds. + Weight::from_parts(5_823_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/parachains/runtimes/assets/statemint/src/weights/frame_system.rs b/parachains/runtimes/assets/statemint/src/weights/frame_system.rs index 3475b7980cb..23a5e25cddb 100644 --- a/parachains/runtimes/assets/statemint/src/weights/frame_system.rs +++ b/parachains/runtimes/assets/statemint/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -52,22 +52,22 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_455 nanoseconds. - Weight::from_parts(1_553_000, 0) + // Minimum execution time: 2_346_000 picoseconds. + Weight::from_parts(2_416_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(368, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(412, 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_602 nanoseconds. - Weight::from_parts(6_725_000, 0) + // Minimum execution time: 8_010_000 picoseconds. + Weight::from_parts(8_171_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_715, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_448, 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) @@ -76,10 +76,10 @@ impl frame_system::WeightInfo for WeightInfo { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 3_555 nanoseconds. - Weight::from_parts(3_745_000, 0) - .saturating_add(Weight::from_parts(0, 495)) + // Estimated: `1485` + // Minimum execution time: 4_684_000 picoseconds. + Weight::from_parts(4_872_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,11 +90,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_690 nanoseconds. - Weight::from_parts(1_735_000, 0) + // Minimum execution time: 2_361_000 picoseconds. + Weight::from_parts(2_402_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_138 - .saturating_add(Weight::from_parts(588_449, 0).saturating_mul(i.into())) + // Standard Error: 1_747 + .saturating_add(Weight::from_parts(682_536, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -104,11 +104,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_695 nanoseconds. - Weight::from_parts(1_771_000, 0) + // Minimum execution time: 2_515_000 picoseconds. + Weight::from_parts(2_565_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 816 - .saturating_add(Weight::from_parts(449_345, 0).saturating_mul(i.into())) + // Standard Error: 859 + .saturating_add(Weight::from_parts(501_791, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -118,11 +118,12 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `81 + p * (69 ±0)` // Estimated: `72 + p * (70 ±0)` - // Minimum execution time: 3_289 nanoseconds. - Weight::from_parts(3_377_000, 0) + // Minimum execution time: 4_524_000 picoseconds. + Weight::from_parts(4_626_000, 0) .saturating_add(Weight::from_parts(0, 72)) - // Standard Error: 922 - .saturating_add(Weight::from_parts(969_103, 0).saturating_mul(p.into())) + // Standard Error: 1_004 + .saturating_add(Weight::from_parts(1_011_603, 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/parachains/runtimes/assets/statemint/src/weights/pallet_assets.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_assets.rs index 0fc7e6fb0af..933dcb4d3af 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_assets.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_assets.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_assets` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -53,11 +53,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `141` - // Estimated: `5288` - // Minimum execution time: 21_786 nanoseconds. - Weight::from_parts(22_084_000, 0) - .saturating_add(Weight::from_parts(0, 5288)) + // Measured: `109` + // Estimated: `7268` + // Minimum execution time: 24_714_000 picoseconds. + Weight::from_parts(25_310_000, 0) + .saturating_add(Weight::from_parts(0, 7268)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -66,10 +66,10 @@ impl pallet_assets::WeightInfo for WeightInfo { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `6` - // Estimated: `2685` - // Minimum execution time: 10_638 nanoseconds. - Weight::from_parts(10_889_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Estimated: `3675` + // Minimum execution time: 12_820_000 picoseconds. + Weight::from_parts(13_118_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -77,11 +77,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 13_146 nanoseconds. - Weight::from_parts(13_421_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 15_292_000 picoseconds. + Weight::from_parts(15_715_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -94,13 +94,13 @@ impl pallet_assets::WeightInfo for WeightInfo { /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + c * (240 ±0)` - // Estimated: `5262 + c * (5180 ±0)` - // Minimum execution time: 15_962 nanoseconds. - Weight::from_parts(16_041_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) - // Standard Error: 9_326 - .saturating_add(Weight::from_parts(13_983_529, 0).saturating_mul(c.into())) + // Measured: `0 + c * (208 ±0)` + // Estimated: `8232 + c * (5180 ±0)` + // Minimum execution time: 17_955_000 picoseconds. + Weight::from_parts(18_157_000, 0) + .saturating_add(Weight::from_parts(0, 8232)) + // Standard Error: 7_214 + .saturating_add(Weight::from_parts(12_316_605, 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)) @@ -114,13 +114,13 @@ impl pallet_assets::WeightInfo for WeightInfo { /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `446 + a * (86 ±0)` - // Estimated: `5308 + a * (2623 ±0)` - // Minimum execution time: 16_343 nanoseconds. - Weight::from_parts(16_490_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) - // Standard Error: 7_664 - .saturating_add(Weight::from_parts(13_585_881, 0).saturating_mul(a.into())) + // Measured: `414 + a * (86 ±0)` + // Estimated: `7288 + a * (2623 ±0)` + // Minimum execution time: 18_626_000 picoseconds. + Weight::from_parts(18_760_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) + // Standard Error: 4_382 + .saturating_add(Weight::from_parts(12_278_198, 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)) @@ -133,11 +133,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 12_531 nanoseconds. - Weight::from_parts(13_108_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 14_576_000 picoseconds. + Weight::from_parts(14_816_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -147,11 +147,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5262` - // Minimum execution time: 22_604 nanoseconds. - Weight::from_parts(22_970_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `243` + // Estimated: `7242` + // Minimum execution time: 26_215_000 picoseconds. + Weight::from_parts(26_571_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -161,11 +161,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 28_407 nanoseconds. - Weight::from_parts(29_012_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 31_944_000 picoseconds. + Weight::from_parts(32_675_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -177,11 +177,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `10442` - // Minimum execution time: 38_044 nanoseconds. - Weight::from_parts(38_562_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 44_126_000 picoseconds. + Weight::from_parts(44_567_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -193,11 +193,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `383` - // Estimated: `10442` - // Minimum execution time: 33_946 nanoseconds. - Weight::from_parts(34_532_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 39_414_000 picoseconds. + Weight::from_parts(39_891_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -209,11 +209,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `10442` - // Minimum execution time: 38_013 nanoseconds. - Weight::from_parts(38_818_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 44_875_000 picoseconds. + Weight::from_parts(45_961_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -223,11 +223,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 15_798 nanoseconds. - Weight::from_parts(16_178_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 18_388_000 picoseconds. + Weight::from_parts(18_718_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -237,11 +237,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 16_196 nanoseconds. - Weight::from_parts(16_525_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 18_292_000 picoseconds. + Weight::from_parts(18_633_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -249,11 +249,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 12_600 nanoseconds. - Weight::from_parts(13_038_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 14_604_000 picoseconds. + Weight::from_parts(14_980_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -261,11 +261,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 12_433 nanoseconds. - Weight::from_parts(12_924_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 14_008_000 picoseconds. + Weight::from_parts(14_428_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -275,11 +275,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 13_754 nanoseconds. - Weight::from_parts(14_069_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 15_453_000 picoseconds. + Weight::from_parts(15_963_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -287,11 +287,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `2685` - // Minimum execution time: 12_640 nanoseconds. - Weight::from_parts(12_846_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 14_515_000 picoseconds. + Weight::from_parts(14_835_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -301,15 +301,17 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn set_metadata(_n: u32, s: u32, ) -> Weight { + fn set_metadata(n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 22_428 nanoseconds. - Weight::from_parts(23_549_955, 0) - .saturating_add(Weight::from_parts(0, 5300)) - // Standard Error: 731 - .saturating_add(Weight::from_parts(893, 0).saturating_mul(s.into())) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 25_865_000 picoseconds. + Weight::from_parts(26_845_899, 0) + .saturating_add(Weight::from_parts(0, 7280)) + // Standard Error: 1_061 + .saturating_add(Weight::from_parts(4_438, 0).saturating_mul(n.into())) + // Standard Error: 1_061 + .saturating_add(Weight::from_parts(5_130, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -319,11 +321,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `471` - // Estimated: `5300` - // Minimum execution time: 22_730 nanoseconds. - Weight::from_parts(23_336_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `407` + // Estimated: `7280` + // Minimum execution time: 25_970_000 picoseconds. + Weight::from_parts(26_439_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -333,15 +335,17 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) /// The range of component `n` is `[0, 50]`. /// The range of component `s` is `[0, 50]`. - fn force_set_metadata(_n: u32, s: u32, ) -> Weight { + fn force_set_metadata(n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `82` - // Estimated: `5300` - // Minimum execution time: 12_289 nanoseconds. - Weight::from_parts(12_841_728, 0) - .saturating_add(Weight::from_parts(0, 5300)) - // Standard Error: 304 - .saturating_add(Weight::from_parts(1_964, 0).saturating_mul(s.into())) + // Estimated: `7280` + // Minimum execution time: 14_101_000 picoseconds. + Weight::from_parts(14_786_155, 0) + .saturating_add(Weight::from_parts(0, 7280)) + // Standard Error: 383 + .saturating_add(Weight::from_parts(581, 0).saturating_mul(n.into())) + // Standard Error: 383 + .saturating_add(Weight::from_parts(4_514, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -351,11 +355,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `471` - // Estimated: `5300` - // Minimum execution time: 23_203 nanoseconds. - Weight::from_parts(23_490_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `407` + // Estimated: `7280` + // Minimum execution time: 26_563_000 picoseconds. + Weight::from_parts(26_733_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -363,11 +367,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `275` - // Estimated: `2685` - // Minimum execution time: 12_042 nanoseconds. - Weight::from_parts(12_246_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 13_948_000 picoseconds. + Weight::from_parts(14_330_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -377,11 +381,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `5308` - // Minimum execution time: 25_898 nanoseconds. - Weight::from_parts(26_128_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `277` + // Estimated: `7288` + // Minimum execution time: 30_307_000 picoseconds. + Weight::from_parts(30_677_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -395,11 +399,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `553` - // Estimated: `13065` - // Minimum execution time: 52_087 nanoseconds. - Weight::from_parts(52_630_000, 0) - .saturating_add(Weight::from_parts(0, 13065)) + // Measured: `521` + // Estimated: `17025` + // Minimum execution time: 59_228_000 picoseconds. + Weight::from_parts(59_702_000, 0) + .saturating_add(Weight::from_parts(0, 17025)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -409,11 +413,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `479` - // Estimated: `5308` - // Minimum execution time: 27_731 nanoseconds. - Weight::from_parts(28_129_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `447` + // Estimated: `7288` + // Minimum execution time: 31_228_000 picoseconds. + Weight::from_parts(31_564_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -423,11 +427,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `479` - // Estimated: `5308` - // Minimum execution time: 27_921 nanoseconds. - Weight::from_parts(28_386_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `447` + // Estimated: `7288` + // Minimum execution time: 32_931_000 picoseconds. + Weight::from_parts(33_406_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -435,12 +439,12 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `383` + // Measured: `243` // Estimated: `3675` - // Minimum execution time: 16_213 nanoseconds. - Weight::from_parts(16_575_000, 0) + // Minimum execution time: 15_084_000 picoseconds. + Weight::from_parts(15_358_000, 0) .saturating_add(Weight::from_parts(0, 3675)) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_balances.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_balances.rs index a80ebe75bc5..e81c1925649 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_balances.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-22, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -51,11 +51,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1178` - // Estimated: `2603` - // Minimum execution time: 45_943 nanoseconds. - Weight::from_parts(46_894_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 35_757_000 picoseconds. + Weight::from_parts(36_417_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -63,11 +63,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1062` - // Estimated: `2603` - // Minimum execution time: 35_842 nanoseconds. - Weight::from_parts(36_089_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 27_074_000 picoseconds. + Weight::from_parts(27_335_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,11 +75,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1174` - // Estimated: `2603` - // Minimum execution time: 26_219 nanoseconds. - Weight::from_parts(26_783_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 16_753_000 picoseconds. + Weight::from_parts(17_141_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -87,11 +87,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1174` - // Estimated: `2603` - // Minimum execution time: 29_939 nanoseconds. - Weight::from_parts(30_394_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 20_459_000 picoseconds. + Weight::from_parts(20_848_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -99,11 +99,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1174` - // Estimated: `5206` - // Minimum execution time: 46_341 nanoseconds. - Weight::from_parts(47_111_000, 0) - .saturating_add(Weight::from_parts(0, 5206)) + // Measured: `103` + // Estimated: `6196` + // Minimum execution time: 41_036_000 picoseconds. + Weight::from_parts(41_265_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,11 +111,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1062` - // Estimated: `2603` - // Minimum execution time: 41_093 nanoseconds. - Weight::from_parts(41_472_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 35_925_000 picoseconds. + Weight::from_parts(36_511_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,11 +126,11 @@ impl pallet_balances::WeightInfo for WeightInfo { } fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1058` - // Estimated: `2603` - // Minimum execution time: 22_961 nanoseconds. - Weight::from_parts(23_413_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 16_377_000 picoseconds. + Weight::from_parts(16_722_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_collator_selection.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_collator_selection.rs index c7b4bcfa771..e86fa5544d0 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_collator_selection.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -55,12 +55,12 @@ impl pallet_collator_selection::WeightInfo for WeightIn fn set_invulnerables(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178 + b * (78 ±0)` - // Estimated: `178 + b * (2554 ±0)` - // Minimum execution time: 14_182 nanoseconds. - Weight::from_parts(16_174_028, 0) - .saturating_add(Weight::from_parts(0, 178)) - // Standard Error: 3_951 - .saturating_add(Weight::from_parts(2_446_152, 0).saturating_mul(b.into())) + // Estimated: `1168 + b * (2554 ±0)` + // Minimum execution time: 15_372_000 picoseconds. + Weight::from_parts(16_916_596, 0) + .saturating_add(Weight::from_parts(0, 1168)) + // Standard Error: 3_537 + .saturating_add(Weight::from_parts(2_583_561, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 2554).saturating_mul(b.into())) @@ -71,8 +71,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_843 nanoseconds. - Weight::from_parts(7_086_000, 0) + // Minimum execution time: 7_637_000 picoseconds. + Weight::from_parts(7_821_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,8 +82,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_075 nanoseconds. - Weight::from_parts(7_294_000, 0) + // Minimum execution time: 7_838_000 picoseconds. + Weight::from_parts(8_092_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,13 +102,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 999]`. fn register_as_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1171 + c * (48 ±0)` - // Estimated: `56784 + c * (49 ±0)` - // Minimum execution time: 34_101 nanoseconds. - Weight::from_parts(27_254_778, 0) - .saturating_add(Weight::from_parts(0, 56784)) - // Standard Error: 1_210 - .saturating_add(Weight::from_parts(105_038, 0).saturating_mul(c.into())) + // Measured: `1108 + c * (48 ±0)` + // Estimated: `61671 + c * (49 ±0)` + // Minimum execution time: 37_630_000 picoseconds. + Weight::from_parts(30_551_625, 0) + .saturating_add(Weight::from_parts(0, 61671)) + // Standard Error: 1_282 + .saturating_add(Weight::from_parts(112_510, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 49).saturating_mul(c.into())) @@ -120,13 +120,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[6, 1000]`. fn leave_intent(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `536 + c * (48 ±0)` - // Estimated: `48497` - // Minimum execution time: 26_156 nanoseconds. - Weight::from_parts(16_543_802, 0) - .saturating_add(Weight::from_parts(0, 48497)) - // Standard Error: 1_209 - .saturating_add(Weight::from_parts(102_889, 0).saturating_mul(c.into())) + // Measured: `452 + c * (48 ±0)` + // Estimated: `49487` + // Minimum execution time: 29_525_000 picoseconds. + Weight::from_parts(19_433_082, 0) + .saturating_add(Weight::from_parts(0, 49487)) + // Standard Error: 1_290 + .saturating_add(Weight::from_parts(108_444, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -138,11 +138,11 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { // Proof Size summary in bytes: - // Measured: `135` - // Estimated: `5749` - // Minimum execution time: 24_859 nanoseconds. - Weight::from_parts(25_423_000, 0) - .saturating_add(Weight::from_parts(0, 5749)) + // Measured: `103` + // Estimated: `7729` + // Minimum execution time: 29_428_000 picoseconds. + Weight::from_parts(29_752_000, 0) + .saturating_add(Weight::from_parts(0, 7729)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -160,18 +160,18 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 1000]`. fn new_session(r: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `22784 + r * (148 ±0) + c * (97 ±0)` - // Estimated: `52737 + c * (2519 ±0) + r * (2602 ±0)` - // Minimum execution time: 16_296 nanoseconds. - Weight::from_parts(16_532_000, 0) - .saturating_add(Weight::from_parts(0, 52737)) - // Standard Error: 758_486 - .saturating_add(Weight::from_parts(27_694_526, 0).saturating_mul(c.into())) + // Measured: `22721 + r * (116 ±0) + c * (97 ±0)` + // Estimated: `56697 + r * (2602 ±0) + c * (2520 ±0)` + // Minimum execution time: 17_105_000 picoseconds. + Weight::from_parts(17_304_000, 0) + .saturating_add(Weight::from_parts(0, 56697)) + // Standard Error: 839_957 + .saturating_add(Weight::from_parts(30_183_103, 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, 2602).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_multisig.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_multisig.rs index a5a5fb3b121..2a93d9e41c2 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_multisig.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -52,11 +52,11 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_557 nanoseconds. - Weight::from_parts(12_087_731, 0) + // Minimum execution time: 12_445_000 picoseconds. + Weight::from_parts(12_887_726, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1 - .saturating_add(Weight::from_parts(493, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(608, 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) @@ -64,15 +64,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 35_027 nanoseconds. - Weight::from_parts(28_254_579, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 541 - .saturating_add(Weight::from_parts(73_609, 0).saturating_mul(s.into())) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_530, 0).saturating_mul(z.into())) + // Measured: `262 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 38_178_000 picoseconds. + Weight::from_parts(31_903_342, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 743 + .saturating_add(Weight::from_parts(67_484, 0).saturating_mul(s.into())) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_353, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,15 +82,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 25_892 nanoseconds. - Weight::from_parts(19_974_491, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 382 - .saturating_add(Weight::from_parts(67_041, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_516, 0).saturating_mul(z.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 28_095_000 picoseconds. + Weight::from_parts(22_610_540, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 571 + .saturating_add(Weight::from_parts(59_325, 0).saturating_mul(s.into())) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_310, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,15 +102,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `448 + s * (33 ±0)` - // Estimated: `8424` - // Minimum execution time: 39_799 nanoseconds. - Weight::from_parts(31_172_141, 0) - .saturating_add(Weight::from_parts(0, 8424)) - // Standard Error: 523 - .saturating_add(Weight::from_parts(91_287, 0).saturating_mul(s.into())) + // Measured: `385 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 43_571_000 picoseconds. + Weight::from_parts(35_747_616, 0) + .saturating_add(Weight::from_parts(0, 10404)) + // Standard Error: 555 + .saturating_add(Weight::from_parts(86_297, 0).saturating_mul(s.into())) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_557, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_333, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -119,13 +119,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `318 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 24_614 nanoseconds. - Weight::from_parts(26_554_159, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 754 - .saturating_add(Weight::from_parts(81_278, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 29_122_000 picoseconds. + Weight::from_parts(30_681_183, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 787 + .saturating_add(Weight::from_parts(69_464, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -134,13 +134,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 17_141 nanoseconds. - Weight::from_parts(18_191_699, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 546 - .saturating_add(Weight::from_parts(74_486, 0).saturating_mul(s.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 19_219_000 picoseconds. + Weight::from_parts(20_598_069, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 572 + .saturating_add(Weight::from_parts(66_940, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,13 +149,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `517 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 25_869 nanoseconds. - Weight::from_parts(28_059_249, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 677 - .saturating_add(Weight::from_parts(80_187, 0).saturating_mul(s.into())) + // Measured: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 29_859_000 picoseconds. + Weight::from_parts(31_610_947, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 739 + .saturating_add(Weight::from_parts(70_349, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_proxy.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_proxy.rs index b160090e259..1471920ba2f 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_proxy.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_proxy.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_proxy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -52,13 +52,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 14_405 nanoseconds. - Weight::from_parts(15_511_983, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 2_104 - .saturating_add(Weight::from_parts(19_450, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 17_484_000 picoseconds. + Weight::from_parts(17_998_669, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_091 + .saturating_add(Weight::from_parts(33_441, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -71,15 +71,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `550 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 31_545 nanoseconds. - Weight::from_parts(31_928_375, 0) - .saturating_add(Weight::from_parts(0, 11027)) - // Standard Error: 2_022 - .saturating_add(Weight::from_parts(114_479, 0).saturating_mul(a.into())) - // Standard Error: 2_089 - .saturating_add(Weight::from_parts(34_696, 0).saturating_mul(p.into())) + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 35_828_000 picoseconds. + Weight::from_parts(36_241_110, 0) + .saturating_add(Weight::from_parts(0, 13997)) + // Standard Error: 2_219 + .saturating_add(Weight::from_parts(156_309, 0).saturating_mul(a.into())) + // Standard Error: 2_292 + .saturating_add(Weight::from_parts(32_167, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -91,15 +91,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 20_215 nanoseconds. - Weight::from_parts(20_970_496, 0) - .saturating_add(Weight::from_parts(0, 7311)) - // Standard Error: 1_277 - .saturating_add(Weight::from_parts(111_015, 0).saturating_mul(a.into())) - // Standard Error: 1_320 - .saturating_add(Weight::from_parts(9_988, 0).saturating_mul(p.into())) + // Measured: `369 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_512_000 picoseconds. + Weight::from_parts(23_254_777, 0) + .saturating_add(Weight::from_parts(0, 9291)) + // Standard Error: 1_318 + .saturating_add(Weight::from_parts(148_302, 0).saturating_mul(a.into())) + // Standard Error: 1_362 + .saturating_add(Weight::from_parts(13_945, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,15 +111,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 20_153 nanoseconds. - Weight::from_parts(21_046_064, 0) - .saturating_add(Weight::from_parts(0, 7311)) - // Standard Error: 1_342 - .saturating_add(Weight::from_parts(108_638, 0).saturating_mul(a.into())) - // Standard Error: 1_386 - .saturating_add(Weight::from_parts(10_617, 0).saturating_mul(p.into())) + // Measured: `369 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_528_000 picoseconds. + Weight::from_parts(23_510_728, 0) + .saturating_add(Weight::from_parts(0, 9291)) + // Standard Error: 1_393 + .saturating_add(Weight::from_parts(143_817, 0).saturating_mul(a.into())) + // Standard Error: 1_439 + .saturating_add(Weight::from_parts(9_334, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -133,15 +133,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 27_692 nanoseconds. - Weight::from_parts(28_900_223, 0) - .saturating_add(Weight::from_parts(0, 11027)) - // Standard Error: 1_751 - .saturating_add(Weight::from_parts(100_648, 0).saturating_mul(a.into())) - // Standard Error: 1_809 - .saturating_add(Weight::from_parts(35_769, 0).saturating_mul(p.into())) + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 31_233_000 picoseconds. + Weight::from_parts(32_142_917, 0) + .saturating_add(Weight::from_parts(0, 13997)) + // Standard Error: 1_888 + .saturating_add(Weight::from_parts(142_949, 0).saturating_mul(a.into())) + // Standard Error: 1_951 + .saturating_add(Weight::from_parts(46_737, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -150,13 +150,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_726 nanoseconds. - Weight::from_parts(21_849_126, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_307 - .saturating_add(Weight::from_parts(43_349, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_085_000 picoseconds. + Weight::from_parts(25_032_056, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_758 + .saturating_add(Weight::from_parts(52_203, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,13 +165,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_681 nanoseconds. - Weight::from_parts(21_733_251, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_555 - .saturating_add(Weight::from_parts(59_461, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_678_000 picoseconds. + Weight::from_parts(24_981_101, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_874 + .saturating_add(Weight::from_parts(73_774, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -180,13 +180,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 16_966 nanoseconds. - Weight::from_parts(17_682_078, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_110 - .saturating_add(Weight::from_parts(28_786, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 19_119_000 picoseconds. + Weight::from_parts(19_982_142, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_174 + .saturating_add(Weight::from_parts(26_182, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -196,12 +196,12 @@ impl pallet_proxy::WeightInfo for WeightInfo { fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `139` - // Estimated: `3716` - // Minimum execution time: 22_237 nanoseconds. - Weight::from_parts(23_324_695, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_481 - .saturating_add(Weight::from_parts(9_284, 0).saturating_mul(p.into())) + // Estimated: `4706` + // Minimum execution time: 26_077_000 picoseconds. + Weight::from_parts(27_130_205, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_539 + .saturating_add(Weight::from_parts(1_625, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -210,13 +210,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `196 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 18_041 nanoseconds. - Weight::from_parts(18_668_925, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_209 - .saturating_add(Weight::from_parts(29_794, 0).saturating_mul(p.into())) + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 20_178_000 picoseconds. + Weight::from_parts(21_090_914, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_488 + .saturating_add(Weight::from_parts(36_285, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_session.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_session.rs index 9ed257e1e80..87458dcd84b 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_session.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -54,10 +54,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `270` - // Estimated: `5490` - // Minimum execution time: 15_561 nanoseconds. - Weight::from_parts(15_843_000, 0) - .saturating_add(Weight::from_parts(0, 5490)) + // Estimated: `7470` + // Minimum execution time: 17_008_000 picoseconds. + Weight::from_parts(17_288_000, 0) + .saturating_add(Weight::from_parts(0, 7470)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `242` - // Estimated: `2959` - // Minimum execution time: 11_757 nanoseconds. - Weight::from_parts(12_093_000, 0) - .saturating_add(Weight::from_parts(0, 2959)) + // Estimated: `3949` + // Minimum execution time: 13_427_000 picoseconds. + Weight::from_parts(13_609_000, 0) + .saturating_add(Weight::from_parts(0, 3949)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_timestamp.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_timestamp.rs index b076a1b4d1e..75d47ae1fd6 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_timestamp.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -54,10 +54,10 @@ impl pallet_timestamp::WeightInfo for WeightInfo { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `86` - // Estimated: `1006` - // Minimum execution time: 8_399 nanoseconds. - Weight::from_parts(8_649_000, 0) - .saturating_add(Weight::from_parts(0, 1006)) + // Estimated: `2986` + // Minimum execution time: 9_174_000 picoseconds. + Weight::from_parts(9_644_000, 0) + .saturating_add(Weight::from_parts(0, 2986)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_timestamp::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `57` // Estimated: `0` - // Minimum execution time: 3_277 nanoseconds. - Weight::from_parts(3_349_000, 0) + // Minimum execution time: 3_121_000 picoseconds. + Weight::from_parts(3_205_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_uniques.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_uniques.rs index d69f456dc24..1c33a12ab3d 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_uniques.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_uniques.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_uniques` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -53,11 +53,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `2653` - // Minimum execution time: 23_738 nanoseconds. - Weight::from_parts(24_550_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `145` + // Estimated: `3643` + // Minimum execution time: 26_653_000 picoseconds. + Weight::from_parts(27_024_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_uniques::WeightInfo for WeightInfo { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2653` - // Minimum execution time: 13_165 nanoseconds. - Weight::from_parts(13_515_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Estimated: `3643` + // Minimum execution time: 15_168_000 picoseconds. + Weight::from_parts(15_535_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -79,14 +79,14 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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 Attribute (r:0 w:1000) - /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, 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 InstanceMetadataOf (r:0 w:1000) - /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, 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) @@ -96,24 +96,28 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `289 + n * (108 ±0) + m * (56 ±0) + a * (107 ±0)` - // Estimated: `5250 + n * (2597 ±0)` - // Minimum execution time: 2_258_129 nanoseconds. - Weight::from_parts(2_289_592_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) - // Standard Error: 26_214 - .saturating_add(Weight::from_parts(8_416_144, 0).saturating_mul(n.into())) - // Standard Error: 26_214 - .saturating_add(Weight::from_parts(256_638, 0).saturating_mul(m.into())) - // Standard Error: 26_214 - .saturating_add(Weight::from_parts(274_803, 0).saturating_mul(a.into())) + // Measured: `257 + n * (76 ±0) + m * (56 ±0) + a * (107 ±0)` + // Estimated: `9210 + n * (2597 ±0) + m * (2662 ±0) + a * (2647 ±0)` + // Minimum execution time: 2_365_108_000 picoseconds. + Weight::from_parts(2_380_000_000, 0) + .saturating_add(Weight::from_parts(0, 9210)) + // Standard Error: 24_588 + .saturating_add(Weight::from_parts(6_339_196, 0).saturating_mul(n.into())) + // Standard Error: 24_588 + .saturating_add(Weight::from_parts(265_876, 0).saturating_mul(m.into())) + // Standard Error: 24_588 + .saturating_add(Weight::from_parts(316_327, 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, 2597).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2662).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 2647).saturating_mul(a.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -125,11 +129,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `7749` - // Minimum execution time: 28_974 nanoseconds. - Weight::from_parts(29_398_000, 0) - .saturating_add(Weight::from_parts(0, 7749)) + // Measured: `282` + // Estimated: `10719` + // Minimum execution time: 32_891_000 picoseconds. + Weight::from_parts(33_169_000, 0) + .saturating_add(Weight::from_parts(0, 10719)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -143,11 +147,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 30_070 nanoseconds. - Weight::from_parts(30_454_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 33_895_000 picoseconds. + Weight::from_parts(34_205_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -161,11 +165,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 24_287 nanoseconds. - Weight::from_parts(24_509_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 27_841_000 picoseconds. + Weight::from_parts(28_213_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -176,13 +180,13 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `770 + i * (108 ±0)` - // Estimated: `2653 + i * (2597 ±0)` - // Minimum execution time: 14_231 nanoseconds. - Weight::from_parts(14_454_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) - // Standard Error: 13_135 - .saturating_add(Weight::from_parts(12_152_067, 0).saturating_mul(i.into())) + // Measured: `738 + i * (76 ±0)` + // Estimated: `4633 + i * (2597 ±0)` + // Minimum execution time: 16_054_000 picoseconds. + Weight::from_parts(16_331_000, 0) + .saturating_add(Weight::from_parts(0, 4633)) + // Standard Error: 12_166 + .saturating_add(Weight::from_parts(13_413_428, 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)) @@ -195,11 +199,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 17_977 nanoseconds. - Weight::from_parts(18_415_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 19_419_000 picoseconds. + Weight::from_parts(19_724_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,11 +213,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 17_421 nanoseconds. - Weight::from_parts(17_830_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 20_053_000 picoseconds. + Weight::from_parts(23_080_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -221,11 +225,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 13_199 nanoseconds. - Weight::from_parts(13_615_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 15_569_000 picoseconds. + Weight::from_parts(16_658_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -233,11 +237,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 13_263 nanoseconds. - Weight::from_parts(13_575_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 15_350_000 picoseconds. + Weight::from_parts(15_771_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -249,11 +253,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `388` - // Estimated: `5180` - // Minimum execution time: 20_850 nanoseconds. - Weight::from_parts(21_223_000, 0) - .saturating_add(Weight::from_parts(0, 5180)) + // Measured: `356` + // Estimated: `7160` + // Minimum execution time: 23_564_000 picoseconds. + Weight::from_parts(24_005_000, 0) + .saturating_add(Weight::from_parts(0, 7160)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -261,11 +265,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 14_218 nanoseconds. - Weight::from_parts(14_680_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 16_165_000 picoseconds. + Weight::from_parts(16_482_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -275,11 +279,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `2653` - // Minimum execution time: 16_581 nanoseconds. - Weight::from_parts(16_856_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 18_377_000 picoseconds. + Weight::from_parts(19_060_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -291,11 +295,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `623` - // Estimated: `7962` - // Minimum execution time: 34_610 nanoseconds. - Weight::from_parts(34_994_000, 0) - .saturating_add(Weight::from_parts(0, 7962)) + // Measured: `559` + // Estimated: `10932` + // Minimum execution time: 39_403_000 picoseconds. + Weight::from_parts(39_925_000, 0) + .saturating_add(Weight::from_parts(0, 10932)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -307,11 +311,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `851` - // Estimated: `7962` - // Minimum execution time: 34_244 nanoseconds. - Weight::from_parts(34_542_000, 0) - .saturating_add(Weight::from_parts(0, 7962)) + // Measured: `756` + // Estimated: `10932` + // Minimum execution time: 36_786_000 picoseconds. + Weight::from_parts(37_558_000, 0) + .saturating_add(Weight::from_parts(0, 10932)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -321,11 +325,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `380` - // Estimated: `5315` - // Minimum execution time: 26_652 nanoseconds. - Weight::from_parts(27_013_000, 0) - .saturating_add(Weight::from_parts(0, 5315)) + // Measured: `348` + // Estimated: `7295` + // Minimum execution time: 30_327_000 picoseconds. + Weight::from_parts(30_769_000, 0) + .saturating_add(Weight::from_parts(0, 7295)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -335,11 +339,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `623` - // Estimated: `5315` - // Minimum execution time: 27_427 nanoseconds. - Weight::from_parts(27_985_000, 0) - .saturating_add(Weight::from_parts(0, 5315)) + // Measured: `559` + // Estimated: `7295` + // Minimum execution time: 29_756_000 picoseconds. + Weight::from_parts(31_077_000, 0) + .saturating_add(Weight::from_parts(0, 7295)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -349,11 +353,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `5295` - // Minimum execution time: 26_557 nanoseconds. - Weight::from_parts(26_973_000, 0) - .saturating_add(Weight::from_parts(0, 5295)) + // Measured: `282` + // Estimated: `7275` + // Minimum execution time: 29_811_000 picoseconds. + Weight::from_parts(30_220_000, 0) + .saturating_add(Weight::from_parts(0, 7275)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -363,11 +367,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `537` - // Estimated: `5295` - // Minimum execution time: 25_091 nanoseconds. - Weight::from_parts(25_510_000, 0) - .saturating_add(Weight::from_parts(0, 5295)) + // Measured: `473` + // Estimated: `7275` + // Minimum execution time: 27_708_000 picoseconds. + Weight::from_parts(28_309_000, 0) + .saturating_add(Weight::from_parts(0, 7275)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -377,11 +381,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 19_129 nanoseconds. - Weight::from_parts(19_831_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 21_525_000 picoseconds. + Weight::from_parts(21_784_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -391,11 +395,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `525` - // Estimated: `5250` - // Minimum execution time: 19_393 nanoseconds. - Weight::from_parts(19_569_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `461` + // Estimated: `7230` + // Minimum execution time: 21_605_000 picoseconds. + Weight::from_parts(21_805_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -404,10 +408,10 @@ impl pallet_uniques::WeightInfo for WeightInfo { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2527` - // Minimum execution time: 14_863 nanoseconds. - Weight::from_parts(15_066_000, 0) - .saturating_add(Weight::from_parts(0, 2527)) + // Estimated: `3517` + // Minimum execution time: 17_046_000 picoseconds. + Weight::from_parts(17_387_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -417,11 +421,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `5152` - // Minimum execution time: 16_144 nanoseconds. - Weight::from_parts(16_510_000, 0) - .saturating_add(Weight::from_parts(0, 5152)) + // Measured: `282` + // Estimated: `7132` + // Minimum execution time: 18_453_000 picoseconds. + Weight::from_parts(18_716_000, 0) + .saturating_add(Weight::from_parts(0, 7132)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -431,11 +435,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `291` - // Estimated: `2597` - // Minimum execution time: 15_884 nanoseconds. - Weight::from_parts(16_215_000, 0) - .saturating_add(Weight::from_parts(0, 2597)) + // Measured: `259` + // Estimated: `3587` + // Minimum execution time: 17_965_000 picoseconds. + Weight::from_parts(18_347_000, 0) + .saturating_add(Weight::from_parts(0, 3587)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -449,11 +453,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `636` - // Estimated: `7814` - // Minimum execution time: 34_190 nanoseconds. - Weight::from_parts(34_497_000, 0) - .saturating_add(Weight::from_parts(0, 7814)) + // Measured: `540` + // Estimated: `10784` + // Minimum execution time: 38_974_000 picoseconds. + Weight::from_parts(39_420_000, 0) + .saturating_add(Weight::from_parts(0, 10784)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_utility.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_utility.rs index af28e0cec58..d14fdba6fad 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_utility.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -52,18 +52,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_005 nanoseconds. - Weight::from_parts(18_139_015, 0) + // Minimum execution time: 7_357_000 picoseconds. + Weight::from_parts(16_071_177, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_178 - .saturating_add(Weight::from_parts(3_979_226, 0).saturating_mul(c.into())) + // Standard Error: 3_492 + .saturating_add(Weight::from_parts(5_041_311, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_441 nanoseconds. - Weight::from_parts(4_622_000, 0) + // Minimum execution time: 5_903_000 picoseconds. + Weight::from_parts(6_075_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +71,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_910 nanoseconds. - Weight::from_parts(18_908_357, 0) + // Minimum execution time: 7_616_000 picoseconds. + Weight::from_parts(17_676_240, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_920 - .saturating_add(Weight::from_parts(4_169_103, 0).saturating_mul(c.into())) + // Standard Error: 2_274 + .saturating_add(Weight::from_parts(5_358_895, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_957 nanoseconds. - Weight::from_parts(8_145_000, 0) + // Minimum execution time: 10_072_000 picoseconds. + Weight::from_parts(10_405_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +90,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_925 nanoseconds. - Weight::from_parts(15_056_349, 0) + // Minimum execution time: 7_207_000 picoseconds. + Weight::from_parts(18_974_639, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_987 - .saturating_add(Weight::from_parts(3_981_287, 0).saturating_mul(c.into())) + // Standard Error: 2_301 + .saturating_add(Weight::from_parts(5_025_161, 0).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/assets/statemint/src/weights/pallet_xcm.rs b/parachains/runtimes/assets/statemint/src/weights/pallet_xcm.rs index 70782f0e2c7..26e19764b8a 100644 --- a/parachains/runtimes/assets/statemint/src/weights/pallet_xcm.rs +++ b/parachains/runtimes/assets/statemint/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 @@ -60,10 +60,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn send() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `4645` - // Minimum execution time: 24_132 nanoseconds. - Weight::from_parts(24_554_000, 0) - .saturating_add(Weight::from_parts(0, 4645)) + // Estimated: `9595` + // Minimum execution time: 27_505_000 picoseconds. + Weight::from_parts(27_841_000, 0) + .saturating_add(Weight::from_parts(0, 9595)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,10 +72,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `499` - // Minimum execution time: 22_350 nanoseconds. - Weight::from_parts(22_760_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 27_156_000 picoseconds. + Weight::from_parts(27_641_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: ParachainInfo ParachainId (r:1 w:0) @@ -83,10 +83,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `499` - // Minimum execution time: 17_723 nanoseconds. - Weight::from_parts(17_951_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 20_954_000 picoseconds. + Weight::from_parts(21_381_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Benchmark Override (r:0 w:0) @@ -95,7 +95,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -105,8 +105,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_641 nanoseconds. - Weight::from_parts(8_925_000, 0) + // Minimum execution time: 10_560_000 picoseconds. + Weight::from_parts(10_752_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -116,8 +116,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_427 nanoseconds. - Weight::from_parts(2_598_000, 0) + // Minimum execution time: 3_451_000 picoseconds. + Weight::from_parts(3_580_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -140,10 +140,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `7729` - // Minimum execution time: 28_650 nanoseconds. - Weight::from_parts(29_035_000, 0) - .saturating_add(Weight::from_parts(0, 7729)) + // Estimated: `14659` + // Minimum execution time: 33_607_000 picoseconds. + Weight::from_parts(33_917_000, 0) + .saturating_add(Weight::from_parts(0, 14659)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -164,10 +164,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `220` - // Estimated: `8470` - // Minimum execution time: 30_797 nanoseconds. - Weight::from_parts(31_491_000, 0) - .saturating_add(Weight::from_parts(0, 8470)) + // Estimated: `14410` + // Minimum execution time: 35_300_000 picoseconds. + Weight::from_parts(35_783_000, 0) + .saturating_add(Weight::from_parts(0, 14410)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -176,10 +176,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `95` - // Estimated: `9995` - // Minimum execution time: 13_639 nanoseconds. - Weight::from_parts(13_980_000, 0) - .saturating_add(Weight::from_parts(0, 9995)) + // Estimated: `10985` + // Minimum execution time: 15_664_000 picoseconds. + Weight::from_parts(15_908_000, 0) + .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -188,10 +188,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `99` - // Estimated: `9999` - // Minimum execution time: 13_954 nanoseconds. - Weight::from_parts(14_276_000, 0) - .saturating_add(Weight::from_parts(0, 9999)) + // Estimated: `10989` + // Minimum execution time: 15_376_000 picoseconds. + Weight::from_parts(15_780_000, 0) + .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -200,10 +200,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `12481` - // Minimum execution time: 15_217 nanoseconds. - Weight::from_parts(15_422_000, 0) - .saturating_add(Weight::from_parts(0, 12481)) + // Estimated: `13471` + // Minimum execution time: 15_898_000 picoseconds. + Weight::from_parts(16_159_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) @@ -221,10 +221,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10041` - // Minimum execution time: 27_362 nanoseconds. - Weight::from_parts(28_034_000, 0) - .saturating_add(Weight::from_parts(0, 10041)) + // Estimated: `15981` + // Minimum execution time: 31_267_000 picoseconds. + Weight::from_parts(31_635_000, 0) + .saturating_add(Weight::from_parts(0, 15981)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -233,10 +233,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `7561` - // Minimum execution time: 7_768 nanoseconds. - Weight::from_parts(7_890_000, 0) - .saturating_add(Weight::from_parts(0, 7561)) + // Estimated: `8551` + // Minimum execution time: 8_659_000 picoseconds. + Weight::from_parts(8_983_000, 0) + .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) @@ -244,10 +244,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10006` - // Minimum execution time: 15_165 nanoseconds. - Weight::from_parts(15_430_000, 0) - .saturating_add(Weight::from_parts(0, 10006)) + // Estimated: `10996` + // Minimum execution time: 16_025_000 picoseconds. + Weight::from_parts(16_296_000, 0) + .saturating_add(Weight::from_parts(0, 10996)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -266,10 +266,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `112` - // Estimated: `15027` - // Minimum execution time: 35_310 nanoseconds. - Weight::from_parts(35_698_000, 0) - .saturating_add(Weight::from_parts(0, 15027)) + // Estimated: `20967` + // Minimum execution time: 37_654_000 picoseconds. + Weight::from_parts(38_144_000, 0) + .saturating_add(Weight::from_parts(0, 20967)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 43de2f7f064..147a348b19d 100644 --- a/parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,27 +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-03-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, 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` +//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./templates/xcm-bench-template.hbs +// --chain=statemint-dev // --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_xcm_benchmarks::fungible -// --chain=statemint-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/assets/statemint/src/weights/xcm/ +// --output=./parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 22_450_000 picoseconds. - Weight::from_parts(22_821_000, 3593) + // Minimum execution time: 23_489_000 picoseconds. + Weight::from_parts(23_993_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 32_079_000 picoseconds. - Weight::from_parts(32_591_000, 6196) + // Minimum execution time: 32_933_000 picoseconds. + Weight::from_parts(33_445_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -89,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `139` // Estimated: `17785` - // Minimum execution time: 53_770_000 picoseconds. - Weight::from_parts(54_393_000, 17785) + // Minimum execution time: 56_285_000 picoseconds. + Weight::from_parts(56_858_000, 17785) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -98,8 +97,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_485_000 picoseconds. - Weight::from_parts(4_650_000, 0) + // Minimum execution time: 4_900_000 picoseconds. + Weight::from_parts(4_996_000, 0) } // Storage: System Account (r:1 w:1) // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -107,8 +106,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 24_725_000 picoseconds. - Weight::from_parts(25_120_000, 3593) + // Minimum execution time: 26_047_000 picoseconds. + Weight::from_parts(26_408_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -130,8 +129,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `14677` - // Minimum execution time: 47_989_000 picoseconds. - Weight::from_parts(48_573_000, 14677) + // Minimum execution time: 48_997_000 picoseconds. + Weight::from_parts(49_605_000, 14677) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -151,8 +150,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `11084` - // Minimum execution time: 34_367_000 picoseconds. - Weight::from_parts(34_995_000, 11084) + // Minimum execution time: 31_114_000 picoseconds. + Weight::from_parts(31_825_000, 11084) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index dbae6ffe404..ca264e8fa17 100644 --- a/parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,27 +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-03-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, 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` +//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("statemint-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./templates/xcm-bench-template.hbs +// --chain=statemint-dev // --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_xcm_benchmarks::generic -// --chain=statemint-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/assets/statemint/src/weights/xcm/ +// --output=./parachains/runtimes/assets/statemint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -65,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `11084` - // Minimum execution time: 365_653_000 picoseconds. - Weight::from_parts(368_340_000, 11084) + // Minimum execution time: 452_120_000 picoseconds. + Weight::from_parts(453_246_000, 11084) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -74,8 +73,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_920_000 picoseconds. - Weight::from_parts(4_150_000, 0) + // Minimum execution time: 4_323_000 picoseconds. + Weight::from_parts(4_409_000, 0) } // Storage: PolkadotXcm Queries (r:1 w:0) // Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) @@ -83,58 +82,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 10_988_000 picoseconds. - Weight::from_parts(11_207_000, 3497) + // Minimum execution time: 12_046_000 picoseconds. + Weight::from_parts(12_316_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: 13_509_000 picoseconds. - Weight::from_parts(13_775_000, 0) + // Minimum execution time: 14_603_000 picoseconds. + Weight::from_parts(14_929_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_497_000 picoseconds. - Weight::from_parts(7_580_000, 0) + // Minimum execution time: 4_461_000 picoseconds. + Weight::from_parts(4_655_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_971_000 picoseconds. - Weight::from_parts(3_086_000, 0) + // Minimum execution time: 3_400_000 picoseconds. + Weight::from_parts(3_487_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_937_000 picoseconds. - Weight::from_parts(3_081_000, 0) + // Minimum execution time: 3_337_000 picoseconds. + Weight::from_parts(3_403_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_960_000 picoseconds. - Weight::from_parts(3_073_000, 0) + // Minimum execution time: 3_259_000 picoseconds. + Weight::from_parts(3_350_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_879_000 picoseconds. - Weight::from_parts(4_040_000, 0) + // Minimum execution time: 4_292_000 picoseconds. + Weight::from_parts(4_471_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_965_000 picoseconds. - Weight::from_parts(3_062_000, 0) + // Minimum execution time: 3_281_000 picoseconds. + Weight::from_parts(3_329_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -152,8 +151,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `11084` - // Minimum execution time: 24_225_000 picoseconds. - Weight::from_parts(24_520_000, 11084) + // Minimum execution time: 26_054_000 picoseconds. + Weight::from_parts(26_386_000, 11084) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -163,8 +162,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 14_899_000 picoseconds. - Weight::from_parts(15_205_000, 3555) + // Minimum execution time: 16_413_000 picoseconds. + Weight::from_parts(16_590_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -172,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_942_000 picoseconds. - Weight::from_parts(3_026_000, 0) + // Minimum execution time: 3_314_000 picoseconds. + Weight::from_parts(3_410_000, 0) } // Storage: PolkadotXcm VersionNotifyTargets (r:1 w:1) // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) @@ -191,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `13098` - // Minimum execution time: 26_636_000 picoseconds. - Weight::from_parts(27_027_000, 13098) + // Minimum execution time: 28_232_000 picoseconds. + Weight::from_parts(28_661_000, 13098) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -202,8 +201,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_074_000 picoseconds. - Weight::from_parts(5_223_000, 0) + // Minimum execution time: 5_517_000 picoseconds. + Weight::from_parts(5_596_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: ParachainInfo ParachainId (r:1 w:0) @@ -222,8 +221,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `11084` - // Minimum execution time: 414_125_000 picoseconds. - Weight::from_parts(456_357_000, 11084) + // Minimum execution time: 502_759_000 picoseconds. + Weight::from_parts(504_262_000, 11084) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -231,36 +230,36 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 134_528_000 picoseconds. - Weight::from_parts(135_936_000, 0) + // Minimum execution time: 157_990_000 picoseconds. + Weight::from_parts(158_216_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_812_000 picoseconds. - Weight::from_parts(12_945_000, 0) + // Minimum execution time: 15_005_000 picoseconds. + Weight::from_parts(15_203_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_011_000 picoseconds. - Weight::from_parts(3_129_000, 0) + // Minimum execution time: 3_475_000 picoseconds. + Weight::from_parts(3_522_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_769_000 picoseconds. - Weight::from_parts(4_847_000, 0) + // Minimum execution time: 3_343_000 picoseconds. + Weight::from_parts(3_417_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_169_000 picoseconds. - Weight::from_parts(3_350_000, 0) + // Minimum execution time: 3_519_000 picoseconds. + Weight::from_parts(3_625_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -278,8 +277,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `11084` - // Minimum execution time: 27_621_000 picoseconds. - Weight::from_parts(28_085_000, 11084) + // Minimum execution time: 29_760_000 picoseconds. + Weight::from_parts(30_340_000, 11084) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -287,8 +286,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_296_000 picoseconds. - Weight::from_parts(5_413_000, 0) + // Minimum execution time: 5_732_000 picoseconds. + Weight::from_parts(5_858_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -306,8 +305,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `11084` - // Minimum execution time: 24_309_000 picoseconds. - Weight::from_parts(24_673_000, 11084) + // Minimum execution time: 26_440_000 picoseconds. + Weight::from_parts(26_870_000, 11084) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -315,35 +314,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_928_000 picoseconds. - Weight::from_parts(3_066_000, 0) + // Minimum execution time: 3_334_000 picoseconds. + Weight::from_parts(3_408_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_904_000 picoseconds. - Weight::from_parts(2_988_000, 0) + // Minimum execution time: 3_263_000 picoseconds. + Weight::from_parts(3_380_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_906_000 picoseconds. - Weight::from_parts(2_989_000, 0) + // Minimum execution time: 3_338_000 picoseconds. + Weight::from_parts(3_388_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_950_000 picoseconds. - Weight::from_parts(3_047_000, 0) + // Minimum execution time: 3_286_000 picoseconds. + Weight::from_parts(3_384_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_150_000 picoseconds. - Weight::from_parts(3_243_000, 0) + // Minimum execution time: 3_494_000 picoseconds. + Weight::from_parts(3_563_000, 0) } } diff --git a/parachains/runtimes/assets/test-utils/src/test_cases.rs b/parachains/runtimes/assets/test-utils/src/test_cases.rs index 3614f03e7d9..079e6bd60ae 100644 --- a/parachains/runtimes/assets/test-utils/src/test_cases.rs +++ b/parachains/runtimes/assets/test-utils/src/test_cases.rs @@ -1131,17 +1131,17 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor BuyExecution { fees: buy_execution_fee.clone().into(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(40_000_000_000, 6000), + require_weight_at_most: Weight::from_parts(40_000_000_000, 8000), call: foreign_asset_create.into(), }, Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(20_000_000_000, 6000), + require_weight_at_most: Weight::from_parts(20_000_000_000, 8000), call: foreign_asset_set_metadata.into(), }, Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: Weight::from_parts(20_000_000_000, 6000), + require_weight_at_most: Weight::from_parts(20_000_000_000, 8000), call: foreign_asset_set_team.into(), }, ExpectTransactStatus(MaybeErrorCode::Success), @@ -1248,7 +1248,7 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor BuyExecution { fees: buy_execution_fee.clone().into(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::Xcm, - require_weight_at_most: Weight::from_parts(20_000_000_000, 6000), + require_weight_at_most: Weight::from_parts(20_000_000_000, 8000), call: foreign_asset_create.into(), }, ExpectTransactStatus(MaybeErrorCode::from(DispatchError::BadOrigin.encode())), diff --git a/parachains/runtimes/assets/westmint/src/weights/cumulus_pallet_xcmp_queue.rs b/parachains/runtimes/assets/westmint/src/weights/cumulus_pallet_xcmp_queue.rs index 9de1fa11fa8..b796e65485d 100644 --- a/parachains/runtimes/assets/westmint/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/parachains/runtimes/assets/westmint/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -52,10 +52,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_844 nanoseconds. - Weight::from_parts(5_119_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_380_000 picoseconds. + Weight::from_parts(5_626_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,10 +64,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_weight() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 5_017 nanoseconds. - Weight::from_parts(5_231_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_537_000 picoseconds. + Weight::from_parts(5_744_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/parachains/runtimes/assets/westmint/src/weights/frame_system.rs b/parachains/runtimes/assets/westmint/src/weights/frame_system.rs index 1dfc223ce3a..9f0e1e43f56 100644 --- a/parachains/runtimes/assets/westmint/src/weights/frame_system.rs +++ b/parachains/runtimes/assets/westmint/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -52,8 +52,8 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_737 nanoseconds. - Weight::from_parts(1_780_000, 0) + // Minimum execution time: 2_150_000 picoseconds. + Weight::from_parts(2_242_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 .saturating_add(Weight::from_parts(368, 0).saturating_mul(b.into())) @@ -63,11 +63,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_941 nanoseconds. - Weight::from_parts(6_990_000, 0) + // Minimum execution time: 7_810_000 picoseconds. + Weight::from_parts(7_949_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_716, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_408, 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) @@ -76,10 +76,10 @@ impl frame_system::WeightInfo for WeightInfo { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 3_697 nanoseconds. - Weight::from_parts(3_855_000, 0) - .saturating_add(Weight::from_parts(0, 495)) + // Estimated: `1485` + // Minimum execution time: 4_446_000 picoseconds. + Weight::from_parts(4_769_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,11 +90,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_957 nanoseconds. - Weight::from_parts(2_009_000, 0) + // Minimum execution time: 2_378_000 picoseconds. + Weight::from_parts(2_458_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_909 - .saturating_add(Weight::from_parts(577_980, 0).saturating_mul(i.into())) + // Standard Error: 1_873 + .saturating_add(Weight::from_parts(680_971, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -104,11 +104,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_921 nanoseconds. - Weight::from_parts(1_983_000, 0) + // Minimum execution time: 2_389_000 picoseconds. + Weight::from_parts(2_433_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 841 - .saturating_add(Weight::from_parts(443_784, 0).saturating_mul(i.into())) + // Standard Error: 765 + .saturating_add(Weight::from_parts(502_307, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -118,11 +118,12 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `84 + p * (69 ±0)` // Estimated: `75 + p * (70 ±0)` - // Minimum execution time: 3_576 nanoseconds. - Weight::from_parts(3_661_000, 0) + // Minimum execution time: 4_077_000 picoseconds. + Weight::from_parts(4_196_000, 0) .saturating_add(Weight::from_parts(0, 75)) - // Standard Error: 919 - .saturating_add(Weight::from_parts(955_752, 0).saturating_mul(p.into())) + // Standard Error: 920 + .saturating_add(Weight::from_parts(1_004_901, 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/parachains/runtimes/assets/westmint/src/weights/pallet_assets.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_assets.rs index 999dfe456b1..f08633cd2ba 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_assets.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_assets.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_assets` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -53,11 +53,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `141` - // Estimated: `5288` - // Minimum execution time: 22_825 nanoseconds. - Weight::from_parts(26_008_000, 0) - .saturating_add(Weight::from_parts(0, 5288)) + // Measured: `109` + // Estimated: `7268` + // Minimum execution time: 24_079_000 picoseconds. + Weight::from_parts(24_532_000, 0) + .saturating_add(Weight::from_parts(0, 7268)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -66,10 +66,10 @@ impl pallet_assets::WeightInfo for WeightInfo { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `6` - // Estimated: `2685` - // Minimum execution time: 10_898 nanoseconds. - Weight::from_parts(12_626_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Estimated: `3675` + // Minimum execution time: 11_873_000 picoseconds. + Weight::from_parts(12_062_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -77,11 +77,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn start_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 13_057 nanoseconds. - Weight::from_parts(13_932_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 14_393_000 picoseconds. + Weight::from_parts(14_598_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -94,13 +94,13 @@ impl pallet_assets::WeightInfo for WeightInfo { /// The range of component `c` is `[0, 1000]`. fn destroy_accounts(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0 + c * (240 ±0)` - // Estimated: `5262 + c * (5180 ±0)` - // Minimum execution time: 16_823 nanoseconds. - Weight::from_parts(31_002_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) - // Standard Error: 10_169 - .saturating_add(Weight::from_parts(13_922_578, 0).saturating_mul(c.into())) + // Measured: `0 + c * (208 ±0)` + // Estimated: `8232 + c * (5180 ±0)` + // Minimum execution time: 17_774_000 picoseconds. + Weight::from_parts(17_985_000, 0) + .saturating_add(Weight::from_parts(0, 8232)) + // Standard Error: 7_528 + .saturating_add(Weight::from_parts(12_132_350, 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)) @@ -114,13 +114,13 @@ impl pallet_assets::WeightInfo for WeightInfo { /// The range of component `a` is `[0, 1000]`. fn destroy_approvals(a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `446 + a * (86 ±0)` - // Estimated: `5308 + a * (2623 ±0)` - // Minimum execution time: 16_683 nanoseconds. - Weight::from_parts(16_754_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) - // Standard Error: 7_193 - .saturating_add(Weight::from_parts(13_722_963, 0).saturating_mul(a.into())) + // Measured: `414 + a * (86 ±0)` + // Estimated: `7288 + a * (2623 ±0)` + // Minimum execution time: 18_455_000 picoseconds. + Weight::from_parts(18_657_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) + // Standard Error: 4_725 + .saturating_add(Weight::from_parts(12_115_840, 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)) @@ -133,11 +133,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn finish_destroy() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 12_892 nanoseconds. - Weight::from_parts(13_218_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 14_340_000 picoseconds. + Weight::from_parts(14_614_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -147,11 +147,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5262` - // Minimum execution time: 23_073 nanoseconds. - Weight::from_parts(23_435_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `243` + // Estimated: `7242` + // Minimum execution time: 25_631_000 picoseconds. + Weight::from_parts(26_337_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -161,11 +161,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 29_411 nanoseconds. - Weight::from_parts(30_019_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 32_363_000 picoseconds. + Weight::from_parts(32_781_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -177,11 +177,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `10442` - // Minimum execution time: 38_929 nanoseconds. - Weight::from_parts(39_602_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 43_852_000 picoseconds. + Weight::from_parts(44_369_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -193,11 +193,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `383` - // Estimated: `10442` - // Minimum execution time: 34_910 nanoseconds. - Weight::from_parts(35_686_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 38_675_000 picoseconds. + Weight::from_parts(39_020_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -209,11 +209,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `10442` - // Minimum execution time: 38_959 nanoseconds. - Weight::from_parts(39_627_000, 0) - .saturating_add(Weight::from_parts(0, 10442)) + // Measured: `351` + // Estimated: `13412` + // Minimum execution time: 43_792_000 picoseconds. + Weight::from_parts(44_412_000, 0) + .saturating_add(Weight::from_parts(0, 13412)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -223,11 +223,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 16_367 nanoseconds. - Weight::from_parts(16_761_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 17_802_000 picoseconds. + Weight::from_parts(18_129_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -237,11 +237,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Account (max_values: None, max_size: Some(102), added: 2577, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `383` - // Estimated: `5262` - // Minimum execution time: 16_361 nanoseconds. - Weight::from_parts(18_506_000, 0) - .saturating_add(Weight::from_parts(0, 5262)) + // Measured: `351` + // Estimated: `7242` + // Minimum execution time: 17_711_000 picoseconds. + Weight::from_parts(18_136_000, 0) + .saturating_add(Weight::from_parts(0, 7242)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -249,11 +249,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn freeze_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 12_980 nanoseconds. - Weight::from_parts(14_272_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 13_776_000 picoseconds. + Weight::from_parts(14_134_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -261,11 +261,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn thaw_asset() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `2685` - // Minimum execution time: 12_510 nanoseconds. - Weight::from_parts(12_996_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `277` + // Estimated: `3675` + // Minimum execution time: 14_376_000 picoseconds. + Weight::from_parts(15_425_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -275,11 +275,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 13_958 nanoseconds. - Weight::from_parts(14_458_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 15_799_000 picoseconds. + Weight::from_parts(16_064_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -287,11 +287,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Asset (max_values: None, max_size: Some(210), added: 2685, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `2685` - // Minimum execution time: 12_820 nanoseconds. - Weight::from_parts(13_136_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 14_359_000 picoseconds. + Weight::from_parts(14_561_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -303,13 +303,13 @@ impl pallet_assets::WeightInfo for WeightInfo { /// The range of component `s` is `[0, 50]`. fn set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `275` - // Estimated: `5300` - // Minimum execution time: 22_433 nanoseconds. - Weight::from_parts(23_664_666, 0) - .saturating_add(Weight::from_parts(0, 5300)) - // Standard Error: 648 - .saturating_add(Weight::from_parts(2_428, 0).saturating_mul(s.into())) + // Measured: `243` + // Estimated: `7280` + // Minimum execution time: 25_337_000 picoseconds. + Weight::from_parts(26_452_841, 0) + .saturating_add(Weight::from_parts(0, 7280)) + // Standard Error: 845 + .saturating_add(Weight::from_parts(2_931, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -319,11 +319,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Metadata (max_values: None, max_size: Some(140), added: 2615, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `471` - // Estimated: `5300` - // Minimum execution time: 22_969 nanoseconds. - Weight::from_parts(23_330_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `407` + // Estimated: `7280` + // Minimum execution time: 25_521_000 picoseconds. + Weight::from_parts(26_621_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -336,12 +336,12 @@ impl pallet_assets::WeightInfo for WeightInfo { fn force_set_metadata(_n: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `82` - // Estimated: `5300` - // Minimum execution time: 11_969 nanoseconds. - Weight::from_parts(12_659_111, 0) - .saturating_add(Weight::from_parts(0, 5300)) - // Standard Error: 345 - .saturating_add(Weight::from_parts(1_879, 0).saturating_mul(s.into())) + // Estimated: `7280` + // Minimum execution time: 13_557_000 picoseconds. + Weight::from_parts(14_292_610, 0) + .saturating_add(Weight::from_parts(0, 7280)) + // Standard Error: 393 + .saturating_add(Weight::from_parts(3_655, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -351,11 +351,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `471` - // Estimated: `5300` - // Minimum execution time: 23_002 nanoseconds. - Weight::from_parts(23_320_000, 0) - .saturating_add(Weight::from_parts(0, 5300)) + // Measured: `407` + // Estimated: `7280` + // Minimum execution time: 25_686_000 picoseconds. + Weight::from_parts(25_982_000, 0) + .saturating_add(Weight::from_parts(0, 7280)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -363,11 +363,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `275` - // Estimated: `2685` - // Minimum execution time: 11_994 nanoseconds. - Weight::from_parts(12_256_000, 0) - .saturating_add(Weight::from_parts(0, 2685)) + // Measured: `243` + // Estimated: `3675` + // Minimum execution time: 13_440_000 picoseconds. + Weight::from_parts(13_684_000, 0) + .saturating_add(Weight::from_parts(0, 3675)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -377,11 +377,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `309` - // Estimated: `5308` - // Minimum execution time: 26_321 nanoseconds. - Weight::from_parts(26_867_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `277` + // Estimated: `7288` + // Minimum execution time: 29_166_000 picoseconds. + Weight::from_parts(29_574_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -395,11 +395,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `553` - // Estimated: `13065` - // Minimum execution time: 52_855 nanoseconds. - Weight::from_parts(54_006_000, 0) - .saturating_add(Weight::from_parts(0, 13065)) + // Measured: `521` + // Estimated: `17025` + // Minimum execution time: 58_808_000 picoseconds. + Weight::from_parts(59_441_000, 0) + .saturating_add(Weight::from_parts(0, 17025)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -409,11 +409,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// Proof: Assets Approvals (max_values: None, max_size: Some(148), added: 2623, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `479` - // Estimated: `5308` - // Minimum execution time: 28_148 nanoseconds. - Weight::from_parts(28_416_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `447` + // Estimated: `7288` + // Minimum execution time: 31_081_000 picoseconds. + Weight::from_parts(31_475_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -423,11 +423,11 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `479` - // Estimated: `5308` - // Minimum execution time: 28_456 nanoseconds. - Weight::from_parts(28_913_000, 0) - .saturating_add(Weight::from_parts(0, 5308)) + // Measured: `447` + // Estimated: `7288` + // Minimum execution time: 30_798_000 picoseconds. + Weight::from_parts(31_934_000, 0) + .saturating_add(Weight::from_parts(0, 7288)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -435,12 +435,12 @@ impl pallet_assets::WeightInfo for WeightInfo { /// 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: `383` + // Measured: `243` // Estimated: `3675` - // Minimum execution time: 16_213 nanoseconds. - Weight::from_parts(16_575_000, 0) + // Minimum execution time: 14_755_000 picoseconds. + Weight::from_parts(14_938_000, 0) .saturating_add(Weight::from_parts(0, 3675)) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_balances.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_balances.rs index fc6ab30e195..acae356b1cb 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_balances.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -51,11 +51,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1177` - // Estimated: `2603` - // Minimum execution time: 45_988 nanoseconds. - Weight::from_parts(46_507_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 35_470_000 picoseconds. + Weight::from_parts(36_170_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -63,11 +63,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1061` - // Estimated: `2603` - // Minimum execution time: 34_574 nanoseconds. - Weight::from_parts(35_575_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 26_173_000 picoseconds. + Weight::from_parts(26_636_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,11 +75,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1173` - // Estimated: `2603` - // Minimum execution time: 25_859 nanoseconds. - Weight::from_parts(26_467_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 15_875_000 picoseconds. + Weight::from_parts(16_109_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -87,11 +87,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1173` - // Estimated: `2603` - // Minimum execution time: 28_563 nanoseconds. - Weight::from_parts(29_082_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 18_726_000 picoseconds. + Weight::from_parts(19_101_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -99,11 +99,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1173` - // Estimated: `5206` - // Minimum execution time: 45_594 nanoseconds. - Weight::from_parts(46_296_000, 0) - .saturating_add(Weight::from_parts(0, 5206)) + // Measured: `103` + // Estimated: `6196` + // Minimum execution time: 37_080_000 picoseconds. + Weight::from_parts(37_562_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,11 +111,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1061` - // Estimated: `2603` - // Minimum execution time: 40_085 nanoseconds. - Weight::from_parts(40_675_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 32_468_000 picoseconds. + Weight::from_parts(32_858_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,11 +126,11 @@ impl pallet_balances::WeightInfo for WeightInfo { } fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1057` - // Estimated: `2603` - // Minimum execution time: 22_208 nanoseconds. - Weight::from_parts(22_815_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 14_725_000 picoseconds. + Weight::from_parts(14_926_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_collator_selection.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_collator_selection.rs index 3537559d4ab..eaabe14f8b1 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_collator_selection.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -55,12 +55,12 @@ impl pallet_collator_selection::WeightInfo for WeightIn fn set_invulnerables(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178 + b * (78 ±0)` - // Estimated: `178 + b * (2554 ±0)` - // Minimum execution time: 13_864 nanoseconds. - Weight::from_parts(14_046_919, 0) - .saturating_add(Weight::from_parts(0, 178)) - // Standard Error: 4_684 - .saturating_add(Weight::from_parts(2_474_689, 0).saturating_mul(b.into())) + // Estimated: `1168 + b * (2554 ±0)` + // Minimum execution time: 15_458_000 picoseconds. + Weight::from_parts(16_243_295, 0) + .saturating_add(Weight::from_parts(0, 1168)) + // Standard Error: 3_682 + .saturating_add(Weight::from_parts(2_601_545, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 2554).saturating_mul(b.into())) @@ -71,8 +71,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_556 nanoseconds. - Weight::from_parts(6_751_000, 0) + // Minimum execution time: 7_542_000 picoseconds. + Weight::from_parts(7_735_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,8 +82,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_816 nanoseconds. - Weight::from_parts(7_009_000, 0) + // Minimum execution time: 7_344_000 picoseconds. + Weight::from_parts(7_660_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,13 +102,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 999]`. fn register_as_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1171 + c * (48 ±0)` - // Estimated: `56784 + c * (49 ±0)` - // Minimum execution time: 35_423 nanoseconds. - Weight::from_parts(27_578_125, 0) - .saturating_add(Weight::from_parts(0, 56784)) - // Standard Error: 1_255 - .saturating_add(Weight::from_parts(105_521, 0).saturating_mul(c.into())) + // Measured: `1108 + c * (48 ±0)` + // Estimated: `61671 + c * (49 ±0)` + // Minimum execution time: 38_651_000 picoseconds. + Weight::from_parts(31_016_267, 0) + .saturating_add(Weight::from_parts(0, 61671)) + // Standard Error: 1_279 + .saturating_add(Weight::from_parts(106_148, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 49).saturating_mul(c.into())) @@ -120,13 +120,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[2, 1000]`. fn leave_intent(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `541 + c * (48 ±0)` - // Estimated: `48497` - // Minimum execution time: 24_550 nanoseconds. - Weight::from_parts(15_908_548, 0) - .saturating_add(Weight::from_parts(0, 48497)) - // Standard Error: 1_238 - .saturating_add(Weight::from_parts(105_175, 0).saturating_mul(c.into())) + // Measured: `469 + c * (48 ±0)` + // Estimated: `49487` + // Minimum execution time: 27_474_000 picoseconds. + Weight::from_parts(18_915_300, 0) + .saturating_add(Weight::from_parts(0, 49487)) + // Standard Error: 1_242 + .saturating_add(Weight::from_parts(107_733, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -138,11 +138,11 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { // Proof Size summary in bytes: - // Measured: `135` - // Estimated: `5749` - // Minimum execution time: 25_675 nanoseconds. - Weight::from_parts(26_392_000, 0) - .saturating_add(Weight::from_parts(0, 5749)) + // Measured: `103` + // Estimated: `7729` + // Minimum execution time: 29_327_000 picoseconds. + Weight::from_parts(29_858_000, 0) + .saturating_add(Weight::from_parts(0, 7729)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -160,18 +160,18 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 1000]`. fn new_session(r: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `22756 + r * (148 ±0) + c * (97 ±0)` - // Estimated: `52737 + c * (2519 ±0) + r * (2603 ±0)` - // Minimum execution time: 16_612 nanoseconds. - Weight::from_parts(16_892_000, 0) - .saturating_add(Weight::from_parts(0, 52737)) - // Standard Error: 755_441 - .saturating_add(Weight::from_parts(27_658_379, 0).saturating_mul(c.into())) + // Measured: `22693 + r * (116 ±0) + c * (97 ±0)` + // Estimated: `56697 + r * (2603 ±0) + c * (2520 ±0)` + // Minimum execution time: 17_185_000 picoseconds. + Weight::from_parts(17_436_000, 0) + .saturating_add(Weight::from_parts(0, 56697)) + // Standard Error: 795_522 + .saturating_add(Weight::from_parts(28_877_010, 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())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_multisig.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_multisig.rs index 375ccc70b85..b01f73c3007 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_multisig.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -52,11 +52,11 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_762 nanoseconds. - Weight::from_parts(12_267_870, 0) + // Minimum execution time: 12_071_000 picoseconds. + Weight::from_parts(12_418_308, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1 - .saturating_add(Weight::from_parts(493, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(495, 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) @@ -64,15 +64,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 35_352 nanoseconds. - Weight::from_parts(28_499_037, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 1_231 - .saturating_add(Weight::from_parts(73_158, 0).saturating_mul(s.into())) - // Standard Error: 12 - .saturating_add(Weight::from_parts(1_528, 0).saturating_mul(z.into())) + // Measured: `262 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 37_454_000 picoseconds. + Weight::from_parts(31_908_123, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 637 + .saturating_add(Weight::from_parts(62_530, 0).saturating_mul(s.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_217, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,15 +82,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 26_412 nanoseconds. - Weight::from_parts(20_296_722, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 402 - .saturating_add(Weight::from_parts(67_954, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_495, 0).saturating_mul(z.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 27_665_000 picoseconds. + Weight::from_parts(21_985_439, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 509 + .saturating_add(Weight::from_parts(63_318, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_187, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,15 +102,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `448 + s * (33 ±0)` - // Estimated: `8424` - // Minimum execution time: 39_936 nanoseconds. - Weight::from_parts(31_699_007, 0) - .saturating_add(Weight::from_parts(0, 8424)) - // Standard Error: 632 - .saturating_add(Weight::from_parts(90_100, 0).saturating_mul(s.into())) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_544, 0).saturating_mul(z.into())) + // Measured: `385 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 42_985_000 picoseconds. + Weight::from_parts(35_504_175, 0) + .saturating_add(Weight::from_parts(0, 10404)) + // Standard Error: 530 + .saturating_add(Weight::from_parts(80_153, 0).saturating_mul(s.into())) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_215, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -119,13 +119,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `318 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 25_146 nanoseconds. - Weight::from_parts(26_857_601, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 669 - .saturating_add(Weight::from_parts(76_520, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 28_498_000 picoseconds. + Weight::from_parts(30_376_601, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 785 + .saturating_add(Weight::from_parts(65_913, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -134,13 +134,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 17_187 nanoseconds. - Weight::from_parts(18_410_072, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 491 - .saturating_add(Weight::from_parts(72_318, 0).saturating_mul(s.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 19_047_000 picoseconds. + Weight::from_parts(20_338_502, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 544 + .saturating_add(Weight::from_parts(66_876, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,13 +149,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `517 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 25_956 nanoseconds. - Weight::from_parts(28_043_929, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 830 - .saturating_add(Weight::from_parts(80_119, 0).saturating_mul(s.into())) + // Measured: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 29_085_000 picoseconds. + Weight::from_parts(31_283_618, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 985 + .saturating_add(Weight::from_parts(67_469, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_nfts.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_nfts.rs index d4d05c7ce25..904f7823041 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_nfts.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_nfts.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_nfts` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -50,7 +50,7 @@ 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(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -59,18 +59,18 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts CollectionAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `3054` - // Minimum execution time: 30_978 nanoseconds. - Weight::from_parts(31_489_000, 0) - .saturating_add(Weight::from_parts(0, 3054)) + // Measured: `145` + // Estimated: `5038` + // Minimum execution time: 34_344_000 picoseconds. + Weight::from_parts(35_251_000, 0) + .saturating_add(Weight::from_parts(0, 5038)) .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(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -80,62 +80,53 @@ impl pallet_nfts::WeightInfo for WeightInfo { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `3054` - // Minimum execution time: 20_101 nanoseconds. - Weight::from_parts(20_488_000, 0) - .saturating_add(Weight::from_parts(0, 3054)) + // Estimated: `5038` + // Minimum execution time: 22_704_000 picoseconds. + Weight::from_parts(23_146_000, 0) + .saturating_add(Weight::from_parts(0, 5038)) .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(80), added: 2555, mode: MaxEncodedLen) - /// Storage: Nfts Item (r:1001 w:1000) - /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) - /// Storage: Nfts ItemMetadataOf (r:1001 w:1000) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(219), added: 2694, mode: MaxEncodedLen) - /// Storage: Nfts Attribute (r:1001 w:1000) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(254), added: 2729, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 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(166), added: 2641, mode: MaxEncodedLen) + /// 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 ItemConfigOf (r:0 w:1000) - /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - /// Storage: Nfts Account (r:0 w:1000) - /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, 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 `n` is `[0, 1000]`. /// 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(_n: u32, m: u32, a: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `172673 + m * (206 ±0) + a * (210 ±0)` - // Estimated: `3347314 + m * (2694 ±0) + a * (2729 ±0)` - // Minimum execution time: 23_505_821 nanoseconds. - Weight::from_parts(16_948_157_713, 0) - .saturating_add(Weight::from_parts(0, 3347314)) - // Standard Error: 20_494 - .saturating_add(Weight::from_parts(7_059_571, 0).saturating_mul(m.into())) - // Standard Error: 20_494 - .saturating_add(Weight::from_parts(8_471_367, 0).saturating_mul(a.into())) + fn destroy(_m: u32, _c: u32, a: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `32170 + a * (366 ±0)` + // Estimated: `2538829 + a * (2954 ±0)` + // Minimum execution time: 976_206_000 picoseconds. + Weight::from_parts(924_770_064, 0) + .saturating_add(Weight::from_parts(0, 2538829)) + // Standard Error: 3_946 + .saturating_add(Weight::from_parts(5_708_229, 0).saturating_mul(a.into())) .saturating_add(T::DbWeight::get().reads(1004)) - .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(3005)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(m.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, 2694).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 2729).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(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -144,11 +135,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `13506` - // Minimum execution time: 39_850 nanoseconds. - Weight::from_parts(40_227_000, 0) - .saturating_add(Weight::from_parts(0, 13506)) + // Measured: `421` + // Estimated: `18460` + // Minimum execution time: 44_592_000 picoseconds. + Weight::from_parts(45_181_000, 0) + .saturating_add(Weight::from_parts(0, 18460)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -157,7 +148,7 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -166,24 +157,22 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn force_mint() -> Weight { // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `13506` - // Minimum execution time: 40_379 nanoseconds. - Weight::from_parts(41_110_000, 0) - .saturating_add(Weight::from_parts(0, 13506)) + // Measured: `421` + // Estimated: `18460` + // Minimum execution time: 43_304_000 picoseconds. + Weight::from_parts(43_977_000, 0) + .saturating_add(Weight::from_parts(0, 18460)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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 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:0) - /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(219), added: 2694, mode: MaxEncodedLen) + /// 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) @@ -194,26 +183,22 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `647` - // Estimated: `13652` - // Minimum execution time: 43_534 nanoseconds. - Weight::from_parts(43_846_000, 0) - .saturating_add(Weight::from_parts(0, 13652)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `530` + // Estimated: `15200` + // Minimum execution time: 45_744_000 picoseconds. + Weight::from_parts(46_056_000, 0) + .saturating_add(Weight::from_parts(0, 15200)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(7)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: 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) @@ -222,16 +207,16 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `811` - // Estimated: `16109` - // Minimum execution time: 49_184 nanoseconds. - Weight::from_parts(49_935_000, 0) - .saturating_add(Weight::from_parts(0, 16109)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `559` + // Estimated: `14926` + // Minimum execution time: 35_663_000 picoseconds. + Weight::from_parts(36_865_000, 0) + .saturating_add(Weight::from_parts(0, 14926)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: Nfts Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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) @@ -239,13 +224,13 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `756 + i * (140 ±0)` - // Estimated: `5103 + i * (3336 ±0)` - // Minimum execution time: 15_668 nanoseconds. - Weight::from_parts(15_762_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) - // Standard Error: 12_791 - .saturating_add(Weight::from_parts(12_224_567, 0).saturating_mul(i.into())) + // Measured: `729 + i * (108 ±0)` + // Estimated: `8077 + i * (3336 ±0)` + // Minimum execution time: 16_987_000 picoseconds. + Weight::from_parts(17_194_000, 0) + .saturating_add(Weight::from_parts(0, 8077)) + // Standard Error: 13_044 + .saturating_add(Weight::from_parts(13_324_147, 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()))) @@ -258,10 +243,10 @@ impl pallet_nfts::WeightInfo for WeightInfo { fn lock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `5067` - // Minimum execution time: 18_861 nanoseconds. - Weight::from_parts(19_195_000, 0) - .saturating_add(Weight::from_parts(0, 5067)) + // Estimated: `7047` + // Minimum execution time: 20_345_000 picoseconds. + Weight::from_parts(20_739_000, 0) + .saturating_add(Weight::from_parts(0, 7047)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -272,145 +257,149 @@ impl pallet_nfts::WeightInfo for WeightInfo { fn unlock_item_transfer() -> Weight { // Proof Size summary in bytes: // Measured: `401` - // Estimated: `5067` - // Minimum execution time: 18_710 nanoseconds. - Weight::from_parts(18_971_000, 0) - .saturating_add(Weight::from_parts(0, 5067)) + // Estimated: `7047` + // Minimum execution time: 20_167_000 picoseconds. + Weight::from_parts(20_580_000, 0) + .saturating_add(Weight::from_parts(0, 7047)) .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 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: `289` - // Estimated: `5092` - // Minimum execution time: 17_067 nanoseconds. - Weight::from_parts(17_233_000, 0) - .saturating_add(Weight::from_parts(0, 5092)) + // Measured: `306` + // Estimated: `7087` + // Minimum execution time: 17_831_000 picoseconds. + Weight::from_parts(18_174_000, 0) + .saturating_add(Weight::from_parts(0, 7087)) .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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `381` - // Estimated: `5082` - // Minimum execution time: 21_203 nanoseconds. - Weight::from_parts(21_468_000, 0) - .saturating_add(Weight::from_parts(0, 5082)) + // Measured: `354` + // Estimated: `7066` + // Minimum execution time: 23_763_000 picoseconds. + Weight::from_parts(24_226_000, 0) + .saturating_add(Weight::from_parts(0, 7066)) .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(80), added: 2555, mode: MaxEncodedLen) - /// Storage: Nfts CollectionRoleOf (r:0 w:4) + /// 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: `362` - // Estimated: `2555` - // Minimum execution time: 24_304 nanoseconds. - Weight::from_parts(24_823_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) - .saturating_add(T::DbWeight::get().reads(1)) + // Measured: `335` + // Estimated: `9627` + // Minimum execution time: 40_034_000 picoseconds. + Weight::from_parts(40_402_000, 0) + .saturating_add(Weight::from_parts(0, 9627)) + .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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `304` - // Estimated: `2555` - // Minimum execution time: 17_173 nanoseconds. - Weight::from_parts(17_448_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) + // Measured: `277` + // Estimated: `3549` + // Minimum execution time: 18_648_000 picoseconds. + Weight::from_parts(18_968_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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `2555` - // Minimum execution time: 13_697 nanoseconds. - Weight::from_parts(13_924_000, 0) - .saturating_add(Weight::from_parts(0, 2555)) + // Estimated: `3549` + // Minimum execution time: 15_282_000 picoseconds. + Weight::from_parts(15_923_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 Collection (r:1 w:0) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) fn lock_item_properties() -> Weight { // Proof Size summary in bytes: - // Measured: `445` - // Estimated: `5078` - // Minimum execution time: 18_063 nanoseconds. - Weight::from_parts(18_438_000, 0) - .saturating_add(Weight::from_parts(0, 5078)) + // Measured: `401` + // Estimated: `7047` + // Minimum execution time: 20_060_000 picoseconds. + Weight::from_parts(20_326_000, 0) + .saturating_add(Weight::from_parts(0, 7047)) .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(80), added: 2555, mode: MaxEncodedLen) + /// 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(254), added: 2729, mode: MaxEncodedLen) + /// Proof: Nfts Attribute (max_values: None, max_size: Some(479), added: 2954, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `10355` - // Minimum execution time: 37_582 nanoseconds. - Weight::from_parts(38_155_000, 0) - .saturating_add(Weight::from_parts(0, 10355)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `505` + // Estimated: `18078` + // Minimum execution time: 48_324_000 picoseconds. + Weight::from_parts(48_745_000, 0) + .saturating_add(Weight::from_parts(0, 18078)) + .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(80), added: 2555, mode: MaxEncodedLen) + /// 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(254), added: 2729, mode: MaxEncodedLen) + /// 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: `337` - // Estimated: `5284` - // Minimum execution time: 24_392 nanoseconds. - Weight::from_parts(24_787_000, 0) - .saturating_add(Weight::from_parts(0, 5284)) + // Measured: `310` + // Estimated: `7493` + // Minimum execution time: 27_935_000 picoseconds. + Weight::from_parts(28_241_000, 0) + .saturating_add(Weight::from_parts(0, 7493)) .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(254), added: 2729, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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: `724` - // Estimated: `7807` - // Minimum execution time: 34_564 nanoseconds. - Weight::from_parts(34_956_000, 0) - .saturating_add(Weight::from_parts(0, 7807)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `949` + // Estimated: `14540` + // Minimum execution time: 44_972_000 picoseconds. + Weight::from_parts(45_618_000, 0) + .saturating_add(Weight::from_parts(0, 14540)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: Nfts Item (r:1 w:0) @@ -419,11 +408,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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: `379` - // Estimated: `6812` - // Minimum execution time: 17_194 nanoseconds. - Weight::from_parts(17_467_000, 0) - .saturating_add(Weight::from_parts(0, 6812)) + // Measured: `347` + // Estimated: `8792` + // Minimum execution time: 19_246_000 picoseconds. + Weight::from_parts(19_715_000, 0) + .saturating_add(Weight::from_parts(0, 8792)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -432,133 +421,135 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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(254), added: 2729, mode: MaxEncodedLen) + /// 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: `828 + n * (204 ±0)` - // Estimated: `12144 + n * (2729 ±0)` - // Minimum execution time: 25_617 nanoseconds. - Weight::from_parts(25_917_000, 0) - .saturating_add(Weight::from_parts(0, 12144)) - // Standard Error: 5_524 - .saturating_add(Weight::from_parts(7_538_893, 0).saturating_mul(n.into())) + // Measured: `726 + n * (398 ±0)` + // Estimated: `16329 + n * (2954 ±0)` + // Minimum execution time: 28_372_000 picoseconds. + Weight::from_parts(28_671_000, 0) + .saturating_add(Weight::from_parts(0, 16329)) + // Standard Error: 3_479 + .saturating_add(Weight::from_parts(5_527_336, 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, 2729).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(80), added: 2555, mode: MaxEncodedLen) + /// 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(219), added: 2694, mode: MaxEncodedLen) + /// Proof: Nfts ItemMetadataOf (max_values: None, max_size: Some(347), added: 2822, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `10320` - // Minimum execution time: 32_053 nanoseconds. - Weight::from_parts(32_510_000, 0) - .saturating_add(Weight::from_parts(0, 10320)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `505` + // Estimated: `17946` + // Minimum execution time: 39_852_000 picoseconds. + Weight::from_parts(40_280_000, 0) + .saturating_add(Weight::from_parts(0, 17946)) + .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(219), added: 2694, mode: MaxEncodedLen) + /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `688` - // Estimated: `7772` - // Minimum execution time: 30_654 nanoseconds. - Weight::from_parts(31_113_000, 0) - .saturating_add(Weight::from_parts(0, 7772)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `815` + // Estimated: `14408` + // Minimum execution time: 36_829_000 picoseconds. + Weight::from_parts(37_513_000, 0) + .saturating_add(Weight::from_parts(0, 14408)) + .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(80), added: 2555, mode: MaxEncodedLen) + /// 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(166), added: 2641, mode: MaxEncodedLen) + /// 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: `333` - // Estimated: `7744` - // Minimum execution time: 27_700 nanoseconds. - Weight::from_parts(28_291_000, 0) - .saturating_add(Weight::from_parts(0, 7744)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `364` + // Estimated: `14380` + // Minimum execution time: 35_398_000 picoseconds. + Weight::from_parts(35_809_000, 0) + .saturating_add(Weight::from_parts(0, 14380)) + .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(80), added: 2555, mode: MaxEncodedLen) + /// 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(166), added: 2641, mode: MaxEncodedLen) + /// 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: `555` - // Estimated: `7744` - // Minimum execution time: 27_483 nanoseconds. - Weight::from_parts(27_830_000, 0) - .saturating_add(Weight::from_parts(0, 7744)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `682` + // Estimated: `14380` + // Minimum execution time: 33_699_000 picoseconds. + Weight::from_parts(34_170_000, 0) + .saturating_add(Weight::from_parts(0, 14380)) + .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) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `466` - // Estimated: `8428` - // Minimum execution time: 23_623 nanoseconds. - Weight::from_parts(24_282_000, 0) - .saturating_add(Weight::from_parts(0, 8428)) - .saturating_add(T::DbWeight::get().reads(3)) + // Measured: `376` + // Estimated: `7864` + // Minimum execution time: 21_789_000 picoseconds. + Weight::from_parts(22_454_000, 0) + .saturating_add(Weight::from_parts(0, 7864)) + .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) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `5880` - // Minimum execution time: 21_115 nanoseconds. - Weight::from_parts(22_036_000, 0) - .saturating_add(Weight::from_parts(0, 5880)) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `384` + // Estimated: `4326` + // Minimum execution time: 19_532_000 picoseconds. + Weight::from_parts(19_761_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) - /// Storage: Nfts CollectionRoleOf (r:1 w:0) - /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) fn clear_all_transfer_approvals() -> Weight { // Proof Size summary in bytes: - // Measured: `474` - // Estimated: `5880` - // Minimum execution time: 20_352 nanoseconds. - Weight::from_parts(20_627_000, 0) - .saturating_add(Weight::from_parts(0, 5880)) - .saturating_add(T::DbWeight::get().reads(2)) + // Measured: `384` + // Estimated: `4326` + // Minimum execution time: 18_620_000 picoseconds. + Weight::from_parts(19_014_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) @@ -566,38 +557,38 @@ impl pallet_nfts::WeightInfo for WeightInfo { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2527` - // Minimum execution time: 14_427 nanoseconds. - Weight::from_parts(15_169_000, 0) - .saturating_add(Weight::from_parts(0, 2527)) + // Estimated: `3517` + // Minimum execution time: 16_491_000 picoseconds. + Weight::from_parts(16_888_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(80), added: 2555, mode: MaxEncodedLen) + /// 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: `333` - // Estimated: `5103` - // Minimum execution time: 18_049 nanoseconds. - Weight::from_parts(18_431_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) + // Measured: `306` + // Estimated: `7087` + // Minimum execution time: 19_929_000 picoseconds. + Weight::from_parts(20_170_000, 0) + .saturating_add(Weight::from_parts(0, 7087)) .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(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:1 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:1) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) fn update_mint_settings() -> Weight { // Proof Size summary in bytes: - // Measured: `333` - // Estimated: `5103` - // Minimum execution time: 17_166 nanoseconds. - Weight::from_parts(17_511_000, 0) - .saturating_add(Weight::from_parts(0, 5103)) + // Measured: `289` + // Estimated: `7072` + // Minimum execution time: 19_500_000 picoseconds. + Weight::from_parts(19_839_000, 0) + .saturating_add(Weight::from_parts(0, 7072)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -611,11 +602,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `516` - // Estimated: `8407` - // Minimum execution time: 22_556 nanoseconds. - Weight::from_parts(22_839_000, 0) - .saturating_add(Weight::from_parts(0, 8407)) + // Measured: `484` + // Estimated: `11377` + // Minimum execution time: 24_542_000 picoseconds. + Weight::from_parts(24_916_000, 0) + .saturating_add(Weight::from_parts(0, 11377)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -624,37 +615,35 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, 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: `897` - // Estimated: `16129` - // Minimum execution time: 53_554 nanoseconds. - Weight::from_parts(54_285_000, 0) - .saturating_add(Weight::from_parts(0, 16129)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `671` + // Estimated: `18480` + // Minimum execution time: 44_311_000 picoseconds. + Weight::from_parts(45_789_000, 0) + .saturating_add(Weight::from_parts(0, 18480)) + .saturating_add(T::DbWeight::get().reads(5)) + .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_031 nanoseconds. - Weight::from_parts(3_579_973, 0) + // Minimum execution time: 2_523_000 picoseconds. + Weight::from_parts(4_349_031, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 8_727 - .saturating_add(Weight::from_parts(3_165_511, 0).saturating_mul(n.into())) + // Standard Error: 10_427 + .saturating_add(Weight::from_parts(3_718_129, 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) @@ -662,11 +651,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts PendingSwapOf (max_values: None, max_size: Some(71), added: 2546, mode: MaxEncodedLen) fn create_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `524` - // Estimated: `6672` - // Minimum execution time: 20_161 nanoseconds. - Weight::from_parts(20_487_000, 0) - .saturating_add(Weight::from_parts(0, 6672)) + // Measured: `460` + // Estimated: `7662` + // Minimum execution time: 23_007_000 picoseconds. + Weight::from_parts(23_305_000, 0) + .saturating_add(Weight::from_parts(0, 7662)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -676,11 +665,11 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) fn cancel_swap() -> Weight { // Proof Size summary in bytes: - // Measured: `511` - // Estimated: `5882` - // Minimum execution time: 19_470 nanoseconds. - Weight::from_parts(19_832_000, 0) - .saturating_add(Weight::from_parts(0, 5882)) + // Measured: `479` + // Estimated: `7862` + // Minimum execution time: 21_173_000 picoseconds. + Weight::from_parts(21_451_000, 0) + .saturating_add(Weight::from_parts(0, 7862)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -689,85 +678,85 @@ impl pallet_nfts::WeightInfo for WeightInfo { /// 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(80), added: 2555, mode: MaxEncodedLen) + /// 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:2 w:0) /// 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 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: `1026` - // Estimated: `21970` - // Minimum execution time: 78_114 nanoseconds. - Weight::from_parts(79_459_000, 0) - .saturating_add(Weight::from_parts(0, 21970)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(11)) + // Measured: `800` + // Estimated: `24321` + // Minimum execution time: 72_213_000 picoseconds. + Weight::from_parts(73_029_000, 0) + .saturating_add(Weight::from_parts(0, 24321)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(10)) } - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// Storage: Nfts CollectionRoleOf (r:2 w:0) + /// Proof: Nfts CollectionRoleOf (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) /// Storage: Nfts CollectionConfigOf (r:1 w:0) /// Proof: Nfts CollectionConfigOf (max_values: None, max_size: Some(73), added: 2548, mode: MaxEncodedLen) /// Storage: Nfts Item (r:1 w:1) /// Proof: Nfts Item (max_values: None, max_size: Some(861), added: 3336, mode: MaxEncodedLen) + /// Storage: Nfts Collection (r:1 w:1) + /// Proof: Nfts Collection (max_values: None, max_size: Some(84), added: 2559, mode: MaxEncodedLen) /// Storage: Nfts ItemConfigOf (r:1 w:1) /// Proof: Nfts ItemConfigOf (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) /// Storage: System Account (r:1 w:1) /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) /// Storage: Nfts Attribute (r:10 w:10) - /// Proof: Nfts Attribute (max_values: None, max_size: Some(254), added: 2729, mode: MaxEncodedLen) + /// 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(219), added: 2694, mode: MaxEncodedLen) + /// 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: `525` - // Estimated: `16259 + n * (2729 ±0)` - // Minimum execution time: 108_373 nanoseconds. - Weight::from_parts(112_094_892, 0) - .saturating_add(Weight::from_parts(0, 16259)) - // Standard Error: 27_186 - .saturating_add(Weight::from_parts(20_710_983, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(6)) + // Measured: `524` + // Estimated: `29399 + n * (2954 ±0)` + // Minimum execution time: 125_518_000 picoseconds. + Weight::from_parts(129_781_908, 0) + .saturating_add(Weight::from_parts(0, 29399)) + // Standard Error: 21_840 + .saturating_add(Weight::from_parts(26_756_136, 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, 2729).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(681), added: 3156, mode: MaxEncodedLen) - /// Storage: Nfts Collection (r:1 w:1) - /// Proof: Nfts Collection (max_values: None, max_size: Some(80), added: 2555, mode: MaxEncodedLen) + /// 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(446), added: 2921, mode: MaxEncodedLen) + /// 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: `716` - // Estimated: `14198 + n * (2921 ±0)` - // Minimum execution time: 84_153 nanoseconds. - Weight::from_parts(96_401_623, 0) - .saturating_add(Weight::from_parts(0, 14198)) - // Standard Error: 70_244 - .saturating_add(Weight::from_parts(26_866_222, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) + // Measured: `554` + // Estimated: `20462 + n * (2954 ±0)` + // Minimum execution time: 76_133_000 picoseconds. + Weight::from_parts(85_559_988, 0) + .saturating_add(Weight::from_parts(0, 20462)) + // Standard Error: 49_851 + .saturating_add(Weight::from_parts(26_551_215, 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_u64)) + .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, 2921).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2954).saturating_mul(n.into())) } } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_proxy.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_proxy.rs index 68b69720caf..fa22bf7bf68 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_proxy.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_proxy.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_proxy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -52,13 +52,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 14_854 nanoseconds. - Weight::from_parts(15_600_203, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_181 - .saturating_add(Weight::from_parts(28_891, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_562_000 picoseconds. + Weight::from_parts(17_305_360, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_081 + .saturating_add(Weight::from_parts(37_267, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -71,15 +71,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `550 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 32_063 nanoseconds. - Weight::from_parts(32_624_200, 0) - .saturating_add(Weight::from_parts(0, 11027)) - // Standard Error: 1_727 - .saturating_add(Weight::from_parts(113_689, 0).saturating_mul(a.into())) - // Standard Error: 1_785 - .saturating_add(Weight::from_parts(29_618, 0).saturating_mul(p.into())) + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 35_181_000 picoseconds. + Weight::from_parts(34_864_956, 0) + .saturating_add(Weight::from_parts(0, 13997)) + // Standard Error: 5_023 + .saturating_add(Weight::from_parts(158_916, 0).saturating_mul(a.into())) + // Standard Error: 5_189 + .saturating_add(Weight::from_parts(60_136, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -91,15 +91,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 20_449 nanoseconds. - Weight::from_parts(21_345_957, 0) - .saturating_add(Weight::from_parts(0, 7311)) - // Standard Error: 1_390 - .saturating_add(Weight::from_parts(105_313, 0).saturating_mul(a.into())) - // Standard Error: 1_436 - .saturating_add(Weight::from_parts(9_437, 0).saturating_mul(p.into())) + // Measured: `369 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 21_758_000 picoseconds. + Weight::from_parts(23_149_882, 0) + .saturating_add(Weight::from_parts(0, 9291)) + // Standard Error: 1_877 + .saturating_add(Weight::from_parts(145_269, 0).saturating_mul(a.into())) + // Standard Error: 1_940 + .saturating_add(Weight::from_parts(5_129, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,15 +111,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 20_423 nanoseconds. - Weight::from_parts(21_290_701, 0) - .saturating_add(Weight::from_parts(0, 7311)) - // Standard Error: 1_398 - .saturating_add(Weight::from_parts(110_034, 0).saturating_mul(a.into())) - // Standard Error: 1_444 - .saturating_add(Weight::from_parts(9_968, 0).saturating_mul(p.into())) + // Measured: `369 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_076_000 picoseconds. + Weight::from_parts(22_959_374, 0) + .saturating_add(Weight::from_parts(0, 9291)) + // Standard Error: 1_377 + .saturating_add(Weight::from_parts(146_462, 0).saturating_mul(a.into())) + // Standard Error: 1_423 + .saturating_add(Weight::from_parts(11_551, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -133,15 +133,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 28_014 nanoseconds. - Weight::from_parts(28_864_371, 0) - .saturating_add(Weight::from_parts(0, 11027)) - // Standard Error: 1_933 - .saturating_add(Weight::from_parts(109_536, 0).saturating_mul(a.into())) - // Standard Error: 1_998 - .saturating_add(Weight::from_parts(43_779, 0).saturating_mul(p.into())) + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 30_751_000 picoseconds. + Weight::from_parts(31_929_484, 0) + .saturating_add(Weight::from_parts(0, 13997)) + // Standard Error: 2_087 + .saturating_add(Weight::from_parts(147_703, 0).saturating_mul(a.into())) + // Standard Error: 2_156 + .saturating_add(Weight::from_parts(27_798, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -150,13 +150,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 21_285 nanoseconds. - Weight::from_parts(22_065_300, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_703 - .saturating_add(Weight::from_parts(42_186, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_700_000 picoseconds. + Weight::from_parts(24_509_575, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_699 + .saturating_add(Weight::from_parts(51_275, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,13 +165,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_992 nanoseconds. - Weight::from_parts(22_026_633, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_663 - .saturating_add(Weight::from_parts(60_910, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_289_000 picoseconds. + Weight::from_parts(24_453_360, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_690 + .saturating_add(Weight::from_parts(62_718, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -180,26 +180,28 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 16_755 nanoseconds. - Weight::from_parts(17_775_492, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_281 - .saturating_add(Weight::from_parts(28_738, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 18_877_000 picoseconds. + Weight::from_parts(19_780_042, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_171 + .saturating_add(Weight::from_parts(20_282, 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 { + fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `139` - // Estimated: `3716` - // Minimum execution time: 22_598 nanoseconds. - Weight::from_parts(23_639_320, 0) - .saturating_add(Weight::from_parts(0, 3716)) + // Estimated: `4706` + // Minimum execution time: 25_354_000 picoseconds. + Weight::from_parts(26_362_285, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_459 + .saturating_add(Weight::from_parts(1_330, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -208,13 +210,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `196 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 17_907 nanoseconds. - Weight::from_parts(18_737_185, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_069 - .saturating_add(Weight::from_parts(26_491, 0).saturating_mul(p.into())) + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 20_057_000 picoseconds. + Weight::from_parts(20_844_608, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_336 + .saturating_add(Weight::from_parts(27_855, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_session.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_session.rs index 5bba2a38022..bb4705ace09 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_session.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -54,10 +54,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `270` - // Estimated: `5490` - // Minimum execution time: 15_416 nanoseconds. - Weight::from_parts(15_764_000, 0) - .saturating_add(Weight::from_parts(0, 5490)) + // Estimated: `7470` + // Minimum execution time: 17_394_000 picoseconds. + Weight::from_parts(17_828_000, 0) + .saturating_add(Weight::from_parts(0, 7470)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `242` - // Estimated: `2959` - // Minimum execution time: 11_720 nanoseconds. - Weight::from_parts(12_152_000, 0) - .saturating_add(Weight::from_parts(0, 2959)) + // Estimated: `3949` + // Minimum execution time: 13_334_000 picoseconds. + Weight::from_parts(13_634_000, 0) + .saturating_add(Weight::from_parts(0, 3949)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_timestamp.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_timestamp.rs index 7cb95d8f8e1..7475e81c9ad 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_timestamp.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -54,10 +54,10 @@ impl pallet_timestamp::WeightInfo for WeightInfo { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `86` - // Estimated: `1006` - // Minimum execution time: 8_384 nanoseconds. - Weight::from_parts(8_706_000, 0) - .saturating_add(Weight::from_parts(0, 1006)) + // Estimated: `2986` + // Minimum execution time: 9_273_000 picoseconds. + Weight::from_parts(9_653_000, 0) + .saturating_add(Weight::from_parts(0, 2986)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_timestamp::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `57` // Estimated: `0` - // Minimum execution time: 3_110 nanoseconds. - Weight::from_parts(3_206_000, 0) + // Minimum execution time: 3_289_000 picoseconds. + Weight::from_parts(3_379_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_uniques.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_uniques.rs index 624879d8e0b..c32eebdc908 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_uniques.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_uniques.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_uniques` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -53,11 +53,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `177` - // Estimated: `2653` - // Minimum execution time: 23_302 nanoseconds. - Weight::from_parts(23_817_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `145` + // Estimated: `3643` + // Minimum execution time: 26_855_000 picoseconds. + Weight::from_parts(27_393_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_uniques::WeightInfo for WeightInfo { fn force_create() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2653` - // Minimum execution time: 12_529 nanoseconds. - Weight::from_parts(13_079_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Estimated: `3643` + // Minimum execution time: 15_006_000 picoseconds. + Weight::from_parts(15_389_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -79,14 +79,14 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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 Attribute (r:0 w:1000) - /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, 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 InstanceMetadataOf (r:0 w:1000) - /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, 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) @@ -96,24 +96,28 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// The range of component `a` is `[0, 1000]`. fn destroy(n: u32, m: u32, a: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `289 + n * (108 ±0) + m * (56 ±0) + a * (107 ±0)` - // Estimated: `5250 + n * (2597 ±0)` - // Minimum execution time: 2_305_045 nanoseconds. - Weight::from_parts(2_312_341_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) - // Standard Error: 26_047 - .saturating_add(Weight::from_parts(8_440_544, 0).saturating_mul(n.into())) - // Standard Error: 26_047 - .saturating_add(Weight::from_parts(223_194, 0).saturating_mul(m.into())) - // Standard Error: 26_047 - .saturating_add(Weight::from_parts(313_891, 0).saturating_mul(a.into())) + // Measured: `257 + n * (76 ±0) + m * (56 ±0) + a * (107 ±0)` + // Estimated: `9210 + a * (2647 ±0) + n * (2597 ±0) + m * (2662 ±0)` + // Minimum execution time: 2_360_211_000 picoseconds. + Weight::from_parts(2_383_759_000, 0) + .saturating_add(Weight::from_parts(0, 9210)) + // Standard Error: 24_849 + .saturating_add(Weight::from_parts(6_304_424, 0).saturating_mul(n.into())) + // Standard Error: 24_849 + .saturating_add(Weight::from_parts(253_862, 0).saturating_mul(m.into())) + // Standard Error: 24_849 + .saturating_add(Weight::from_parts(324_295, 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, 2597).saturating_mul(n.into())) + .saturating_add(Weight::from_parts(0, 2662).saturating_mul(m.into())) } /// Storage: Uniques Asset (r:1 w:1) /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) @@ -125,11 +129,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn mint() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `7749` - // Minimum execution time: 28_581 nanoseconds. - Weight::from_parts(29_011_000, 0) - .saturating_add(Weight::from_parts(0, 7749)) + // Measured: `282` + // Estimated: `10719` + // Minimum execution time: 33_245_000 picoseconds. + Weight::from_parts(33_516_000, 0) + .saturating_add(Weight::from_parts(0, 10719)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -143,11 +147,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn burn() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 29_869 nanoseconds. - Weight::from_parts(30_206_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 34_237_000 picoseconds. + Weight::from_parts(34_725_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -161,11 +165,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 23_945 nanoseconds. - Weight::from_parts(24_259_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 27_588_000 picoseconds. + Weight::from_parts(27_994_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -176,13 +180,13 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// The range of component `i` is `[0, 5000]`. fn redeposit(i: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `770 + i * (108 ±0)` - // Estimated: `2653 + i * (2597 ±0)` - // Minimum execution time: 13_847 nanoseconds. - Weight::from_parts(14_105_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) - // Standard Error: 12_887 - .saturating_add(Weight::from_parts(12_017_604, 0).saturating_mul(i.into())) + // Measured: `738 + i * (76 ±0)` + // Estimated: `4633 + i * (2597 ±0)` + // Minimum execution time: 15_958_000 picoseconds. + Weight::from_parts(16_175_000, 0) + .saturating_add(Weight::from_parts(0, 4633)) + // Standard Error: 12_904 + .saturating_add(Weight::from_parts(13_261_405, 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)) @@ -195,11 +199,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 17_259 nanoseconds. - Weight::from_parts(17_731_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 19_124_000 picoseconds. + Weight::from_parts(19_432_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -209,11 +213,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 16_951 nanoseconds. - Weight::from_parts(17_177_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 19_725_000 picoseconds. + Weight::from_parts(19_903_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -221,11 +225,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn freeze_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 12_733 nanoseconds. - Weight::from_parts(13_154_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 15_091_000 picoseconds. + Weight::from_parts(15_405_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -233,11 +237,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn thaw_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 12_624 nanoseconds. - Weight::from_parts(12_887_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 14_440_000 picoseconds. + Weight::from_parts(14_836_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -249,11 +253,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ClassAccount (max_values: None, max_size: Some(68), added: 2543, mode: MaxEncodedLen) fn transfer_ownership() -> Weight { // Proof Size summary in bytes: - // Measured: `388` - // Estimated: `5180` - // Minimum execution time: 20_089 nanoseconds. - Weight::from_parts(20_583_000, 0) - .saturating_add(Weight::from_parts(0, 5180)) + // Measured: `356` + // Estimated: `7160` + // Minimum execution time: 22_729_000 picoseconds. + Weight::from_parts(23_039_000, 0) + .saturating_add(Weight::from_parts(0, 7160)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -261,11 +265,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Class (max_values: None, max_size: Some(178), added: 2653, mode: MaxEncodedLen) fn set_team() -> Weight { // Proof Size summary in bytes: - // Measured: `314` - // Estimated: `2653` - // Minimum execution time: 13_647 nanoseconds. - Weight::from_parts(13_894_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 15_506_000 picoseconds. + Weight::from_parts(15_864_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -275,11 +279,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `2653` - // Minimum execution time: 16_035 nanoseconds. - Weight::from_parts(16_232_000, 0) - .saturating_add(Weight::from_parts(0, 2653)) + // Measured: `282` + // Estimated: `3643` + // Minimum execution time: 18_244_000 picoseconds. + Weight::from_parts(18_591_000, 0) + .saturating_add(Weight::from_parts(0, 3643)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -291,11 +295,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, mode: MaxEncodedLen) fn set_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `623` - // Estimated: `7962` - // Minimum execution time: 33_357 nanoseconds. - Weight::from_parts(34_794_000, 0) - .saturating_add(Weight::from_parts(0, 7962)) + // Measured: `559` + // Estimated: `10932` + // Minimum execution time: 37_528_000 picoseconds. + Weight::from_parts(38_282_000, 0) + .saturating_add(Weight::from_parts(0, 10932)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -307,11 +311,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Attribute (max_values: None, max_size: Some(172), added: 2647, mode: MaxEncodedLen) fn clear_attribute() -> Weight { // Proof Size summary in bytes: - // Measured: `851` - // Estimated: `7962` - // Minimum execution time: 32_496 nanoseconds. - Weight::from_parts(33_068_000, 0) - .saturating_add(Weight::from_parts(0, 7962)) + // Measured: `756` + // Estimated: `10932` + // Minimum execution time: 36_654_000 picoseconds. + Weight::from_parts(36_947_000, 0) + .saturating_add(Weight::from_parts(0, 10932)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -321,11 +325,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, mode: MaxEncodedLen) fn set_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `380` - // Estimated: `5315` - // Minimum execution time: 25_557 nanoseconds. - Weight::from_parts(25_923_000, 0) - .saturating_add(Weight::from_parts(0, 5315)) + // Measured: `348` + // Estimated: `7295` + // Minimum execution time: 29_703_000 picoseconds. + Weight::from_parts(30_032_000, 0) + .saturating_add(Weight::from_parts(0, 7295)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -335,11 +339,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques InstanceMetadataOf (max_values: None, max_size: Some(187), added: 2662, mode: MaxEncodedLen) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `623` - // Estimated: `5315` - // Minimum execution time: 26_147 nanoseconds. - Weight::from_parts(26_386_000, 0) - .saturating_add(Weight::from_parts(0, 5315)) + // Measured: `559` + // Estimated: `7295` + // Minimum execution time: 29_941_000 picoseconds. + Weight::from_parts(30_222_000, 0) + .saturating_add(Weight::from_parts(0, 7295)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -349,11 +353,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `5295` - // Minimum execution time: 25_233 nanoseconds. - Weight::from_parts(25_665_000, 0) - .saturating_add(Weight::from_parts(0, 5295)) + // Measured: `282` + // Estimated: `7275` + // Minimum execution time: 28_466_000 picoseconds. + Weight::from_parts(29_037_000, 0) + .saturating_add(Weight::from_parts(0, 7275)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -363,11 +367,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `537` - // Estimated: `5295` - // Minimum execution time: 24_311 nanoseconds. - Weight::from_parts(24_544_000, 0) - .saturating_add(Weight::from_parts(0, 5295)) + // Measured: `473` + // Estimated: `7275` + // Minimum execution time: 27_072_000 picoseconds. + Weight::from_parts(27_514_000, 0) + .saturating_add(Weight::from_parts(0, 7275)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -377,11 +381,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn approve_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `492` - // Estimated: `5250` - // Minimum execution time: 18_197 nanoseconds. - Weight::from_parts(18_442_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `428` + // Estimated: `7230` + // Minimum execution time: 20_791_000 picoseconds. + Weight::from_parts(21_072_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -391,11 +395,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Asset (max_values: None, max_size: Some(122), added: 2597, mode: MaxEncodedLen) fn cancel_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `525` - // Estimated: `5250` - // Minimum execution time: 18_606 nanoseconds. - Weight::from_parts(19_032_000, 0) - .saturating_add(Weight::from_parts(0, 5250)) + // Measured: `461` + // Estimated: `7230` + // Minimum execution time: 20_467_000 picoseconds. + Weight::from_parts(20_842_000, 0) + .saturating_add(Weight::from_parts(0, 7230)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -404,10 +408,10 @@ impl pallet_uniques::WeightInfo for WeightInfo { fn set_accept_ownership() -> Weight { // Proof Size summary in bytes: // Measured: `42` - // Estimated: `2527` - // Minimum execution time: 14_902 nanoseconds. - Weight::from_parts(15_216_000, 0) - .saturating_add(Weight::from_parts(0, 2527)) + // Estimated: `3517` + // Minimum execution time: 16_836_000 picoseconds. + Weight::from_parts(17_418_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -417,11 +421,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// 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: `314` - // Estimated: `5152` - // Minimum execution time: 15_771 nanoseconds. - Weight::from_parts(16_013_000, 0) - .saturating_add(Weight::from_parts(0, 5152)) + // Measured: `282` + // Estimated: `7132` + // Minimum execution time: 17_721_000 picoseconds. + Weight::from_parts(18_109_000, 0) + .saturating_add(Weight::from_parts(0, 7132)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -431,11 +435,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques ItemPriceOf (max_values: None, max_size: Some(89), added: 2564, mode: MaxEncodedLen) fn set_price() -> Weight { // Proof Size summary in bytes: - // Measured: `291` - // Estimated: `2597` - // Minimum execution time: 15_703 nanoseconds. - Weight::from_parts(15_905_000, 0) - .saturating_add(Weight::from_parts(0, 2597)) + // Measured: `259` + // Estimated: `3587` + // Minimum execution time: 17_599_000 picoseconds. + Weight::from_parts(17_802_000, 0) + .saturating_add(Weight::from_parts(0, 3587)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -449,11 +453,11 @@ impl pallet_uniques::WeightInfo for WeightInfo { /// Proof: Uniques Account (max_values: None, max_size: Some(88), added: 2563, mode: MaxEncodedLen) fn buy_item() -> Weight { // Proof Size summary in bytes: - // Measured: `636` - // Estimated: `7814` - // Minimum execution time: 33_712 nanoseconds. - Weight::from_parts(34_365_000, 0) - .saturating_add(Weight::from_parts(0, 7814)) + // Measured: `540` + // Estimated: `10784` + // Minimum execution time: 38_642_000 picoseconds. + Weight::from_parts(39_168_000, 0) + .saturating_add(Weight::from_parts(0, 10784)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_utility.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_utility.rs index a7fbd58a87d..76db89d9078 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_utility.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -52,18 +52,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_171 nanoseconds. - Weight::from_parts(14_264_475, 0) + // Minimum execution time: 6_995_000 picoseconds. + Weight::from_parts(19_761_796, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_826 - .saturating_add(Weight::from_parts(4_102_412, 0).saturating_mul(c.into())) + // Standard Error: 3_672 + .saturating_add(Weight::from_parts(4_682_116, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_750 nanoseconds. - Weight::from_parts(4_872_000, 0) + // Minimum execution time: 5_549_000 picoseconds. + Weight::from_parts(5_723_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +71,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_448 nanoseconds. - Weight::from_parts(20_274_161, 0) + // Minimum execution time: 7_210_000 picoseconds. + Weight::from_parts(15_002_117, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 4_587 - .saturating_add(Weight::from_parts(4_321_327, 0).saturating_mul(c.into())) + // Standard Error: 2_199 + .saturating_add(Weight::from_parts(4_917_852, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_092 nanoseconds. - Weight::from_parts(8_417_000, 0) + // Minimum execution time: 9_596_000 picoseconds. + Weight::from_parts(9_875_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +90,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_410 nanoseconds. - Weight::from_parts(19_538_670, 0) + // Minimum execution time: 7_024_000 picoseconds. + Weight::from_parts(15_781_473, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 4_387 - .saturating_add(Weight::from_parts(4_098_456, 0).saturating_mul(c.into())) + // Standard Error: 2_344 + .saturating_add(Weight::from_parts(4_665_530, 0).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/assets/westmint/src/weights/pallet_xcm.rs b/parachains/runtimes/assets/westmint/src/weights/pallet_xcm.rs index 65a8649c5b5..12b4dd66653 100644 --- a/parachains/runtimes/assets/westmint/src/weights/pallet_xcm.rs +++ b/parachains/runtimes/assets/westmint/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,7 +17,7 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 @@ -60,10 +60,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn send() -> Weight { // Proof Size summary in bytes: // Measured: `75` - // Estimated: `4830` - // Minimum execution time: 26_692 nanoseconds. - Weight::from_parts(27_382_000, 0) - .saturating_add(Weight::from_parts(0, 4830)) + // Estimated: `9780` + // Minimum execution time: 28_019_000 picoseconds. + Weight::from_parts(29_053_000, 0) + .saturating_add(Weight::from_parts(0, 9780)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,10 +72,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `499` - // Minimum execution time: 22_056 nanoseconds. - Weight::from_parts(22_401_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 24_127_000 picoseconds. + Weight::from_parts(24_609_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: ParachainInfo ParachainId (r:1 w:0) @@ -83,18 +83,18 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn reserve_transfer_assets() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `499` - // Minimum execution time: 16_901 nanoseconds. - Weight::from_parts(17_262_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 18_826_000 picoseconds. + Weight::from_parts(19_183_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } fn execute() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_467 nanoseconds. - Weight::from_parts(8_708_000, 0) + // Minimum execution time: 9_865_000 picoseconds. + Weight::from_parts(10_129_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: PolkadotXcm SupportedVersion (r:0 w:1) @@ -103,8 +103,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_532 nanoseconds. - Weight::from_parts(8_766_000, 0) + // Minimum execution time: 9_995_000 picoseconds. + Weight::from_parts(10_290_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -114,8 +114,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_399 nanoseconds. - Weight::from_parts(2_586_000, 0) + // Minimum execution time: 3_144_000 picoseconds. + Weight::from_parts(3_225_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -138,10 +138,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `75` - // Estimated: `8025` - // Minimum execution time: 30_956 nanoseconds. - Weight::from_parts(31_602_000, 0) - .saturating_add(Weight::from_parts(0, 8025)) + // Estimated: `14955` + // Minimum execution time: 33_946_000 picoseconds. + Weight::from_parts(34_595_000, 0) + .saturating_add(Weight::from_parts(0, 14955)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -162,10 +162,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `257` - // Estimated: `8729` - // Minimum execution time: 33_283 nanoseconds. - Weight::from_parts(34_433_000, 0) - .saturating_add(Weight::from_parts(0, 8729)) + // Estimated: `14669` + // Minimum execution time: 34_408_000 picoseconds. + Weight::from_parts(34_845_000, 0) + .saturating_add(Weight::from_parts(0, 14669)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -174,10 +174,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `129` - // Estimated: `10029` - // Minimum execution time: 17_349 nanoseconds. - Weight::from_parts(18_701_000, 0) - .saturating_add(Weight::from_parts(0, 10029)) + // Estimated: `11019` + // Minimum execution time: 17_219_000 picoseconds. + Weight::from_parts(17_552_000, 0) + .saturating_add(Weight::from_parts(0, 11019)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -186,10 +186,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `133` - // Estimated: `10033` - // Minimum execution time: 18_574 nanoseconds. - Weight::from_parts(19_071_000, 0) - .saturating_add(Weight::from_parts(0, 10033)) + // Estimated: `11023` + // Minimum execution time: 17_382_000 picoseconds. + Weight::from_parts(17_791_000, 0) + .saturating_add(Weight::from_parts(0, 11023)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -198,10 +198,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `140` - // Estimated: `12515` - // Minimum execution time: 22_520 nanoseconds. - Weight::from_parts(23_083_000, 0) - .saturating_add(Weight::from_parts(0, 12515)) + // Estimated: `13505` + // Minimum execution time: 18_051_000 picoseconds. + Weight::from_parts(18_643_000, 0) + .saturating_add(Weight::from_parts(0, 13505)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) @@ -219,10 +219,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `142` - // Estimated: `10257` - // Minimum execution time: 39_510 nanoseconds. - Weight::from_parts(40_272_000, 0) - .saturating_add(Weight::from_parts(0, 10257)) + // Estimated: `16197` + // Minimum execution time: 33_113_000 picoseconds. + Weight::from_parts(34_048_000, 0) + .saturating_add(Weight::from_parts(0, 16197)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -231,10 +231,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `172` - // Estimated: `7597` - // Minimum execution time: 11_057 nanoseconds. - Weight::from_parts(11_408_000, 0) - .saturating_add(Weight::from_parts(0, 7597)) + // Estimated: `8587` + // Minimum execution time: 9_569_000 picoseconds. + Weight::from_parts(9_933_000, 0) + .saturating_add(Weight::from_parts(0, 8587)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) @@ -242,10 +242,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `140` - // Estimated: `10040` - // Minimum execution time: 22_914 nanoseconds. - Weight::from_parts(23_231_000, 0) - .saturating_add(Weight::from_parts(0, 10040)) + // Estimated: `11030` + // Minimum execution time: 19_098_000 picoseconds. + Weight::from_parts(19_550_000, 0) + .saturating_add(Weight::from_parts(0, 11030)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -264,10 +264,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `146` - // Estimated: `15231` - // Minimum execution time: 47_637 nanoseconds. - Weight::from_parts(48_179_000, 0) - .saturating_add(Weight::from_parts(0, 15231)) + // Estimated: `21171` + // Minimum execution time: 40_365_000 picoseconds. + Weight::from_parts(41_092_000, 0) + .saturating_add(Weight::from_parts(0, 21171)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index bbaef6c16ec..66f6bd713d5 100644 --- a/parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -17,27 +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-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, 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` +//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./templates/xcm-bench-template.hbs +// --chain=westmint-dev // --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_xcm_benchmarks::fungible -// --chain=westmint-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/assets/westmint/src/weights/xcm/ +// --output=./parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -55,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 37_770_000 picoseconds. - Weight::from_parts(38_616_000, 3593) + // Minimum execution time: 22_591_000 picoseconds. + Weight::from_parts(23_052_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -66,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `6196` - // Minimum execution time: 33_080_000 picoseconds. - Weight::from_parts(33_350_000, 6196) + // Minimum execution time: 32_036_000 picoseconds. + Weight::from_parts(32_396_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -89,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `176` // Estimated: `17970` - // Minimum execution time: 94_868_000 picoseconds. - Weight::from_parts(95_349_000, 17970) + // Minimum execution time: 58_331_000 picoseconds. + Weight::from_parts(59_048_000, 17970) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -98,8 +97,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_378_000 picoseconds. - Weight::from_parts(4_471_000, 0) + // Minimum execution time: 4_474_000 picoseconds. + Weight::from_parts(4_577_000, 0) } // Storage: System Account (r:1 w:1) // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -107,8 +106,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `3593` - // Minimum execution time: 25_401_000 picoseconds. - Weight::from_parts(25_744_000, 3593) + // Minimum execution time: 28_611_000 picoseconds. + Weight::from_parts(28_992_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -130,8 +129,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `14862` - // Minimum execution time: 54_166_000 picoseconds. - Weight::from_parts(54_680_000, 14862) + // Minimum execution time: 57_179_000 picoseconds. + Weight::from_parts(58_149_000, 14862) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -151,8 +150,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `11269` - // Minimum execution time: 34_063_000 picoseconds. - Weight::from_parts(34_404_000, 11269) + // Minimum execution time: 30_477_000 picoseconds. + Weight::from_parts(30_841_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 1da9e6ecca4..67c2b083f89 100644 --- a/parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,27 +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-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, 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` +//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westmint-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./templates/xcm-bench-template.hbs +// --chain=westmint-dev // --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_xcm_benchmarks::generic -// --chain=westmint-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/assets/westmint/src/weights/xcm/ +// --output=./parachains/runtimes/assets/westmint/src/weights/xcm/pallet_xcm_benchmarks_generic.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -65,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `11269` - // Minimum execution time: 366_645_000 picoseconds. - Weight::from_parts(368_433_000, 11269) + // Minimum execution time: 355_263_000 picoseconds. + Weight::from_parts(357_327_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -74,8 +73,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_034_000 picoseconds. - Weight::from_parts(4_167_000, 0) + // Minimum execution time: 4_068_000 picoseconds. + Weight::from_parts(4_273_000, 0) } // Storage: PolkadotXcm Queries (r:1 w:0) // Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) @@ -83,58 +82,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `69` // Estimated: `3534` - // Minimum execution time: 11_582_000 picoseconds. - Weight::from_parts(11_769_000, 3534) + // Minimum execution time: 11_279_000 picoseconds. + Weight::from_parts(11_626_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_412_000 picoseconds. - Weight::from_parts(13_744_000, 0) + // Minimum execution time: 13_246_000 picoseconds. + Weight::from_parts(13_425_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_363_000 picoseconds. - Weight::from_parts(7_435_000, 0) + // Minimum execution time: 4_426_000 picoseconds. + Weight::from_parts(4_600_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_950_000 picoseconds. - Weight::from_parts(3_067_000, 0) + // Minimum execution time: 2_838_000 picoseconds. + Weight::from_parts(2_921_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_024_000 picoseconds. - Weight::from_parts(3_077_000, 0) + // Minimum execution time: 2_858_000 picoseconds. + Weight::from_parts(2_981_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_962_000 picoseconds. - Weight::from_parts(3_034_000, 0) + // Minimum execution time: 2_848_000 picoseconds. + Weight::from_parts(2_922_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_660_000 picoseconds. - Weight::from_parts(5_745_000, 0) + // Minimum execution time: 3_732_000 picoseconds. + Weight::from_parts(3_801_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_934_000 picoseconds. - Weight::from_parts(3_053_000, 0) + // Minimum execution time: 2_882_000 picoseconds. + Weight::from_parts(2_971_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -152,8 +151,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `11269` - // Minimum execution time: 25_725_000 picoseconds. - Weight::from_parts(26_363_000, 11269) + // Minimum execution time: 25_538_000 picoseconds. + Weight::from_parts(25_964_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -163,8 +162,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `126` // Estimated: `3591` - // Minimum execution time: 16_532_000 picoseconds. - Weight::from_parts(16_751_000, 3591) + // Minimum execution time: 16_187_000 picoseconds. + Weight::from_parts(16_478_000, 3591) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -172,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_902_000 picoseconds. - Weight::from_parts(3_028_000, 0) + // Minimum execution time: 2_804_000 picoseconds. + Weight::from_parts(2_874_000, 0) } // Storage: PolkadotXcm VersionNotifyTargets (r:1 w:1) // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) @@ -191,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `13320` - // Minimum execution time: 47_079_000 picoseconds. - Weight::from_parts(47_483_000, 13320) + // Minimum execution time: 28_208_000 picoseconds. + Weight::from_parts(28_512_000, 13320) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -202,8 +201,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_275_000 picoseconds. - Weight::from_parts(5_381_000, 0) + // Minimum execution time: 5_021_000 picoseconds. + Weight::from_parts(5_128_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: ParachainInfo ParachainId (r:1 w:0) @@ -222,8 +221,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `11269` - // Minimum execution time: 411_960_000 picoseconds. - Weight::from_parts(422_231_000, 11269) + // Minimum execution time: 403_561_000 picoseconds. + Weight::from_parts(404_798_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -231,36 +230,36 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 128_264_000 picoseconds. - Weight::from_parts(129_704_000, 0) + // Minimum execution time: 122_646_000 picoseconds. + Weight::from_parts(123_057_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_474_000 picoseconds. - Weight::from_parts(12_684_000, 0) + // Minimum execution time: 13_916_000 picoseconds. + Weight::from_parts(14_178_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_005_000 picoseconds. - Weight::from_parts(3_157_000, 0) + // Minimum execution time: 3_025_000 picoseconds. + Weight::from_parts(3_083_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_737_000 picoseconds. - Weight::from_parts(4_777_000, 0) + // Minimum execution time: 2_879_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: 3_126_000 picoseconds. - Weight::from_parts(3_195_000, 0) + // Minimum execution time: 3_067_000 picoseconds. + Weight::from_parts(3_129_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -278,8 +277,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `11269` - // Minimum execution time: 30_134_000 picoseconds. - Weight::from_parts(30_412_000, 11269) + // Minimum execution time: 29_511_000 picoseconds. + Weight::from_parts(29_922_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -287,8 +286,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_087_000 picoseconds. - Weight::from_parts(10_289_000, 0) + // Minimum execution time: 5_410_000 picoseconds. + Weight::from_parts(5_531_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -306,8 +305,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `75` // Estimated: `11269` - // Minimum execution time: 26_158_000 picoseconds. - Weight::from_parts(26_668_000, 11269) + // Minimum execution time: 26_044_000 picoseconds. + Weight::from_parts(26_397_000, 11269) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -315,35 +314,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_035_000 picoseconds. - Weight::from_parts(3_172_000, 0) + // Minimum execution time: 2_950_000 picoseconds. + Weight::from_parts(2_989_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_687_000 picoseconds. - Weight::from_parts(4_738_000, 0) + // Minimum execution time: 2_877_000 picoseconds. + Weight::from_parts(2_928_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_976_000 picoseconds. - Weight::from_parts(3_113_000, 0) + // Minimum execution time: 2_884_000 picoseconds. + Weight::from_parts(2_959_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_918_000 picoseconds. - Weight::from_parts(3_033_000, 0) + // Minimum execution time: 2_733_000 picoseconds. + Weight::from_parts(2_862_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_191_000 picoseconds. - Weight::from_parts(3_257_000, 0) + // Minimum execution time: 2_917_000 picoseconds. + Weight::from_parts(2_990_000, 0) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs index 8f8db4b53c5..4fa7848e6ff 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -52,10 +52,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_956 nanoseconds. - Weight::from_parts(5_247_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_373_000 picoseconds. + Weight::from_parts(5_599_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,10 +64,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_weight() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_875 nanoseconds. - Weight::from_parts(5_123_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_534_000 picoseconds. + Weight::from_parts(5_769_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/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs index 0d8b7fd939e..65925307177 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -52,22 +52,22 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_541 nanoseconds. - Weight::from_parts(1_600_000, 0) + // Minimum execution time: 2_314_000 picoseconds. + Weight::from_parts(2_371_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(368, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(369, 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_433 nanoseconds. - Weight::from_parts(6_528_000, 0) + // Minimum execution time: 7_667_000 picoseconds. + Weight::from_parts(7_755_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_718, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_414, 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) @@ -76,10 +76,10 @@ impl frame_system::WeightInfo for WeightInfo { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 3_378 nanoseconds. - Weight::from_parts(3_546_000, 0) - .saturating_add(Weight::from_parts(0, 495)) + // Estimated: `1485` + // Minimum execution time: 4_135_000 picoseconds. + Weight::from_parts(4_368_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,11 +90,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_595 nanoseconds. - Weight::from_parts(1_637_000, 0) + // Minimum execution time: 2_351_000 picoseconds. + Weight::from_parts(2_396_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_677 - .saturating_add(Weight::from_parts(581_830, 0).saturating_mul(i.into())) + // Standard Error: 1_912 + .saturating_add(Weight::from_parts(729_478, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -104,11 +104,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_602 nanoseconds. - Weight::from_parts(1_645_000, 0) + // Minimum execution time: 2_417_000 picoseconds. + Weight::from_parts(2_546_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 808 - .saturating_add(Weight::from_parts(448_210, 0).saturating_mul(i.into())) + // Standard Error: 842 + .saturating_add(Weight::from_parts(542_458, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -118,11 +118,12 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `68 + p * (69 ±0)` // Estimated: `66 + p * (70 ±0)` - // Minimum execution time: 3_400 nanoseconds. - Weight::from_parts(3_518_000, 0) + // Minimum execution time: 4_324_000 picoseconds. + Weight::from_parts(4_432_000, 0) .saturating_add(Weight::from_parts(0, 66)) - // Standard Error: 949 - .saturating_add(Weight::from_parts(952_748, 0).saturating_mul(p.into())) + // Standard Error: 1_165 + .saturating_add(Weight::from_parts(1_070_662, 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/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs index ad28ef7692c..7ea0437075a 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -51,11 +51,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1314` - // Estimated: `2603` - // Minimum execution time: 45_555 nanoseconds. - Weight::from_parts(46_097_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 34_147_000 picoseconds. + Weight::from_parts(34_681_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -63,11 +63,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1198` - // Estimated: `2603` - // Minimum execution time: 34_465 nanoseconds. - Weight::from_parts(35_054_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 25_961_000 picoseconds. + Weight::from_parts(26_543_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,11 +75,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1348` - // Estimated: `2603` - // Minimum execution time: 25_670 nanoseconds. - Weight::from_parts(26_254_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 15_954_000 picoseconds. + Weight::from_parts(16_276_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -87,11 +87,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1348` - // Estimated: `2603` - // Minimum execution time: 28_919 nanoseconds. - Weight::from_parts(29_611_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 19_074_000 picoseconds. + Weight::from_parts(19_635_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -99,11 +99,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1310` - // Estimated: `5206` - // Minimum execution time: 44_604 nanoseconds. - Weight::from_parts(45_498_000, 0) - .saturating_add(Weight::from_parts(0, 5206)) + // Measured: `103` + // Estimated: `6196` + // Minimum execution time: 36_772_000 picoseconds. + Weight::from_parts(37_193_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,11 +111,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1198` - // Estimated: `2603` - // Minimum execution time: 39_412 nanoseconds. - Weight::from_parts(40_181_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 32_430_000 picoseconds. + Weight::from_parts(32_766_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,11 +126,11 @@ impl pallet_balances::WeightInfo for WeightInfo { } fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1232` - // Estimated: `2603` - // Minimum execution time: 22_520 nanoseconds. - Weight::from_parts(23_045_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 15_239_000 picoseconds. + Weight::from_parts(15_620_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs index 7dc16ab0f0e..37d874e0b75 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -55,12 +55,12 @@ impl pallet_collator_selection::WeightInfo for WeightIn fn set_invulnerables(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `214 + b * (78 ±0)` - // Estimated: `213 + b * (2554 ±0)` - // Minimum execution time: 13_768 nanoseconds. - Weight::from_parts(15_128_018, 0) - .saturating_add(Weight::from_parts(0, 213)) - // Standard Error: 3_110 - .saturating_add(Weight::from_parts(2_490_861, 0).saturating_mul(b.into())) + // Estimated: `1203 + b * (2554 ±0)` + // Minimum execution time: 14_680_000 picoseconds. + Weight::from_parts(15_646_800, 0) + .saturating_add(Weight::from_parts(0, 1203)) + // Standard Error: 4_021 + .saturating_add(Weight::from_parts(2_556_895, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 2554).saturating_mul(b.into())) @@ -71,8 +71,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_359 nanoseconds. - Weight::from_parts(6_591_000, 0) + // Minimum execution time: 6_979_000 picoseconds. + Weight::from_parts(7_322_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,8 +82,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_722 nanoseconds. - Weight::from_parts(6_963_000, 0) + // Minimum execution time: 7_328_000 picoseconds. + Weight::from_parts(7_524_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,13 +102,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 999]`. fn register_as_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1167 + c * (48 ±0)` - // Estimated: `56785 + c * (49 ±0)` - // Minimum execution time: 35_190 nanoseconds. - Weight::from_parts(27_223_783, 0) - .saturating_add(Weight::from_parts(0, 56785)) - // Standard Error: 1_270 - .saturating_add(Weight::from_parts(103_824, 0).saturating_mul(c.into())) + // Measured: `1104 + c * (48 ±0)` + // Estimated: `61672 + c * (49 ±0)` + // Minimum execution time: 37_388_000 picoseconds. + Weight::from_parts(30_491_072, 0) + .saturating_add(Weight::from_parts(0, 61672)) + // Standard Error: 1_155 + .saturating_add(Weight::from_parts(100_794, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 49).saturating_mul(c.into())) @@ -120,13 +120,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[6, 1000]`. fn leave_intent(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `503 + c * (48 ±0)` - // Estimated: `48497` - // Minimum execution time: 26_271 nanoseconds. - Weight::from_parts(16_336_190, 0) - .saturating_add(Weight::from_parts(0, 48497)) - // Standard Error: 1_250 - .saturating_add(Weight::from_parts(105_123, 0).saturating_mul(c.into())) + // Measured: `428 + c * (48 ±0)` + // Estimated: `49487` + // Minimum execution time: 29_110_000 picoseconds. + Weight::from_parts(19_158_409, 0) + .saturating_add(Weight::from_parts(0, 49487)) + // Standard Error: 1_269 + .saturating_add(Weight::from_parts(104_083, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -138,11 +138,11 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { // Proof Size summary in bytes: - // Measured: `187` - // Estimated: `5749` - // Minimum execution time: 26_583 nanoseconds. - Weight::from_parts(26_888_000, 0) - .saturating_add(Weight::from_parts(0, 5749)) + // Measured: `155` + // Estimated: `7729` + // Minimum execution time: 29_086_000 picoseconds. + Weight::from_parts(29_931_000, 0) + .saturating_add(Weight::from_parts(0, 7729)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -160,18 +160,18 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 1000]`. fn new_session(r: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `22878 + r * (148 ±0) + c * (97 ±0)` - // Estimated: `52737 + c * (2519 ±0) + r * (2602 ±0)` - // Minimum execution time: 16_250 nanoseconds. - Weight::from_parts(16_601_000, 0) - .saturating_add(Weight::from_parts(0, 52737)) - // Standard Error: 763_853 - .saturating_add(Weight::from_parts(27_869_355, 0).saturating_mul(c.into())) + // Measured: `22815 + r * (116 ±0) + c * (97 ±0)` + // Estimated: `56697 + r * (2602 ±0) + c * (2520 ±0)` + // Minimum execution time: 16_710_000 picoseconds. + Weight::from_parts(16_907_000, 0) + .saturating_add(Weight::from_parts(0, 56697)) + // Standard Error: 800_677 + .saturating_add(Weight::from_parts(29_001_374, 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, 2602).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs index 0a0445094a1..56d954f12a0 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -52,11 +52,11 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_039 nanoseconds. - Weight::from_parts(12_378_049, 0) + // Minimum execution time: 12_068_000 picoseconds. + Weight::from_parts(12_319_883, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 1 - .saturating_add(Weight::from_parts(485, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(493, 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) @@ -64,15 +64,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `314 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 35_309 nanoseconds. - Weight::from_parts(28_767_595, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 572 - .saturating_add(Weight::from_parts(73_429, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 36_523_000 picoseconds. + Weight::from_parts(31_295_135, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 542 + .saturating_add(Weight::from_parts(60_423, 0).saturating_mul(s.into())) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_487, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_200, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,15 +82,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 26_191 nanoseconds. - Weight::from_parts(19_850_530, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 440 - .saturating_add(Weight::from_parts(68_426, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_505, 0).saturating_mul(z.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 27_342_000 picoseconds. + Weight::from_parts(21_614_247, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 546 + .saturating_add(Weight::from_parts(57_563, 0).saturating_mul(s.into())) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_202, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,15 +102,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// 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: `8424` - // Minimum execution time: 39_875 nanoseconds. - Weight::from_parts(32_057_678, 0) - .saturating_add(Weight::from_parts(0, 8424)) - // Standard Error: 715 - .saturating_add(Weight::from_parts(84_736, 0).saturating_mul(s.into())) - // Standard Error: 7 - .saturating_add(Weight::from_parts(1_511, 0).saturating_mul(z.into())) + // Measured: `388 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 41_465_000 picoseconds. + Weight::from_parts(34_511_085, 0) + .saturating_add(Weight::from_parts(0, 10404)) + // Standard Error: 467 + .saturating_add(Weight::from_parts(78_918, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_201, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -119,13 +119,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `321 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 25_536 nanoseconds. - Weight::from_parts(27_146_180, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 991 - .saturating_add(Weight::from_parts(77_408, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 27_868_000 picoseconds. + Weight::from_parts(29_407_652, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 632 + .saturating_add(Weight::from_parts(69_333, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -134,13 +134,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 17_409 nanoseconds. - Weight::from_parts(18_559_189, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 518 - .saturating_add(Weight::from_parts(72_083, 0).saturating_mul(s.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 18_599_000 picoseconds. + Weight::from_parts(19_776_275, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 522 + .saturating_add(Weight::from_parts(64_680, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,13 +149,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `517 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 26_502 nanoseconds. - Weight::from_parts(28_258_573, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 819 - .saturating_add(Weight::from_parts(78_480, 0).saturating_mul(s.into())) + // Measured: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 28_857_000 picoseconds. + Weight::from_parts(30_337_509, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 652 + .saturating_add(Weight::from_parts(67_443, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs index 2ec610d8eb1..bef2a83bc7c 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `297` - // Estimated: `5544` - // Minimum execution time: 15_673 nanoseconds. - Weight::from_parts(16_101_000, 0) - .saturating_add(Weight::from_parts(0, 5544)) + // Estimated: `7524` + // Minimum execution time: 17_925_000 picoseconds. + Weight::from_parts(18_292_000, 0) + .saturating_add(Weight::from_parts(0, 7524)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `279` - // Estimated: `3033` - // Minimum execution time: 12_241 nanoseconds. - Weight::from_parts(12_552_000, 0) - .saturating_add(Weight::from_parts(0, 3033)) + // Estimated: `4023` + // Minimum execution time: 13_384_000 picoseconds. + Weight::from_parts(13_788_000, 0) + .saturating_add(Weight::from_parts(0, 4023)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs index 47ec5a76e3f..c6b5b01504f 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl pallet_timestamp::WeightInfo for WeightInfo { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `49` - // Estimated: `1006` - // Minimum execution time: 7_105 nanoseconds. - Weight::from_parts(7_296_000, 0) - .saturating_add(Weight::from_parts(0, 1006)) + // Estimated: `2986` + // Minimum execution time: 7_946_000 picoseconds. + Weight::from_parts(8_181_000, 0) + .saturating_add(Weight::from_parts(0, 2986)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_timestamp::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `57` // Estimated: `0` - // Minimum execution time: 3_270 nanoseconds. - Weight::from_parts(3_398_000, 0) + // Minimum execution time: 3_219_000 picoseconds. + Weight::from_parts(3_298_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs index 2e3d628c32d..93eaff447ae 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -52,18 +52,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_752 nanoseconds. - Weight::from_parts(15_025_089, 0) + // Minimum execution time: 6_837_000 picoseconds. + Weight::from_parts(16_686_299, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_912 - .saturating_add(Weight::from_parts(3_735_986, 0).saturating_mul(c.into())) + // Standard Error: 3_233 + .saturating_add(Weight::from_parts(4_587_331, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_237 nanoseconds. - Weight::from_parts(4_392_000, 0) + // Minimum execution time: 5_582_000 picoseconds. + Weight::from_parts(5_700_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +71,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_645 nanoseconds. - Weight::from_parts(16_082_395, 0) + // Minimum execution time: 6_907_000 picoseconds. + Weight::from_parts(4_826_975, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_061 - .saturating_add(Weight::from_parts(3_918_503, 0).saturating_mul(c.into())) + // Standard Error: 3_801 + .saturating_add(Weight::from_parts(4_836_457, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_613 nanoseconds. - Weight::from_parts(7_868_000, 0) + // Minimum execution time: 8_998_000 picoseconds. + Weight::from_parts(9_220_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +90,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_909 nanoseconds. - Weight::from_parts(11_406_668, 0) + // Minimum execution time: 6_961_000 picoseconds. + Weight::from_parts(7_518_503, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_399 - .saturating_add(Weight::from_parts(3_759_278, 0).saturating_mul(c.into())) + // Standard Error: 3_307 + .saturating_add(Weight::from_parts(4_649_665, 0).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs index f625acb21f0..6210755b2bd 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: @@ -60,10 +60,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn send() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `4645` - // Minimum execution time: 23_601 nanoseconds. - Weight::from_parts(24_078_000, 0) - .saturating_add(Weight::from_parts(0, 4645)) + // Estimated: `9595` + // Minimum execution time: 26_368_000 picoseconds. + Weight::from_parts(27_314_000, 0) + .saturating_add(Weight::from_parts(0, 9595)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,10 +72,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `32` - // Estimated: `499` - // Minimum execution time: 23_225 nanoseconds. - Weight::from_parts(23_887_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 24_998_000 picoseconds. + Weight::from_parts(25_321_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Benchmark Override (r:0 w:0) @@ -84,7 +84,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -94,7 +94,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -104,8 +104,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_434 nanoseconds. - Weight::from_parts(8_839_000, 0) + // Minimum execution time: 9_733_000 picoseconds. + Weight::from_parts(10_002_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -115,8 +115,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_484 nanoseconds. - Weight::from_parts(2_611_000, 0) + // Minimum execution time: 3_073_000 picoseconds. + Weight::from_parts(3_178_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -139,10 +139,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `7729` - // Minimum execution time: 28_465 nanoseconds. - Weight::from_parts(29_023_000, 0) - .saturating_add(Weight::from_parts(0, 7729)) + // Estimated: `14659` + // Minimum execution time: 31_313_000 picoseconds. + Weight::from_parts(31_916_000, 0) + .saturating_add(Weight::from_parts(0, 14659)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -163,10 +163,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `220` - // Estimated: `8470` - // Minimum execution time: 31_086 nanoseconds. - Weight::from_parts(31_385_000, 0) - .saturating_add(Weight::from_parts(0, 8470)) + // Estimated: `14410` + // Minimum execution time: 32_721_000 picoseconds. + Weight::from_parts(33_013_000, 0) + .saturating_add(Weight::from_parts(0, 14410)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -175,10 +175,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `95` - // Estimated: `9995` - // Minimum execution time: 13_701 nanoseconds. - Weight::from_parts(13_987_000, 0) - .saturating_add(Weight::from_parts(0, 9995)) + // Estimated: `10985` + // Minimum execution time: 15_020_000 picoseconds. + Weight::from_parts(15_358_000, 0) + .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -187,10 +187,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `99` - // Estimated: `9999` - // Minimum execution time: 13_723 nanoseconds. - Weight::from_parts(14_166_000, 0) - .saturating_add(Weight::from_parts(0, 9999)) + // Estimated: `10989` + // Minimum execution time: 15_095_000 picoseconds. + Weight::from_parts(15_309_000, 0) + .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -199,10 +199,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `12481` - // Minimum execution time: 15_381 nanoseconds. - Weight::from_parts(16_770_000, 0) - .saturating_add(Weight::from_parts(0, 12481)) + // Estimated: `13471` + // Minimum execution time: 15_809_000 picoseconds. + Weight::from_parts(16_139_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) @@ -220,10 +220,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10041` - // Minimum execution time: 27_952 nanoseconds. - Weight::from_parts(28_321_000, 0) - .saturating_add(Weight::from_parts(0, 10041)) + // Estimated: `15981` + // Minimum execution time: 28_167_000 picoseconds. + Weight::from_parts(28_747_000, 0) + .saturating_add(Weight::from_parts(0, 15981)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -232,10 +232,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `7561` - // Minimum execution time: 8_516 nanoseconds. - Weight::from_parts(8_922_000, 0) - .saturating_add(Weight::from_parts(0, 7561)) + // Estimated: `8551` + // Minimum execution time: 8_484_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) @@ -243,10 +243,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10006` - // Minimum execution time: 16_615 nanoseconds. - Weight::from_parts(17_074_000, 0) - .saturating_add(Weight::from_parts(0, 10006)) + // Estimated: `10996` + // Minimum execution time: 15_814_000 picoseconds. + Weight::from_parts(16_131_000, 0) + .saturating_add(Weight::from_parts(0, 10996)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,10 +265,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `112` - // Estimated: `15027` - // Minimum execution time: 36_726 nanoseconds. - Weight::from_parts(37_319_000, 0) - .saturating_add(Weight::from_parts(0, 15027)) + // Estimated: `20967` + // Minimum execution time: 34_500_000 picoseconds. + Weight::from_parts(34_978_000, 0) + .saturating_add(Weight::from_parts(0, 20967)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index f2bda0d0fdf..648e0c7368a 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -19,24 +19,24 @@ //! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic= +// --template=./templates/xcm-bench-template.hbs +// --chain=bridge-hub-kusama-dev // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 // --pallet=pallet_xcm_benchmarks::fungible -// --chain=bridge-hub-kusama-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/ +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 22_950_000 picoseconds. - Weight::from_parts(23_170_000, 3593) + // Minimum execution time: 19_924_000 picoseconds. + Weight::from_parts(20_322_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 48_472_000 picoseconds. - Weight::from_parts(49_063_000, 6196) + // Minimum execution time: 32_669_000 picoseconds. + Weight::from_parts(33_313_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `223` // Estimated: `18205` - // Minimum execution time: 71_887_000 picoseconds. - Weight::from_parts(73_047_000, 18205) + // Minimum execution time: 55_574_000 picoseconds. + Weight::from_parts(56_148_000, 18205) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -97,8 +97,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_215_000 picoseconds. - Weight::from_parts(4_324_000, 0) + // Minimum execution time: 4_271_000 picoseconds. + Weight::from_parts(4_338_000, 0) } // Storage: System Account (r:1 w:1) // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -106,8 +106,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 26_047_000 picoseconds. - Weight::from_parts(26_386_000, 3593) + // Minimum execution time: 23_972_000 picoseconds. + Weight::from_parts(24_305_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -129,8 +129,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `15097` - // Minimum execution time: 51_076_000 picoseconds. - Weight::from_parts(51_638_000, 15097) + // Minimum execution time: 53_095_000 picoseconds. + Weight::from_parts(53_586_000, 15097) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -150,8 +150,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 28_242_000 picoseconds. - Weight::from_parts(28_778_000, 11244) + // Minimum execution time: 30_394_000 picoseconds. + Weight::from_parts(31_238_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 06d99ecdc55..738940ca868 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,27 +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-03-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, 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` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-kusama-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./templates/xcm-bench-template.hbs +// --chain=bridge-hub-kusama-dev // --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_xcm_benchmarks::generic -// --chain=bridge-hub-kusama-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/ +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/weights/xcm/pallet_xcm_benchmarks_generic.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -65,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 32_352_000 picoseconds. - Weight::from_parts(32_888_000, 11244) + // Minimum execution time: 30_841_000 picoseconds. + Weight::from_parts(31_223_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -74,8 +73,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_953_000 picoseconds. - Weight::from_parts(3_074_000, 0) + // Minimum execution time: 2_749_000 picoseconds. + Weight::from_parts(2_894_000, 0) } // Storage: PolkadotXcm Queries (r:1 w:0) // Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) @@ -83,58 +82,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 10_911_000 picoseconds. - Weight::from_parts(11_165_000, 3497) + // Minimum execution time: 10_637_000 picoseconds. + Weight::from_parts(10_904_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: 13_130_000 picoseconds. - Weight::from_parts(13_550_000, 0) + // Minimum execution time: 12_587_000 picoseconds. + Weight::from_parts(12_882_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_254_000 picoseconds. - Weight::from_parts(3_371_000, 0) + // Minimum execution time: 3_088_000 picoseconds. + Weight::from_parts(3_165_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_729_000 picoseconds. - Weight::from_parts(4_785_000, 0) + // Minimum execution time: 2_748_000 picoseconds. + Weight::from_parts(2_868_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_686_000 picoseconds. - Weight::from_parts(4_740_000, 0) + // Minimum execution time: 2_897_000 picoseconds. + Weight::from_parts(2_970_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_921_000 picoseconds. - Weight::from_parts(3_038_000, 0) + // Minimum execution time: 2_793_000 picoseconds. + Weight::from_parts(2_883_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_927_000 picoseconds. - Weight::from_parts(4_046_000, 0) + // Minimum execution time: 3_690_000 picoseconds. + Weight::from_parts(3_745_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_990_000 picoseconds. - Weight::from_parts(3_109_000, 0) + // Minimum execution time: 2_760_000 picoseconds. + Weight::from_parts(2_807_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -152,8 +151,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 25_335_000 picoseconds. - Weight::from_parts(25_862_000, 11244) + // Minimum execution time: 24_591_000 picoseconds. + Weight::from_parts(25_237_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -163,8 +162,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 15_097_000 picoseconds. - Weight::from_parts(15_401_000, 3555) + // Minimum execution time: 14_596_000 picoseconds. + Weight::from_parts(15_010_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -172,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_693_000 picoseconds. - Weight::from_parts(4_750_000, 0) + // Minimum execution time: 2_770_000 picoseconds. + Weight::from_parts(2_860_000, 0) } // Storage: PolkadotXcm VersionNotifyTargets (r:1 w:1) // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) @@ -191,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `13098` - // Minimum execution time: 26_630_000 picoseconds. - Weight::from_parts(27_169_000, 13098) + // Minimum execution time: 25_644_000 picoseconds. + Weight::from_parts(26_269_000, 13098) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -202,8 +201,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_050_000 picoseconds. - Weight::from_parts(5_304_000, 0) + // Minimum execution time: 4_969_000 picoseconds. + Weight::from_parts(5_167_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: ParachainInfo ParachainId (r:1 w:0) @@ -222,8 +221,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 28_942_000 picoseconds. - Weight::from_parts(29_475_000, 11244) + // Minimum execution time: 27_894_000 picoseconds. + Weight::from_parts(28_294_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -231,36 +230,36 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_736_000 picoseconds. - Weight::from_parts(4_871_000, 0) + // Minimum execution time: 4_595_000 picoseconds. + Weight::from_parts(4_709_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_127_000 picoseconds. - Weight::from_parts(3_217_000, 0) + // Minimum execution time: 2_957_000 picoseconds. + Weight::from_parts(3_035_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_972_000 picoseconds. - Weight::from_parts(3_073_000, 0) + // Minimum execution time: 3_091_000 picoseconds. + Weight::from_parts(3_197_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_737_000 picoseconds. - Weight::from_parts(4_810_000, 0) + // Minimum execution time: 2_953_000 picoseconds. + Weight::from_parts(3_036_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_166_000 picoseconds. - Weight::from_parts(3_240_000, 0) + // Minimum execution time: 3_275_000 picoseconds. + Weight::from_parts(3_382_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -278,8 +277,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 44_516_000 picoseconds. - Weight::from_parts(45_018_000, 11244) + // Minimum execution time: 30_240_000 picoseconds. + Weight::from_parts(30_533_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -287,8 +286,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_137_000 picoseconds. - Weight::from_parts(5_289_000, 0) + // Minimum execution time: 5_276_000 picoseconds. + Weight::from_parts(5_363_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -306,8 +305,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 25_978_000 picoseconds. - Weight::from_parts(26_490_000, 11244) + // Minimum execution time: 27_019_000 picoseconds. + Weight::from_parts(27_675_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -315,35 +314,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_018_000 picoseconds. - Weight::from_parts(3_148_000, 0) + // Minimum execution time: 3_136_000 picoseconds. + Weight::from_parts(3_210_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_667_000 picoseconds. - Weight::from_parts(4_737_000, 0) + // Minimum execution time: 2_989_000 picoseconds. + Weight::from_parts(3_067_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_955_000 picoseconds. - Weight::from_parts(3_018_000, 0) + // Minimum execution time: 3_004_000 picoseconds. + Weight::from_parts(3_101_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_008_000 picoseconds. - Weight::from_parts(3_113_000, 0) + // Minimum execution time: 2_996_000 picoseconds. + Weight::from_parts(3_068_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_137_000 picoseconds. - Weight::from_parts(3_230_000, 0) + // Minimum execution time: 3_102_000 picoseconds. + Weight::from_parts(3_210_000, 0) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs index 9ef3bbf0e06..77de70742ca 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,10 +52,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_798 nanoseconds. - Weight::from_parts(5_139_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_593_000 picoseconds. + Weight::from_parts(5_728_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,10 +64,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_weight() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_942 nanoseconds. - Weight::from_parts(5_056_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_432_000 picoseconds. + Weight::from_parts(5_592_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/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs index 996fbc01dc8..6560a1546a5 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,22 +52,22 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_628 nanoseconds. - Weight::from_parts(1_691_000, 0) + // Minimum execution time: 2_129_000 picoseconds. + Weight::from_parts(2_213_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(369, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(370, 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_332 nanoseconds. - Weight::from_parts(6_564_000, 0) + // Minimum execution time: 7_415_000 picoseconds. + Weight::from_parts(7_510_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_714, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_412, 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) @@ -76,10 +76,10 @@ impl frame_system::WeightInfo for WeightInfo { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 3_441 nanoseconds. - Weight::from_parts(3_684_000, 0) - .saturating_add(Weight::from_parts(0, 495)) + // Estimated: `1485` + // Minimum execution time: 4_227_000 picoseconds. + Weight::from_parts(4_495_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,11 +90,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_698 nanoseconds. - Weight::from_parts(1_802_000, 0) + // Minimum execution time: 2_349_000 picoseconds. + Weight::from_parts(2_381_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_738 - .saturating_add(Weight::from_parts(576_825, 0).saturating_mul(i.into())) + // Standard Error: 1_813 + .saturating_add(Weight::from_parts(685_377, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -104,11 +104,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_782 nanoseconds. - Weight::from_parts(1_826_000, 0) + // Minimum execution time: 2_250_000 picoseconds. + Weight::from_parts(2_317_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 808 - .saturating_add(Weight::from_parts(446_795, 0).saturating_mul(i.into())) + // Standard Error: 911 + .saturating_add(Weight::from_parts(494_503, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -118,11 +118,12 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `68 + p * (69 ±0)` // Estimated: `66 + p * (70 ±0)` - // Minimum execution time: 3_444 nanoseconds. - Weight::from_parts(3_538_000, 0) + // Minimum execution time: 4_239_000 picoseconds. + Weight::from_parts(4_380_000, 0) .saturating_add(Weight::from_parts(0, 66)) - // Standard Error: 920 - .saturating_add(Weight::from_parts(950_898, 0).saturating_mul(p.into())) + // Standard Error: 1_255 + .saturating_add(Weight::from_parts(1_012_115, 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/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs index 12aceb95985..a6547ab46fb 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -51,11 +51,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1316` - // Estimated: `2603` - // Minimum execution time: 44_427 nanoseconds. - Weight::from_parts(45_164_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 35_006_000 picoseconds. + Weight::from_parts(35_375_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -63,11 +63,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1200` - // Estimated: `2603` - // Minimum execution time: 34_287 nanoseconds. - Weight::from_parts(34_918_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 25_755_000 picoseconds. + Weight::from_parts(26_176_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,11 +75,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1350` - // Estimated: `2603` - // Minimum execution time: 25_850 nanoseconds. - Weight::from_parts(26_521_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 15_651_000 picoseconds. + Weight::from_parts(16_056_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -87,11 +87,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1350` - // Estimated: `2603` - // Minimum execution time: 29_118 nanoseconds. - Weight::from_parts(29_706_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 18_932_000 picoseconds. + Weight::from_parts(19_186_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -99,11 +99,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1312` - // Estimated: `5206` - // Minimum execution time: 45_010 nanoseconds. - Weight::from_parts(45_568_000, 0) - .saturating_add(Weight::from_parts(0, 5206)) + // Measured: `103` + // Estimated: `6196` + // Minimum execution time: 36_593_000 picoseconds. + Weight::from_parts(36_971_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,11 +111,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1200` - // Estimated: `2603` - // Minimum execution time: 39_332 nanoseconds. - Weight::from_parts(40_015_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 31_795_000 picoseconds. + Weight::from_parts(32_237_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,11 +126,11 @@ impl pallet_balances::WeightInfo for WeightInfo { } fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1234` - // Estimated: `2603` - // Minimum execution time: 22_710 nanoseconds. - Weight::from_parts(23_111_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 15_120_000 picoseconds. + Weight::from_parts(15_360_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs index 6140c4de67d..5c35eff5f53 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -55,12 +55,12 @@ impl pallet_collator_selection::WeightInfo for WeightIn fn set_invulnerables(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `214 + b * (78 ±0)` - // Estimated: `213 + b * (2554 ±0)` - // Minimum execution time: 13_937 nanoseconds. - Weight::from_parts(14_498_919, 0) - .saturating_add(Weight::from_parts(0, 213)) - // Standard Error: 2_987 - .saturating_add(Weight::from_parts(2_491_437, 0).saturating_mul(b.into())) + // Estimated: `1203 + b * (2554 ±0)` + // Minimum execution time: 14_444_000 picoseconds. + Weight::from_parts(15_006_377, 0) + .saturating_add(Weight::from_parts(0, 1203)) + // Standard Error: 2_965 + .saturating_add(Weight::from_parts(2_598_095, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 2554).saturating_mul(b.into())) @@ -71,8 +71,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_465 nanoseconds. - Weight::from_parts(6_739_000, 0) + // Minimum execution time: 6_886_000 picoseconds. + Weight::from_parts(7_053_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,8 +82,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_624 nanoseconds. - Weight::from_parts(6_822_000, 0) + // Minimum execution time: 7_233_000 picoseconds. + Weight::from_parts(7_420_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,13 +102,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 999]`. fn register_as_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1167 + c * (48 ±0)` - // Estimated: `56785 + c * (49 ±0)` - // Minimum execution time: 34_794 nanoseconds. - Weight::from_parts(27_197_409, 0) - .saturating_add(Weight::from_parts(0, 56785)) - // Standard Error: 1_259 - .saturating_add(Weight::from_parts(101_424, 0).saturating_mul(c.into())) + // Measured: `1104 + c * (48 ±0)` + // Estimated: `61672 + c * (49 ±0)` + // Minimum execution time: 37_455_000 picoseconds. + Weight::from_parts(29_651_534, 0) + .saturating_add(Weight::from_parts(0, 61672)) + // Standard Error: 1_287 + .saturating_add(Weight::from_parts(103_531, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 49).saturating_mul(c.into())) @@ -120,13 +120,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[6, 1000]`. fn leave_intent(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `503 + c * (48 ±0)` - // Estimated: `48497` - // Minimum execution time: 26_471 nanoseconds. - Weight::from_parts(16_092_836, 0) - .saturating_add(Weight::from_parts(0, 48497)) - // Standard Error: 1_283 - .saturating_add(Weight::from_parts(103_788, 0).saturating_mul(c.into())) + // Measured: `428 + c * (48 ±0)` + // Estimated: `49487` + // Minimum execution time: 29_548_000 picoseconds. + Weight::from_parts(18_882_873, 0) + .saturating_add(Weight::from_parts(0, 49487)) + // Standard Error: 1_273 + .saturating_add(Weight::from_parts(105_000, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -138,11 +138,11 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { // Proof Size summary in bytes: - // Measured: `187` - // Estimated: `5749` - // Minimum execution time: 25_597 nanoseconds. - Weight::from_parts(25_981_000, 0) - .saturating_add(Weight::from_parts(0, 5749)) + // Measured: `155` + // Estimated: `7729` + // Minimum execution time: 28_960_000 picoseconds. + Weight::from_parts(29_435_000, 0) + .saturating_add(Weight::from_parts(0, 7729)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -160,18 +160,18 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 1000]`. fn new_session(r: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `22878 + r * (148 ±0) + c * (97 ±0)` - // Estimated: `52737 + c * (2519 ±0) + r * (2602 ±0)` - // Minimum execution time: 15_961 nanoseconds. - Weight::from_parts(16_207_000, 0) - .saturating_add(Weight::from_parts(0, 52737)) - // Standard Error: 748_921 - .saturating_add(Weight::from_parts(27_460_211, 0).saturating_mul(c.into())) + // Measured: `22815 + r * (116 ±0) + c * (97 ±0)` + // Estimated: `56697 + c * (2520 ±0) + r * (2602 ±0)` + // Minimum execution time: 16_727_000 picoseconds. + Weight::from_parts(16_932_000, 0) + .saturating_add(Weight::from_parts(0, 56697)) + // Standard Error: 798_306 + .saturating_add(Weight::from_parts(28_951_019, 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, 2520).saturating_mul(c.into())) .saturating_add(Weight::from_parts(0, 2602).saturating_mul(r.into())) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs index aec763c0d53..9ab2d5a58a6 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,11 +52,11 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_693 nanoseconds. - Weight::from_parts(12_218_501, 0) + // Minimum execution time: 11_761_000 picoseconds. + Weight::from_parts(12_373_119, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(479, 0).saturating_mul(z.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(482, 0).saturating_mul(z.into())) } /// Storage: Multisig Multisigs (r:1 w:1) /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) @@ -64,15 +64,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `314 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 35_181 nanoseconds. - Weight::from_parts(28_585_764, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 609 - .saturating_add(Weight::from_parts(72_658, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 36_964_000 picoseconds. + Weight::from_parts(31_553_347, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 571 + .saturating_add(Weight::from_parts(62_042, 0).saturating_mul(s.into())) // Standard Error: 5 - .saturating_add(Weight::from_parts(1_476, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_178, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,15 +82,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 26_110 nanoseconds. - Weight::from_parts(19_809_417, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 448 - .saturating_add(Weight::from_parts(69_542, 0).saturating_mul(s.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 27_113_000 picoseconds. + Weight::from_parts(21_794_796, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 423 + .saturating_add(Weight::from_parts(59_156, 0).saturating_mul(s.into())) // Standard Error: 4 - .saturating_add(Weight::from_parts(1_514, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_193, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,15 +102,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// 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: `8424` - // Minimum execution time: 39_991 nanoseconds. - Weight::from_parts(31_329_529, 0) - .saturating_add(Weight::from_parts(0, 8424)) - // Standard Error: 567 - .saturating_add(Weight::from_parts(90_826, 0).saturating_mul(s.into())) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_527, 0).saturating_mul(z.into())) + // Measured: `388 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 41_979_000 picoseconds. + Weight::from_parts(34_970_639, 0) + .saturating_add(Weight::from_parts(0, 10404)) + // Standard Error: 481 + .saturating_add(Weight::from_parts(76_814, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_191, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -119,13 +119,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `321 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 25_124 nanoseconds. - Weight::from_parts(26_655_548, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 743 - .saturating_add(Weight::from_parts(78_904, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 28_113_000 picoseconds. + Weight::from_parts(29_657_007, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 746 + .saturating_add(Weight::from_parts(67_176, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -134,13 +134,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 16_950 nanoseconds. - Weight::from_parts(18_308_894, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 676 - .saturating_add(Weight::from_parts(71_574, 0).saturating_mul(s.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 19_227_000 picoseconds. + Weight::from_parts(20_043_765, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_458 + .saturating_add(Weight::from_parts(70_065, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,13 +149,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `517 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 26_127 nanoseconds. - Weight::from_parts(27_889_146, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 729 - .saturating_add(Weight::from_parts(78_618, 0).saturating_mul(s.into())) + // Measured: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 29_358_000 picoseconds. + Weight::from_parts(30_953_779, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 662 + .saturating_add(Weight::from_parts(62_100, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs index 9008424b30b..cd7f40253b5 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `297` - // Estimated: `5544` - // Minimum execution time: 15_314 nanoseconds. - Weight::from_parts(15_944_000, 0) - .saturating_add(Weight::from_parts(0, 5544)) + // Estimated: `7524` + // Minimum execution time: 17_305_000 picoseconds. + Weight::from_parts(17_673_000, 0) + .saturating_add(Weight::from_parts(0, 7524)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `279` - // Estimated: `3033` - // Minimum execution time: 11_831 nanoseconds. - Weight::from_parts(12_113_000, 0) - .saturating_add(Weight::from_parts(0, 3033)) + // Estimated: `4023` + // Minimum execution time: 13_593_000 picoseconds. + Weight::from_parts(13_826_000, 0) + .saturating_add(Weight::from_parts(0, 4023)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs index 0d1f0325958..b22fe963f12 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl pallet_timestamp::WeightInfo for WeightInfo { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `49` - // Estimated: `1006` - // Minimum execution time: 6_885 nanoseconds. - Weight::from_parts(7_281_000, 0) - .saturating_add(Weight::from_parts(0, 1006)) + // Estimated: `2986` + // Minimum execution time: 7_665_000 picoseconds. + Weight::from_parts(7_892_000, 0) + .saturating_add(Weight::from_parts(0, 2986)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_timestamp::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `57` // Estimated: `0` - // Minimum execution time: 3_222 nanoseconds. - Weight::from_parts(3_321_000, 0) + // Minimum execution time: 3_226_000 picoseconds. + Weight::from_parts(3_339_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs index a88680f69c5..34c36b874a1 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,18 +52,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_910 nanoseconds. - Weight::from_parts(5_269_110, 0) + // Minimum execution time: 7_083_000 picoseconds. + Weight::from_parts(13_037_767, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_509 - .saturating_add(Weight::from_parts(3_869_188, 0).saturating_mul(c.into())) + // Standard Error: 3_155 + .saturating_add(Weight::from_parts(4_503_244, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_304 nanoseconds. - Weight::from_parts(4_463_000, 0) + // Minimum execution time: 5_705_000 picoseconds. + Weight::from_parts(5_799_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +71,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_985 nanoseconds. - Weight::from_parts(10_119_502, 0) + // Minimum execution time: 7_248_000 picoseconds. + Weight::from_parts(14_495_670, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_585 - .saturating_add(Weight::from_parts(4_063_211, 0).saturating_mul(c.into())) + // Standard Error: 3_240 + .saturating_add(Weight::from_parts(4_790_508, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_746 nanoseconds. - Weight::from_parts(8_027_000, 0) + // Minimum execution time: 9_355_000 picoseconds. + Weight::from_parts(9_596_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +90,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_082 nanoseconds. - Weight::from_parts(10_385_233, 0) + // Minimum execution time: 6_985_000 picoseconds. + Weight::from_parts(17_435_570, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_217 - .saturating_add(Weight::from_parts(3_855_940, 0).saturating_mul(c.into())) + // Standard Error: 3_165 + .saturating_add(Weight::from_parts(4_492_577, 0).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs index c1d015a2442..db01f989e76 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -60,10 +60,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn send() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `4645` - // Minimum execution time: 24_136 nanoseconds. - Weight::from_parts(24_562_000, 0) - .saturating_add(Weight::from_parts(0, 4645)) + // Estimated: `9595` + // Minimum execution time: 25_890_000 picoseconds. + Weight::from_parts(26_601_000, 0) + .saturating_add(Weight::from_parts(0, 9595)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,10 +72,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `32` - // Estimated: `499` - // Minimum execution time: 23_272 nanoseconds. - Weight::from_parts(23_644_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 24_961_000 picoseconds. + Weight::from_parts(25_332_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Benchmark Override (r:0 w:0) @@ -84,7 +84,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -94,7 +94,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -104,8 +104,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_377 nanoseconds. - Weight::from_parts(8_642_000, 0) + // Minimum execution time: 9_662_000 picoseconds. + Weight::from_parts(9_844_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -115,8 +115,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_435 nanoseconds. - Weight::from_parts(2_556_000, 0) + // Minimum execution time: 2_994_000 picoseconds. + Weight::from_parts(3_160_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -139,10 +139,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `7729` - // Minimum execution time: 28_539 nanoseconds. - Weight::from_parts(29_177_000, 0) - .saturating_add(Weight::from_parts(0, 7729)) + // Estimated: `14659` + // Minimum execution time: 31_632_000 picoseconds. + Weight::from_parts(31_919_000, 0) + .saturating_add(Weight::from_parts(0, 14659)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -163,10 +163,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `220` - // Estimated: `8470` - // Minimum execution time: 30_607 nanoseconds. - Weight::from_parts(31_019_000, 0) - .saturating_add(Weight::from_parts(0, 8470)) + // Estimated: `14410` + // Minimum execution time: 32_570_000 picoseconds. + Weight::from_parts(33_292_000, 0) + .saturating_add(Weight::from_parts(0, 14410)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -175,10 +175,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `95` - // Estimated: `9995` - // Minimum execution time: 13_842 nanoseconds. - Weight::from_parts(14_281_000, 0) - .saturating_add(Weight::from_parts(0, 9995)) + // Estimated: `10985` + // Minimum execution time: 14_829_000 picoseconds. + Weight::from_parts(15_171_000, 0) + .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -187,10 +187,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `99` - // Estimated: `9999` - // Minimum execution time: 13_505 nanoseconds. - Weight::from_parts(13_981_000, 0) - .saturating_add(Weight::from_parts(0, 9999)) + // Estimated: `10989` + // Minimum execution time: 14_774_000 picoseconds. + Weight::from_parts(15_232_000, 0) + .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -199,10 +199,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `12481` - // Minimum execution time: 16_415 nanoseconds. - Weight::from_parts(16_752_000, 0) - .saturating_add(Weight::from_parts(0, 12481)) + // Estimated: `13471` + // Minimum execution time: 15_289_000 picoseconds. + Weight::from_parts(15_543_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) @@ -220,10 +220,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10041` - // Minimum execution time: 29_952 nanoseconds. - Weight::from_parts(30_592_000, 0) - .saturating_add(Weight::from_parts(0, 10041)) + // Estimated: `15981` + // Minimum execution time: 27_849_000 picoseconds. + Weight::from_parts(28_243_000, 0) + .saturating_add(Weight::from_parts(0, 15981)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -232,10 +232,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `7561` - // Minimum execution time: 8_259 nanoseconds. - Weight::from_parts(8_608_000, 0) - .saturating_add(Weight::from_parts(0, 7561)) + // Estimated: `8551` + // Minimum execution time: 8_260_000 picoseconds. + Weight::from_parts(8_477_000, 0) + .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) @@ -243,10 +243,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10006` - // Minimum execution time: 16_259 nanoseconds. - Weight::from_parts(16_574_000, 0) - .saturating_add(Weight::from_parts(0, 10006)) + // Estimated: `10996` + // Minimum execution time: 15_132_000 picoseconds. + Weight::from_parts(15_581_000, 0) + .saturating_add(Weight::from_parts(0, 10996)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,10 +265,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `112` - // Estimated: `15027` - // Minimum execution time: 35_748 nanoseconds. - Weight::from_parts(36_667_000, 0) - .saturating_add(Weight::from_parts(0, 15027)) + // Estimated: `20967` + // Minimum execution time: 34_016_000 picoseconds. + Weight::from_parts(34_627_000, 0) + .saturating_add(Weight::from_parts(0, 20967)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index a7527f00baf..16110f554b2 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -19,24 +19,24 @@ //! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic= +// --template=./templates/xcm-bench-template.hbs +// --chain=bridge-hub-polkadot-dev // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 // --pallet=pallet_xcm_benchmarks::fungible -// --chain=bridge-hub-polkadot-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/ +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 22_155_000 picoseconds. - Weight::from_parts(22_991_000, 3593) + // Minimum execution time: 20_647_000 picoseconds. + Weight::from_parts(20_978_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 48_986_000 picoseconds. - Weight::from_parts(49_467_000, 6196) + // Minimum execution time: 32_995_000 picoseconds. + Weight::from_parts(33_365_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `223` // Estimated: `18205` - // Minimum execution time: 72_291_000 picoseconds. - Weight::from_parts(72_898_000, 18205) + // Minimum execution time: 56_568_000 picoseconds. + Weight::from_parts(57_462_000, 18205) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -97,8 +97,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_225_000 picoseconds. - Weight::from_parts(4_328_000, 0) + // Minimum execution time: 4_070_000 picoseconds. + Weight::from_parts(4_200_000, 0) } // Storage: System Account (r:1 w:1) // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -106,8 +106,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 26_357_000 picoseconds. - Weight::from_parts(26_841_000, 3593) + // Minimum execution time: 24_036_000 picoseconds. + Weight::from_parts(24_587_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -129,8 +129,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `15097` - // Minimum execution time: 50_981_000 picoseconds. - Weight::from_parts(51_488_000, 15097) + // Minimum execution time: 49_836_000 picoseconds. + Weight::from_parts(50_507_000, 15097) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -150,8 +150,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 28_333_000 picoseconds. - Weight::from_parts(28_863_000, 11244) + // Minimum execution time: 28_353_000 picoseconds. + Weight::from_parts(29_151_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 44bd54ab174..f8320dad59b 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,27 +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-03-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, 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` +//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("bridge-hub-polkadot-dev"), DB CACHE: 1024 // Executed Command: -// target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* +// --template=./templates/xcm-bench-template.hbs +// --chain=bridge-hub-polkadot-dev // --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_xcm_benchmarks::generic -// --chain=bridge-hub-polkadot-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/ +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/weights/xcm/pallet_xcm_benchmarks_generic.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -65,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 47_079_000 picoseconds. - Weight::from_parts(47_477_000, 11244) + // Minimum execution time: 30_983_000 picoseconds. + Weight::from_parts(31_396_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -74,8 +73,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_810_000 picoseconds. - Weight::from_parts(4_856_000, 0) + // Minimum execution time: 2_966_000 picoseconds. + Weight::from_parts(3_066_000, 0) } // Storage: PolkadotXcm Queries (r:1 w:0) // Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) @@ -83,58 +82,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 11_148_000 picoseconds. - Weight::from_parts(17_709_000, 3497) + // Minimum execution time: 11_159_000 picoseconds. + Weight::from_parts(11_390_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: 12_942_000 picoseconds. - Weight::from_parts(13_226_000, 0) + // Minimum execution time: 12_987_000 picoseconds. + Weight::from_parts(13_337_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_413_000 picoseconds. - Weight::from_parts(3_490_000, 0) + // Minimum execution time: 3_107_000 picoseconds. + Weight::from_parts(3_182_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_110_000 picoseconds. - Weight::from_parts(3_144_000, 0) + // Minimum execution time: 2_957_000 picoseconds. + Weight::from_parts(3_022_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_038_000 picoseconds. - Weight::from_parts(3_118_000, 0) + // Minimum execution time: 2_979_000 picoseconds. + Weight::from_parts(3_088_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_044_000 picoseconds. - Weight::from_parts(4_700_000, 0) + // Minimum execution time: 2_934_000 picoseconds. + Weight::from_parts(2_989_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_936_000 picoseconds. - Weight::from_parts(4_039_000, 0) + // Minimum execution time: 3_817_000 picoseconds. + Weight::from_parts(3_898_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_070_000 picoseconds. - Weight::from_parts(3_286_000, 0) + // Minimum execution time: 3_021_000 picoseconds. + Weight::from_parts(3_083_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -152,8 +151,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 25_430_000 picoseconds. - Weight::from_parts(25_714_000, 11244) + // Minimum execution time: 25_036_000 picoseconds. + Weight::from_parts(25_379_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -163,8 +162,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 15_180_000 picoseconds. - Weight::from_parts(24_431_000, 3555) + // Minimum execution time: 15_074_000 picoseconds. + Weight::from_parts(15_310_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -172,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_682_000 picoseconds. - Weight::from_parts(4_753_000, 0) + // Minimum execution time: 2_996_000 picoseconds. + Weight::from_parts(3_040_000, 0) } // Storage: PolkadotXcm VersionNotifyTargets (r:1 w:1) // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) @@ -191,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `13098` - // Minimum execution time: 26_337_000 picoseconds. - Weight::from_parts(26_730_000, 13098) + // Minimum execution time: 26_142_000 picoseconds. + Weight::from_parts(26_578_000, 13098) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -202,8 +201,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_260_000 picoseconds. - Weight::from_parts(5_417_000, 0) + // Minimum execution time: 5_216_000 picoseconds. + Weight::from_parts(5_304_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: ParachainInfo ParachainId (r:1 w:0) @@ -222,8 +221,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 28_590_000 picoseconds. - Weight::from_parts(28_931_000, 11244) + // Minimum execution time: 28_236_000 picoseconds. + Weight::from_parts(28_614_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -231,36 +230,36 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_745_000 picoseconds. - Weight::from_parts(4_853_000, 0) + // Minimum execution time: 4_701_000 picoseconds. + Weight::from_parts(4_783_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_214_000 picoseconds. - Weight::from_parts(3_276_000, 0) + // Minimum execution time: 3_121_000 picoseconds. + Weight::from_parts(3_177_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_779_000 picoseconds. - Weight::from_parts(4_824_000, 0) + // Minimum execution time: 3_106_000 picoseconds. + Weight::from_parts(3_343_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_986_000 picoseconds. - Weight::from_parts(3_098_000, 0) + // Minimum execution time: 3_151_000 picoseconds. + Weight::from_parts(3_226_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_272_000 picoseconds. - Weight::from_parts(3_351_000, 0) + // Minimum execution time: 3_362_000 picoseconds. + Weight::from_parts(3_453_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -278,8 +277,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 28_219_000 picoseconds. - Weight::from_parts(28_796_000, 11244) + // Minimum execution time: 30_472_000 picoseconds. + Weight::from_parts(30_906_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -287,8 +286,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_023_000 picoseconds. - Weight::from_parts(5_108_000, 0) + // Minimum execution time: 5_383_000 picoseconds. + Weight::from_parts(5_496_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -306,8 +305,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 25_253_000 picoseconds. - Weight::from_parts(25_685_000, 11244) + // Minimum execution time: 26_946_000 picoseconds. + Weight::from_parts(27_774_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -315,35 +314,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_085_000 picoseconds. - Weight::from_parts(3_135_000, 0) + // Minimum execution time: 3_192_000 picoseconds. + Weight::from_parts(3_262_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_099_000 picoseconds. - Weight::from_parts(3_147_000, 0) + // Minimum execution time: 3_129_000 picoseconds. + Weight::from_parts(3_199_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_101_000 picoseconds. - Weight::from_parts(3_174_000, 0) + // Minimum execution time: 3_156_000 picoseconds. + Weight::from_parts(3_202_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_034_000 picoseconds. - Weight::from_parts(3_118_000, 0) + // Minimum execution time: 3_114_000 picoseconds. + Weight::from_parts(3_208_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_156_000 picoseconds. - Weight::from_parts(3_254_000, 0) + // Minimum execution time: 3_315_000 picoseconds. + Weight::from_parts(3_374_000, 0) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs index 5b1d95701e3..638e1354d91 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -52,10 +52,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_865 nanoseconds. - Weight::from_parts(5_007_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_434_000 picoseconds. + Weight::from_parts(5_663_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,10 +64,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_weight() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_893 nanoseconds. - Weight::from_parts(5_198_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_301_000 picoseconds. + Weight::from_parts(5_415_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/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs index 612ff1690fb..ed5e6270415 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -52,22 +52,22 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_592 nanoseconds. - Weight::from_parts(679_524, 0) + // Minimum execution time: 2_311_000 picoseconds. + Weight::from_parts(2_347_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(367, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(370, 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_673 nanoseconds. - Weight::from_parts(6_751_000, 0) + // Minimum execution time: 7_875_000 picoseconds. + Weight::from_parts(7_972_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_715, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_410, 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) @@ -76,10 +76,10 @@ impl frame_system::WeightInfo for WeightInfo { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 3_408 nanoseconds. - Weight::from_parts(3_633_000, 0) - .saturating_add(Weight::from_parts(0, 495)) + // Estimated: `1485` + // Minimum execution time: 4_309_000 picoseconds. + Weight::from_parts(4_457_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,11 +90,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_727 nanoseconds. - Weight::from_parts(1_753_000, 0) + // Minimum execution time: 2_526_000 picoseconds. + Weight::from_parts(2_564_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1_876 - .saturating_add(Weight::from_parts(581_935, 0).saturating_mul(i.into())) + // Standard Error: 1_869 + .saturating_add(Weight::from_parts(678_765, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -104,11 +104,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_743 nanoseconds. - Weight::from_parts(1_769_000, 0) + // Minimum execution time: 2_526_000 picoseconds. + Weight::from_parts(2_603_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 803 - .saturating_add(Weight::from_parts(446_779, 0).saturating_mul(i.into())) + // Standard Error: 899 + .saturating_add(Weight::from_parts(497_948, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -118,11 +118,12 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `68 + p * (69 ±0)` // Estimated: `66 + p * (70 ±0)` - // Minimum execution time: 3_536 nanoseconds. - Weight::from_parts(3_649_000, 0) + // Minimum execution time: 4_280_000 picoseconds. + Weight::from_parts(4_398_000, 0) .saturating_add(Weight::from_parts(0, 66)) - // Standard Error: 949 - .saturating_add(Weight::from_parts(986_632, 0).saturating_mul(p.into())) + // Standard Error: 1_108 + .saturating_add(Weight::from_parts(1_011_188, 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/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs index 4d364d79ba3..5b57a5b7b4d 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -51,11 +51,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1314` - // Estimated: `2603` - // Minimum execution time: 47_893 nanoseconds. - Weight::from_parts(48_384_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 35_746_000 picoseconds. + Weight::from_parts(36_167_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -63,11 +63,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1198` - // Estimated: `2603` - // Minimum execution time: 35_027 nanoseconds. - Weight::from_parts(35_675_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 26_301_000 picoseconds. + Weight::from_parts(26_847_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,11 +75,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1348` - // Estimated: `2603` - // Minimum execution time: 26_009 nanoseconds. - Weight::from_parts(26_448_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 16_073_000 picoseconds. + Weight::from_parts(16_292_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -87,11 +87,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1348` - // Estimated: `2603` - // Minimum execution time: 30_006 nanoseconds. - Weight::from_parts(30_501_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 19_589_000 picoseconds. + Weight::from_parts(20_034_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -99,11 +99,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1310` - // Estimated: `5206` - // Minimum execution time: 46_787 nanoseconds. - Weight::from_parts(47_700_000, 0) - .saturating_add(Weight::from_parts(0, 5206)) + // Measured: `103` + // Estimated: `6196` + // Minimum execution time: 37_416_000 picoseconds. + Weight::from_parts(37_894_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,11 +111,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1198` - // Estimated: `2603` - // Minimum execution time: 43_890 nanoseconds. - Weight::from_parts(44_914_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 32_565_000 picoseconds. + Weight::from_parts(33_087_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,11 +126,11 @@ impl pallet_balances::WeightInfo for WeightInfo { } fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1232` - // Estimated: `2603` - // Minimum execution time: 26_785 nanoseconds. - Weight::from_parts(27_404_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `174` + // Estimated: `3593` + // Minimum execution time: 15_291_000 picoseconds. + Weight::from_parts(15_614_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs index dcf8f3170b5..cf4ee2028f7 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -55,12 +55,12 @@ impl pallet_collator_selection::WeightInfo for WeightIn fn set_invulnerables(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `214 + b * (78 ±0)` - // Estimated: `213 + b * (2554 ±0)` - // Minimum execution time: 14_254 nanoseconds. - Weight::from_parts(15_028_628, 0) - .saturating_add(Weight::from_parts(0, 213)) - // Standard Error: 3_094 - .saturating_add(Weight::from_parts(2_490_219, 0).saturating_mul(b.into())) + // Estimated: `1203 + b * (2554 ±0)` + // Minimum execution time: 14_833_000 picoseconds. + Weight::from_parts(15_349_415, 0) + .saturating_add(Weight::from_parts(0, 1203)) + // Standard Error: 3_477 + .saturating_add(Weight::from_parts(2_639_530, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 2554).saturating_mul(b.into())) @@ -71,8 +71,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_548 nanoseconds. - Weight::from_parts(6_775_000, 0) + // Minimum execution time: 7_190_000 picoseconds. + Weight::from_parts(7_558_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,8 +82,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_922 nanoseconds. - Weight::from_parts(7_184_000, 0) + // Minimum execution time: 7_435_000 picoseconds. + Weight::from_parts(7_790_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,13 +102,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 999]`. fn register_as_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1167 + c * (48 ±0)` - // Estimated: `56785 + c * (49 ±0)` - // Minimum execution time: 35_329 nanoseconds. - Weight::from_parts(27_879_325, 0) - .saturating_add(Weight::from_parts(0, 56785)) - // Standard Error: 1_269 - .saturating_add(Weight::from_parts(108_458, 0).saturating_mul(c.into())) + // Measured: `1104 + c * (48 ±0)` + // Estimated: `61672 + c * (49 ±0)` + // Minimum execution time: 38_999_000 picoseconds. + Weight::from_parts(31_254_595, 0) + .saturating_add(Weight::from_parts(0, 61672)) + // Standard Error: 1_266 + .saturating_add(Weight::from_parts(108_612, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 49).saturating_mul(c.into())) @@ -120,13 +120,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[6, 1000]`. fn leave_intent(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `503 + c * (48 ±0)` - // Estimated: `48497` - // Minimum execution time: 27_322 nanoseconds. - Weight::from_parts(16_354_913, 0) - .saturating_add(Weight::from_parts(0, 48497)) - // Standard Error: 1_399 - .saturating_add(Weight::from_parts(108_840, 0).saturating_mul(c.into())) + // Measured: `428 + c * (48 ±0)` + // Estimated: `49487` + // Minimum execution time: 29_894_000 picoseconds. + Weight::from_parts(19_491_329, 0) + .saturating_add(Weight::from_parts(0, 49487)) + // Standard Error: 1_328 + .saturating_add(Weight::from_parts(109_217, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -138,11 +138,11 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { // Proof Size summary in bytes: - // Measured: `187` - // Estimated: `5749` - // Minimum execution time: 26_074 nanoseconds. - Weight::from_parts(26_574_000, 0) - .saturating_add(Weight::from_parts(0, 5749)) + // Measured: `155` + // Estimated: `7729` + // Minimum execution time: 29_666_000 picoseconds. + Weight::from_parts(30_017_000, 0) + .saturating_add(Weight::from_parts(0, 7729)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -160,18 +160,18 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 1000]`. fn new_session(r: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `22878 + r * (148 ±0) + c * (97 ±0)` - // Estimated: `52737 + r * (2602 ±0) + c * (2519 ±0)` - // Minimum execution time: 15_727 nanoseconds. - Weight::from_parts(16_001_000, 0) - .saturating_add(Weight::from_parts(0, 52737)) - // Standard Error: 792_964 - .saturating_add(Weight::from_parts(28_827_951, 0).saturating_mul(c.into())) + // Measured: `22815 + r * (116 ±0) + c * (97 ±0)` + // Estimated: `56697 + r * (2602 ±0) + c * (2520 ±0)` + // Minimum execution time: 17_009_000 picoseconds. + Weight::from_parts(17_119_000, 0) + .saturating_add(Weight::from_parts(0, 56697)) + // Standard Error: 839_085 + .saturating_add(Weight::from_parts(30_312_617, 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, 2602).saturating_mul(r.into())) - .saturating_add(Weight::from_parts(0, 2519).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs index c39e4a6bd31..df58cf7952a 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -52,11 +52,11 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_903 nanoseconds. - Weight::from_parts(12_398_025, 0) + // Minimum execution time: 12_203_000 picoseconds. + Weight::from_parts(12_687_394, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(550, 0).saturating_mul(z.into())) + // Standard Error: 2 + .saturating_add(Weight::from_parts(556, 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) @@ -64,15 +64,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `314 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 35_780 nanoseconds. - Weight::from_parts(29_310_705, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 602 - .saturating_add(Weight::from_parts(70_837, 0).saturating_mul(s.into())) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_545, 0).saturating_mul(z.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 37_793_000 picoseconds. + Weight::from_parts(32_841_866, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 973 + .saturating_add(Weight::from_parts(64_271, 0).saturating_mul(s.into())) + // Standard Error: 9 + .saturating_add(Weight::from_parts(1_189, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,15 +82,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 26_552 nanoseconds. - Weight::from_parts(19_998_713, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 711 - .saturating_add(Weight::from_parts(72_463, 0).saturating_mul(s.into())) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_573, 0).saturating_mul(z.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 27_835_000 picoseconds. + Weight::from_parts(22_419_199, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 535 + .saturating_add(Weight::from_parts(59_729, 0).saturating_mul(s.into())) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_259, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,15 +102,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// 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: `8424` - // Minimum execution time: 40_836 nanoseconds. - Weight::from_parts(32_275_692, 0) - .saturating_add(Weight::from_parts(0, 8424)) - // Standard Error: 673 - .saturating_add(Weight::from_parts(92_895, 0).saturating_mul(s.into())) - // Standard Error: 6 - .saturating_add(Weight::from_parts(1_569, 0).saturating_mul(z.into())) + // Measured: `388 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 43_060_000 picoseconds. + Weight::from_parts(36_326_276, 0) + .saturating_add(Weight::from_parts(0, 10404)) + // Standard Error: 497 + .saturating_add(Weight::from_parts(76_443, 0).saturating_mul(s.into())) + // Standard Error: 4 + .saturating_add(Weight::from_parts(1_257, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -119,13 +119,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `321 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 26_440 nanoseconds. - Weight::from_parts(27_434_937, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 725 - .saturating_add(Weight::from_parts(80_283, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 29_242_000 picoseconds. + Weight::from_parts(30_673_516, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 651 + .saturating_add(Weight::from_parts(67_820, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -134,13 +134,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 17_335 nanoseconds. - Weight::from_parts(18_873_349, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 490 - .saturating_add(Weight::from_parts(74_017, 0).saturating_mul(s.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 19_344_000 picoseconds. + Weight::from_parts(20_956_909, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 781 + .saturating_add(Weight::from_parts(65_374, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,13 +149,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `517 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 26_731 nanoseconds. - Weight::from_parts(28_534_422, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 740 - .saturating_add(Weight::from_parts(78_223, 0).saturating_mul(s.into())) + // Measured: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 30_222_000 picoseconds. + Weight::from_parts(31_457_558, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 648 + .saturating_add(Weight::from_parts(67_068, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs index 136f7ec532e..67883fab331 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -54,10 +54,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `297` - // Estimated: `5544` - // Minimum execution time: 15_721 nanoseconds. - Weight::from_parts(16_081_000, 0) - .saturating_add(Weight::from_parts(0, 5544)) + // Estimated: `7524` + // Minimum execution time: 17_590_000 picoseconds. + Weight::from_parts(18_134_000, 0) + .saturating_add(Weight::from_parts(0, 7524)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `279` - // Estimated: `3033` - // Minimum execution time: 12_031 nanoseconds. - Weight::from_parts(12_339_000, 0) - .saturating_add(Weight::from_parts(0, 3033)) + // Estimated: `4023` + // Minimum execution time: 13_479_000 picoseconds. + Weight::from_parts(13_956_000, 0) + .saturating_add(Weight::from_parts(0, 4023)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs index d3db098c7f7..7be7f6691f0 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -54,10 +54,10 @@ impl pallet_timestamp::WeightInfo for WeightInfo { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `49` - // Estimated: `1006` - // Minimum execution time: 7_216 nanoseconds. - Weight::from_parts(7_445_000, 0) - .saturating_add(Weight::from_parts(0, 1006)) + // Estimated: `2986` + // Minimum execution time: 7_610_000 picoseconds. + Weight::from_parts(7_887_000, 0) + .saturating_add(Weight::from_parts(0, 2986)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_timestamp::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `57` // Estimated: `0` - // Minimum execution time: 3_181 nanoseconds. - Weight::from_parts(3_322_000, 0) + // Minimum execution time: 3_100_000 picoseconds. + Weight::from_parts(3_180_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs index ad7c0b79161..2420a70d1fb 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -52,18 +52,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_179 nanoseconds. - Weight::from_parts(19_315_482, 0) + // Minimum execution time: 7_051_000 picoseconds. + Weight::from_parts(10_722_806, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_383 - .saturating_add(Weight::from_parts(4_126_811, 0).saturating_mul(c.into())) + // Standard Error: 4_213 + .saturating_add(Weight::from_parts(4_992_366, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_474 nanoseconds. - Weight::from_parts(4_666_000, 0) + // Minimum execution time: 5_831_000 picoseconds. + Weight::from_parts(6_014_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +71,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_210 nanoseconds. - Weight::from_parts(12_190_913, 0) + // Minimum execution time: 7_394_000 picoseconds. + Weight::from_parts(15_396_332, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_328 - .saturating_add(Weight::from_parts(4_370_533, 0).saturating_mul(c.into())) + // Standard Error: 3_533 + .saturating_add(Weight::from_parts(5_302_383, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_194 nanoseconds. - Weight::from_parts(8_300_000, 0) + // Minimum execution time: 9_730_000 picoseconds. + Weight::from_parts(9_988_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +90,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_207 nanoseconds. - Weight::from_parts(9_704_236, 0) + // Minimum execution time: 7_395_000 picoseconds. + Weight::from_parts(14_933_943, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 4_155 - .saturating_add(Weight::from_parts(4_130_222, 0).saturating_mul(c.into())) + // Standard Error: 3_208 + .saturating_add(Weight::from_parts(4_963_051, 0).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs index d640aa27a07..6472867bfbc 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: @@ -60,10 +60,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn send() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `4645` - // Minimum execution time: 25_656 nanoseconds. - Weight::from_parts(25_942_000, 0) - .saturating_add(Weight::from_parts(0, 4645)) + // Estimated: `9595` + // Minimum execution time: 27_429_000 picoseconds. + Weight::from_parts(28_626_000, 0) + .saturating_add(Weight::from_parts(0, 9595)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,10 +72,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `32` - // Estimated: `499` - // Minimum execution time: 26_559 nanoseconds. - Weight::from_parts(27_040_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 27_626_000 picoseconds. + Weight::from_parts(28_561_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Benchmark Override (r:0 w:0) @@ -84,7 +84,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -94,7 +94,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -104,8 +104,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_204 nanoseconds. - Weight::from_parts(9_400_000, 0) + // Minimum execution time: 10_264_000 picoseconds. + Weight::from_parts(10_601_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -115,8 +115,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_652 nanoseconds. - Weight::from_parts(2_790_000, 0) + // Minimum execution time: 3_218_000 picoseconds. + Weight::from_parts(3_311_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -139,10 +139,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `7729` - // Minimum execution time: 29_636 nanoseconds. - Weight::from_parts(30_041_000, 0) - .saturating_add(Weight::from_parts(0, 7729)) + // Estimated: `14659` + // Minimum execution time: 33_037_000 picoseconds. + Weight::from_parts(33_559_000, 0) + .saturating_add(Weight::from_parts(0, 14659)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -163,10 +163,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `220` - // Estimated: `8470` - // Minimum execution time: 31_854 nanoseconds. - Weight::from_parts(32_416_000, 0) - .saturating_add(Weight::from_parts(0, 8470)) + // Estimated: `14410` + // Minimum execution time: 34_280_000 picoseconds. + Weight::from_parts(34_943_000, 0) + .saturating_add(Weight::from_parts(0, 14410)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -175,10 +175,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `95` - // Estimated: `9995` - // Minimum execution time: 13_994 nanoseconds. - Weight::from_parts(14_361_000, 0) - .saturating_add(Weight::from_parts(0, 9995)) + // Estimated: `10985` + // Minimum execution time: 15_106_000 picoseconds. + Weight::from_parts(15_383_000, 0) + .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -187,10 +187,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `99` - // Estimated: `9999` - // Minimum execution time: 14_337 nanoseconds. - Weight::from_parts(14_651_000, 0) - .saturating_add(Weight::from_parts(0, 9999)) + // Estimated: `10989` + // Minimum execution time: 15_129_000 picoseconds. + Weight::from_parts(15_489_000, 0) + .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -199,10 +199,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `12481` - // Minimum execution time: 15_624 nanoseconds. - Weight::from_parts(15_936_000, 0) - .saturating_add(Weight::from_parts(0, 12481)) + // Estimated: `13471` + // Minimum execution time: 15_526_000 picoseconds. + Weight::from_parts(15_778_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) @@ -220,10 +220,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10041` - // Minimum execution time: 26_774 nanoseconds. - Weight::from_parts(27_140_000, 0) - .saturating_add(Weight::from_parts(0, 10041)) + // Estimated: `15981` + // Minimum execution time: 29_457_000 picoseconds. + Weight::from_parts(29_970_000, 0) + .saturating_add(Weight::from_parts(0, 15981)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -232,10 +232,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `7561` - // Minimum execution time: 7_233 nanoseconds. - Weight::from_parts(7_487_000, 0) - .saturating_add(Weight::from_parts(0, 7561)) + // Estimated: `8551` + // Minimum execution time: 8_264_000 picoseconds. + Weight::from_parts(8_518_000, 0) + .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) @@ -243,10 +243,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10006` - // Minimum execution time: 14_801 nanoseconds. - Weight::from_parts(15_090_000, 0) - .saturating_add(Weight::from_parts(0, 10006)) + // Estimated: `10996` + // Minimum execution time: 15_633_000 picoseconds. + Weight::from_parts(16_006_000, 0) + .saturating_add(Weight::from_parts(0, 10996)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,10 +265,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `112` - // Estimated: `15027` - // Minimum execution time: 32_613 nanoseconds. - Weight::from_parts(32_978_000, 0) - .saturating_add(Weight::from_parts(0, 15027)) + // Estimated: `20967` + // Minimum execution time: 35_849_000 picoseconds. + Weight::from_parts(36_545_000, 0) + .saturating_add(Weight::from_parts(0, 20967)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs index 36bcef1cc4a..731111e358e 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs @@ -19,24 +19,24 @@ //! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: -// ./target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic= +// --template=./templates/xcm-bench-template.hbs +// --chain=bridge-hub-rococo-dev // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 // --pallet=pallet_xcm_benchmarks::fungible -// --chain=bridge-hub-rococo-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/ +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_fungible.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,8 +54,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `101` // Estimated: `3593` - // Minimum execution time: 22_222_000 picoseconds. - Weight::from_parts(22_591_000, 3593) + // Minimum execution time: 21_045_000 picoseconds. + Weight::from_parts(21_781_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `153` // Estimated: `6196` - // Minimum execution time: 47_612_000 picoseconds. - Weight::from_parts(48_901_000, 6196) + // Minimum execution time: 33_123_000 picoseconds. + Weight::from_parts(33_378_000, 6196) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -88,8 +88,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `223` // Estimated: `18205` - // Minimum execution time: 72_062_000 picoseconds. - Weight::from_parts(73_077_000, 18205) + // Minimum execution time: 57_689_000 picoseconds. + Weight::from_parts(58_320_000, 18205) .saturating_add(T::DbWeight::get().reads(8)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -97,8 +97,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_363_000 picoseconds. - Weight::from_parts(4_430_000, 0) + // Minimum execution time: 4_838_000 picoseconds. + Weight::from_parts(4_906_000, 0) } // Storage: System Account (r:1 w:1) // Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) @@ -106,8 +106,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `52` // Estimated: `3593` - // Minimum execution time: 26_314_000 picoseconds. - Weight::from_parts(26_624_000, 3593) + // Minimum execution time: 25_197_000 picoseconds. + Weight::from_parts(25_562_000, 3593) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -129,8 +129,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `122` // Estimated: `15097` - // Minimum execution time: 51_846_000 picoseconds. - Weight::from_parts(52_430_000, 15097) + // Minimum execution time: 52_159_000 picoseconds. + Weight::from_parts(52_637_000, 15097) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -150,8 +150,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 28_548_000 picoseconds. - Weight::from_parts(28_880_000, 11244) + // Minimum execution time: 30_471_000 picoseconds. + Weight::from_parts(31_112_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index d3df54c32e5..8572163a52b 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -19,24 +19,24 @@ //! 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: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm2`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm5`, 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: -// ./target/production/polkadot-parachain +// ./artifacts/polkadot-parachain // benchmark // pallet -// --steps=50 -// --repeat=20 -// --extrinsic= +// --template=./templates/xcm-bench-template.hbs +// --chain=bridge-hub-rococo-dev // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 // --pallet=pallet_xcm_benchmarks::generic -// --chain=bridge-hub-rococo-dev +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json // --header=./file_header.txt -// --template=./templates/xcm-bench-template.hbs -// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/ +// --output=./parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -64,8 +64,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 32_220_000 picoseconds. - Weight::from_parts(32_574_000, 11244) + // Minimum execution time: 34_238_000 picoseconds. + Weight::from_parts(34_851_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -73,8 +73,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_996_000 picoseconds. - Weight::from_parts(3_070_000, 0) + // Minimum execution time: 3_358_000 picoseconds. + Weight::from_parts(3_437_000, 0) } // Storage: PolkadotXcm Queries (r:1 w:0) // Proof Skipped: PolkadotXcm Queries (max_values: None, max_size: None, mode: Measured) @@ -82,58 +82,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 11_181_000 picoseconds. - Weight::from_parts(11_426_000, 3497) + // Minimum execution time: 11_623_000 picoseconds. + Weight::from_parts(11_814_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: 13_273_000 picoseconds. - Weight::from_parts(13_574_000, 0) + // Minimum execution time: 13_934_000 picoseconds. + Weight::from_parts(14_111_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_283_000 picoseconds. - Weight::from_parts(3_387_000, 0) + // Minimum execution time: 3_562_000 picoseconds. + Weight::from_parts(3_689_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_008_000 picoseconds. - Weight::from_parts(3_062_000, 0) + // Minimum execution time: 3_280_000 picoseconds. + Weight::from_parts(3_345_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_901_000 picoseconds. - Weight::from_parts(2_989_000, 0) + // Minimum execution time: 3_243_000 picoseconds. + Weight::from_parts(3_335_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_924_000 picoseconds. - Weight::from_parts(3_008_000, 0) + // Minimum execution time: 3_280_000 picoseconds. + Weight::from_parts(3_347_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_820_000 picoseconds. - Weight::from_parts(3_887_000, 0) + // Minimum execution time: 4_270_000 picoseconds. + Weight::from_parts(4_358_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_939_000 picoseconds. - Weight::from_parts(3_004_000, 0) + // Minimum execution time: 3_245_000 picoseconds. + Weight::from_parts(3_320_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -151,8 +151,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 25_166_000 picoseconds. - Weight::from_parts(25_591_000, 11244) + // Minimum execution time: 26_653_000 picoseconds. + Weight::from_parts(27_139_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -162,8 +162,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 15_169_000 picoseconds. - Weight::from_parts(15_391_000, 3555) + // Minimum execution time: 15_478_000 picoseconds. + Weight::from_parts(15_763_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -171,8 +171,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_909_000 picoseconds. - Weight::from_parts(3_048_000, 0) + // Minimum execution time: 3_237_000 picoseconds. + Weight::from_parts(3_314_000, 0) } // Storage: PolkadotXcm VersionNotifyTargets (r:1 w:1) // Proof Skipped: PolkadotXcm VersionNotifyTargets (max_values: None, max_size: None, mode: Measured) @@ -190,8 +190,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `13098` - // Minimum execution time: 26_031_000 picoseconds. - Weight::from_parts(26_630_000, 13098) + // Minimum execution time: 29_098_000 picoseconds. + Weight::from_parts(29_368_000, 13098) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -201,8 +201,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_011_000 picoseconds. - Weight::from_parts(5_237_000, 0) + // Minimum execution time: 6_253_000 picoseconds. + Weight::from_parts(6_467_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } // Storage: ParachainInfo ParachainId (r:1 w:0) @@ -221,8 +221,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 28_361_000 picoseconds. - Weight::from_parts(28_811_000, 11244) + // Minimum execution time: 35_061_000 picoseconds. + Weight::from_parts(35_510_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -230,36 +230,36 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_542_000 picoseconds. - Weight::from_parts(4_636_000, 0) + // Minimum execution time: 6_154_000 picoseconds. + Weight::from_parts(6_266_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_041_000 picoseconds. - Weight::from_parts(3_123_000, 0) + // Minimum execution time: 4_009_000 picoseconds. + Weight::from_parts(4_088_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_004_000 picoseconds. - Weight::from_parts(3_103_000, 0) + // Minimum execution time: 3_873_000 picoseconds. + Weight::from_parts(3_996_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_976_000 picoseconds. - Weight::from_parts(3_033_000, 0) + // Minimum execution time: 3_759_000 picoseconds. + Weight::from_parts(3_820_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_116_000 picoseconds. - Weight::from_parts(3_196_000, 0) + // Minimum execution time: 3_985_000 picoseconds. + Weight::from_parts(4_132_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -277,8 +277,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 28_513_000 picoseconds. - Weight::from_parts(28_839_000, 11244) + // Minimum execution time: 34_686_000 picoseconds. + Weight::from_parts(35_233_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -286,8 +286,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_977_000 picoseconds. - Weight::from_parts(5_091_000, 0) + // Minimum execution time: 6_129_000 picoseconds. + Weight::from_parts(6_244_000, 0) } // Storage: ParachainInfo ParachainId (r:1 w:0) // Proof: ParachainInfo ParachainId (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) @@ -305,8 +305,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `70` // Estimated: `11244` - // Minimum execution time: 25_256_000 picoseconds. - Weight::from_parts(25_827_000, 11244) + // Minimum execution time: 31_502_000 picoseconds. + Weight::from_parts(32_131_000, 11244) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -314,35 +314,35 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_979_000 picoseconds. - Weight::from_parts(3_078_000, 0) + // Minimum execution time: 3_747_000 picoseconds. + Weight::from_parts(3_832_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_939_000 picoseconds. - Weight::from_parts(3_000_000, 0) + // Minimum execution time: 3_825_000 picoseconds. + Weight::from_parts(3_857_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_832_000 picoseconds. - Weight::from_parts(2_910_000, 0) + // Minimum execution time: 3_777_000 picoseconds. + Weight::from_parts(3_868_000, 0) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_901_000 picoseconds. - Weight::from_parts(2_977_000, 0) + // Minimum execution time: 3_710_000 picoseconds. + Weight::from_parts(3_820_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_031_000 picoseconds. - Weight::from_parts(3_128_000, 0) + // Minimum execution time: 3_876_000 picoseconds. + Weight::from_parts(4_012_000, 0) } } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs index 1d777ad3d11..0e7cf604304 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/cumulus_pallet_xcmp_queue.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `cumulus_pallet_xcmp_queue` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,10 +52,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_u32() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 4_808 nanoseconds. - Weight::from_parts(4_966_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_477_000 picoseconds. + Weight::from_parts(5_623_000, 0) + .saturating_add(Weight::from_parts(0, 1561)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -64,10 +64,10 @@ impl cumulus_pallet_xcmp_queue::WeightInfo for WeightIn fn set_config_with_weight() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `571` - // Minimum execution time: 5_014 nanoseconds. - Weight::from_parts(5_135_000, 0) - .saturating_add(Weight::from_parts(0, 571)) + // Estimated: `1561` + // Minimum execution time: 5_510_000 picoseconds. + Weight::from_parts(5_676_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/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs index 763568d1811..7bd018bd341 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/frame_system.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `frame_system` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,22 +52,22 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_643 nanoseconds. - Weight::from_parts(1_672_000, 0) + // Minimum execution time: 2_300_000 picoseconds. + Weight::from_parts(2_345_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(368, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(370, 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_679 nanoseconds. - Weight::from_parts(6_737_000, 0) + // Minimum execution time: 8_053_000 picoseconds. + Weight::from_parts(8_155_000, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(1_714, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(1_414, 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) @@ -76,10 +76,10 @@ impl frame_system::WeightInfo for WeightInfo { fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` - // Estimated: `495` - // Minimum execution time: 3_675 nanoseconds. - Weight::from_parts(3_915_000, 0) - .saturating_add(Weight::from_parts(0, 495)) + // Estimated: `1485` + // Minimum execution time: 4_456_000 picoseconds. + Weight::from_parts(4_609_000, 0) + .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -90,11 +90,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_789 nanoseconds. - Weight::from_parts(1_840_000, 0) + // Minimum execution time: 2_370_000 picoseconds. + Weight::from_parts(2_403_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_081 - .saturating_add(Weight::from_parts(587_667, 0).saturating_mul(i.into())) + // Standard Error: 1_643 + .saturating_add(Weight::from_parts(676_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) @@ -104,11 +104,11 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_849 nanoseconds. - Weight::from_parts(1_915_000, 0) + // Minimum execution time: 2_342_000 picoseconds. + Weight::from_parts(2_394_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 798 - .saturating_add(Weight::from_parts(446_723, 0).saturating_mul(i.into())) + // Standard Error: 917 + .saturating_add(Weight::from_parts(502_661, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } /// Storage: Skipped Metadata (r:0 w:0) @@ -118,11 +118,12 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `68 + p * (69 ±0)` // Estimated: `69 + p * (70 ±0)` - // Minimum execution time: 3_503 nanoseconds. - Weight::from_parts(3_574_000, 0) + // Minimum execution time: 4_461_000 picoseconds. + Weight::from_parts(4_561_000, 0) .saturating_add(Weight::from_parts(0, 69)) - // Standard Error: 948 - .saturating_add(Weight::from_parts(949_091, 0).saturating_mul(p.into())) + // Standard Error: 1_428 + .saturating_add(Weight::from_parts(1_016_381, 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/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs index 7016937d11c..f8bf9ca73dd 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_alliance.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_alliance` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -62,17 +62,17 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `502 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `10983 + m * (128 ±0) + p * (144 ±0)` - // Minimum execution time: 26_997 nanoseconds. - Weight::from_parts(28_875_691, 0) - .saturating_add(Weight::from_parts(0, 10983)) - // Standard Error: 65 - .saturating_add(Weight::from_parts(235, 0).saturating_mul(b.into())) - // Standard Error: 683 - .saturating_add(Weight::from_parts(17_740, 0).saturating_mul(m.into())) - // Standard Error: 675 - .saturating_add(Weight::from_parts(88_731, 0).saturating_mul(p.into())) + // Measured: `439 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `14703 + m * (128 ±0) + p * (144 ±0)` + // Minimum execution time: 29_793_000 picoseconds. + Weight::from_parts(31_622_009, 0) + .saturating_add(Weight::from_parts(0, 14703)) + // Standard Error: 59 + .saturating_add(Weight::from_parts(194, 0).saturating_mul(b.into())) + // Standard Error: 626 + .saturating_add(Weight::from_parts(16_277, 0).saturating_mul(m.into())) + // Standard Error: 618 + .saturating_add(Weight::from_parts(115_342, 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, 128).saturating_mul(m.into())) @@ -85,13 +85,13 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `932 + m * (64 ±0)` - // Estimated: `9092 + m * (64 ±0)` - // Minimum execution time: 23_241 nanoseconds. - Weight::from_parts(23_786_275, 0) - .saturating_add(Weight::from_parts(0, 9092)) - // Standard Error: 563 - .saturating_add(Weight::from_parts(44_164, 0).saturating_mul(m.into())) + // Measured: `868 + m * (64 ±0)` + // Estimated: `11008 + m * (64 ±0)` + // Minimum execution time: 24_860_000 picoseconds. + Weight::from_parts(25_540_583, 0) + .saturating_add(Weight::from_parts(0, 11008)) + // Standard Error: 1_049 + .saturating_add(Weight::from_parts(44_450, 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())) @@ -110,15 +110,15 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `438 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `11067 + m * (388 ±0) + p * (144 ±0)` - // Minimum execution time: 32_551 nanoseconds. - Weight::from_parts(30_322_236, 0) - .saturating_add(Weight::from_parts(0, 11067)) - // Standard Error: 695 - .saturating_add(Weight::from_parts(44_336, 0).saturating_mul(m.into())) - // Standard Error: 678 - .saturating_add(Weight::from_parts(83_273, 0).saturating_mul(p.into())) + // Measured: `312 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `14519 + m * (388 ±0) + p * (144 ±0)` + // Minimum execution time: 35_120_000 picoseconds. + Weight::from_parts(33_274_472, 0) + .saturating_add(Weight::from_parts(0, 14519)) + // Standard Error: 1_030 + .saturating_add(Weight::from_parts(41_853, 0).saturating_mul(m.into())) + // Standard Error: 1_004 + .saturating_add(Weight::from_parts(111_626, 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, 388).saturating_mul(m.into())) @@ -139,15 +139,15 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// 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: `923 + m * (96 ±0) + p * (41 ±0)` - // Estimated: `15422 + m * (388 ±0) + p * (160 ±0)` - // Minimum execution time: 42_592 nanoseconds. - Weight::from_parts(42_349_696, 0) - .saturating_add(Weight::from_parts(0, 15422)) - // Standard Error: 1_776 - .saturating_add(Weight::from_parts(53_830, 0).saturating_mul(m.into())) - // Standard Error: 1_731 - .saturating_add(Weight::from_parts(94_827, 0).saturating_mul(p.into())) + // Measured: `762 + m * (96 ±0) + p * (41 ±0)` + // Estimated: `19732 + m * (388 ±0) + p * (160 ±0)` + // Minimum execution time: 47_135_000 picoseconds. + Weight::from_parts(42_191_348, 0) + .saturating_add(Weight::from_parts(0, 19732)) + // Standard Error: 4_449 + .saturating_add(Weight::from_parts(76_548, 0).saturating_mul(m.into())) + // Standard Error: 4_337 + .saturating_add(Weight::from_parts(143_406, 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, 388).saturating_mul(m.into())) @@ -171,19 +171,19 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `677 + m * (96 ±0) + p * (41 ±0)` - // Estimated: `14232 + m * (507 ±0) + p * (202 ±0)` - // Minimum execution time: 39_735 nanoseconds. - Weight::from_parts(42_276_266, 0) - .saturating_add(Weight::from_parts(0, 14232)) - // Standard Error: 3_451 - .saturating_add(Weight::from_parts(94_755, 0).saturating_mul(m.into())) - // Standard Error: 3_409 - .saturating_add(Weight::from_parts(108_485, 0).saturating_mul(p.into())) + // Measured: `518 + m * (96 ±0) + p * (41 ±0)` + // Estimated: `19135 + m * (509 ±0) + p * (203 ±0)` + // Minimum execution time: 45_329_000 picoseconds. + Weight::from_parts(46_859_108, 0) + .saturating_add(Weight::from_parts(0, 19135)) + // Standard Error: 3_831 + .saturating_add(Weight::from_parts(100_587, 0).saturating_mul(m.into())) + // Standard Error: 3_785 + .saturating_add(Weight::from_parts(134_469, 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, 507).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 202).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(0, 509).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(0, 203).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) @@ -202,15 +202,15 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_approved(_b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `545 + m * (96 ±0) + p * (36 ±0)` - // Estimated: `12436 + m * (480 ±0) + p * (180 ±0)` - // Minimum execution time: 33_604 nanoseconds. - Weight::from_parts(32_382_610, 0) - .saturating_add(Weight::from_parts(0, 12436)) - // Standard Error: 564 - .saturating_add(Weight::from_parts(41_625, 0).saturating_mul(m.into())) - // Standard Error: 544 - .saturating_add(Weight::from_parts(80_954, 0).saturating_mul(p.into())) + // Measured: `417 + m * (96 ±0) + p * (36 ±0)` + // Estimated: `16746 + m * (480 ±0) + p * (180 ±0)` + // Minimum execution time: 36_795_000 picoseconds. + Weight::from_parts(35_568_715, 0) + .saturating_add(Weight::from_parts(0, 16746)) + // Standard Error: 630 + .saturating_add(Weight::from_parts(42_253, 0).saturating_mul(m.into())) + // Standard Error: 607 + .saturating_add(Weight::from_parts(107_080, 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, 480).saturating_mul(m.into())) @@ -225,14 +225,14 @@ impl pallet_alliance::WeightInfo for WeightInfo { fn init_members(m: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `12` - // Estimated: `11879` - // Minimum execution time: 27_970 nanoseconds. - Weight::from_parts(16_763_631, 0) - .saturating_add(Weight::from_parts(0, 11879)) - // Standard Error: 496 - .saturating_add(Weight::from_parts(130_747, 0).saturating_mul(m.into())) - // Standard Error: 490 - .saturating_add(Weight::from_parts(112_074, 0).saturating_mul(z.into())) + // Estimated: `13859` + // Minimum execution time: 30_057_000 picoseconds. + Weight::from_parts(19_584_887, 0) + .saturating_add(Weight::from_parts(0, 13859)) + // Standard Error: 657 + .saturating_add(Weight::from_parts(127_220, 0).saturating_mul(m.into())) + // Standard Error: 649 + .saturating_add(Weight::from_parts(111_719, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -253,17 +253,17 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// 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 * (282 ±0)` - // Estimated: `31580 + x * (2590 ±0) + y * (2590 ±0) + z * (3200 ±1)` - // Minimum execution time: 221_464 nanoseconds. - Weight::from_parts(223_114_000, 0) - .saturating_add(Weight::from_parts(0, 31580)) - // Standard Error: 19_600 - .saturating_add(Weight::from_parts(471_527, 0).saturating_mul(x.into())) - // Standard Error: 19_506 - .saturating_add(Weight::from_parts(424_033, 0).saturating_mul(y.into())) - // Standard Error: 38_976 - .saturating_add(Weight::from_parts(9_666_599, 0).saturating_mul(z.into())) + // Measured: `0 + x * (52 ±0) + y * (53 ±0) + z * (250 ±0)` + // Estimated: `35354 + x * (2590 ±0) + y * (2590 ±0) + z * (3104 ±1)` + // Minimum execution time: 257_465_000 picoseconds. + Weight::from_parts(258_993_000, 0) + .saturating_add(Weight::from_parts(0, 35354)) + // Standard Error: 22_094 + .saturating_add(Weight::from_parts(469_539, 0).saturating_mul(x.into())) + // Standard Error: 21_987 + .saturating_add(Weight::from_parts(478_507, 0).saturating_mul(y.into())) + // Standard Error: 43_935 + .saturating_add(Weight::from_parts(10_541_803, 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()))) @@ -272,7 +272,7 @@ impl pallet_alliance::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(z.into()))) .saturating_add(Weight::from_parts(0, 2590).saturating_mul(x.into())) .saturating_add(Weight::from_parts(0, 2590).saturating_mul(y.into())) - .saturating_add(Weight::from_parts(0, 3200).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(0, 3104).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) @@ -280,8 +280,8 @@ impl pallet_alliance::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_585 nanoseconds. - Weight::from_parts(8_746_000, 0) + // Minimum execution time: 9_973_000 picoseconds. + Weight::from_parts(10_247_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -290,10 +290,10 @@ impl pallet_alliance::WeightInfo for WeightInfo { fn announce() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `9197` - // Minimum execution time: 10_728 nanoseconds. - Weight::from_parts(10_974_000, 0) - .saturating_add(Weight::from_parts(0, 9197)) + // Estimated: `10187` + // Minimum execution time: 12_510_000 picoseconds. + Weight::from_parts(12_659_000, 0) + .saturating_add(Weight::from_parts(0, 10187)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -301,11 +301,11 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// 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: `181` - // Estimated: `9197` - // Minimum execution time: 11_751 nanoseconds. - Weight::from_parts(12_205_000, 0) - .saturating_add(Weight::from_parts(0, 9197)) + // Measured: `149` + // Estimated: `10187` + // Minimum execution time: 13_365_000 picoseconds. + Weight::from_parts(13_575_000, 0) + .saturating_add(Weight::from_parts(0, 10187)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -319,11 +319,11 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// Proof: Alliance DepositOf (max_values: None, max_size: Some(64), added: 2539, mode: MaxEncodedLen) fn join_alliance() -> Weight { // Proof Size summary in bytes: - // Measured: `388` - // Estimated: `23358` - // Minimum execution time: 38_798 nanoseconds. - Weight::from_parts(39_255_000, 0) - .saturating_add(Weight::from_parts(0, 23358)) + // Measured: `294` + // Estimated: `26328` + // Minimum execution time: 40_044_000 picoseconds. + Weight::from_parts(41_623_000, 0) + .saturating_add(Weight::from_parts(0, 26328)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -333,11 +333,11 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// 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: `255` - // Estimated: `20755` - // Minimum execution time: 27_702 nanoseconds. - Weight::from_parts(28_189_000, 0) - .saturating_add(Weight::from_parts(0, 20755)) + // Measured: `193` + // Estimated: `22735` + // Minimum execution time: 28_166_000 picoseconds. + Weight::from_parts(28_756_000, 0) + .saturating_add(Weight::from_parts(0, 22735)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -351,11 +351,11 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn elevate_ally() -> Weight { // Proof Size summary in bytes: - // Measured: `298` - // Estimated: `12761` - // Minimum execution time: 23_033 nanoseconds. - Weight::from_parts(23_589_000, 0) - .saturating_add(Weight::from_parts(0, 12761)) + // Measured: `236` + // Estimated: `14555` + // Minimum execution time: 25_759_000 picoseconds. + Weight::from_parts(26_083_000, 0) + .saturating_add(Weight::from_parts(0, 14555)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -371,11 +371,11 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// 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: `298` - // Estimated: `24133` - // Minimum execution time: 31_352 nanoseconds. - Weight::from_parts(31_848_000, 0) - .saturating_add(Weight::from_parts(0, 24133)) + // Measured: `236` + // Estimated: `25927` + // Minimum execution time: 32_603_000 picoseconds. + Weight::from_parts(33_091_000, 0) + .saturating_add(Weight::from_parts(0, 25927)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -389,11 +389,11 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn retire() -> Weight { // Proof Size summary in bytes: - // Measured: `580` - // Estimated: `13355` - // Minimum execution time: 31_872 nanoseconds. - Weight::from_parts(32_156_000, 0) - .saturating_add(Weight::from_parts(0, 13355)) + // Measured: `517` + // Estimated: `17315` + // Minimum execution time: 36_169_000 picoseconds. + Weight::from_parts(36_746_000, 0) + .saturating_add(Weight::from_parts(0, 17315)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -423,11 +423,11 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn kick_member() -> Weight { // Proof Size summary in bytes: - // Measured: `716` - // Estimated: `35980` - // Minimum execution time: 115_869 nanoseconds. - Weight::from_parts(116_954_000, 0) - .saturating_add(Weight::from_parts(0, 35980)) + // Measured: `622` + // Estimated: `45128` + // Minimum execution time: 127_845_000 picoseconds. + Weight::from_parts(129_248_000, 0) + .saturating_add(Weight::from_parts(0, 45128)) .saturating_add(T::DbWeight::get().reads(13)) .saturating_add(T::DbWeight::get().writes(8)) } @@ -440,14 +440,14 @@ impl pallet_alliance::WeightInfo for WeightInfo { fn add_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `29894` - // Minimum execution time: 6_956 nanoseconds. - Weight::from_parts(7_074_000, 0) - .saturating_add(Weight::from_parts(0, 29894)) - // Standard Error: 2_782 - .saturating_add(Weight::from_parts(1_178_647, 0).saturating_mul(n.into())) - // Standard Error: 1_089 - .saturating_add(Weight::from_parts(65_684, 0).saturating_mul(l.into())) + // Estimated: `31874` + // Minimum execution time: 8_183_000 picoseconds. + Weight::from_parts(8_256_000, 0) + .saturating_add(Weight::from_parts(0, 31874)) + // Standard Error: 2_929 + .saturating_add(Weight::from_parts(1_444_558, 0).saturating_mul(n.into())) + // Standard Error: 1_147 + .saturating_add(Weight::from_parts(68_146, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -460,14 +460,14 @@ impl pallet_alliance::WeightInfo for WeightInfo { fn remove_unscrupulous_items(n: u32, l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + n * (289 ±0) + l * (100 ±0)` - // Estimated: `29894` - // Minimum execution time: 6_939 nanoseconds. - Weight::from_parts(7_100_000, 0) - .saturating_add(Weight::from_parts(0, 29894)) - // Standard Error: 170_977 - .saturating_add(Weight::from_parts(13_668_797, 0).saturating_mul(n.into())) - // Standard Error: 66_962 - .saturating_add(Weight::from_parts(451_782, 0).saturating_mul(l.into())) + // Estimated: `31874` + // Minimum execution time: 7_982_000 picoseconds. + Weight::from_parts(8_084_000, 0) + .saturating_add(Weight::from_parts(0, 31874)) + // Standard Error: 185_716 + .saturating_add(Weight::from_parts(16_937_748, 0).saturating_mul(n.into())) + // Standard Error: 72_734 + .saturating_add(Weight::from_parts(291_993, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -481,11 +481,11 @@ impl pallet_alliance::WeightInfo for WeightInfo { /// Proof Skipped: AllianceMotion Prime (max_values: Some(1), max_size: None, mode: Measured) fn abdicate_fellow_status() -> Weight { // Proof Size summary in bytes: - // Measured: `298` - // Estimated: `18447` - // Minimum execution time: 29_564 nanoseconds. - Weight::from_parts(30_313_000, 0) - .saturating_add(Weight::from_parts(0, 18447)) + // Measured: `236` + // Estimated: `20241` + // Minimum execution time: 31_916_000 picoseconds. + Weight::from_parts(32_301_000, 0) + .saturating_add(Weight::from_parts(0, 20241)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs index 0b8b6ef7078..d36ba31bdb7 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_balances.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_balances` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -51,11 +51,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1176` - // Estimated: `2603` - // Minimum execution time: 45_207 nanoseconds. - Weight::from_parts(45_620_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 35_300_000 picoseconds. + Weight::from_parts(35_618_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -63,11 +63,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1060` - // Estimated: `2603` - // Minimum execution time: 35_103 nanoseconds. - Weight::from_parts(35_730_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 26_091_000 picoseconds. + Weight::from_parts(26_666_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -75,11 +75,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1172` - // Estimated: `2603` - // Minimum execution time: 26_007 nanoseconds. - Weight::from_parts(26_347_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 15_271_000 picoseconds. + Weight::from_parts(15_835_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -87,11 +87,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// 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: `1172` - // Estimated: `2603` - // Minimum execution time: 28_971 nanoseconds. - Weight::from_parts(29_435_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 18_684_000 picoseconds. + Weight::from_parts(19_146_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -99,11 +99,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `1172` - // Estimated: `5206` - // Minimum execution time: 45_554 nanoseconds. - Weight::from_parts(46_156_000, 0) - .saturating_add(Weight::from_parts(0, 5206)) + // Measured: `103` + // Estimated: `6196` + // Minimum execution time: 36_588_000 picoseconds. + Weight::from_parts(37_315_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,11 +111,11 @@ impl pallet_balances::WeightInfo for WeightInfo { /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) fn transfer_all() -> Weight { // Proof Size summary in bytes: - // Measured: `1060` - // Estimated: `2603` - // Minimum execution time: 40_290 nanoseconds. - Weight::from_parts(40_805_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 32_278_000 picoseconds. + Weight::from_parts(32_546_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -126,11 +126,11 @@ impl pallet_balances::WeightInfo for WeightInfo { } fn force_unreserve() -> Weight { // Proof Size summary in bytes: - // Measured: `1056` - // Estimated: `2603` - // Minimum execution time: 22_459 nanoseconds. - Weight::from_parts(23_037_000, 0) - .saturating_add(Weight::from_parts(0, 2603)) + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 14_817_000 picoseconds. + Weight::from_parts(15_115_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs index 2eb232574ce..fb14fb9f956 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collator_selection.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_collator_selection` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -55,12 +55,12 @@ impl pallet_collator_selection::WeightInfo for WeightIn fn set_invulnerables(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178 + b * (78 ±0)` - // Estimated: `178 + b * (2554 ±0)` - // Minimum execution time: 13_471 nanoseconds. - Weight::from_parts(13_949_440, 0) - .saturating_add(Weight::from_parts(0, 178)) - // Standard Error: 3_549 - .saturating_add(Weight::from_parts(2_497_077, 0).saturating_mul(b.into())) + // Estimated: `1168 + b * (2554 ±0)` + // Minimum execution time: 14_884_000 picoseconds. + Weight::from_parts(14_947_157, 0) + .saturating_add(Weight::from_parts(0, 1168)) + // Standard Error: 4_169 + .saturating_add(Weight::from_parts(2_615_559, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 2554).saturating_mul(b.into())) @@ -71,8 +71,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_444 nanoseconds. - Weight::from_parts(6_763_000, 0) + // Minimum execution time: 7_057_000 picoseconds. + Weight::from_parts(7_226_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,8 +82,8 @@ impl pallet_collator_selection::WeightInfo for WeightIn // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_610 nanoseconds. - Weight::from_parts(6_807_000, 0) + // Minimum execution time: 7_216_000 picoseconds. + Weight::from_parts(7_502_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,13 +102,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 999]`. fn register_as_candidate(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `1171 + c * (48 ±0)` - // Estimated: `56784 + c * (49 ±0)` - // Minimum execution time: 35_411 nanoseconds. - Weight::from_parts(26_990_808, 0) - .saturating_add(Weight::from_parts(0, 56784)) - // Standard Error: 1_294 - .saturating_add(Weight::from_parts(107_975, 0).saturating_mul(c.into())) + // Measured: `1108 + c * (48 ±0)` + // Estimated: `61671 + c * (49 ±0)` + // Minimum execution time: 38_806_000 picoseconds. + Weight::from_parts(31_477_823, 0) + .saturating_add(Weight::from_parts(0, 61671)) + // Standard Error: 1_220 + .saturating_add(Weight::from_parts(108_369, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 49).saturating_mul(c.into())) @@ -120,13 +120,13 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[6, 1000]`. fn leave_intent(c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `536 + c * (48 ±0)` - // Estimated: `48497` - // Minimum execution time: 25_912 nanoseconds. - Weight::from_parts(15_664_296, 0) - .saturating_add(Weight::from_parts(0, 48497)) - // Standard Error: 1_292 - .saturating_add(Weight::from_parts(105_672, 0).saturating_mul(c.into())) + // Measured: `452 + c * (48 ±0)` + // Estimated: `49487` + // Minimum execution time: 29_463_000 picoseconds. + Weight::from_parts(19_105_316, 0) + .saturating_add(Weight::from_parts(0, 49487)) + // Standard Error: 1_307 + .saturating_add(Weight::from_parts(106_299, 0).saturating_mul(c.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -138,11 +138,11 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// Proof: CollatorSelection LastAuthoredBlock (max_values: None, max_size: Some(44), added: 2519, mode: MaxEncodedLen) fn note_author() -> Weight { // Proof Size summary in bytes: - // Measured: `135` - // Estimated: `5749` - // Minimum execution time: 24_773 nanoseconds. - Weight::from_parts(25_088_000, 0) - .saturating_add(Weight::from_parts(0, 5749)) + // Measured: `103` + // Estimated: `7729` + // Minimum execution time: 28_319_000 picoseconds. + Weight::from_parts(28_880_000, 0) + .saturating_add(Weight::from_parts(0, 7729)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -160,18 +160,18 @@ impl pallet_collator_selection::WeightInfo for WeightIn /// The range of component `c` is `[1, 1000]`. fn new_session(r: u32, c: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `22784 + r * (148 ±0) + c * (97 ±0)` - // Estimated: `52737 + c * (2519 ±0) + r * (2602 ±0)` - // Minimum execution time: 16_174 nanoseconds. - Weight::from_parts(16_337_000, 0) - .saturating_add(Weight::from_parts(0, 52737)) - // Standard Error: 759_621 - .saturating_add(Weight::from_parts(27_780_906, 0).saturating_mul(c.into())) + // Measured: `22721 + r * (116 ±0) + c * (97 ±0)` + // Estimated: `56697 + r * (2602 ±0) + c * (2520 ±0)` + // Minimum execution time: 17_111_000 picoseconds. + Weight::from_parts(17_332_000, 0) + .saturating_add(Weight::from_parts(0, 56697)) + // Standard Error: 800_597 + .saturating_add(Weight::from_parts(29_089_719, 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, 2602).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 2520).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs index 38369b02f26..5e7f67bea35 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_collective.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_collective` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -60,21 +60,21 @@ impl pallet_collective::WeightInfo for WeightInfo { /// 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 * (3233 ±0) + p * (3223 ±0)` - // Estimated: `15906 + m * (7809 ±23) + p * (10238 ±23)` - // Minimum execution time: 15_797 nanoseconds. - Weight::from_parts(16_028_000, 0) - .saturating_add(Weight::from_parts(0, 15906)) - // Standard Error: 70_308 - .saturating_add(Weight::from_parts(5_642_347, 0).saturating_mul(m.into())) - // Standard Error: 70_308 - .saturating_add(Weight::from_parts(8_133_950, 0).saturating_mul(p.into())) + // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` + // Estimated: `18748 + m * (7799 ±23) + p * (10110 ±23)` + // Minimum execution time: 16_280_000 picoseconds. + Weight::from_parts(16_431_000, 0) + .saturating_add(Weight::from_parts(0, 18748)) + // Standard Error: 67_432 + .saturating_add(Weight::from_parts(5_382_109, 0).saturating_mul(m.into())) + // Standard Error: 67_432 + .saturating_add(Weight::from_parts(8_022_628, 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, 7809).saturating_mul(m.into())) - .saturating_add(Weight::from_parts(0, 10238).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: AllianceMotion Members (r:1 w:0) /// Proof Skipped: AllianceMotion Members (max_values: Some(1), max_size: None, mode: Measured) @@ -82,15 +82,15 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `64 + m * (32 ±0)` - // Estimated: `560 + m * (32 ±0)` - // Minimum execution time: 14_039 nanoseconds. - Weight::from_parts(13_145_821, 0) - .saturating_add(Weight::from_parts(0, 560)) + // Measured: `32 + m * (32 ±0)` + // Estimated: `1518 + m * (32 ±0)` + // Minimum execution time: 15_340_000 picoseconds. + Weight::from_parts(14_971_140, 0) + .saturating_add(Weight::from_parts(0, 1518)) // Standard Error: 24 - .saturating_add(Weight::from_parts(1_434, 0).saturating_mul(b.into())) - // Standard Error: 248 - .saturating_add(Weight::from_parts(14_559, 0).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(1_237, 0).saturating_mul(b.into())) + // Standard Error: 252 + .saturating_add(Weight::from_parts(13_257, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -102,15 +102,15 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `64 + m * (32 ±0)` - // Estimated: `3100 + m * (64 ±0)` - // Minimum execution time: 16_235 nanoseconds. - Weight::from_parts(14_913_854, 0) - .saturating_add(Weight::from_parts(0, 3100)) + // Measured: `32 + m * (32 ±0)` + // Estimated: `5016 + m * (64 ±0)` + // Minimum execution time: 18_083_000 picoseconds. + Weight::from_parts(17_322_823, 0) + .saturating_add(Weight::from_parts(0, 5016)) // Standard Error: 26 - .saturating_add(Weight::from_parts(1_744, 0).saturating_mul(b.into())) - // Standard Error: 273 - .saturating_add(Weight::from_parts(23_908, 0).saturating_mul(m.into())) + .saturating_add(Weight::from_parts(1_248, 0).saturating_mul(b.into())) + // Standard Error: 272 + .saturating_add(Weight::from_parts(22_423, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) } @@ -129,17 +129,17 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `386 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `5505 + m * (165 ±0) + p * (180 ±0)` - // Minimum execution time: 21_595 nanoseconds. - Weight::from_parts(23_162_876, 0) - .saturating_add(Weight::from_parts(0, 5505)) - // Standard Error: 76 - .saturating_add(Weight::from_parts(2_647, 0).saturating_mul(b.into())) - // Standard Error: 797 - .saturating_add(Weight::from_parts(19_673, 0).saturating_mul(m.into())) - // Standard Error: 787 - .saturating_add(Weight::from_parts(95_242, 0).saturating_mul(p.into())) + // Measured: `322 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `9165 + m * (165 ±0) + p * (180 ±0)` + // Minimum execution time: 24_019_000 picoseconds. + Weight::from_parts(26_316_662, 0) + .saturating_add(Weight::from_parts(0, 9165)) + // Standard Error: 77 + .saturating_add(Weight::from_parts(2_166, 0).saturating_mul(b.into())) + // Standard Error: 810 + .saturating_add(Weight::from_parts(20_438, 0).saturating_mul(m.into())) + // Standard Error: 799 + .saturating_add(Weight::from_parts(122_504, 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())) @@ -152,13 +152,13 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `836 + m * (64 ±0)` - // Estimated: `4640 + m * (128 ±0)` - // Minimum execution time: 20_793 nanoseconds. - Weight::from_parts(21_342_865, 0) - .saturating_add(Weight::from_parts(0, 4640)) - // Standard Error: 394 - .saturating_add(Weight::from_parts(43_236, 0).saturating_mul(m.into())) + // Measured: `771 + m * (64 ±0)` + // Estimated: `6490 + m * (128 ±0)` + // Minimum execution time: 22_516_000 picoseconds. + Weight::from_parts(23_803_657, 0) + .saturating_add(Weight::from_parts(0, 6490)) + // Standard Error: 1_968 + .saturating_add(Weight::from_parts(38_988, 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())) @@ -175,15 +175,15 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `456 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `5213 + m * (260 ±0) + p * (144 ±0)` - // Minimum execution time: 24_859 nanoseconds. - Weight::from_parts(26_156_065, 0) - .saturating_add(Weight::from_parts(0, 5213)) - // Standard Error: 737 - .saturating_add(Weight::from_parts(20_578, 0).saturating_mul(m.into())) - // Standard Error: 718 - .saturating_add(Weight::from_parts(86_327, 0).saturating_mul(p.into())) + // Measured: `360 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `7795 + m * (260 ±0) + p * (144 ±0)` + // Minimum execution time: 26_841_000 picoseconds. + Weight::from_parts(28_166_692, 0) + .saturating_add(Weight::from_parts(0, 7795)) + // Standard Error: 657 + .saturating_add(Weight::from_parts(20_102, 0).saturating_mul(m.into())) + // Standard Error: 641 + .saturating_add(Weight::from_parts(113_841, 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())) @@ -202,17 +202,17 @@ impl pallet_collective::WeightInfo for WeightInfo { /// 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: `792 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `8484 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` - // Minimum execution time: 34_729 nanoseconds. - Weight::from_parts(36_499_058, 0) - .saturating_add(Weight::from_parts(0, 8484)) + // Measured: `662 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `11956 + b * (4 ±0) + m * (264 ±0) + p * (160 ±0)` + // Minimum execution time: 38_310_000 picoseconds. + Weight::from_parts(40_050_347, 0) + .saturating_add(Weight::from_parts(0, 11956)) // Standard Error: 84 - .saturating_add(Weight::from_parts(1_409, 0).saturating_mul(b.into())) - // Standard Error: 893 - .saturating_add(Weight::from_parts(14_167, 0).saturating_mul(m.into())) - // Standard Error: 871 - .saturating_add(Weight::from_parts(101_999, 0).saturating_mul(p.into())) + .saturating_add(Weight::from_parts(1_379, 0).saturating_mul(b.into())) + // Standard Error: 892 + .saturating_add(Weight::from_parts(13_153, 0).saturating_mul(m.into())) + // Standard Error: 870 + .saturating_add(Weight::from_parts(132_394, 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())) @@ -233,15 +233,15 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `553 + m * (48 ±0) + p * (36 ±0)` - // Estimated: `6605 + m * (245 ±0) + p * (180 ±0)` - // Minimum execution time: 27_113 nanoseconds. - Weight::from_parts(28_105_174, 0) - .saturating_add(Weight::from_parts(0, 6605)) - // Standard Error: 686 - .saturating_add(Weight::from_parts(20_379, 0).saturating_mul(m.into())) - // Standard Error: 669 - .saturating_add(Weight::from_parts(89_284, 0).saturating_mul(p.into())) + // Measured: `458 + m * (48 ±0) + p * (36 ±0)` + // Estimated: `10085 + m * (245 ±0) + p * (180 ±0)` + // Minimum execution time: 29_071_000 picoseconds. + Weight::from_parts(30_524_865, 0) + .saturating_add(Weight::from_parts(0, 10085)) + // Standard Error: 658 + .saturating_add(Weight::from_parts(18_125, 0).saturating_mul(m.into())) + // Standard Error: 641 + .saturating_add(Weight::from_parts(115_123, 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, 245).saturating_mul(m.into())) @@ -262,17 +262,17 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `812 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `9715 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` - // Minimum execution time: 37_242 nanoseconds. - Weight::from_parts(38_722_168, 0) - .saturating_add(Weight::from_parts(0, 9715)) - // Standard Error: 89 - .saturating_add(Weight::from_parts(1_419, 0).saturating_mul(b.into())) - // Standard Error: 947 - .saturating_add(Weight::from_parts(15_417, 0).saturating_mul(m.into())) - // Standard Error: 923 - .saturating_add(Weight::from_parts(103_094, 0).saturating_mul(p.into())) + // Measured: `682 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `14055 + b * (5 ±0) + m * (330 ±0) + p * (200 ±0)` + // Minimum execution time: 40_932_000 picoseconds. + Weight::from_parts(42_564_375, 0) + .saturating_add(Weight::from_parts(0, 14055)) + // Standard Error: 91 + .saturating_add(Weight::from_parts(1_354, 0).saturating_mul(b.into())) + // Standard Error: 962 + .saturating_add(Weight::from_parts(14_498, 0).saturating_mul(m.into())) + // Standard Error: 937 + .saturating_add(Weight::from_parts(133_672, 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())) @@ -288,13 +288,13 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `221 + p * (32 ±0)` - // Estimated: `1158 + p * (96 ±0)` - // Minimum execution time: 13_173 nanoseconds. - Weight::from_parts(14_787_145, 0) - .saturating_add(Weight::from_parts(0, 1158)) - // Standard Error: 614 - .saturating_add(Weight::from_parts(81_286, 0).saturating_mul(p.into())) + // Measured: `189 + p * (32 ±0)` + // Estimated: `2052 + p * (96 ±0)` + // Minimum execution time: 14_577_000 picoseconds. + Weight::from_parts(17_078_204, 0) + .saturating_add(Weight::from_parts(0, 2052)) + // Standard Error: 1_851 + .saturating_add(Weight::from_parts(96_610, 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/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs index e5fa9b0aaea..46e8b35ad17 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_multisig.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_multisig` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,11 +52,11 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_628 nanoseconds. - Weight::from_parts(12_058_313, 0) + // Minimum execution time: 11_874_000 picoseconds. + Weight::from_parts(12_338_482, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3 - .saturating_add(Weight::from_parts(500, 0).saturating_mul(z.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(501, 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) @@ -64,15 +64,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `311 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 34_764 nanoseconds. - Weight::from_parts(27_813_109, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 630 - .saturating_add(Weight::from_parts(73_821, 0).saturating_mul(s.into())) + // Measured: `262 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 37_113_000 picoseconds. + Weight::from_parts(31_650_752, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 685 + .saturating_add(Weight::from_parts(60_611, 0).saturating_mul(s.into())) // Standard Error: 6 - .saturating_add(Weight::from_parts(1_542, 0).saturating_mul(z.into())) + .saturating_add(Weight::from_parts(1_223, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -82,15 +82,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 25_932 nanoseconds. - Weight::from_parts(19_364_026, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 490 - .saturating_add(Weight::from_parts(69_834, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_520, 0).saturating_mul(z.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 27_063_000 picoseconds. + Weight::from_parts(21_745_286, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 540 + .saturating_add(Weight::from_parts(59_750, 0).saturating_mul(s.into())) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_199, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -102,15 +102,15 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `448 + s * (33 ±0)` - // Estimated: `8424` - // Minimum execution time: 39_495 nanoseconds. - Weight::from_parts(31_235_649, 0) - .saturating_add(Weight::from_parts(0, 8424)) - // Standard Error: 570 - .saturating_add(Weight::from_parts(88_719, 0).saturating_mul(s.into())) - // Standard Error: 5 - .saturating_add(Weight::from_parts(1_523, 0).saturating_mul(z.into())) + // Measured: `385 + s * (33 ±0)` + // Estimated: `10404` + // Minimum execution time: 41_635_000 picoseconds. + Weight::from_parts(35_205_750, 0) + .saturating_add(Weight::from_parts(0, 10404)) + // Standard Error: 614 + .saturating_add(Weight::from_parts(77_394, 0).saturating_mul(s.into())) + // Standard Error: 6 + .saturating_add(Weight::from_parts(1_194, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -119,13 +119,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `318 + s * (2 ±0)` - // Estimated: `5821` - // Minimum execution time: 24_708 nanoseconds. - Weight::from_parts(26_673_173, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 863 - .saturating_add(Weight::from_parts(81_459, 0).saturating_mul(s.into())) + // Measured: `263 + s * (2 ±0)` + // Estimated: `6811` + // Minimum execution time: 28_179_000 picoseconds. + Weight::from_parts(29_964_208, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 692 + .saturating_add(Weight::from_parts(67_380, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -134,13 +134,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `313` - // Estimated: `5821` - // Minimum execution time: 16_520 nanoseconds. - Weight::from_parts(18_123_705, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 661 - .saturating_add(Weight::from_parts(74_405, 0).saturating_mul(s.into())) + // Measured: `282` + // Estimated: `6811` + // Minimum execution time: 18_604_000 picoseconds. + Weight::from_parts(20_059_859, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 1_469 + .saturating_add(Weight::from_parts(65_134, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,13 +149,13 @@ impl pallet_multisig::WeightInfo for WeightInfo { /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `517 + s * (1 ±0)` - // Estimated: `5821` - // Minimum execution time: 25_476 nanoseconds. - Weight::from_parts(27_845_581, 0) - .saturating_add(Weight::from_parts(0, 5821)) - // Standard Error: 868 - .saturating_add(Weight::from_parts(77_797, 0).saturating_mul(s.into())) + // Measured: `454 + s * (1 ±0)` + // Estimated: `6811` + // Minimum execution time: 28_438_000 picoseconds. + Weight::from_parts(30_815_747, 0) + .saturating_add(Weight::from_parts(0, 6811)) + // Standard Error: 774 + .saturating_add(Weight::from_parts(67_365, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs index 4eb83d8067f..5c168e89d47 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_proxy.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_proxy` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,13 +52,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 14_443 nanoseconds. - Weight::from_parts(15_158_969, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_249 - .saturating_add(Weight::from_parts(33_941, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_370_000 picoseconds. + Weight::from_parts(17_099_234, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_021 + .saturating_add(Weight::from_parts(27_747, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Proxy Proxies (r:1 w:0) @@ -71,15 +71,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `550 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 32_060 nanoseconds. - Weight::from_parts(32_192_294, 0) - .saturating_add(Weight::from_parts(0, 11027)) - // Standard Error: 1_900 - .saturating_add(Weight::from_parts(109_332, 0).saturating_mul(a.into())) - // Standard Error: 1_963 - .saturating_add(Weight::from_parts(39_154, 0).saturating_mul(p.into())) + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 34_655_000 picoseconds. + Weight::from_parts(35_088_843, 0) + .saturating_add(Weight::from_parts(0, 13997)) + // Standard Error: 1_939 + .saturating_add(Weight::from_parts(146_356, 0).saturating_mul(a.into())) + // Standard Error: 2_004 + .saturating_add(Weight::from_parts(38_363, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -91,15 +91,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 20_084 nanoseconds. - Weight::from_parts(21_187_531, 0) - .saturating_add(Weight::from_parts(0, 7311)) - // Standard Error: 1_412 - .saturating_add(Weight::from_parts(112_601, 0).saturating_mul(a.into())) - // Standard Error: 1_458 - .saturating_add(Weight::from_parts(6_862, 0).saturating_mul(p.into())) + // Measured: `369 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 21_893_000 picoseconds. + Weight::from_parts(22_495_271, 0) + .saturating_add(Weight::from_parts(0, 9291)) + // Standard Error: 1_612 + .saturating_add(Weight::from_parts(149_480, 0).saturating_mul(a.into())) + // Standard Error: 1_665 + .saturating_add(Weight::from_parts(20_216, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -111,15 +111,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `433 + a * (68 ±0)` - // Estimated: `7311` - // Minimum execution time: 20_658 nanoseconds. - Weight::from_parts(21_184_810, 0) - .saturating_add(Weight::from_parts(0, 7311)) - // Standard Error: 1_259 - .saturating_add(Weight::from_parts(112_012, 0).saturating_mul(a.into())) - // Standard Error: 1_301 - .saturating_add(Weight::from_parts(10_767, 0).saturating_mul(p.into())) + // Measured: `369 + a * (68 ±0)` + // Estimated: `9291` + // Minimum execution time: 22_129_000 picoseconds. + Weight::from_parts(22_971_862, 0) + .saturating_add(Weight::from_parts(0, 9291)) + // Standard Error: 1_324 + .saturating_add(Weight::from_parts(139_140, 0).saturating_mul(a.into())) + // Standard Error: 1_368 + .saturating_add(Weight::from_parts(9_720, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -133,15 +133,15 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `482 + a * (68 ±0) + p * (37 ±0)` - // Estimated: `11027` - // Minimum execution time: 28_670 nanoseconds. - Weight::from_parts(29_411_875, 0) - .saturating_add(Weight::from_parts(0, 11027)) - // Standard Error: 1_864 - .saturating_add(Weight::from_parts(94_146, 0).saturating_mul(a.into())) - // Standard Error: 1_926 - .saturating_add(Weight::from_parts(36_523, 0).saturating_mul(p.into())) + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `13997` + // Minimum execution time: 30_496_000 picoseconds. + Weight::from_parts(31_777_493, 0) + .saturating_add(Weight::from_parts(0, 13997)) + // Standard Error: 2_153 + .saturating_add(Weight::from_parts(139_635, 0).saturating_mul(a.into())) + // Standard Error: 2_224 + .saturating_add(Weight::from_parts(36_392, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -150,13 +150,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 21_273 nanoseconds. - Weight::from_parts(22_137_672, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_345 - .saturating_add(Weight::from_parts(44_075, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_465_000 picoseconds. + Weight::from_parts(24_342_756, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_559 + .saturating_add(Weight::from_parts(50_636, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -165,13 +165,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 20_888 nanoseconds. - Weight::from_parts(22_120_940, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_516 - .saturating_add(Weight::from_parts(55_407, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_620_000 picoseconds. + Weight::from_parts(24_514_511, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_749 + .saturating_add(Weight::from_parts(47_870, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -180,28 +180,26 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `159 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 17_007 nanoseconds. - Weight::from_parts(17_746_585, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_201 - .saturating_add(Weight::from_parts(22_307, 0).saturating_mul(p.into())) + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 18_506_000 picoseconds. + Weight::from_parts(19_463_396, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_241 + .saturating_add(Weight::from_parts(25_525, 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 { + fn create_pure(_p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `139` - // Estimated: `3716` - // Minimum execution time: 22_625 nanoseconds. - Weight::from_parts(23_598_172, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_668 - .saturating_add(Weight::from_parts(113, 0).saturating_mul(p.into())) + // Estimated: `4706` + // Minimum execution time: 25_291_000 picoseconds. + Weight::from_parts(26_456_465, 0) + .saturating_add(Weight::from_parts(0, 4706)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -210,13 +208,13 @@ impl pallet_proxy::WeightInfo for WeightInfo { /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `196 + p * (37 ±0)` - // Estimated: `3716` - // Minimum execution time: 17_969 nanoseconds. - Weight::from_parts(18_830_934, 0) - .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 1_340 - .saturating_add(Weight::from_parts(23_749, 0).saturating_mul(p.into())) + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 19_931_000 picoseconds. + Weight::from_parts(20_842_319, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_467 + .saturating_add(Weight::from_parts(26_062, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs index f5e7b9f2dde..5c5f61d40b2 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_session.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_session` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn set_keys() -> Weight { // Proof Size summary in bytes: // Measured: `270` - // Estimated: `5490` - // Minimum execution time: 15_653 nanoseconds. - Weight::from_parts(16_004_000, 0) - .saturating_add(Weight::from_parts(0, 5490)) + // Estimated: `7470` + // Minimum execution time: 17_635_000 picoseconds. + Weight::from_parts(17_997_000, 0) + .saturating_add(Weight::from_parts(0, 7470)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -68,10 +68,10 @@ impl pallet_session::WeightInfo for WeightInfo { fn purge_keys() -> Weight { // Proof Size summary in bytes: // Measured: `242` - // Estimated: `2959` - // Minimum execution time: 11_729 nanoseconds. - Weight::from_parts(12_081_000, 0) - .saturating_add(Weight::from_parts(0, 2959)) + // Estimated: `3949` + // Minimum execution time: 12_878_000 picoseconds. + Weight::from_parts(13_245_000, 0) + .saturating_add(Weight::from_parts(0, 3949)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs index 9bebfff45ef..5d0636e87d1 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_timestamp.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_timestamp` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -54,10 +54,10 @@ impl pallet_timestamp::WeightInfo for WeightInfo { fn set() -> Weight { // Proof Size summary in bytes: // Measured: `49` - // Estimated: `1006` - // Minimum execution time: 6_995 nanoseconds. - Weight::from_parts(7_169_000, 0) - .saturating_add(Weight::from_parts(0, 1006)) + // Estimated: `2986` + // Minimum execution time: 7_660_000 picoseconds. + Weight::from_parts(7_967_000, 0) + .saturating_add(Weight::from_parts(0, 2986)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -65,8 +65,8 @@ impl pallet_timestamp::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `57` // Estimated: `0` - // Minimum execution time: 3_166 nanoseconds. - Weight::from_parts(3_331_000, 0) + // Minimum execution time: 3_258_000 picoseconds. + Weight::from_parts(3_348_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs index bf25e13c752..5ff7d46c142 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_utility.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_utility` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -52,18 +52,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_987 nanoseconds. - Weight::from_parts(19_221_047, 0) + // Minimum execution time: 7_002_000 picoseconds. + Weight::from_parts(17_384_645, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_233 - .saturating_add(Weight::from_parts(3_808_598, 0).saturating_mul(c.into())) + // Standard Error: 3_488 + .saturating_add(Weight::from_parts(4_736_077, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_203 nanoseconds. - Weight::from_parts(4_337_000, 0) + // Minimum execution time: 5_352_000 picoseconds. + Weight::from_parts(5_532_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +71,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_986 nanoseconds. - Weight::from_parts(14_991_349, 0) + // Minimum execution time: 7_030_000 picoseconds. + Weight::from_parts(18_968_785, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_440 - .saturating_add(Weight::from_parts(4_032_363, 0).saturating_mul(c.into())) + // Standard Error: 3_112 + .saturating_add(Weight::from_parts(4_960_336, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_768 nanoseconds. - Weight::from_parts(7_998_000, 0) + // Minimum execution time: 9_703_000 picoseconds. + Weight::from_parts(10_012_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +90,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_906 nanoseconds. - Weight::from_parts(16_782_253, 0) + // Minimum execution time: 7_029_000 picoseconds. + Weight::from_parts(13_505_714, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_131 - .saturating_add(Weight::from_parts(3_780_339, 0).saturating_mul(c.into())) + // Standard Error: 3_032 + .saturating_add(Weight::from_parts(4_709_262, 0).saturating_mul(c.into())) } } diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs index b257834df07..43fee0b52e6 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/weights/pallet_xcm.rs @@ -1,4 +1,4 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. +// Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. // Cumulus is free software: you can redistribute it and/or modify @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-02-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-03-23, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm6`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! HOSTNAME: `bm4`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("collectives-polkadot-dev"), DB CACHE: 1024 // Executed Command: @@ -60,10 +60,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn send() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `4645` - // Minimum execution time: 23_618 nanoseconds. - Weight::from_parts(24_118_000, 0) - .saturating_add(Weight::from_parts(0, 4645)) + // Estimated: `9595` + // Minimum execution time: 25_963_000 picoseconds. + Weight::from_parts(26_569_000, 0) + .saturating_add(Weight::from_parts(0, 9595)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -72,10 +72,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn teleport_assets() -> Weight { // Proof Size summary in bytes: // Measured: `32` - // Estimated: `499` - // Minimum execution time: 23_764 nanoseconds. - Weight::from_parts(24_114_000, 0) - .saturating_add(Weight::from_parts(0, 499)) + // Estimated: `1489` + // Minimum execution time: 26_187_000 picoseconds. + Weight::from_parts(26_643_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) } /// Storage: Benchmark Override (r:0 w:0) @@ -84,7 +84,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -94,7 +94,7 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 18_446_744_073_709_551 nanoseconds. + // 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)) } @@ -104,8 +104,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 8_266 nanoseconds. - Weight::from_parts(8_578_000, 0) + // Minimum execution time: 9_755_000 picoseconds. + Weight::from_parts(10_010_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -115,8 +115,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_289 nanoseconds. - Weight::from_parts(2_382_000, 0) + // Minimum execution time: 2_994_000 picoseconds. + Weight::from_parts(3_125_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -139,10 +139,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_subscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `38` - // Estimated: `7729` - // Minimum execution time: 28_592 nanoseconds. - Weight::from_parts(29_116_000, 0) - .saturating_add(Weight::from_parts(0, 7729)) + // Estimated: `14659` + // Minimum execution time: 31_393_000 picoseconds. + Weight::from_parts(31_976_000, 0) + .saturating_add(Weight::from_parts(0, 14659)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -163,10 +163,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn force_unsubscribe_version_notify() -> Weight { // Proof Size summary in bytes: // Measured: `220` - // Estimated: `8470` - // Minimum execution time: 30_604 nanoseconds. - Weight::from_parts(31_361_000, 0) - .saturating_add(Weight::from_parts(0, 8470)) + // Estimated: `14410` + // Minimum execution time: 34_048_000 picoseconds. + Weight::from_parts(35_696_000, 0) + .saturating_add(Weight::from_parts(0, 14410)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -175,10 +175,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_supported_version() -> Weight { // Proof Size summary in bytes: // Measured: `95` - // Estimated: `9995` - // Minimum execution time: 13_750 nanoseconds. - Weight::from_parts(14_051_000, 0) - .saturating_add(Weight::from_parts(0, 9995)) + // Estimated: `10985` + // Minimum execution time: 16_432_000 picoseconds. + Weight::from_parts(16_898_000, 0) + .saturating_add(Weight::from_parts(0, 10985)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -187,10 +187,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notifiers() -> Weight { // Proof Size summary in bytes: // Measured: `99` - // Estimated: `9999` - // Minimum execution time: 13_897 nanoseconds. - Weight::from_parts(14_080_000, 0) - .saturating_add(Weight::from_parts(0, 9999)) + // Estimated: `10989` + // Minimum execution time: 15_950_000 picoseconds. + Weight::from_parts(16_441_000, 0) + .saturating_add(Weight::from_parts(0, 10989)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -199,10 +199,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn already_notified_target() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `12481` - // Minimum execution time: 16_364 nanoseconds. - Weight::from_parts(16_867_000, 0) - .saturating_add(Weight::from_parts(0, 12481)) + // Estimated: `13471` + // Minimum execution time: 16_585_000 picoseconds. + Weight::from_parts(16_939_000, 0) + .saturating_add(Weight::from_parts(0, 13471)) .saturating_add(T::DbWeight::get().reads(5)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:2 w:1) @@ -220,10 +220,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_current_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10041` - // Minimum execution time: 27_372 nanoseconds. - Weight::from_parts(28_128_000, 0) - .saturating_add(Weight::from_parts(0, 10041)) + // Estimated: `15981` + // Minimum execution time: 30_278_000 picoseconds. + Weight::from_parts(30_676_000, 0) + .saturating_add(Weight::from_parts(0, 15981)) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -232,10 +232,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn notify_target_migration_fail() -> Weight { // Proof Size summary in bytes: // Measured: `136` - // Estimated: `7561` - // Minimum execution time: 7_804 nanoseconds. - Weight::from_parts(8_096_000, 0) - .saturating_add(Weight::from_parts(0, 7561)) + // Estimated: `8551` + // Minimum execution time: 8_923_000 picoseconds. + Weight::from_parts(9_257_000, 0) + .saturating_add(Weight::from_parts(0, 8551)) .saturating_add(T::DbWeight::get().reads(3)) } /// Storage: PolkadotXcm VersionNotifyTargets (r:4 w:2) @@ -243,10 +243,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_version_notify_targets() -> Weight { // Proof Size summary in bytes: // Measured: `106` - // Estimated: `10006` - // Minimum execution time: 14_948 nanoseconds. - Weight::from_parts(15_422_000, 0) - .saturating_add(Weight::from_parts(0, 10006)) + // Estimated: `10996` + // Minimum execution time: 16_897_000 picoseconds. + Weight::from_parts(17_998_000, 0) + .saturating_add(Weight::from_parts(0, 10996)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -265,10 +265,10 @@ impl pallet_xcm::WeightInfo for WeightInfo { fn migrate_and_notify_old_targets() -> Weight { // Proof Size summary in bytes: // Measured: `112` - // Estimated: `15027` - // Minimum execution time: 33_791 nanoseconds. - Weight::from_parts(34_282_000, 0) - .saturating_add(Weight::from_parts(0, 15027)) + // Estimated: `20967` + // Minimum execution time: 40_145_000 picoseconds. + Weight::from_parts(41_423_000, 0) + .saturating_add(Weight::from_parts(0, 20967)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } From 88ead41f9d3629f0d278338b124bb3ae4db3c0c1 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 4 Apr 2023 17:05:38 +0200 Subject: [PATCH 29/57] Cleanup: Remove polkadot-service dependency from minimal node (#2430) * Remove polkadot-service dependency from minimal-node * Clean up error handline * Remove unwanted changes * Unused deps --- Cargo.lock | 5 ++- client/relay-chain-interface/src/lib.rs | 10 +++++- client/relay-chain-minimal-node/Cargo.toml | 6 +++- .../src/collator_overseer.rs | 31 ++++++++++--------- client/relay-chain-minimal-node/src/lib.rs | 3 +- 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 163917a1be1..81c49a2eae0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2332,13 +2332,16 @@ dependencies = [ "cumulus-relay-chain-rpc-interface", "futures", "lru 0.9.0", + "polkadot-availability-recovery", + "polkadot-collator-protocol", "polkadot-core-primitives", "polkadot-network-bridge", + "polkadot-node-collation-generation", + "polkadot-node-core-runtime-api", "polkadot-node-network-protocol", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-primitives", - "polkadot-service", "sc-authority-discovery", "sc-client-api", "sc-network", diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index db4fd24c64f..3629aea84cd 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -46,7 +46,9 @@ pub enum RelayChainError { WaitTimeout(PHash), #[error("Import listener closed while waiting for relay-chain block `{0}` to be imported.")] ImportListenerClosed(PHash), - #[error("Blockchain returned an error while waiting for relay-chain block `{0}` to be imported: {1}")] + #[error( + "Blockchain returned an error while waiting for relay-chain block `{0}` to be imported: {1}" + )] WaitBlockchainError(PHash, sp_blockchain::Error), #[error("Blockchain returned an error: {0}")] BlockchainError(#[from] sp_blockchain::Error), @@ -86,6 +88,12 @@ impl From for sp_blockchain::Error { } } +impl From> for RelayChainError { + fn from(r: Box) -> Self { + RelayChainError::Application(r) + } +} + /// Trait that provides all necessary methods for interaction between collator and relay chain. #[async_trait] pub trait RelayChainInterface: Send + Sync { diff --git a/client/relay-chain-minimal-node/Cargo.toml b/client/relay-chain-minimal-node/Cargo.toml index 737445c30c1..ff8d8bc11d3 100644 --- a/client/relay-chain-minimal-node/Cargo.toml +++ b/client/relay-chain-minimal-node/Cargo.toml @@ -9,10 +9,14 @@ edition = "2021" polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-core-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-node-subsystem-util = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-node-network-protocol = { git = "https://github.com/paritytech/polkadot", branch = "master" } + +polkadot-availability-recovery = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-collator-protocol = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-network-bridge = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-node-collation-generation = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-node-core-runtime-api = { git = "https://github.com/paritytech/polkadot", branch = "master" } # substrate deps sc-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/client/relay-chain-minimal-node/src/collator_overseer.rs b/client/relay-chain-minimal-node/src/collator_overseer.rs index 9bcbc2a67a8..bd3dfa8e0f8 100644 --- a/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -18,6 +18,14 @@ use futures::{select, StreamExt}; use lru::LruCache; use std::sync::Arc; +use polkadot_availability_recovery::AvailabilityRecoverySubsystem; +use polkadot_collator_protocol::{CollatorProtocolSubsystem, ProtocolSide}; +use polkadot_network_bridge::{ + Metrics as NetworkBridgeMetrics, NetworkBridgeRx as NetworkBridgeRxSubsystem, + NetworkBridgeTx as NetworkBridgeTxSubsystem, +}; +use polkadot_node_collation_generation::CollationGenerationSubsystem; +use polkadot_node_core_runtime_api::RuntimeApiSubsystem; use polkadot_node_network_protocol::{ peer_set::PeerSetProtocolNames, request_response::{ @@ -27,18 +35,10 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_subsystem_util::metrics::{prometheus::Registry, Metrics}; use polkadot_overseer::{ - BlockInfo, DummySubsystem, Handle, MetricsTrait, Overseer, OverseerHandle, OverseerMetrics, - SpawnGlue, KNOWN_LEAVES_CACHE_SIZE, + BlockInfo, DummySubsystem, Handle, Overseer, OverseerConnector, OverseerHandle, SpawnGlue, + KNOWN_LEAVES_CACHE_SIZE, }; use polkadot_primitives::CollatorPair; -use polkadot_service::{ - overseer::{ - AvailabilityRecoverySubsystem, CollationGenerationSubsystem, CollatorProtocolSubsystem, - NetworkBridgeMetrics, NetworkBridgeRxSubsystem, NetworkBridgeTxSubsystem, ProtocolSide, - RuntimeApiSubsystem, - }, - Error, OverseerConnector, -}; use sc_authority_discovery::Service as AuthorityDiscoveryService; use sc_network::NetworkStateInfo; @@ -93,9 +93,8 @@ fn build_overseer<'a>( }: CollatorOverseerGenArgs<'a>, ) -> Result< (Overseer, Arc>, OverseerHandle), - Error, + RelayChainError, > { - let metrics = ::register(registry)?; let spawner = SpawnGlue(spawner); let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; let builder = Overseer::builder() @@ -153,17 +152,19 @@ fn build_overseer<'a>( .active_leaves(Default::default()) .supports_parachains(runtime_client) .known_leaves(LruCache::new(KNOWN_LEAVES_CACHE_SIZE)) - .metrics(metrics) + .metrics(Metrics::register(registry)?) .spawner(spawner); - builder.build_with_connector(connector).map_err(|e| e.into()) + builder + .build_with_connector(connector) + .map_err(|e| RelayChainError::Application(e.into())) } pub(crate) fn spawn_overseer( overseer_args: CollatorOverseerGenArgs, task_manager: &TaskManager, relay_chain_rpc_client: Arc, -) -> Result { +) -> Result { let (overseer, overseer_handle) = build_overseer(OverseerConnector::default(), overseer_args) .map_err(|e| { tracing::error!("Failed to initialize overseer: {}", e); diff --git a/client/relay-chain-minimal-node/src/lib.rs b/client/relay-chain-minimal-node/src/lib.rs index 90afd31b8b6..102a8582745 100644 --- a/client/relay-chain-minimal-node/src/lib.rs +++ b/client/relay-chain-minimal-node/src/lib.rs @@ -181,8 +181,7 @@ async fn new_minimal_relay_chain( }; let overseer_handle = - collator_overseer::spawn_overseer(overseer_args, &task_manager, relay_chain_rpc_client) - .map_err(|e| RelayChainError::Application(Box::new(e) as Box<_>))?; + collator_overseer::spawn_overseer(overseer_args, &task_manager, relay_chain_rpc_client)?; network_starter.start_network(); From 2cbaa3910d52c9ec58951a9499ec572729f9ecfc Mon Sep 17 00:00:00 2001 From: Oliver Tale-Yazdi Date: Tue, 4 Apr 2023 22:31:39 +0200 Subject: [PATCH 30/57] Co #13699: Remove old calls (#2431) * Remove old calls Signed-off-by: Oliver Tale-Yazdi * update lockfile for {"substrate", "polkadot"} * Ignore warning in pallet ping Signed-off-by: Oliver Tale-Yazdi * Ignore more warnings... Signed-off-by: Oliver Tale-Yazdi * ... Signed-off-by: Oliver Tale-Yazdi --------- Signed-off-by: Oliver Tale-Yazdi Co-authored-by: parity-processbot <> --- Cargo.lock | 524 +++++++++--------- pallets/parachain-system/src/lib.rs | 2 +- pallets/solo-to-para/src/lib.rs | 2 +- parachains/pallets/ping/src/lib.rs | 12 +- .../collectives-polkadot/src/xcm_config.rs | 2 - 5 files changed, 276 insertions(+), 266 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 81c49a2eae0..8a9810b8a0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -523,7 +523,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "hash-db", "log", @@ -3367,7 +3367,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", ] @@ -3390,7 +3390,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-support-procedural", @@ -3415,7 +3415,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -3462,7 +3462,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3473,7 +3473,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3490,7 +3490,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -3519,7 +3519,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "log", @@ -3535,7 +3535,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "bitflags", "environmental", @@ -3568,13 +3568,14 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "Inflector", "cfg-expr", "derive-syn-parse", "frame-support-procedural-tools", "itertools", + "proc-macro-warning", "proc-macro2", "quote", "syn 1.0.109", @@ -3583,7 +3584,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3595,7 +3596,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro2", "quote", @@ -3605,7 +3606,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "log", @@ -3623,7 +3624,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -3638,7 +3639,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "sp-api", @@ -3647,7 +3648,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "parity-scale-codec", @@ -4616,7 +4617,7 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "frame-benchmarking", @@ -4714,7 +4715,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "frame-support", "polkadot-primitives", @@ -5568,7 +5569,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "log", @@ -5587,7 +5588,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "anyhow", "jsonrpsee", @@ -6086,7 +6087,7 @@ dependencies = [ [[package]] name = "pallet-alliance" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -6107,7 +6108,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6125,7 +6126,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6140,7 +6141,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6156,7 +6157,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6172,7 +6173,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6186,7 +6187,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6210,7 +6211,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6230,7 +6231,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6245,7 +6246,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6264,7 +6265,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6288,7 +6289,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6306,7 +6307,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6350,7 +6351,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6367,7 +6368,7 @@ dependencies = [ [[package]] name = "pallet-contracts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "bitflags", "environmental", @@ -6397,7 +6398,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "bitflags", "parity-scale-codec", @@ -6410,7 +6411,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro2", "quote", @@ -6420,7 +6421,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6437,7 +6438,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6455,7 +6456,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6478,7 +6479,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6491,7 +6492,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6509,7 +6510,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6527,7 +6528,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6550,7 +6551,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6566,7 +6567,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6586,7 +6587,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6603,7 +6604,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6617,7 +6618,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6634,7 +6635,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6651,7 +6652,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6667,7 +6668,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6685,7 +6686,7 @@ dependencies = [ [[package]] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "pallet-nfts", @@ -6696,7 +6697,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6712,7 +6713,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6729,7 +6730,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6749,7 +6750,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6760,7 +6761,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6777,7 +6778,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6801,7 +6802,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6818,7 +6819,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6833,7 +6834,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6851,7 +6852,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6866,7 +6867,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6885,7 +6886,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6902,7 +6903,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6923,7 +6924,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -6939,7 +6940,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -6953,7 +6954,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6976,7 +6977,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6987,7 +6988,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "log", "sp-arithmetic", @@ -6996,7 +6997,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "sp-api", @@ -7005,7 +7006,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -7022,7 +7023,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -7051,7 +7052,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -7069,7 +7070,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -7088,7 +7089,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-support", "frame-system", @@ -7104,7 +7105,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7120,7 +7121,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7132,7 +7133,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -7149,7 +7150,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -7164,7 +7165,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -7180,7 +7181,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -7195,7 +7196,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-benchmarking", "frame-support", @@ -7210,7 +7211,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7231,7 +7232,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "frame-benchmarking", "frame-support", @@ -7780,7 +7781,7 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "polkadot-node-jaeger", @@ -7796,7 +7797,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7810,7 +7811,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "derive_more", "fatality", @@ -7833,7 +7834,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "fatality", "futures", @@ -7854,7 +7855,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "clap 4.1.14", "frame-benchmarking-cli", @@ -7882,7 +7883,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "frame-benchmarking", @@ -7925,7 +7926,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "always-assert", "bitvec", @@ -7947,7 +7948,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "parity-scale-codec", "scale-info", @@ -7959,7 +7960,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "derive_more", "fatality", @@ -7984,7 +7985,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7998,7 +7999,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "futures-timer", @@ -8018,7 +8019,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "always-assert", "async-trait", @@ -8041,7 +8042,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "parity-scale-codec", @@ -8059,7 +8060,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "derive_more", @@ -8088,7 +8089,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "futures", @@ -8109,7 +8110,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "fatality", @@ -8128,7 +8129,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8143,7 +8144,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "futures", @@ -8163,7 +8164,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "polkadot-node-metrics", @@ -8178,7 +8179,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "futures-timer", @@ -8195,7 +8196,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "fatality", "futures", @@ -8214,7 +8215,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "futures", @@ -8231,7 +8232,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "fatality", @@ -8249,7 +8250,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "always-assert", "assert_matches", @@ -8286,7 +8287,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "polkadot-node-primitives", @@ -8302,7 +8303,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "futures", "lru 0.9.0", @@ -8317,7 +8318,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "lazy_static", "log", @@ -8335,7 +8336,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bs58", "futures", @@ -8354,7 +8355,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "derive_more", @@ -8376,7 +8377,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bounded-vec", "futures", @@ -8399,7 +8400,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8409,7 +8410,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "futures", @@ -8427,7 +8428,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "derive_more", @@ -8450,7 +8451,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "derive_more", @@ -8483,7 +8484,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "futures", @@ -8506,7 +8507,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bounded-collections", "derive_more", @@ -8604,7 +8605,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -8620,7 +8621,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "hex-literal 0.3.4", @@ -8646,7 +8647,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8678,7 +8679,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "frame-benchmarking", @@ -8772,7 +8773,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "frame-benchmarking", @@ -8818,7 +8819,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "frame-support", "polkadot-primitives", @@ -8832,7 +8833,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bs58", "parity-scale-codec", @@ -8844,7 +8845,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitflags", "bitvec", @@ -8888,7 +8889,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "async-trait", "frame-benchmarking-cli", @@ -8998,7 +8999,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -9019,7 +9020,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -9029,7 +9030,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -9054,7 +9055,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "frame-election-provider-support", @@ -9115,7 +9116,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "frame-benchmarking", "frame-system", @@ -9332,6 +9333,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-warning" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4f284d87b9cedc2ff57223cbc4e3937cd6063c01e92c8e2a8c080df0013933" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "proc-macro2" version = "1.0.56" @@ -9860,7 +9872,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9946,7 +9958,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "frame-support", "polkadot-primitives", @@ -10193,7 +10205,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "log", "sp-core", @@ -10204,7 +10216,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "futures", @@ -10232,7 +10244,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "futures-timer", @@ -10255,7 +10267,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10270,7 +10282,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10289,7 +10301,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10300,7 +10312,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -10340,7 +10352,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "fnv", "futures", @@ -10366,7 +10378,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "hash-db", "kvdb", @@ -10392,7 +10404,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "futures", @@ -10417,7 +10429,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "futures", @@ -10446,7 +10458,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "fork-tree", @@ -10485,7 +10497,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "jsonrpsee", @@ -10507,7 +10519,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10542,7 +10554,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "jsonrpsee", @@ -10561,7 +10573,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10574,7 +10586,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "ahash 0.8.2", "array-bytes 4.2.0", @@ -10614,7 +10626,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "finality-grandpa", "futures", @@ -10634,7 +10646,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "futures", @@ -10657,7 +10669,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10681,7 +10693,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10694,7 +10706,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "log", "sc-allocator", @@ -10707,7 +10719,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "anyhow", "cfg-if", @@ -10725,7 +10737,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "ansi_term", "futures", @@ -10741,7 +10753,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10756,7 +10768,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10801,7 +10813,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "cid", "futures", @@ -10821,7 +10833,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10849,7 +10861,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "ahash 0.8.2", "futures", @@ -10868,7 +10880,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10890,7 +10902,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10924,7 +10936,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10944,7 +10956,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10975,7 +10987,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "libp2p", @@ -10988,7 +11000,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -10997,7 +11009,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "jsonrpsee", @@ -11027,7 +11039,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11046,7 +11058,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "http", "jsonrpsee", @@ -11061,7 +11073,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "futures", @@ -11087,7 +11099,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "directories", @@ -11153,7 +11165,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "log", "parity-scale-codec", @@ -11164,7 +11176,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "clap 4.1.14", "fs4", @@ -11180,7 +11192,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11199,7 +11211,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "libc", @@ -11218,7 +11230,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "chrono", "futures", @@ -11237,7 +11249,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "ansi_term", "atty", @@ -11268,7 +11280,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11279,7 +11291,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "futures", @@ -11306,7 +11318,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "futures", @@ -11320,7 +11332,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-channel", "futures", @@ -11801,7 +11813,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "enumn", "parity-scale-codec", @@ -11878,7 +11890,7 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "hash-db", "log", @@ -11896,7 +11908,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "Inflector", "blake2", @@ -11910,7 +11922,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "scale-info", @@ -11923,7 +11935,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "integer-sqrt", "num-traits", @@ -11937,7 +11949,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "scale-info", @@ -11950,7 +11962,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "sp-api", @@ -11962,7 +11974,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "log", @@ -11980,7 +11992,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "futures", @@ -11995,7 +12007,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "parity-scale-codec", @@ -12013,7 +12025,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "merlin", @@ -12036,7 +12048,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "lazy_static", "parity-scale-codec", @@ -12055,7 +12067,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "finality-grandpa", "log", @@ -12073,7 +12085,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "scale-info", @@ -12085,7 +12097,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "scale-info", @@ -12098,7 +12110,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "bitflags", @@ -12141,7 +12153,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "blake2b_simd", "byteorder", @@ -12155,7 +12167,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro2", "quote", @@ -12166,7 +12178,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12175,7 +12187,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro2", "quote", @@ -12185,7 +12197,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "environmental", "parity-scale-codec", @@ -12196,7 +12208,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12211,7 +12223,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "bytes", "ed25519", @@ -12237,7 +12249,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "lazy_static", "sp-core", @@ -12248,7 +12260,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "merlin", @@ -12264,7 +12276,7 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "thiserror", "zstd", @@ -12273,7 +12285,7 @@ dependencies = [ [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12291,7 +12303,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "scale-info", @@ -12305,7 +12317,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "sp-api", "sp-core", @@ -12315,7 +12327,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "backtrace", "lazy_static", @@ -12325,7 +12337,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "rustc-hash", "serde", @@ -12335,7 +12347,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "either", "hash256-std-hasher", @@ -12357,7 +12369,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12375,7 +12387,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "Inflector", "proc-macro-crate", @@ -12387,7 +12399,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "serde", "serde_json", @@ -12396,7 +12408,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "scale-info", @@ -12410,7 +12422,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "scale-info", @@ -12422,7 +12434,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "hash-db", "log", @@ -12442,12 +12454,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12460,7 +12472,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "futures-timer", @@ -12475,7 +12487,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "sp-std", @@ -12487,7 +12499,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "sp-api", "sp-runtime", @@ -12496,7 +12508,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "log", @@ -12512,7 +12524,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "ahash 0.8.2", "hash-db", @@ -12535,7 +12547,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12552,7 +12564,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12563,7 +12575,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12577,7 +12589,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "parity-scale-codec", "scale-info", @@ -12901,7 +12913,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "platforms 2.0.0", ] @@ -12909,7 +12921,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12928,7 +12940,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "hyper", "log", @@ -12940,7 +12952,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "jsonrpsee", @@ -12953,7 +12965,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "jsonrpsee", "log", @@ -12972,7 +12984,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -12998,7 +13010,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "futures", "substrate-test-utils-derive", @@ -13008,7 +13020,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -13019,7 +13031,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "ansi_term", "build-helper", @@ -13146,7 +13158,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "frame-support", "polkadot-primitives", @@ -13536,7 +13548,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13547,7 +13559,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -13677,7 +13689,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#bbcc63a96c8b77b9d07968cc2612a5c15b8cc0e5" +source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" dependencies = [ "async-trait", "clap 4.1.14", @@ -14605,7 +14617,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bitvec", "frame-benchmarking", @@ -14697,7 +14709,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "frame-support", "polkadot-primitives", @@ -15133,7 +15145,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "bounded-collections", "derivative", @@ -15149,7 +15161,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "frame-support", "frame-system", @@ -15170,7 +15182,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "environmental", "frame-benchmarking", @@ -15190,7 +15202,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#00b80ecadbef54ddcc652718385b54b0d05ef5d9" +source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" dependencies = [ "Inflector", "proc-macro2", diff --git a/pallets/parachain-system/src/lib.rs b/pallets/parachain-system/src/lib.rs index 97c6cfe368d..ac3b8648c65 100644 --- a/pallets/parachain-system/src/lib.rs +++ b/pallets/parachain-system/src/lib.rs @@ -492,7 +492,7 @@ pub mod pallet { /// /// All origins are allowed. #[pallet::call_index(3)] - #[pallet::weight(1_000_000)] + #[pallet::weight({1_000_000})] pub fn enact_authorized_upgrade( _: OriginFor, code: Vec, diff --git a/pallets/solo-to-para/src/lib.rs b/pallets/solo-to-para/src/lib.rs index 515dd385e7b..a05a5121de1 100644 --- a/pallets/solo-to-para/src/lib.rs +++ b/pallets/solo-to-para/src/lib.rs @@ -61,7 +61,7 @@ pub mod pallet { #[pallet::call] impl Pallet { #[pallet::call_index(0)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn schedule_migration( origin: OriginFor, code: Vec, diff --git a/parachains/pallets/ping/src/lib.rs b/parachains/pallets/ping/src/lib.rs index 956457f5916..0260f05dad2 100644 --- a/parachains/pallets/ping/src/lib.rs +++ b/parachains/pallets/ping/src/lib.rs @@ -141,7 +141,7 @@ pub mod pallet { #[pallet::call] impl Pallet { #[pallet::call_index(0)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn start(origin: OriginFor, para: ParaId, payload: Vec) -> DispatchResult { ensure_root(origin)?; let payload = BoundedVec::::try_from(payload) @@ -153,7 +153,7 @@ pub mod pallet { } #[pallet::call_index(1)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn start_many( origin: OriginFor, para: ParaId, @@ -173,7 +173,7 @@ pub mod pallet { } #[pallet::call_index(2)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn stop(origin: OriginFor, para: ParaId) -> DispatchResult { ensure_root(origin)?; Targets::::mutate(|t| { @@ -185,7 +185,7 @@ pub mod pallet { } #[pallet::call_index(3)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn stop_all(origin: OriginFor, maybe_para: Option) -> DispatchResult { ensure_root(origin)?; if let Some(para) = maybe_para { @@ -197,7 +197,7 @@ pub mod pallet { } #[pallet::call_index(4)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn ping(origin: OriginFor, seq: u32, payload: Vec) -> DispatchResult { // Only accept pings from other chains. let para = ensure_sibling_para(::RuntimeOrigin::from(origin))?; @@ -224,7 +224,7 @@ pub mod pallet { } #[pallet::call_index(5)] - #[pallet::weight(0)] + #[pallet::weight({0})] pub fn pong(origin: OriginFor, seq: u32, payload: Vec) -> DispatchResult { // Only accept pings from other chains. let para = ensure_sibling_para(::RuntimeOrigin::from(origin))?; diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs b/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs index 3e726b5b4b7..9c1fda61bd8 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/xcm_config.rs @@ -163,7 +163,6 @@ impl Contains for SafeCallFilter { // but the call can be initiated only by root origin. pallet_alliance::Call::init_members { .. } | pallet_alliance::Call::vote { .. } | - pallet_alliance::Call::close_old_weight { .. } | pallet_alliance::Call::disband { .. } | pallet_alliance::Call::set_rule { .. } | pallet_alliance::Call::announce { .. } | @@ -179,7 +178,6 @@ impl Contains for SafeCallFilter { ) | RuntimeCall::AllianceMotion( pallet_collective::Call::vote { .. } | - pallet_collective::Call::close_old_weight { .. } | pallet_collective::Call::disapprove_proposal { .. } | pallet_collective::Call::close { .. }, ) | From b49628f316c1086fd2f5cc8ef2a52cceca8b8818 Mon Sep 17 00:00:00 2001 From: Egor_P Date: Wed, 5 Apr 2023 13:08:13 +0200 Subject: [PATCH 31/57] [Backport] version bumps 9400 (#2424) * Bump crate versions * Bump spec_version to 9400 * bump transaction versions (#2364) --- Cargo.lock | 2 +- parachains/runtimes/assets/statemine/src/lib.rs | 8 ++++---- parachains/runtimes/assets/statemint/src/lib.rs | 4 ++-- parachains/runtimes/assets/westmint/src/lib.rs | 4 ++-- .../runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs | 4 ++-- .../runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs | 4 ++-- .../runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 4 ++-- .../runtimes/collectives/collectives-polkadot/src/lib.rs | 4 ++-- parachains/runtimes/contracts/contracts-rococo/src/lib.rs | 4 ++-- parachains/runtimes/starters/seedling/src/lib.rs | 2 +- parachains/runtimes/testing/penpal/src/lib.rs | 2 +- parachains/runtimes/testing/rococo-parachain/src/lib.rs | 4 ++-- polkadot-parachain/Cargo.toml | 2 +- 13 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a9810b8a0f..9a6be69e4e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8523,7 +8523,7 @@ dependencies = [ [[package]] name = "polkadot-parachain-bin" -version = "0.9.380" +version = "0.9.400" dependencies = [ "assert_cmd", "async-trait", diff --git a/parachains/runtimes/assets/statemine/src/lib.rs b/parachains/runtimes/assets/statemine/src/lib.rs index 6c332a11520..62425aa7496 100644 --- a/parachains/runtimes/assets/statemine/src/lib.rs +++ b/parachains/runtimes/assets/statemine/src/lib.rs @@ -97,10 +97,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 12, + transaction_version: 13, state_version: 1, }; @@ -110,10 +110,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemine"), impl_name: create_runtime_str!("statemine"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 12, + transaction_version: 13, state_version: 0, }; diff --git a/parachains/runtimes/assets/statemint/src/lib.rs b/parachains/runtimes/assets/statemint/src/lib.rs index d62b19be844..a72df7314e6 100644 --- a/parachains/runtimes/assets/statemint/src/lib.rs +++ b/parachains/runtimes/assets/statemint/src/lib.rs @@ -120,10 +120,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("statemint"), impl_name: create_runtime_str!("statemint"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 12, + transaction_version: 13, state_version: 0, }; diff --git a/parachains/runtimes/assets/westmint/src/lib.rs b/parachains/runtimes/assets/westmint/src/lib.rs index 45c0e9f27b2..97d2596a4bd 100644 --- a/parachains/runtimes/assets/westmint/src/lib.rs +++ b/parachains/runtimes/assets/westmint/src/lib.rs @@ -96,10 +96,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("westmint"), impl_name: create_runtime_str!("westmint"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 12, + transaction_version: 13, state_version: 0, }; diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs index 3c77d40086c..4ebf760e849 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/src/lib.rs @@ -128,10 +128,10 @@ 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: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 2, + transaction_version: 3, state_version: 1, }; diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs index 9c9c8ba1c58..109cd2434b3 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/src/lib.rs @@ -128,10 +128,10 @@ 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: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 1, + transaction_version: 2, state_version: 1, }; diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 9c52457d164..04eddf59e3a 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -187,10 +187,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("bridge-hub-rococo"), impl_name: create_runtime_str!("bridge-hub-rococo"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 2, + transaction_version: 3, state_version: 1, }; diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index 4d89bfd8718..c928eda49d1 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -105,10 +105,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("collectives"), impl_name: create_runtime_str!("collectives"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 3, + transaction_version: 4, state_version: 0, }; diff --git a/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 57396a3a0e7..819bb7ba537 100644 --- a/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -120,10 +120,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("contracts-rococo"), impl_name: create_runtime_str!("contracts-rococo"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 5, + transaction_version: 6, state_version: 1, }; diff --git a/parachains/runtimes/starters/seedling/src/lib.rs b/parachains/runtimes/starters/seedling/src/lib.rs index a1754002cd9..2861cac1fe4 100644 --- a/parachains/runtimes/starters/seedling/src/lib.rs +++ b/parachains/runtimes/starters/seedling/src/lib.rs @@ -67,7 +67,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("seedling"), impl_name: create_runtime_str!("seedling"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, diff --git a/parachains/runtimes/testing/penpal/src/lib.rs b/parachains/runtimes/testing/penpal/src/lib.rs index 62a048bdbe2..7ade3bd2f63 100644 --- a/parachains/runtimes/testing/penpal/src/lib.rs +++ b/parachains/runtimes/testing/penpal/src/lib.rs @@ -224,7 +224,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: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, diff --git a/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 532f39f368b..1a26290f2a3 100644 --- a/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -101,10 +101,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("test-parachain"), impl_name: create_runtime_str!("test-parachain"), authoring_version: 1, - spec_version: 9381, + spec_version: 9400, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 5, + transaction_version: 6, state_version: 0, }; diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index 9b1e0e10484..7c45491e1ea 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "polkadot-parachain-bin" -version = "0.9.380" +version = "0.9.400" authors = ["Parity Technologies "] build = "build.rs" edition = "2021" From 25b7b445745fb78e6aebe1df80d9e13f500cb307 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 5 Apr 2023 17:14:51 +0200 Subject: [PATCH 32/57] Cargo.lock --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3245303d462..d1a96657fc5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -743,7 +743,7 @@ dependencies = [ "finality-grandpa", "frame-support", "hex", - "hex-literal", + "hex-literal 0.3.4", "parity-scale-codec", "scale-info", "serde", @@ -760,7 +760,7 @@ dependencies = [ "bp-runtime", "frame-support", "hex", - "hex-literal", + "hex-literal 0.3.4", "parity-scale-codec", "scale-info", "serde", @@ -810,7 +810,7 @@ dependencies = [ "bp-runtime", "frame-support", "hex", - "hex-literal", + "hex-literal 0.3.4", "parity-scale-codec", "scale-info", "sp-runtime", @@ -835,7 +835,7 @@ dependencies = [ "frame-support", "frame-system", "hash-db", - "hex-literal", + "hex-literal 0.3.4", "impl-trait-for-tuples", "num-traits", "parity-scale-codec", From 98f6ca732b17e36bb6b2968614241c4c4b5cc44a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:57:14 +0000 Subject: [PATCH 33/57] Bump hex-literal from 0.4.0 to 0.4.1 (#2434) Bumps [hex-literal](https://github.com/RustCrypto/utils) from 0.4.0 to 0.4.1. - [Release notes](https://github.com/RustCrypto/utils/releases) - [Commits](https://github.com/RustCrypto/utils/compare/hex-literal-v0.4.0...hex-literal-v0.4.1) --- updated-dependencies: - dependency-name: hex-literal 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 | 28 +++++++++---------- pallets/parachain-system/Cargo.toml | 2 +- parachain-template/runtime/Cargo.toml | 2 +- .../runtimes/assets/statemine/Cargo.toml | 2 +- .../runtimes/assets/statemint/Cargo.toml | 4 +-- .../runtimes/assets/westmint/Cargo.toml | 4 +-- .../bridge-hubs/bridge-hub-kusama/Cargo.toml | 2 +- .../bridge-hub-polkadot/Cargo.toml | 2 +- .../bridge-hubs/bridge-hub-rococo/Cargo.toml | 2 +- .../collectives-polkadot/Cargo.toml | 4 +-- .../contracts/contracts-rococo/Cargo.toml | 2 +- parachains/runtimes/testing/penpal/Cargo.toml | 2 +- polkadot-parachain/Cargo.toml | 2 +- 13 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a6be69e4e5..99d36d95246 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -716,7 +716,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "kusama-runtime-constants", "log", "pallet-aura", @@ -779,7 +779,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "log", "pallet-aura", "pallet-authorship", @@ -842,7 +842,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "log", "pallet-aura", "pallet-authorship", @@ -1283,7 +1283,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "log", "pallet-alliance", "pallet-aura", @@ -1418,7 +1418,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "kusama-runtime-constants", "log", "pallet-aura", @@ -2090,7 +2090,7 @@ dependencies = [ "environmental", "frame-support", "frame-system", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "impl-trait-for-tuples", "lazy_static", "log", @@ -4067,9 +4067,9 @@ checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" [[package]] name = "hex-literal" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcb5b3e439c92a7191df2f9bbe733de8de55c3f86368cdb1c63f8be7e9e328e" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hkdf" @@ -7333,7 +7333,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "log", "pallet-aura", "pallet-authorship", @@ -7576,7 +7576,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "log", "pallet-asset-tx-payment", "pallet-assets", @@ -8545,7 +8545,7 @@ dependencies = [ "frame-benchmarking", "frame-benchmarking-cli", "futures", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "jsonrpsee", "log", "nix 0.26.2", @@ -12676,7 +12676,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "kusama-runtime-constants", "log", "pallet-asset-tx-payment", @@ -12746,7 +12746,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "log", "pallet-asset-tx-payment", "pallet-assets", @@ -14742,7 +14742,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal 0.4.0", + "hex-literal 0.4.1", "log", "pallet-asset-tx-payment", "pallet-assets", diff --git a/pallets/parachain-system/Cargo.toml b/pallets/parachain-system/Cargo.toml index c4aa4ffa1e3..107705901b9 100644 --- a/pallets/parachain-system/Cargo.toml +++ b/pallets/parachain-system/Cargo.toml @@ -36,7 +36,7 @@ cumulus-primitives-core = { path = "../../primitives/core", default-features = f cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent", default-features = false } [dev-dependencies] -hex-literal = "0.4.0" +hex-literal = "0.4.1" lazy_static = "1.4" # Substrate diff --git a/parachain-template/runtime/Cargo.toml b/parachain-template/runtime/Cargo.toml index 0fa6948d58b..ed56ee83e52 100644 --- a/parachain-template/runtime/Cargo.toml +++ b/parachain-template/runtime/Cargo.toml @@ -16,7 +16,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.0", optional = true } +hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" diff --git a/parachains/runtimes/assets/statemine/Cargo.toml b/parachains/runtimes/assets/statemine/Cargo.toml index 3fdac10c637..8328106fade 100644 --- a/parachains/runtimes/assets/statemine/Cargo.toml +++ b/parachains/runtimes/assets/statemine/Cargo.toml @@ -7,7 +7,7 @@ description = "Kusama variant of Statemint 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.0" } +hex-literal = { version = "0.4.1" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" diff --git a/parachains/runtimes/assets/statemint/Cargo.toml b/parachains/runtimes/assets/statemint/Cargo.toml index 273c3ff5c2c..a5d2841418a 100644 --- a/parachains/runtimes/assets/statemint/Cargo.toml +++ b/parachains/runtimes/assets/statemint/Cargo.toml @@ -7,7 +7,7 @@ description = "Statemint 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.0", optional = true } +hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" @@ -73,7 +73,7 @@ parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } [dev-dependencies] -hex-literal = "0.4.0" +hex-literal = "0.4.1" asset-test-utils = { path = "../test-utils"} [build-dependencies] diff --git a/parachains/runtimes/assets/westmint/Cargo.toml b/parachains/runtimes/assets/westmint/Cargo.toml index 89b59b7def4..a63353adb4e 100644 --- a/parachains/runtimes/assets/westmint/Cargo.toml +++ b/parachains/runtimes/assets/westmint/Cargo.toml @@ -7,7 +7,7 @@ description = "Westend variant of Statemint 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.0", optional = true } +hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" @@ -74,7 +74,7 @@ parachains-common = { path = "../../../common", default-features = false } assets-common = { path = "../common", default-features = false } [dev-dependencies] -hex-literal = "0.4.0" +hex-literal = "0.4.1" asset-test-utils = { path = "../test-utils"} [build-dependencies] diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml index 9d8703a6ab8..7a08937cca9 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml @@ -10,7 +10,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.0" } +hex-literal = { version = "0.4.1" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml index 2d00cd9fce3..adda06b0b3e 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml @@ -10,7 +10,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.0" } +hex-literal = { version = "0.4.1" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 8cc54ac2672..04aefe39ea3 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -10,7 +10,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.0" } +hex-literal = { version = "0.4.1" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0.159", optional = true, features = ["derive"] } diff --git a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index c0659ffb825..eca2c8caa98 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -7,7 +7,7 @@ description = "Polkadot 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.0", optional = true } +hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" @@ -74,7 +74,7 @@ parachain-info = { path = "../../../pallets/parachain-info", default-features = parachains-common = { path = "../../../common", default-features = false } [dev-dependencies] -hex-literal = "0.4.0" +hex-literal = "0.4.1" [build-dependencies] substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } diff --git a/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 9b5809b3d38..10f222713f9 100644 --- a/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -12,7 +12,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.0", optional = true } +hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" diff --git a/parachains/runtimes/testing/penpal/Cargo.toml b/parachains/runtimes/testing/penpal/Cargo.toml index 105f5f8072a..460e3b1d4b4 100644 --- a/parachains/runtimes/testing/penpal/Cargo.toml +++ b/parachains/runtimes/testing/penpal/Cargo.toml @@ -16,7 +16,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -hex-literal = { version = "0.4.0", optional = true } +hex-literal = { version = "0.4.1", optional = true } log = { version = "0.4.16", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index 7c45491e1ea..b4ced899f25 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -15,7 +15,7 @@ async-trait = "0.1.68" clap = { version = "4.1.14", features = ["derive"] } codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" -hex-literal = "0.4.0" +hex-literal = "0.4.1" log = "0.4.17" serde = { version = "1.0.159", features = ["derive"] } From a5a79db4f81725d10e0f1dd339fe7d9b9e837d9f Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Thu, 6 Apr 2023 10:55:42 +0200 Subject: [PATCH 34/57] Updated bridge-hub-polkadot.json (#2435) --- parachains/chain-specs/bridge-hub-polkadot.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parachains/chain-specs/bridge-hub-polkadot.json b/parachains/chain-specs/bridge-hub-polkadot.json index b317aab8df5..4c28b9d419d 100644 --- a/parachains/chain-specs/bridge-hub-polkadot.json +++ b/parachains/chain-specs/bridge-hub-polkadot.json @@ -31,7 +31,7 @@ "0x15464cac3378d46f113cd5b7a4d71c844e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x15464cac3378d46f113cd5b7a4d71c845579297f4dfb9609e7e4c2ebab9ce40a": "0x105ae18c05a78be70e49f4495fdfca8389f99173d7f1b4019e077e24e15abd6e2eccc1177642b30456ecd401c75684a9c1cc1c529879d65cc65c32766fcd6b8a3d28d22cb1ad64189d654e3a0270dfcfac27fdbacb78fd65a11584bcce1f01e656d2a621a4e8851a00566daeb02c845da19f19f208f52ec456d4e77600fc41c314", "0x15464cac3378d46f113cd5b7a4d71c84579f5a43435b04a98d64da0cefe18505": "0x00a0acb9030000000000000000000000", - "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x0000000042db356800", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x000000008253c5660a700600", "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", @@ -41,9 +41,9 @@ "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da96bec8fda58278126c5774c03718a23c75ae18c05a78be70e49f4495fdfca8389f99173d7f1b4019e077e24e15abd6e2e": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9a445791c00e77ce0bb8202f63e548da4ccc1177642b30456ecd401c75684a9c1cc1c529879d65cc65c32766fcd6b8a3d": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9ed0583dc7b08b990b14d4f0d7acf521928d22cb1ad64189d654e3a0270dfcfac27fdbacb78fd65a11584bcce1f01e656": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x69924c6272696467652d6875622d706f6c6b61646f74", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x99924c6272696467652d6875622d706f6c6b61646f74", "0x3a63": "0x", - "0x3a636f6465": "0x52bc537646db8e0528b52ffd0058a4ff04ee24062c13521068789374086c8a09b146729cc19a3a00f0b70c566b8fd8314d221ba56002f06409b933ae037c2e03f3526190dee8ccce245707d3bb3735cce81f7778285a9bbf7ef6d0faff1b698d1042c8267bef2db70c761401123213308b39e7a42ce79c52e0484bf106560e34410eea7067a8a35d9e429d0c4a4e165a773ec9671df3496217cdb1528a8d7f1c949c1b582c010b1a2507a855b4a11538c6baa3c4efbd6b6333d9dd98c1c7cc5104c5c6cab7653db3ba4badceeaa0667599e4d7308a987df4b5895d4349a9f5cbf1f5d8460be6d16888b4b39ad807fcf4c17b6d63e37b3382c314634cc1467ed184296e54d9c0103664e3a50cb8786c081ba202fb418e951503a33901038381c186380a6040810ddda88282691d522b392b99e5e8d764a5e837c74a39adf5f9ccea689bb870965573d3a85e538ea8de1c7b39205bbd40b86bf552d2339ad255ef91409d9a4a532a912a18ae5e4ae9f5cb597ae6ebb764290f59c9a7ebf4aaf7b15e2636dec6ef40dadddbcb60ec9456c776ced1993367e6b4b10245d5d6128d07ff608d575e95ed17888ddaaf0d369e6cec6ca4d70d973888f59d1d5ca07125a8c3bc037584802746319bee0c567eab77062d63ac5e0a4f9786b1f09487da5a150afb80cfa0c0bd5f0e13638c58a01ab70349c84b153bd857c5320daaecc52c8c0903d5ca848183bf241bcf1c647291c1d4628795750e4d610e4d79f6cea1c9050b182d938b56a6d3882c46083b1fbb6bb2f13e3646ce5228261be1a3b3e3b897ac5f4e077b3469c13a206d822f411deebe4a4d4b6d952c3cdc7864dda14df05a10b8f70b84da0b647ea767bdcf46d3cd1853c081c9c636318ba12f5e4172367df9d7c927df7b37f66bd9958b5ca97471a5cb599bd2d54979fa276ffdc9d3cacfa4253fa5ecad88ac5a6ff40adcfbec984df22c2bff58f9f7de8a442b399bd2eb9e2d55c043b2de22ac7cec6ec946cd725176504a564aebd7c646faabd9181f3bd60ba564e323165c8cf2f04ceba59c95b766354d817bbfa629d15e5389004bc06209b1c443f04c3c4722f17dd9b54da9bb7b2ba58cddf589b6df26d95dee8827bb58b93b829b1b352fe569eb5897f5ca2b3829676775257882b769133c4502f77e39de789a469f68e5df66440167ce9ce191f27d599388d11e9621aea8f6ea0512b2ef520aeebe2bf799b1319e379eb6cc3ee2794bd22986a7cb646cacfdbaee68ac1ce5b85b8a2f02ea588ff56179666c3ce55ac0c55f6a35ee0959f95b6232f6b6d0c39204a6acda65e0095e9ec1bddf16ba5cc6de16a21af7ccc42a5f083d33b6876bd37b5c59a601e8a962c7151d718f8b71b130b60976a08cedc7ee6632055c3c6f447858661f3772b1f13bbd03bb8322abd886bf240b7fa30d6c7ce4c241e463bd710b17a30e1d62708c869dbf242ef64a2c652c7c6f43006065bdc0b00f78da857bbf12cbec6eb481bd124bcb28e7ac5064151bff36232f085470c2c68e5ade62c529d2b14691556c6cd3c3b858a641151f14231bf163eb0071abd5aa89d4963e9fe57bfaeff0b193f13a7484c1f5d9c6c37e6f0e506dfd22fd57639ba00abec703f82c7e76d18a1a5faac3f044ff9e71c65a7c1b4fd7abb27d3b0fb3df12f6cb313c5dbfd45a67d6e1e009deaa37d66c7617166e12999572f3253b9fd55be2ec3c56219f2eb5f357bdd4f2acdc2679f9d8a8cbc4cecbefc04c6afc34b915b99d35b649be379e3e6f46689bdeadef74a3e2e13cb4ea7d96be67bdf144eb6fe381ad557da49d7f9b9119ce9c396367c529d29fefcf9a84b4b14db23e7b3dc846501533232eb8fea516c2437808e1170b2184b007d4801357bc51fdbea95137daeef768d4b3ed04151d98ea1adade1db6cf7d2939232f381efa001596879a60c35e93ede36079a88921cb1b0fb7d31ca7358adff2969fc98e2dec9ecd1807eed90935d9cdbf8d07cef3e600959dd9db8ac8cf7ae5e5b3de8a70569eb7d8a6f82c6ab07b3683daece4dfc66dba36f63dcb789bf5aaec3cec2e9587b0bbd1ceef7406bbcb000b9ff166d5bb84b50ebbcb43165e7697dbb4849422980861e12fb7e922b1f057f260e177a0ecd85add11f0cc993366ac3cecee0e363e7b1aece265c796b7239685b33bc2b2b2de67613de29d3973e68cbd2a0b1f3b6ed3abb14def39966950cd179dc8f834e282e3a126b858da281e6a428be56badf352fc52a3786865c6f277583ef7e09d8c75b8b28c1bc5cfbef3b311378a63a3fafcec6551e346b1bdd4329388a471a54d6c613c7c1f6e3c5df99188a481a54d6cdf61c7b1be8d87b6099e371ed8be8da7bfd38f0819dbeebfeebad3aaf71c90bdbf6e44036e6825c6de68fbf49d52863adca7cbd9f7cbd9f81e11f0c17ef03bfd208410be43f8ba4f6d571c23fdf87e45debbde3eecf7c064dce3def633ce81cb18078e0fcf1b0fff6d439658ad564d58aedca64b6d3f6b8d1bf5de286e537fa76117dbd4bf81bb9ced7e566a145bae517d9b46c1f74b8d7a3c307649cc60915051fb4eedab3846dee3df63f5791656de785ebdcfbeeff44e738fae3db74c830abe67848c2df7b89ced67b45157870e31b8f7abd9fe85e736fde0dee1f9bc1d79efe136dd68f93b9dbd0eda4d8c4d4213654f7b5db41a0799f2cad8232c9b048d7def6f1c64ca5bd923146093d0ec7b5fc441a6bc953d4201368969dffb230e32e5adec110ab0ef7dde8ac4d5cabeef74d61a7390f70bcf6de2d346dd67e1f919ec689bf806e0e0f9bc11896de2c34adbc4dfe9acb5d7b5d538c89437649398f6bdbf7190296f658f50807defbfed08b7b2ef5aa3d8f6792bf256f67da7777aa7779a3b6e139f7b74ede12cd3a0ead76964dcd93b37eaf25fe536f1f9aaf76e643cb4c262d9cab88608dc3b9f311d573c2b380803d311021d3bd0a145c7133aa8e810d211850e11dc6471e38452144a612861b901a3a482521ba533375a94ccdcac4a6428ada0e4829b266e667073a5948392144a502801a154849214a51f94be28bda034460906a516947050d2a264831215251d94845062418908375f94aab80142690ca52194a628597163831b2ea52ba52b6eb028f9a0d483120f6ecab889c1cd1525316ea070d3821b1adcfca08446e909374fb831e386073756dcf4a0a4e5468a9ba11b2f4a61dcf8e0668a9b1594bedceca014849b2e72f0200717395e90438a1c2cc831458e2b39aae410410e2a38b080a308388880430c1c2ac0e1021c2cc071021c2dc0f1011c2b1c2fc091054709709000c7087050c1e1c48d3338a2c0d1040e28703c81030438826ab2d408e188010e18d4c8a02606385280c30438aaa859a3e60a354ba821a3268c1a2f3553a8095353460d18355fd400a166a8e607355ed4f8a0a68b9a1ed4f0a06607355d6a7450c3454d0e6ad4a8195323859a346aa25023a6068d1a28d43ca1e68c1a27d4985103a6e6083546a82942cd18354aa849420d126ab2a8c1a2664b0d0d6a6650a3a5a6053554d4bca0c6053557d4ac68ca40a306cd1668d2a0294353041a23d0784193058d0868a8d040411203e909a433484e209981438834041218d2114844202d8124041219a42e483f20ed80c4039217241d907c40828214054988440212159208482020a18064853bc3b5c19581e6061c19b82b382b381b7020e062c04d814b83430227032e099c161c1a1c182e07dc16dc0e381c705c7059381870419c135c16345f8cbc30eac2e80aa3354644180d612484d1975110463f186531d232526384c5a88cd10c465d8c7230c2c1e806a32c23334653185931aa620483511646564658462f18b960d482110b46538cae8ca418a96084021c6be0b8028e2388c488a6205243faa0b34824c823cc362e3266182498c702915096846703894624c2d382de001bc24684cd0bdb17747429d5601b336fa045a1594112e1468c1b186851c8b1821c56908c404202290ca90cb9031c34104931aac2768211998d04a2283c33b431af8ccb890c0c99992c0c1a1a120c9a14ac2ab62c58566c5bc8dad0d4905f906c685390429062889a10adb23188d0905ec8c830323302030d970c0a121a5a17b632db1a518dcd0aa31088ba200a83c8cc48484486519551094624184531a2321ac14804223188ce88be300a12c560f401111b23274620108d61f484a80d9116910c4459445788c0202a83c80ba3d5080a9113a220d1073032d24bdc8206085c19394e8099c9c47058b817702ee05ac051c1b1805b0137057785938253019702ce0a8702ee049c09b82a5c0938127023e0a87022e0a29043d886b2236854c801830d0bdb1568ae9855e09041cd0a465b6a6a70055d57240f2418db131e0a6410de0ba80e2e31640fe417b4049b162c32ac2c2c24585c2c30d60c2c2dac1a583bb0b6585bbc135c41d884f04c603d61396159d9bab071a1c48524038d151a991a2b6f0a1c584420c0d8b8c2d0702075a0dd807e80367179913920ad484dd095b6856e42c6408342010830aa8196469c822606a3c2c646acc284415c63e4031c56d0048186058f8a672516e181e195e0128204c255048d0b1c1bd78a860ca51d5c5f6e6430cd94b028758181a1e485080a9aa00d0824205c4428a5006b83060c4c0c2f05375594cca0f9520a53ca525a83d4031c5794bc4c2fd4b0a04403cd079711ae21605f209940f3e22608372fa019832c82c6c636846b0c2c0c3754e4c0721d4176b939a34d7093e54608328cd2961218ae264a5626186ed0e8291a8a0eea271a04ad8216ea1474085a049c191d45c7401a01f3021302f683f805a98d08463626b342a6c66bc19342669158482d4f05cf056f05740bc90ab406d109110af18c7705ab01a6034c0b8a03cc0cec0cac8c0d05db0a362bcf0913cb134373e661e1adb189b185f1ce7865de169e161e175e161e1baf0b9b0eb62e5b0e361e6c38d8bad87af09e406386a4851a10d08081460ca40fc82ea4175b15a8094a43f4049a164843f20be60539147330bf20c7a82981fc41cd14920b9a30d0b4413a018d0d5e959115727cd850c3680b4984ec597e99145743274834b9c012294d9c14b16449f62011519c2c59828d4e209a5318628911188852040a142316e033841328508c584001a61a45f864208a132863d889130c2c31c267894f111978e24489d394022301e549131f27442c71e20403039869b0111888f2640907a638d9c0114b9e48b13e519c6880034d907c46819d0c11c588284b9a2c7922c53a19228a1110f089b201238618c2f29862883062082744cc30d1602438e0a46709124870c0899128463c410209273e74130aacc41329768a939e29460471a49b4f60273e4d887802a549124b9c6cc0c906922821c2490632d0444901e6198c44cf104e8a18c2098c844f1427539c1411e5c9a719519e60006796c1433c4122ca93293e4b3859c2012852a4345932c50911509e6c20d533841150523b6618d6c092263e4d8868e2e3e401a4d9840e3c81d2e489cf93284f6e4c2670cf104640b9c012273e1b18c2c9124e68e612788a110bd026198c8493273e4fa6185184cf069ad44c257014239ef83499b2012296f818010589254fa4d8265336606ff07302e5024d7ca26c00034b7c867032e50911519e2c5972539253b082908618cbaa8c87562bfb54f066ca31e4184fcab3a249eed8b143ee30bd2230c2ee8670c21cb31bce39678430079c0d59ce9edd3d99e7e4399b19ce397bce9e3c67cf286aeec931c2b8bd37e57bf4bdc7a2191bd2c873cad19c9452d81d23e46608638434526eeec9909be59c7cd16ed9d08a6d61104e8b36e489031fc3ee19bb63532cd2502adaa22582f01271431e6ee684b41bc248244e9e1a6c8673c2d8dd52ce9edd947273c38e0d3b32e59e3c39c638a4616466e6c8b121336d9e9125b38c94f2e408657c30c2399f7c70ce08e3a458d3607177eb98cd0db91b3277a47113d188d150cbb220a4dd13462cf2e428e3e4813032f7a4dcb02303e69c81be271790b233ccb02347734e39e700149000284751d2393738e70dd9168c316211c608796618737c8f6933a5a2b8e98031d28e5076531869209c7342c698638fb01e80860052001ac21d6e6e649437982184338790daac71cb8d528ad118196a91d42d636cc8734e66ca0c21c60cadd96c4186f0eac9dd3d7b4e9e934711366d6c72cf09a1462977649e54eb86021080c6ddefbdf728a5cc936adcaf39088c1c0f0044d381ccb0a1c5dc1cb9c8dc28e6c71a37b786a3e11580c910728c3de89c73c2c93cdf7bdd1d63b7d6ddcd5c4fe6ae1ba71f0eecf728edd910f2eb86b02373472999658c18c64c29a514d218b72d6e5b8c8d61dd10521a23a510520823a558d34067f786619b8e39fb3ad06e0921e41b489b3684dd8d8d646719ed39e77cf375430dc2d1ec863ce3d6cd5b0eb0453c98b979e210218492524a23c422061bc238bb617733ed9eadddd0b099fbbdc7dddccc1036cfee39999961f394cd10764308e19bb0bb658434cad8a552a9444303bb21cf391936d7ced1b0b9236c1c8c43638deb20e50821c44636e47073c70821843146d8af1bc2d7ddb161c3eeb63aca097bf27bade30a1d328034dc1c986284069c68603a49c20994254b34d1c00c3832600494251988f22403193002cacd0f229c4c7142c4142396a074b8c1c993293e0418c0cd0d1d3d4334b90014284610c0003a00000000dcd4583e433441224a93293e4b7c9e68400346986c2a0e298a1329529a3cb641030060274ea66060c914237c9a0c610414284d00c03668e0894f940d4ca91c067c36c0c349114b7ca23c992265c910483cd1c08e1c503c963042091f00a074b8e1356c03901b6c587283939e26502eb02403519e14814493224e3ab7841322a23c5912e549932286c000068ca8384081f2a427c7071203a8816ff031c2085301d886264ea6d838e959e2b384932835d8f838c9c000ce3620e183c493259c1080007cc3124f30e0648a941cd294264ea00cb1c449069a4c31c207892544407952c4104b7ca06ca009069c1071b27ca634f141620037d070621b9cf83499e2248a930c4c41220019df40841324907032458a068c1862c914274918318493294b9a2041c4104e96d8d083d2e1062943384142e72a62089f2617585204124fa23cc1802989284e200fb6614914239e2031c549124b38808127539c24b1e40036e8a0c30d44385962848f140e4c196289cf124e6848228a134880ed8b563d2056010101c18d89eaa99e6a040414a104a2aa0904c41148a59a2a20958a32513d0c0848a5b298a86033017a2a2020a0080499a81e1010902a32513d954a0504a49240404f95316120205601351315d00352412020555f4c18085349c804e8a91e13a00704d44c540fe8a9281306026a260cf498a89eeaa92c260c04a452452640ac9a4c548f5592093313d553a9221356a9549009ab54cd44f5548f09ab1e930644331e333f0d20d184034d48a3d3e038cb43283843060ab00006b7591e4281989c130055610b24e802cc1364d046cd91183421042a98410cc4a841c363065244e184952d508982f4c51621a0528ac1ca962c0f457106d7046ad9947634eaf6b0d7aa507a58939712c4150c4d259c004e2146aa014573259bd21466225fe13debafd21584810cdfa766ad92b5a60083b51ea9a4acdb9c83700fcb6de2aae0d85e2ec582153cb1951ced6c6ef56585479826a8b145680b4f400277802a60f1654b09ae10c39651507b9145155010a65a1e2a410b4e40c6dee758e15432c7956050ea0462381b1d9687a260c34acb4326c082bd5c63414b3940d8cbb3fcf8da0cae47a3e4df4d3534ea42e961699b5e1c81089460dfbb0bb7c3f29008d8a082cb5165065c8e2c4d7037bc4802575282139c8de5212a578045e06e581ea272c642311c8de5a11158b1f731f56ed2d9b1c20c3cb1a5f63d3acb4324e062a3e5212bb4d8fb9c1845895bad564d685f7c1163a5d01a20b0b15caab13cb445c86e9687b210434721e391161c0341e88b25590602089c609f7cd66f0d96cf6c4d8deac3cfaedb7854565431d3c5184d08d2a28c94c8ca7340088112acfc8ed6e1a1d56a05454abe8709ea702a567a65c1b1a5a9f778c8ca0eec35d9329cc00b2284e0036840a1456ab34326e08285b7d9e93ebdd34881bbe5212b5358ccf2909512d877eef16a0f07a1d0ec35e5ac562b2790b0420d2b76d0440fb458e5e4dc202ba2055bacd448838cd5180c480959004212ce18d30426d85b0a12edfb6ab5fa40ca085120610b131c61044268428a5a212508d2810c6a2085316c21f57ecbdb7b5364dc3a6fb55aad56a99b63397581f097206d190c62084317a6c0620a62c090e2738db22cdfb4d33a31c5e71e32863ab0cfe79e10d829601505a15402ceb4404c2a6bad3b1c25f507014143295839787a57a5326e08f9125d95e51f4df86295ea8e5340fd9680562ccb32124f4f249e569585b493f05365a14f5b596f783f5a25df2ba3bbfeebdefb4eb7469ff136e4595a7178604b4f842dad3a88c0517b1f154b0fafb256f7acf58e9770a72d95959d0fb4b1bf0355f2bd3063a2181385485e544522a128c688a2182314c59828b6df6827094681cd39cdccc9c69c65e65c634e3273d63746f4fbc64c51e5be6134bfd947dce47a3b6df546dbf56a76abf3db693ae6d33661c77c8ae74e87181c5635fec8075a2cd68fb0da7355ec2c3a7f24faa8de4765ab3da26398b55d547be836e7d3ce1b4f463f2fbb292f29fda4dab5b173c2ebb48b62637be6af6750c3baeb96c56559e53a9a6f9df52cdc773a6e3dd49c44693aad4ff33b70eb2c9a8ebb3e491df7899eb3b0633616d32c761dc3b873a4da8e36bd7350e77d7a367d1a33664c0e07c6ecd8cecf3a5275e162924ee5398e548f90e9428654afca924e3b3a27fd9c64462775a3c705a5afcba35b4c2e5e9746cd47c6d229252ac7d29bc3e362be299f651df6ab63cb356a5a5dcde1a71c237e815e7a887661e716b4be2e6d9a5decdd6e9ddeee42f3576f76d2f9d8b9431d9ac3775a2f109d9abf7a732c1d9d7217777aeed37558afeb65158a6649b1de1c6b5d74ec6ed5a7b1f76849b527234dadfe76c5ea8d8f8b278474ebbd1921d5c7c5fb618dea5565b5e7bdfab8b0ba587a2a376c3efa289596acb13b8287cc63cfa046d3d57c76a267d967979da6ab79169aeff4a473ce476f3d6b5a59849ea2f94ec38d08bde870e3b92aade9689fe6b3ee7256373baea63b3c61a28ea6e33e7da733da65bfbad8a6ecb3bb9ca536fbdb8660cfb2bf8e7697e3e1b40cbbba529bde0f7576f4e9d9b4e99d9ed62e5c8c9a864ba692124ba4025e692bcfc65a45a83e2a6d92f331fe768df59dd27ae9af9b233ae4631775dc27ac6a1df335cd6235fe521d6270b442d12c7d76598ff53ecba7bfa495bd19a113a3efda6359343ecee2a4d53d8e9a35245e46d16c4fac54fb79aaf7e47bf3d625ea72e009ce7a2407eacc6a7542d68be251699475fad9d17a55f659d6ab6c9d9f10b38d7f5464c7d1c6ac754497f139504754ffba67657d16020efea7eec019c5fb111f2f77e01150ca98b5a809dc4fac616f7928088bcd386b8db79a9a77535353f39d7e1b4f0de9394fc88d93ce8d22fdc6e56f78426ed42337ea55d91b2775949e44a294747ab8f1d09bdfe86eea55d91a12e96fe32165dca89a7a9f259dcf94cadf7068a551f492d4d19aee3e5bf31bde0f4b63a6f4ee7073b0b45e199f0347a986471eeaece4c05192ddbc173b00cb4320a0a28cbdb13c0402326c0635a9255e01b13415cfca7ac5ce9c2784adacd04a9be673fc5dde68715cfe6297721bf2787cc72fc5f9e574d44b7acdb951377eb96fdf813a3c2a137882df51712ac353a6a3323cf56f894b7ce6ebcc3a67225faaef7a4b5cb3abde1dacac94fe46c76dba372e7f4a730d52ed34b7a9b77475dae96b3a1d6270a4ea236d0d4dbd396c9d0e3138aefab4adf9cd4189f4d0475b537b48b5e6d749bf70549fbe58dda4d56a0fe935af7937b4936a0fbdb4703b222dad37bc1f9abce1fd90d2ca46e78d47f49d7e7f1b11ebef5af72c5f5836b76b44b64f1d263590c4a3318117cc6e0f3bcf04eac43ecd6bd4c6ce1dbd0dd93e3538ea445ddc3aad4def5ac7753650a7d4a7f71cfb4cb7efc7cecbae5a37bc1ff2f2b3bbaad9a6585739ba4605345a171a9588e5be15e53e3aff5979571a85fdda61af6ebbd54df825a04eafe0099ee6192465d925655f939ac559f775599a6665ef3a7d22ad8a2e8d8ab5a49495f6af9455caae3dd7e9e52f148d33a861aa1f4b93b7b42b58d7d30d2debef61d7849e90774cab62c9d6a868513c21d8e7b35b56bd1a153b4fadc746896eddba9665bd5745134d6b094b62960e28cfadb3043c416afd55d95d1684ef15d4814236a7e99585525e4aeb9a90d5ad51b91a158b711b119afe880683b0e63650deb0115995e69b052dabde8057ac43cba6a6421a6de3c1b42e6c76d1ebba5a6a42d6da81a26e74ade39e75d8b7ee8a5f02ea402133a54651d12849a4ed281e0a411d78e555211bff4eea1eedaeafdbaf66b3d6b428decac2cbeb6359f692c7fe6abf0bfbf5ec3decda36f9cdaa9afcd6d1639fb7abd87878054678c5b2ec76d1ef13b218767acb8cbdd46ebf508b8de73a6ed3f65117dbb4d5eb6359eba2ca9af5ac6a5160d8e7c6836954ec655996a545f17ecc88c5320d2a9a972388f4daca7b63b21d6fd4756eeadce8edafdb324829855d8f85510ae1a41846b94bba7552bd6de11ba393d3f03e6b5d280d6fbd698f4689ba5eefee2e73753df440b6e19c37dabeaefac834a47fdcef1b03c7748cf073c2dad31746cd4ed9a7af9b3007ea7076acffb60758dd5d1ff851f7bbe977201d33c65edf3ad14684f4ae3d7dfa8da4750d8d467a166b68fa246ce3b9acd80c766cbb21ec3a5ad875d3b95d76cd75d76dba1b5b37b796368f95833a36f5db5fd728ea1b2d7dd4aa3dfded34eb1e11be6bbd50b4ae37da404b6b4f7ffe3a7df666531d9bd3bfadc8f6dea7ddf581b65fa4db3568dfaf0fb4dbb3b9c9ed71d3e26ff8404b9fc531dddddd6dd3319f9a87b8ae09f320f492412b76d5d7e6eeb83d22ad21a751d6b57e5d1f76fdecbaaeeb3deb7a46f4bab20ce7efa2f4f03b7d937d242f6fdbd1b17adb66df69d95d6885c94757be5fb527fbe8f2f77a16b51c1a75e32c2b67e154fdc83f78ceb1108bbdf33edd731dc84aa892d27ace13026fc12bf25d87bff91dfdbd7aa1153bdff455a883569fb6d9fb1d559fb6b034c6652f7707fbce7c73b04ffeb23ad8bdee76650275b8742dc7311ca7e746e978c03bacf7d9ecb2bb38f5aa37da577146b73e2f3ae93545e0e5e5df76045ebee73c21f2afeec09d9617e7f3175ab1d65bb4117997b547fefaf6ba1bde0fcb86e60c3909df79c05f9cba43db88c0f73c9c67db11cdc233795ac5eae578d0ba03cae3605e6c96c969471ddb4ccaac939d1c5df586f743e6d8f7b91181ef77f33abaed379df51d085f770c750e4ff1a57a29e939eae56a8ea31eeaec8c7eddb0a9b754536f89a6926eb92a8a17cdb067574647cf30faacb51b9e90fb7268947c0e3b58c979b13c8695753ed3a123084f878e20d4ecd97b80f56b667f5b9151bde1fdb82e9f75d7a7adbc2a0ebdf5f91da8c3049ee24b258e8bbfe109b93ea5b4a38b7e73b0d67564a36b9f1b91ec3da37a9fbd8e5d6e47349b9dc9e8948e7e393bba2eaa37073b7f4b76ebae6bf5862724bb8edd8256ecbb3a392dedd84a29e5d5454bad7ac3fb31e55b59a641a5e3e5c08117ab59d1bb000115ab83e52128c8b0198f74c0f11014575893e5a127c66087a0d8c266f6fd51b13b1ab59daf75ee39e794efaea7b539a59cda6ddbd15e1ddb47455e97b3de47c5cafbb48d74d239cf9b91f8bebafb66b4b264a14da3acf329cfcefaebacb308da1b2b55fd00bdbe4cd8f8aeefbe2b769e763dda816cec2e2c026df6e83bad0c63775f15fa7904b4f7d9acf6d06b47467fdfe917c513d29fe746653eedd3d7a72df751bd6db573f5f6a362a7a85e6aa1d5e8b5c71bd1e65fdde9382b8e9603753e3af680f7586f91f778e43d7efe093d21f1b3bf036d773ac4e07cdac6ebd3f751b1d7ad6edb88881e6b4f7c5f1375f7d977611fc5513645c7661dd51be345571736a3725aad634ba33d226dd4ba677b2b92d98e1dbf1ff709d9695d76f1b393cfbaeb3bf0cd67518b3bae6725dbb745780eea90ea766e94f6d8a77ecc74e808020745b33df1f4d6af66ad78846e8f76ab38d6afcb6bf5f4f242d1acf6ec37daeb7423f2dea31dbbb51dd1ec7b8ea6d167f545f184bc7a9150597aecd7afcf8de7a26267c7b1634b3b39add5b18ddde5808dcff8758bae07ce5b116963b45691cccefaa2783f641535d7858c7ffbf502de7bcf5e87c3678b33e4597ebfedb31cbfbf21b07256059f125007eacca766c77c52825ac829d9bd146f47e8036a15ec1745c6a32744f86c04994d17befb1eb0f0f1d91e5839213620847cfeab971f21e4cb4386104208639bf8350cb7d9086706f6c15759b6bc0180c70e1c1d37a51c386ed8d4d090b89168d332eca2d69411f6631f7cde8e78676c16f89da6946f490756e6d33bdf3ea0a7eaee3119332a46a8d2a1d482273ed07b44326621fdcbb7dcd154c1b5e5bff366e4d91eaef4fde0abde23c29144448c9936b18d1c638c31c6c7c7183f1da08a36d61e8e4cf755361bf11f07e98ed9c7ed1b81ef27eb90eed8aae24b82ebe55ebdf35766f25dbe65a56dea5906ae7f350baf35ea556694fc7da7345570d1be43dbd3f075b44dfd777e50c8a0bcc20be69cb3a5946fb29c7342f9031347fabac560cd796959b846cd2b4f4f3723d6e7ad78f98cdeda78e8a4dd232715e80ada38030c4d464a8a9a59289ba66627ed984f932e41a1685c97f94235ced44506667cc1e6edb0cf14a78ded78245ac9334bf7f0046db438d4c999f5529bb536bb529b72da042f04a79daff0648c7f1eb0dec663b1659bf57b328b2df2bd2927a453c2a90449352e8e996678640d669536784a389f10e918d97cece67cf34fbef7e69373723cd675d14ff9792bce5bcf2ced48bcfc4e67b28b6d9ab71e371e0bc6ad48ac5a6cd3ac3cab10379ebee46c4a5d784146d806fc9c8f1f718d9a7fbff17133023f0fb722f1b3de9652f644188407468585c5d878290517cf626c374f165303f94b9a554a97a00c97e148590cb6042c96c0621e182178f125fe9c8dfc7becdebb5034fb2ea566e593dd1d01dfe34a2549b9528c345ad3d2216394314ecea6d4f11d35d9518d24401b403ae11326d5381c4829a794528a216f20e52307993ed04a39034e6e467a4eab6336cd09ed3c63cd24a07cbd8559866af5422eb63f21151b61156b159996d9c78542436e34181bd9ce0e0ae462e3dfa31c776d9a0c1bdf601a05b9dc40e3ceb06930f6c2211c56d659a54df022326093612fa41a075b8b2d4e00b9d8196990f1e809f1f723343816c30a2a56deba64473fbbcbc44ecbcaa4263729ad5f1d63d9b47ae5b1679cb51989a7f5dec8122bdfdf81587751ebb22c4a2f6abd6fd524a49db547d61a21173800667229c3e4b2058bbb2e4f39c8bcfcc541a866ad2c4150e4a428e3201f741d8aa7300c08eb26e320a995406d6995ec434e2b553ccfce1ad98794aaab63d621fe44cdca25448d9b0dbdd04619327e46d94d190f3f3b1d6170f16ce533a8bded08bceca29572e3816dac7233f28cc0ead3b67f04ecc7f7ce78116e3c196796c61b91f7dee7c613df7b2fce586d2818b8f1f433f980f77690bdb5d84528e59c734e28bf8009a1075819eb576ab151c2c04639858dd204365e8680753829548170b1c1552acd3083bd9c9542f6ca210b7f81587656ec0b1b72081302172f80e00517acccca9292ce6bce296f3d931d6d1316eca2d39a9694334c6bd69c3c5992ab523e74384a7cf8043e81fae3c355a9ac0b0febc3025087029fc0182f728d1e70924ac12df99564b003e0d7b7255dc625360a47bbca6a3bce56fb8e8eb66606b5f101b5c2dd8c8b853a1638bc2403757e5eca0215473ba72c70cd02180ab81112b66bdff10cdb7876d46c0e50d9edbc3da0dbd13d4b3723d7b78a63e4faf6adf674350bba118b0ab6479be09374384a92dc02b740fd497255ea32833b3ce9c2d9b48ccbd5d9b40967ab43da6ed733315027085691820a0f4941e5d99b301999357438ccd06ab56a22059f7969140f4dd18585cfbe409d9782dfb42be3d2a82bc9d82d1a7563e15b92813ad9157882a75492d98410e213386f4004710afc6d4038e013f8db8078c02950332cf0043f812ed3f2e07b8fa5e852c06657da04ffbc704cf87021ce44920701af589809e1fc6d43da66424ac8842cbcd6d1fbd0712a090e103ffc704e09d1e100010410e754766541d7c5c35dbfd9cac2ebfadbae3a45b3f18f7fc49f1dcf9e765defc73e1ac85edff10c6abd1981577d6c8acf56d703702b12ed8ec3ed08d4ae2e89b61a43d1f69ddeea11d06a7547acd9aa4dd9a5652bf82c28c3b4deae679ae6c3f5241da7b2d7f1418dba2a7cb66a148fc377c1a3c3b9feecf508743857956452728d3ec15f62e0b2a19a756913bc150507808afd665d22fbb8aaf64cd3ac4ed39208d1ff397220ea4f104ff21f3a1fce1b10ef3f48ee43fdf1e1ab0a9c091ffe9274ab0a9c8920de975b124e55c0cade96a41fc47fe8de81e8eec38f40e2d9eb231ef546bb63479b7890b84ddc261ef56a76c7699b769c371ee746f1a83bbea36266ae9a44a6249930b89b752153c5ce709c675da04e922791a92415c9d5b1ddcce0ba0b07c92c26aa506c6cf6ade6b4091e8915c84e1fb92a0fdb11ccca4dc991e300d14adee794dc9420390e10ef499ea432d1c3df39b5037de8381544c7a9193a9ceed27797b315e87e5e0a02cf72da34b51e3a4e29e938f5361eda046f9debac7a9fe52c29f2d649a7bf488fdb1079ee5b179ac35b34cfc604714592313d5cf1c31942683e9cd1a84b45a32e196184c8c40471c58724611a75b32811d3a89ba5875f69d4cd02c469ddc06c581a75b3fc70ab6e61ba10397cd6c590c367433c0c387cd61d3efbe1b3190e9f01e0f0199946dd015cc8e1b3351a7505f020651a750ff08d0c1b8dba40bead919959c0e1b331a45636684708a37255a1562c2d8dbaa8eb64d1a89bc375e082c31637745140170938bc368480c36b5e7638bcf6653bbc368676780d8c46069946dd9cdb70786d8d465d03fcc7e1b5323e0eafb151c3e135338dba3587d7c6d0a86b73f86dd5a87be3f05b50a32e8ec36f428dba3acee3f01b9546dd9bef38fc56a551b7749cc36f561a75735c4ba32e015e80c36f5934ea9a7e3afcc6a551b7c70370f86d8b46dd7a1a7e624a0287dfbad0746c33de68ea55599acfd0754d4e3b6cc9b36eabc0713a1e9d12d604feee41fc40821012c40c448218522f0d627bbd433e4310428e5395e0820082b331c98238009a5c881ab4e5f27890aa04bddb0f70009e7a67f8190080035425b8076d99a1de20d6907a19f0035425a8907a0f40831012e4330431c30cf5760740103300e0415b18506f96202e448803047120421c00c883b604a97786f374f502e00cf89908b151217032ec9d10f4af4a684274cf22c471986c423c632224c883b660f5762742ebfd87fceaae24375c9ceb54256892ed415b16902455ef759a04a33c922ce05b921b52db310b5cf562a7496e2db97cd0b90e3ef0380e38d81dcbd2e1385425381f1eb485d6ab73ab2a6151cb1e87aa045d40bd38d0243b3aa74928ad37bb95845a0fda62ebcd92e43b3ee090e4375425381c6ea0b7d6777e5920d3a15e9da77ce0417dd061f301ab37fbe503763d688b4ebd597cb80e16e0e1c3712ca0a3c383b62c20abf77aea5aa7f55083b65c1e6e0db7a12a417be0f1a02d0a4840bdda96d9d0430df516398f1e6a48008f6f14d0eadd9ef5f058014d490dda7215707f501b10506f766d87186da8d786fbf8f1a02d59bd3b583cdc47558216a9d707ed01013b3ceb21cb620f597cd0161eeacdd2c311a0c4470faf41898f1a1eb465877ab323207e876b1450c013a0c406aa24014ab67a71ae29d9b4076d5140bd59943c0114b041c97f50c0861f0fdac2a3deed0aa8577b02be23023fd05095a0948702ecc0f981074e030a5095e07e30c2038faa8465ebe5719c1f2eea94b06c9609ec00a2066db945eee901a84ad0020460070e91a800a77a0bf000542538204e38f5deb01a701c3fd070235509fa038e1bc7f9010747f4038ee8415b1a506f961f1e002068f8e1388008000d0fda72a35e9cdf101dc77754252c9b25023645a8cd02440128103cd4dc06081ef5da7c475542b3f589a02d3c763c684b917ab300711e2250807ab3083d05c44f5509ce3e11b4a500a7076da9a997c76b6ceadd719bef4022437818b08094dd51400210b083906e000fd209e007e87a1c4857afd3a174e8727829091c87aec76fe8ea6de8727e7406e89404eea3ebf11abafa0274043875a61f9892400dda3280ba8969133c144f6d1140ddc6b4093e005d8f9a2502a7a1ab11a81b197882ef3a1d7f77f319bad201d0e5388f4ec7777437c7e94a177539be753aae7537cfbad26397e358a7a36e437d53372f5daadb972e47ddc6e87c78105d9203d1f9f01fba2457d2f9503730f004df4397a46e61308ba39b6534310436ec8dce2282901937b0361d9ca2892f59b035dd140110caa861792bc24396a66e5d20a9db6993e561d41d118f45ac23d2367bb5bafb179b42cda2bf36d6a2bf96a5bf3bac657d07d22396b0ec55d1232c9b7547c48de7d779f3695ba457abd58a07b6b4fab49567b62e8dda861a651d7ef3b27d69d475f86d8c466187dfc0342a3bfc4646a3b4c36f611ab51d7e3ba351a2c36f62a00ea7e046c6ae2cdb9b75e9b21db0099e76990f3803029be0b12e0b834df0599709814df05a9715814df05b9721814df0a22e5b029b601711776cb18eedc5677260af3453c395642cbcdc78ac6a7a01774d599936c123e9b22ef0047fa4cb86e0091e025df6059ee01fd06561e009de0199180b7f95e16ed6e5220317bb8b0dee665d2c1459f6b2b2c2deec8b8559171d622cd300844355a479b690710f0abb1bc4eb90439b1e576ee6e6e608238c3042781b0be1fbd9c74cbab1fc9fd64ba9352b6f3c4d77de7bf55a3c44eb11ae0cdca5b1099cac40daf472ae2d7037e7ba48a41b7b6f1eeb5c7c7a67f67189e13e2d7b69828b1dea3203dbcfb29231d461eeed201111c385ae80dba1513846faf0b0e2c447d8f59aec2b5114701c95ac7bbc2a70a536f55fe5dad4a72be0f8943b0a4ffd0c075e6561bd6c235f6670b73dd4850d7b4f51c05d4aa10ebf3fe405aadfb3ee92e82271b59ae2c3d98c7dc05ffc031e01cf8ca148af629d12ef43edc53e60c753c476bdd8049fc9b7c967538b1d0fdbee9268abb70740d90f8afabc0d813656ca3ee0e3799ee461c64844c488b1d25e6a35cb3d6027411ec3300c83d8b93b02fe75fcec6591524acf2c648a761f6ab5f33513076921f17f4262455239c8ab3db00f791c22e08e04ea882e2f04d451a5624abe08288dda2e2fc567090ef2ac7c1146d19c1c1a755d1ec80e8dc250d9e519d02878791e388875f94b54c626f96c76cf8a3a1e93da1eb7326814ace42ad897844ff2ef73e37972e3d934db1b12f6217f31811363df23c7f8a2e8aa980cfbd86e5d14759cea8d08b5cc3e26ec7cda241fbb22da249f7552da248f7550da247f7544b4499e764cda84049e780c569e036c925f827d886ac0c53318fb443678abab29978cdfeb87060761941242880677354bdf8f86536b835e5cf6e0a50c38782184527236ddbdb74d2e1c8402f7a0c05dcd7276418d07d618e346e4d92c4a39bb5b0391b626f6412d4aafee52229db114cd6969310b77a985efb667a0faf08f0ccbbf3bec0b63f93cb489790c08a94f8c94fbc20cc662e1ee0e54a354bb22fb60cba21a84107684b093d0e6d2e6160ed6ab61589669daa66da267517af5c0b48705774b96b94ccb726c3f28ba2a4bd907b375cd4b4678f5c3708a64f0d0c27a3960bb32fbe0e7dcf822e31e9762b1f1d97ba71c979873b0bc2aca82bb3c745f98db5d9a0cd4113dbecb401deef64e02c03c2c582857dae1209b8def2e50470a3cc553ca71a5d2ffc2409da7059ee2395a7a61ecc3024fb1abe06e7709d3527097872c7390f752191c1284d03d4b5750e762ec7d616cbc14a8f3d0e0533c15a816b832b14170c5c6534ed6cbd967ad3d2cb8ec098167ccf2a53c21b076974fe120b4360fd8477c7cf68424412dfdbd2cf32907a1e7c36dc8b5040e6e44a845c23ede455da768956470308bda43831f159e166c7c60b0f19db1b1414057f0144fbb0c3cc58fda8c4e7781a7f8d1b57a4d59bd27fdaa97a3b4d2701ca954e25e6654afc95e2e93a453a2da64e0295e44038ec1acb074b1f10f0ba51c774bf7b49ae2e9caa2ab49577465b77a787a148b651a80a6eaea11171cb3a73dfb9ee114998f9f8fa79736b8c2f2900dacd802581ee242c652cd06666c10c66631839bd4a4cc2c08b0cd2404d84efa66fac841a636b5b711998f46e63b7677f2f4c91e16a748db7e1219b82adbd691f9d6e6e3ec02d0f5b024c86c3064832d6cc659d46410fa1b3f393ef6717dc64e6b13bf87951d7f76d86317006b615707e9b3d8c95825fb788fdb90fe11f938f9b19bb7ba2b8df4b0dce3f4fcb4703ddc5c59f80c09932488795ebc764103d9093204b98091306211250fe47c0110208d8ad3ea52fac5c1f26db0fcc78e7b42ba92f807ac5cf385ac0c2153229b65f6c10577594c46354ae7a109ea98984008219cb5539915eeb21833720c8dba625b1e1e09d499871702ea30e424536bca08fbadba495b8c11032a62c0058c2c6bd81d96c1c81202c8c5ceb6384834558abfa37b983858c2897ff69fedf43d70aa34bf5d957a0e3cddced373ef8153149ee6b97a5a2f37facd91294e893e5f87138f049ee6941e38c543fdd981a7794d957a06c6ceade228d14eafd5d576edb46e8992c2e98a2301faec4a2eaefe6ce9aa843eab3f2f452f0ff1c88a23ff2c4e9178f98864ab3848ace328d16e5dbbf597824938a53d8b5df6981f14919ac0f5d06a655b0d305aacacd6bd2bf0349f9009b8cb66e2777ad43181a77951372f05ea609f5f02ea689fbf0007498263f28474cdc27d7e08d60982c294da2e544a719f6f9500a1d215ec3cf30e424052db2f6bc1ce6758f7525af7aac027d4a6799d9e64dfbf4f0849509076d183b28fce7538f1dc55a9addbb6c76f5cfd19d537f41f51fd62e7b5ab5259d6691d179cf8edaa54179c58719268cf1e6355927dab585e15789affd162e7b577c54eed09c1d3c45ee5d8473c897d44788ab7aa7c8f597b2017cb340061aad71714d99423de19cbf7a17704a6ebbf2e096a8fb0ce946165fb031c12a8236fe2203a2ca6737d523156c2cc64e52f7fb1f29db15de31038ed38b0e24038eb6532f0a2fac3049e9abbb659d6e1f0456070f8a2ab5261ace4ec4ab067e767f5670b5725d945f527079ee47fbec8cc044ff29d08db2925f6d127b18f63cf0e372deb189ee0e9651d8e12edd9eb631d8e928cc2d33b567b78a9ee02b1fcd95d1ee2f8c42fd15b96b7642fda71d756cd812796b5674455dd724bc63daeac62a98ce7670c75b628813adbf9def24d5027c37e732c77154befebf2b8a1e88877c66e1dc3d379c8d26b1dc3538733af4a611dceac48829a0c3cd1abe06a8e004b8a535bdee96ba0e038b595d9c2041ef4a0ca6a95c27e78a2dfa2a47f29b98ed51faeeb6d320c4f54c710c7a99c2d4aaefe55b7dc2cd7817859c8c11056292680ae5f15284a018b29524c00d5153ce30a5656a97e571c25d7fbd7fbd815eeeada0c3cd1f709b8db642ca5b54756896564d6b3db9de2f313d22b5bb27c93e573d72f0f597e0ed4a1e7f381401decfc8c762f8575176d93752c0b8e2d0e92a0fe3bc93e8b23ffa31d3b3dad3fd9afab521b0f92a020ec5a1db241d7b3ba034fd6af0eeb7270e4b3ab52407064c54982fdba12ecaa3f5b6455723dabe7e0c9fa8f75ac323ca952aa54f634ace3d4d5718a371e24149e2c4e3d2b388e7dc893d8878427f979ee610149d56b48052ed653fcccea7e180d2d8256a91fa02d7debd0bec36863198c32f8c0c27a73ecaba14d396d7a6fd37bedd3a6772957191c938135e4409db85aad565852ef401a55b2ef3b7010b633c6d81d5be6facb59793ebd43cc32186324c1765b1d8361056aac526d6f8b78425a32195944a39ee5a12b5616b3efefcabba275342c3e8de2a1147cb12f759fd0d01551d8fbaa6058aea881bd8f8a97ba6ce6be201e22699cb1f5d0a9c3d3fb4e6354707ff60878e68ccdbc5066289571936cda84d367314800c6429cae43dacab3182518b2115a1e0ac11816877d474281d6b9b8ac56ab26523c44822a96c9d8f7bb034cdddbfba058e5f297a06b680b0f910009f63219a527a489a411a62382c6181d1134c0b4896d118dba544aa32e8e251a754b501a95c3bee37842e0d9c0612f8fe14a83bbbdbf6179c8042eb05d218988187b6fdb1249e38c36b1dde92e4cb81e976c060cc6b6fca5ef97839cc3a73e95f552eed5cbd986f5966ccf60736ce31899c1bedfb2657b5fc529720b7f0b7f73dea63eec4cf03ddad4a646c17aa33531a3a6144290842ee8c4545b06039bd06206638880860a5e50842f3776bee0e2021f60414119d6b0e19eb0a202e885154164b891e5a12abcd003eeb23c54c51a6d050eb33c54451a65e0a2e5a12aa0d03ce02ccb43550455e86eda60b0200b0b1f4f447458373270f3d9ebb3e3ae8a0d7916fbec4667accefac6a01a839127754e904e032f127ba13018d29986f43949a4c3ceaaa48eaf0756365aa4932c49e5a49432a04dd46241175284c0beed88f558e9796813a55a70daad297034dbe977c68bdda2f9b80d8176fe69e12059340aabef8cec91e1b4bf54b2acdb569e8530f73624da595f18f6416f5981c33e4f4fdb846597dd94c73d2d5aa63c3beaee1bc3d28be0b3ad7b54b4895eeb6e8ea57f62e06e0b597a581f9636d167f55d6913fd0c0247ffc2401aad9c46454bef8046bdd32b69549f5e080ef22cfdcfaa51d7a320ebe5aa70790b96522d86ec653096be204b5f152b3b589a83a561e089d25f26e028f6c2404a9b363d6fb1ab5c3d8a42c63d6e63b1f091f9c5c85d3feefa75b2259411d6af4e960f70190896ff564f0c990344c186324e2cdfea55d9c1bbf280c042b8efbd823a4c20f715310f067c1263030bdf15cec0c2bf6a55e6d37d3bb0f0ada67df561d146c0757cac3950e7a5805858e53201d75866968cf9c44bcc78f927ace360c355d9cbac03eb707fe2df7bc69b11ce76bd526c9f9fa08f7fc2927f225639697d82f909e6d395622fbf6f5592accc36f07b23f252d2c8b3b67fe443504a3d113f6b0868ea09200ea3850c4f9031660965d8927a42d62dfd58f9dc1548aaba651a5d6aa0c516c0f2d01616747763163b8d0ad5a8b429ee40cbc203595d949aacfc7ec8c34ec8c2b8f13c2d76308af7035e5e9e08912e7e8348106158db7ab007553878860c2f90459e21bbc99a8c1e63dfa19826230c1992490e2fca69d14829ec47dfb4e835b5f7e885655ad434d84fa3da7b58a66d5e44512482fd444398f69ef6b637ca41e66822d116f67dc4c5be67a32bec3bc769afbbadc5be93fa0a9a484303fbd1349636bd9b61a3837ac5861936ca7cf14206182f5fbc0cbd2b1e9667e55d79559a0dfb0ecbc031720c931cfab217fb0e79c8e60024e7754318a39c714ed86fbe86304629a7152d0bf6b3a29cd3b228bdb08861b01f66d1ebc2b02cd3b60df6dbb04cd3b64d241a7191e3603f6ed35aa4f568a435c7694d22694d53136b6a60bf9af7ba4bdf8d1bdac381437b394ab15482fd4aa48ca6a646ebce6623f22c67a375776323f26c77383622cfc61c31470ed82f0715e114b96cffd9aef7c7c27a838a708a5c246c8369d37bfd4125e3ce72c87ab200e5a4b6c05b9d13d6a9143b7b9280364b07acb3953faa94ca3612ab5a9fdd646265653c6f3d70ca82b73a2754ab212c5584823ed0c42af5842ac5f0547bd8fa9e22e3f3c8091c8791032cf6ad74ba91185c0f3cdbfb5696c3c80117fbecfbdb8ebc262cd7fb56f1dc25118d8c2c1f765715e4c6e314c16cac478c2c9f9b6073ece533f6c23777dc8da8c0b50efcb71d71cec2ca648a90c54776c272e5c83efa196f90bb11181c7f91053036721049d29ee53072f0015b6ad37bc7f57d1163fb1997b1cf8e80eb3ec741ba29cf4e79f67252ba04dc7d606cff8169d4a58f0c4d8c1832f05ca1091578ae20a40a4dd37c269c10ae0adca1681ca4350ec2f0b09e7b935321e7f513d262812a5491069657455ad6a59452525a92d37a5520ad3a94e34a26139b6e8ea5409ffa63e00cc250a04d2dc403b8c8547855a00e05c6d87e15215e60823a4c844ca6bf54e2848882f5e60d2216ee321807b40eb783cee10e03786814fd5b27079efa3b6e0f2e7b55f27b4f5ed775ee8ee02803da15d111b15d41709149731f09d421a24ffde6356cf3308930e07ab0893ea75fcae83302ad752670abb7a475d63d2ca58095cc267ade8adc5a4510d1a6e6e1b45f16a33dab8c8c368a992b71ac130f2b37b23d3076777777f7bb1ba855dd3d052d36f2553bb841155cca30d3852e6491a2c1be7348b0ef363d741acc6ab54a41eabdb423530202ecedc14ab0b7869bc30e237bd90b672f8f41c31937ece531bc8685365c1e033c3cdf67c5c230f63e2a44f6be2b627086858ff0540637b0f05c49063eb0f0cf52c5c29bb214c1c2e768c162e181ec682963e179d072c6c2232981851782c90d2c7c11330882859722020bbf441716fead84b018aa62c5c2bf2b8de2211a5cc1c23f2c8de2a12cc0b0f0adc5f68b61e02e05cde322908417b49183277c81c61a1506a557650c2a7c30832cc0f083125851a673a20d52ebc414b57dca0c9590718f8705f75e11f084d3b7ae4a59f527fbfc0f764b96ad0ec9d5e1f4b1ab52383dafe49ac760e959c1c94a4a718a569abaa573108e7dc0f3b9221a065cacf75db1eff0b02118734e089fd499d48227ee112f3b42a859d137ca8bb8e0def9992c739a15dc3b5b229c2296857f16d62b047522a3cf6a6e46192f84104a8d368a3b682f8410cea68d62aef49666172884b2a3f0c4e760532e71c6986916a56b586b689bc8a2740d6b0dd1c8a2740d6b8d113747228e24451b8986372dd2d4d8dcb028fd82d5319faefcd43623f0f1d9664489cbc66f5b116a7b6e68d9c62387c8b662302d2b0b330bd3b2b230b3302d2b0b330b734e4b3e36c9b3847f715a1618f8f494b0f0ef491f64fdac2f243cf0172642449a6332ed00893c3b8e3e4b099eb0c0bd6772ce69498b6ab151cca6773e3fcbaf51d036aa35f97933b393024f5d846686e3135de2da8a509b65d855b9ca313cce9ee658265caa2964d046195480851f78e1837b5959218210c278d1c613194c1520b0fd8d0aa5ce704119585ab0650d16cc8084512a5edb7862a33a7b35336c9f4e0106546c3fdb789ab3104208218410428875ff328266841d2fa00210b068c1f2050b4fcf71ec05325ce14a0d8270041550010065c8681823c0927aef0d61088d2aabd43b12f82e44a3de5bad52d7f4822a6c8761fbd6c6d354086d982cfcb4a6700111ec0f0b2fc5ac562b28babbdb7e800a6a5c61861457b4a49a87eda6b1dddddd71e36932ecd56c98e0c5de1e167e616f0d1666a1092c08838a292ca4420b3cd482302c1c7241082c3cb4a4e0deef392d168a61216d148440a0ce2153a863841a52d872a5042c600307a91d163ea751f039348a642184f0adc0091b80f8381870b1f3db07b8b703d619f1b0f0f3ef0ad4117dfe61813adbe79f96c705ea649f7f5d38083df6fb90207f9f1074e2ef03829d37419d518d945eae522edb3a7951873db3ba5773da94d23a4e61a5ac629d56ad6ec78b9d1775f35b67b2b4f44c16eb72467c9aa75d0ef631ff3a93959dd605bd1414341504c5534150702911db30af3d1ce669eb30ff84a04e099ee64d6d9a5b1438f9f8f922a0ceab97d27a39324250a075300e9259d4fbec323ecd6f5d0d9fe6b50ea7a3c15a1d012ceca63c8bb18f79fa7ecc675d10144f31db700760e769601db0ae863ecdbf59439ba665bd5b1d146c28a74da63615c13ee6777abe807b572e94c905bbf504609fd6adcf17c141d8ce430b9ee0651de7bae89f50a3a29d7f551a7563e75f172fadc34658cd3f2b8de2a12b57d869b2f3f75d61e7f951e18b5aa646cdd7d0289c0740ea05077f29c7253636940dbdf99aeb4a3632e0eec8f6f91943d89538d86782e78c5c84b534e2203dba7190c9c7eedd803bcd779a74ec57875dd764af67d745c23e228daeeedad811363a09c37830925837eab8cea60c5ca94d32b3b1eff2401cf6eb97d7b82ce6ea6e6a93bc1505273a76268dd22e4f44a6c55ea779f63412a95e1f6847cf46dd35036e746ed348b3a4ef344d77a325d55bf32317cd77fa6d4726181c5b8cb3366fedd9bcb722d6af6a736b0a9eec5895370abb1e43d175559cebda692df3a15d1da59674d263a338085b52bd506c2ce91ca92b69c191a43ca996fa7ae420dbafeba48fba9eeba467571747cf9e46ea684615c7c8e8d8898c2ab7c9a6de9a0ac5c6d2d47b3d896747e78e5d65777ad471a35a6a93cca8f6b6ecd9c5ef41d156997d5cbfcf5e35eb902869d3cb70171938e61e55c212b6b0345806830c2fcdd3831c29aa02d7232febed817f7fb5c7bae8974a9ff9ec892a146dc8f52cab97d5bdf783df8f1ba730fbb8979567f671e9ccf8ba1e06ee32996b5e66d7f69108675487b41dd93e0f3d1ad537ed401d4ef59128e953a0759e50997e0d41b69fb3437fa4898ac427e45d7e3e21f3f294e9a9d5ae594dbba69ddb745dc169d72ab7896a177da7b72e0bf7d9e16c9f67fb3a9cad0e798f3c8b88e6ac6f93a86ebdd5b78929155c7c9b1111f7ed588723fab3224c54b9944d9ffa971838537d9bda82827bcfe2f680f789dda64d7dad2b317c50c4614ce032acbbd887fcebe2fb213fbbf97e48796d483cb7895e76d76116b5ab63fbc2c0413acf9b9c36bee3e38395622baeccc646c63daee462615b86961b95c5bad636ad4353fc1d9dbcd2492b6d82afca2a5b705762a962e125962b5a871ec63ef56387f32eed630d4c6c1ddb904ce214a1369eda588f7867ecedb1516b1d4b0a75e120b109f6461bd8776aafb057b34378442e1c8447e4c23ede2597d83006586c9f63a3ba67398c2ea061398c2e946171e42f3bedd52cb37dfc7b6d1fe0de13acc3f1a906db7f411ce45dbf3c96e0203c6c9f60bd8ff59a5a60fbccf5be11d87e0e6dea0d0c614332c08680d88ef1ef5d96817b5026971cdad43bd8cee1c1016d12a24d146813ed81994763d9cb076e6061c7847ea77f38c0bd555da24d7d28cc14d141913a7edf8b68533f7b9d94cb0b4efebd226953bfe71d4a9b9a8736f5a548b952dad42fc272bf08a8f3527d298d62db9f4f48263b22eca31fbbb75926805f22083f5fdeaa5197c9b0fd3612df8ff758e7fbf186a458c3de6079488a2e568836359346bdcae409e158af7c66755716cefae5304428d0a6bed55d1f7bb5fb863cd9090145b35665d2a63eb6e22e8731f28ec42ab9356fe4f5bcdf47e49d91e78a53049e9e083c85b28395f5be27f15456febd20ab7b54dad49fddabd2a6beec9e9536f55bb5a9c1f4a917eee6d8ee13e1206c73a04ed32fb83e3787456b83cbcc391b524ad9e0342770f73a281b8fb231297d421e6543ca97023097981a78884b0acab097bf5449c118ec65327276a02ee02e93d9b80ce5416c66cae7c028830fac8de503610012666614db1863012cb4c2030be110387ebb2063297bfaf152878b6f1f69fbda015f9649af088fe142a46d82ccf11cdfc391d25ff948e9af756a04da7825e3bff817df7bbf9aedda31c618e107ae805cecee662e7244f52194afb364d132a3e0bbcf6deaacfbbd26b49496fc8c9b11231eb0f2dd5d196d8f3c7c776ddb169187f7d948a4ad6abe9746267a028c30c218638cf1c6f3cd8931be11a59472890feb2dfceb8187f0dc5dfa2cfcab94fb311465c151d2a97ea7bafe30916278e2067a1d8b90f1880b8ec5f0024ca3580c2fb2b0f0734ccf328d62317c408585930dab4a12ebd771e2e931ecf4184eac4058bf6efd3a3f53c563ef59fdf9512df1458822340ec3c388c97c21c36122e9d86355f2337a7615d6e1c4abc3891527c975ec40bc679589eceff59d893bcdd814e94034ec3f5b946c27d59f123c4125dab7fa63d28094e8c8444d165ea5778e4060cf2a135b948c9e9d09d2b1039131317a764e5d2012d0bee1445287132b73c73ad169ae4af5eb522364537f9e962b5db408bd2b349ca8fbf75db9a105c74b57a5729c53a2dfd7c5c2d74041f367069ee0ffb3454976d27fb660ff62a192d169eacf5342faa8fe3c5265787af5a7febc2f2f0cf6050b93bd67c6c28bbaabc391b7709258efe3c80a84f5c60182fe9d5e8c13b260e30b5856ab94e834dfa284fbf5ebbae84aae8b2e2d16d2d49f168227f8abb6962bd76f0b5d7d450b14226346884c9b297539ba89a3bb81916933d93995fd42219bf77fb6fc6c5152f3eb3ff0420a48d15c547fb62811dda6fed85ca484bba8fed8d4e6c2fc744d85e2a568fa0be99c22fd761752c59157a5a699d13935aa38b2220962788af5523bc5c013bc2a35cb74180b718078a9eb2f759d74ee5b94883efaa8fe6cc149323ae94a4627d59f2d7114ab92d1b9fa0347157681b383643a329cc27ee115ac32b18553176a6122ab384abe1dab384068dfaed59f2d3848b0f7c029ac0231cda8e00a2d68c197d52a057f843aa51d28fb861d76b1f03a84c0710a86815f2c845d8820074630c298d52ac529ad320194d5d5f5eb1786b1f034617008081ab24c047b21190b8f75934b0ab80b078c85e72c83b1370a591885a0998e460c8e5358ead90bcd58788b4615dba60b0fb3fc76b0f18b8d349e6bd466e3731a159f43a3a68d07d228f8780634aa1f8f8483b08df542e13036461c7031426863a36e6c9fc9b0bdd39d45c63dae0e3116f6a0e4fcccc48036412896763d506c6c4679c0f564d78e912c8341862b39b4095e28506c76ebd8b3a7f146ebb58e7da7a1d8f036443b3dd655ed56776db4de78ac9db6d852ad02f16226c8b2172c7b4103cb752a85d4782b92f9d0fdf0203a209e591d0f3cecb489071a701703d6e8ad873e10efad87f71fde5b0f9c0af2e149f881c13d8bb18feb3d743f3d3cc995743f4aee4376201c0f5d39c3b2e5315aa38dd27e69f5aaec8eefa8dca6abdec8a35df58abed59c1c1e1138dbab665db2d6aeeed90b888bbfae74c986da74ec728debdbaf8cc15edfc280a28bbdb11c0614606c17363e7bc6a31d703c74258b8c6ab48bcf568dd282e876e4b2da6347afd12da57ba8444ad6e98381a0848e3135232341081a03150030381c160b47e4114994851f14000f97b45660220ab428c9510c21648821c600110010000118cc060d0ff62933bf68d2ff401b160a2dcf5435a72c62ef8375a5b29701ebf2affae0792edcd89e22d6eac7b3a7a46daec8097005c14f543031ce44c1c0c1c719de22355b8fb8c9906fd452fc935a40472dc90045a5f7777220147c562739d0cad23215c1b49ab1044b61cb92106d0c550132db4a8bacaf187e80ed926dc6ccfab123abb408011235777f43054632d45e2a1aff69a624a105d76e923bce0963417ad494e03d6e8b7691bf90964058ea2c30d15e86e888333a89223fa912615f6bc4e53790195c7e036e564e8df2f589f91f4ac8a941434b1945da3da7f8bad53230ac41cce1dac146a67f498213e6dbe3b945295a29600e2ebe4e6957b82513c744e5aaf2108b07e0acb797d346a49c64bc317b742030083fac5331563d57c3e0f35cc846b369d5482834510786e729d9e8757d7d612e1d7909b574700b020605b196e176b4a774d6bfafbb0a26b453bf5bb0fad18ea02ceb31944dd88777d861d54098b99a99540bfd4488089a5917f4b63732dd3405a3ce6390c4711c389670515ca230eaf79b655257745c0662bbe43c631b91443e74518dd10efdb1ec8befb13474e65a2432b553d0f2eb9dd9d61ee18fffa6978f63f54e90024012c0101fe8d322df69d0d79a8dff9cf8d25981adf94255146d9953952740fdc32e731349db81e8d390282f7718f8897eaf3fe208904e9c84c816fd4c6686af603d7dd740ec4a522c7e8d848b68e9f9fbf85214dcd1ad1e4b7f382153f880bca63c01b0f1aa31dc51b6175765d6c1b8ab84313582fc6cb66376498bdb7cabf6eb2d97cb866181199814387282caf343dd7fbd6cd51bf8e4b5093e1654c1e2fd78c423db7159ede5911fab01a196c8b30760518c917c41f3af0b5635d967ab4d5e124b048b8aeba7849c261366331489248bdd2b959557cd9d89808305c95838e99259315c22c16230b6e0ba6f80ed6235a0ea729f9bb7b3c9e3642e2c02fdbbed404a411aa56243e9402f08e6223bd1b0958e5db4535d0ff52f6e8bb4f0de71cf8230d1e968e642b452b542d6c24f20139c267f1f426cacd2cc462304357329219188aca881c9665695a223dc8690181ee0cab0b8bc9cd60fb9353424be6b5cb2d4ffc20d1d4722e81e06f965270cb8434b89ada1806545cc6c174db2a9122d25b38d668b47344e98edf21a13f011770d46bcc57bbf78c86ec7cf0707eb41b4fdd0b6cf1dbc6cc7500da720cae072f6ba6f735c85124bb98b85a96c48ba9fe46fae874de82dd1707c0b33b7b57b5b54d0106105c2964e71cb0516e7afb9cb204bbedde04034a02f39138f59f4e8590f9356a2c05dbf650485724994ce31e2c49e5e8f94c311277a1054956b05950e10a287dc8e20b93f16e8d6044b90d2accd070ff26ae3695d9b7c4c6221ef61b9ba0cd46650c4427246824b98c76dc2b49b7570ec34cd12438bbe2349675962fa1280c5b8531dd192b09ca0ae23baff9860002a799734598e2299c44063c12c1669556e0aa5391c856b0a5b2d4ea64ac4a5b84d52424b7937ccfd6026b8a6666550022a17060cb8a6876fef1784ab7c62743e702f57f56e9ecb2e51250bb6bd9f38d4779f3bd9fe3be27bf302c9e7e961c857a49d3a44188026f82f3cc50f6f3208999798e8f7d3a5b3a9407d3c9341d499ea322f137b2da6bda537325609383c675eae6386d8ece255192ae8ce88eaafa30a8eb5f2a175f2345cb96bfd6608cba3e107828ca3c7f53b332023274b1e4df23c096176b6a52ee1d11e45eba7680a53076f950386629f741f56e3b803b948270bba726d79147e8206f1afea586af813224860c69719d09712488a6aa2835a874ea31f1026bf2f3d385bef09cfe61d879a5a398c7a1a5e351f8e5a46739a18e886061d7ba90cdd3161a40d5a348d7bd8f774da756a4e8e76f4f5a59bda0fd6b57b849f7fd997859c0b41a12c3384d17c31e022daaf118080132a6f48e2cb6edf0f232ef0cc00fe66593c18acd22a0b47d286977a54779156465c5f672faed85f0239274cb59f0d7766cf73c27838d9162505c6defaec1c9df12050c934071ea283de36db6a0a1ec1149f1b3b3c1902f2017dd41a941fce49a6d88e19f4115d32759708af5bf8e83c2f3ac10743aec3d0ca2bd31ff969e0ce4490e73004e80ba5a621bf8b0545a566ddd23ede09c3d28858b12dfad7c73564fe95cae43ccbedf74068b29d29f0cd7b5c89b36358cadb45c10fe41697a457828bb095bed2a47ab3177ccecfa336639c7f5ee193aea4d8672492e095fbcf4708e25dd5f521268436767684b0b4066a089964b0a560856846e6d1d34dd1c9fa12ae8123f9bd0da92d11511e8f3c44089d2076ba8c5cd6a4f8a8650691e3ea70cc4511ed66c115c0c575a95e69a20473e168d5eba86e372b6b460abb2d46a56beef0c3104d661ada0b347d8d106f03093e3343ca2acacea7c0a4d2d717b5ce30adc7c92154f0bfd2b530e5663808ab5bbab18309a983b2ef95de8018dafe54aa6f4fb9a480cc07e79c2e0fdb48f9bcf61b6d7bb61be1ab22f4065ae2e6f1d4cd3219c32a0114a86abf2eec390c532ccf35c6d365741e1046a49045badf1dc95d0bb9c0a981f49d39fbed4390bd4aabdcdc3c9f6b3930e27c8f4869b084cbf4296140f5bab383d77f5218b6729e28721ea43600f8c8994b465b710502a7c91deef74555e9730e10e26c046a7659360b140b7b445adcfa37478f02b158480f18dd0081308757ea5455e80eabb3d30b24e1c8b179159b87bef84e8d5c32bc42321699f8b3d08ac5854eed7c823ffb54cac22b267db846d4b5e9744433a3d4d22c4f6431ba9f59da5ae6dd931735f76e60b202972507ec77dac41255a9f247eeb9638a66b65fe035d600e2939ff405167657b3b6b814dbf5563a0db1ce51935712a20bf4c70eed1252dacddc6c94a08c45912e0e07d2ea62f85d86794f431068eb85ee98be21200a08579fb642aeac89f9bc4e70f378e81e04a204522489f0b55eeeaef83cc9591a98993d75e4a37d11be382d10659965cdfa1742622417356d984e6bb619604319ceef293a0f30c957ee44d3fd3e06014be51722472b1315caa77c419c917374daa92aa18b995d04a1cad1b66f2ee0d4c78d9fad1132fad20f2a5b173ddc4cfaa4bb23719e5a58c3cbf00a5dcbe94915aac97d0f40a154b1a3f4f0db35195bb49c9bf1b446106c0db3403171eaf86e103799730e18529d4d92bea45cd0bd173a379998dfef059e5b828e4aed3131cd281c447f88620032b016a06380df4ac41498367ba20aa6429588840e9d080e6d1fb4c020d7cbcdf2ee791bde31d82cbec4d3da612e1447d5e3621ec99b2d7ff48642f906574e95ab6e90dfc550c924bac085e356740abea8e7721dd6540de2d24228bb52cda031ed0019afc47af0d901e84ec1f458a11d1634e5e208562bcb580b9c2e9cf32ea2ef6457d4e52709f9f4eaa802639b9e921cebaabb69bf2c206fcb53e3672d3c4dd34d46a27c798cb88bd00fa94f31f7b9f8f4c997e3abae7e155e658d2b5231c2a541d4e68c08ada35e0b09b4b5f44504ad343aabe417bb91e51d7e8977f1e427d6d5b2720bcb6b48b30cf4ace423844a2a3c07a72a8147c13f892c0e44f5b8de97d9d0ba11b2dd32e9c9460aaae74e82e13bef999cab1596a34eb4471131c7f13b3230f1f26257109d58c8690708c04f8c4e1b77ccef3186521f788a90a5650e53e6c4291b0aff75c7c05c2039fa66fc33204c4692e1930bd2444df76a8e11b1e66b698c64cb712e11e860522aa5ef99d1830aaf2f43888796209f8c8d09806e429effa9ae00ca66251c28c7b024b869730bc019f93b97497d1009c054ec10612d5de1e682572663ed98b0503bfae9998b1bf6e1c0bf46c0b0b514e33f089ace9952fe1ec0baf74f33e4d538a49a0e5d24c5c96e7411d361bbe2d1c4188a2b95dc7db3d2fffdf66d0d1f440c2e75880dc48f4d4aa86166d68a5804fc759be57857ce3d705f403cf3f2698647bbf1a0b69004f4bcb51371f06fdf47c4b7dffcf4091c0a081a0c5a31b8063574456d87a65ecbad5529a8d46569b897494e39296d42182d6af58d0cf604c4a4c2513d2fe0ef6294c84cb486c7fc60a58f3c24141cdf3782a645d6e737270712924f287ffac049d56b76acc02462aeb1476f4d91b1b97b464a708efa5630e2b0c2aef950899032a5ea544d5c29cf204bd528785159c784c6ddc43f41ee38078426469deab44d3336d23611f1151e1d942d98748d7d1e3756615ac9a5b0c2cdaa690d57162d21ec5d2f96c09c1e39598ee4c35b085d06ac62c9a96bc6454e6e77ca9f70f32d542c1963f2d5836dc3d76d6c7769802c2ff1f87661799814e974b11c39b672da52e1d369c811114460a74158342b507e26a4c60c3ee720922b0d0afc9685c43957906957586655dd73e19addbd2b2370edabfc4f729e7275ff79104500ef4ef4270735907ead21a58735fde16353a55b0a6f916a2bc4be889bbb80c16b74c7c053e9cf38f10508b28c64e7b96a896ccd302a19218c394fdae8f30c4b06b9fc71d906c209521f98de4ac7e2d5a9914b56d5148016b8e4c163c33784c2f90fb74dcadf642c87ac823ac4817c294628d0ea41a2be2ebd60fcb1edac4e8eb987f77b30bc4b55aae1f3fe5f2849269b912ad7c9b5b1576ef788e3f9ab7d1227fb3a263d8303dedcc72cdf788715e5741094856345421209178ffb3f711bb6965cb9fd27640b4fa0f6d0b650f09ebca7565a4ca9e489190bf76c1dc9a2e5280fdaf35da0603f80a4620b6ccb57499ec930f187959808368deee4d8b4bb826d10e545128479e6262d43fd7858bff5098f0d0e48545a8a97c94b14d555d8d24e97665a361faafbd3db6e9b35093acfaea4ece393d2ff41c245f31a609dff54017517f4685bd86a18bfc09140423ec49c62f48efa6184664252fae7509dfcd871e426d9084d84770013be82861f7db051da6a363f9c0538ec7c8d8d286113f5773203a27b8244e8550e049ab006ecbae22b3046638a568fc226e5446df05d4fbcc88364697033b04d65bed5f717cab4b93a4fa751f20e7ec870f36bbe2bfc3b826890afc8d7ef2b4f235bfd35a4d0d2e0a3d54308f94a09bb51a19494beef3494857afabed5cb6e444d65f532eede37fb660f51bb21e4e4e82d901f22f68c12b19812b4082388de39851a0436c83823a059c5b85418f1334794cd8feab6909bd62a0093794219ef05bcd3fea0cfe6dd3df46a5a7d4f6ea9c236ff526c47b8e6f19dcce1eeffb5098926c5dd68e2097e2b06269840d92ff92fd93b0901236582fb9a0c559d788733fcee7401be8c0188a31e41528b84b589a841be2b2de27b7a58cba11c6a03af912241e036bfc77384fc610631cbd9b08b1bf334bc11db8d10ba55513dad177f1bbabef78188bb229580eedea500ee510a538de2f6684f4d50ca7afd425c56161b94ee1078964c656a11db8cbfbd65a978ba873ca6cb5aefde5d3b71e3d07be9426edd1d41036e37cce56365187e9a8fa7e511d3d6d6899bf0eb90418a923e3712f39c73ddb5581b95790202cf1c7429f7dc6c388be7e4dd40d45d2a23eba2dda1f91bdfc875cb7ccde3c2c65700974bce2d34b796c531d5515942a91e7fa8fc32506fc37b283e9b03964308d7d6866e95212c05386cd89f6f280a83d800804ff99f000f44a1bc814691854d3912b1442198ffeca8240d6052e74f745e512767d6c31254313721820fd113cb5830b30211c4743213da813ae7813a29bc452b811e62e303adc121e866a6cfd06c5e854c1c53834933af84a19ea2036a346b4a7765575e647c02c0fd20c40e5438846e78bb305a0e4f573700468e06f6ddd5a3d665a351f64aba1852bffed9170708250577c4923e4f986b2c6d936f9d7eb85b5efce107d30e210ed2c99dbe657fe93b74b8ac4d197953659f526b782b4db60e2259afc0dd95ad52f17e0193e88559b0af0686c2bc80cac953b2f937f695fcd9ddf8dc3ff92f11b0af69fdc25eea926ccdf1c5706b80974fc497173fdc1683f04a1d1b84e0d667ad3a725ea86d1aa1f54c192652998ed41a2cb1c2618107ca2a255fbafe6a4d6638e64197430ccf458539c046955028c28a48b3633f59c314fc22cefd9f0676d6cd90eeec1c5aa369f09c87f74243578047b0e04f8a376682d97a1a19878da20878bc53ec9530550c34643a21feee1bc8c60713a84b8de2c893cae65aa2851af2a105eb7183f91ddb8296247eafb5103c78306f05f213bf35f54a800cca558f492b37275572a4a40678c2fdaeae39e9cbcbf2618a6974e7232a380f8a689a549809ca109cf18dcb7dcab787f023cd9e27aa6d417529188f8c5fa2c500cbd285763729fe1f0677b12dce0d5e3f28fc1defb75a827d343100ecdbca7de5c05725444932fe4185ea039cb6035e6dbfbe75b8e9b6fe1914056dfd157ab36321543c410168e8a5b9dced53be4db3af4b7206dd07816675c1440ea5995a587c84cf03e5d06efd20d994c582c38def2e20a74f46492fad22c78eb2461c3566052d534d9409bb037f4274d0b474998c218e233661e267712c4ba94f5c58e33c794dc28c648834d7002cb490a29e4018f5767d9bb7585ac9eca7f8381721f0727a83101d7d508ee39ad49acc256957598115416a8330908657a13b6d68839f6261df9870bc21d442f8eca09eb106da7cbd350301b175859159656a4b5e4a743daec640478020f1793b9458aabd801efd43bd6ba728f4547f9391d97f4a81aa1d1762949d930d0ec106262741d1b786b081cb4b0aab3be402d16883468eb0e4773263accb1697789f01c4e8eaa06a35bcbc636a0532317838192653f74eb718fbe99cb77d17d065a96136736a116989b3c6ef4a22b79c8e5329eadd6c96162631ab79fc5b8a96ebffd3aa7b6ec7a55dc6bca07da4f09692ace4b3a52d4be211f4c0b10766d4dbf9b13f2e53f3403a9c053e1bb31911763120ff137ac5eb8fd13dd95e80d7aead681ff3f472ede3b77f5c5a37089ba16e2dd2c6f55cb6c18f4cc486b7ba693e02740d57eac130c4f15eb6c2b97b68ae6a14c5f38829a82ef8d2cd8a4ac1bb85c0986bd1b5f92e29d4d028939a8dfab71d92ec2db5890861318a13de0dfac5d20497dc52a6442dc01380158fd9b027b3992132cc2ce004fb2c82b2ba63c64dcf7c76226a0baf5d28739c25af1b8e378e1a46c504b08df7ba0e7862895a7c5fc0356aea5181745cde5e638723e2befe9fed7b1d8e725302cfb30c1c2f505eaabbe84996d33b779a1366ff2a2b2294e99803ab7d13691ce38af7067dba96b07a5b46f06d1af427b0bd01db04d1c3e3fcbd2309b26f79bb1aac9b875de2d205009d5797c70f1cff89852c0c46c1e0f68c1ccaac2ecfe42360269058cb470eaeab14d3d3b5249c425e2cca8bf6d307759ba578a5cb757f8077cb1b37a0d2264980899cbc70ca2fed2685ab2e4626d0608a9a7dac0cfdbb7e6ac96abe913278c1bc3258e5468d65eb3bf40f6afe00004a98fd4c509a472bda83fe932a1686bdec4f984fa903e253c59dfdd71b37a5165728aecc8c44ccff0370e23b554242c3961f2708b51454d4b61686355787812a7b1df9d15c3c3b435c0fec1158e94118e880635dd826f17f870323e867810cd95c3e30d48156df0a86062e2c942c3cd0f63a6fe52443d0450b4054112cca2318037a5102e92307ef600e6f284155a56b063a190b8333fe3eb7c7761b8a064715d5895d360dd6be3d18826e65048d652741822e3ed33b8082d638688c55df625cb5068af745d8ab5d9f65eea728acd310188dcc3e476aca75dbb0e44b69f14d04a382cc32a69caa1dd332b0f03c64210f23426c30a8824f00a44e4c41da16d3724014c0f6f805ee01a57cae2c030cd67b0eb95ccff706a9bb0e4043d4e5312a7108684964b35305af1c2630b2dcf82166d2f676cf6587651facc2e943bccc4a12d13236bd446e746229396172a067bcf59915085d99a11a7fb24018efeefd157a0908dad0d2468ffb95a98d45bbbff3a4f681d405738756dd2f707e67e07c7fa6d4a8a6362deae6419e37e6d0828b5d5343343779f8d63b44a34c1007830116a3e20d1683868b3556a1addb1856c74c360fdf973d353dc62fc1a3286bbeb2fe3b3ca380fa14b0a7e6e614060c30965aa2a69386a34bb032695b5a338cf7971057eaacba7705ba7fb17cf24b83396ebc5ba4cc5a96441250c1deb6907744b7b4f54d7cab583dec91fd090e45de1e34825403d0cb00b4fa2ca2b9f68c744776f1211558d5ded46a44029e4065d3adb9a249f65b013d7721fc9618fe25f26f753df26b8307c4a49c5565019fc45603dab771fd89ae1b50bd182a247ddcb4c2c6c0b3e1afaf36d75c4ecf5e244ddb06fa4903bc5c39a374dc6cd56012e2d42a83797eb4b50938aecfe800eba7c120b8b3e373b147553c18962344a122149adb0019ad9bff7f563b26e02a5c817c86ae40604c62eb6177b8820d731e8d80ae5fdc52797e9bddf60282d9d404f4f3a4417a85dc46135127620d2f1ec1b0d036a4576f1f0ea660ab93b14fe9c9387cb9d67694f2f693df43e61c643cc8260abf5cb0ec49652d95e3b520c76d903940f14a6fc513e1aa08f3247d9c6b7d40c49fc83b661e41ada9b6aeabcd53afb60743fe0d869be1b1eb1b5d6a5b3c66ae4c6c94ff65e6c648133527b38e4ea511f0116488318c9eb3cdcc3abb9873d96adbd83f5b2a9a3f52dd3e56d12902f4c71e9c51c0227f347e5f7c840311157382d9ea09153023d4e1b35f5c90839b285cb347b40c464ec595f1287f097dc660c9a10a6a41d2a868d1574b65d4c12da501c07b016786a390040addc6a27b3e1ae51861fbc6a5b0b3b44f23a63f11d68e2aa629c2c93bab219c73a2f0d15256196c7ba26cd7631f352c8507b6e8b8e89bd67df70166dae38358e344a3d83c7de9c0acefb2e93fbda3442815493fed210fd056dd219456a3adc1eb3f3fa75a564737e1ed4a9801cc22f6cf7683bbd6547538011b7cc3420a7722e236b85ed4ab208e106b370c961cdfde8437c6643245cba5b1a783df288f48e3b29da7c6b1cb6c3f703baf77c714db39c76d2e60ac525dd0490a7264d8b90224e56e2aff89c8ab1f59bd62e371301a87a3d3174a200775fb4ddca919fd30be14cee9d29cc142e4ebba9804a91f6a8e9c34ef9d9ca4233c0f632e3a2d031ba656fd4e3e38eeed5c97d1fbd7658f0e05014d88799d401b2e7bb33e7e3bb7eb2d24556b9954a758fa7e70ebe20d52490ee4b94cf2bc34d801d9691a7202691720f5141cf060a423e5d0aa0113f5eb7e4907057d2e2afb8fbd16abc6c308a7b3c15e6ad44552cf87f2d74f2a4c2b3339f752220d6bbfed397247ddd4d53a96f600dbfe905dcb17648b122513162cf6e6c6f032a571c455f41a158910cf462954d9ada18adea34fbbd2620f80a77a1efcc4b1cba45d0cd50bc4026155e841754c3c0ca6e0b7ba6e0d553d98364ac9491cebf34d4e642895beacbe167c4de2ea3c2c85f8658b4b78a2c1c792ff8bb5c122c6d653ab71468ba5eb6389436c1484023af502d16541eeed9bb86db5b1858dd71bf56705389040694e6209fe9343912021ddfda4af51460f940ed43884bf211fe544bc6e7f8f4a324c9c7124b65b0050d77e635c32d4ecee1e8018811d419a160aa0f3523bf69b705894a9d4a1bab282c10163db68a0a416fd7c6479a0e1b16e06cfadda3e139f316d9a5131f5a2899c76c4e97457eed15f4060fcbd220d87f03c2e51fe6b767b06cb3c27e442ae939fd0c229bea63cbae39b260dd3a3a916967adf503d0238dd3bf36a7ce6159beed78352aee79ead57464ba9b35305da5d343fe8878782377ece598800a5aceb0c337bd173df8ac33d57022e7d417da90d0da634a7740327931e462cc4f53b575098094c8801611110cb17d19df75da24a5d2cd691612703709560da4b832f81d092c1d655d519734354be921b2a6506e1dfa3f6cc5939419b32657e19891e2c877bc99b12a3aea444fe49485132afd436b10f70ed579dd798ee2ada2630f5b464689b99f361648cfeb0adccdf05f2716071dcb092a44e0cac23d4e2d2f3422252273817d13a769e06698884f6ac5a60550a13ac2c804b80cdc597de574c0d68b42ae9780d47eefbefe2aea74e2cd44b794e196aa65e208965fea4a69a598de29877b94a5c007beb5000e9bfa7105c650dbc81cd1dd53aa18a0e532765827ac10f2d1b81877daed56376b24bf3b1de2a08563f101facbfd61708130797240104eb03f60270bff4d65ba8815753e9c4aab81271285dcd53175a9293160ee89f84959704675a844945de8786b25e69238d1b9696d055f6272256a2f1e11cf05aaaac437fb3ec7d8be591b246eb7be8f11803dc3ab1170398d0d6e062a0998c111987b1a86379964f3e88ed67ec6eb9f5bca7cf43e08860a50126d99bd98b4c5ee9ee3633919202573854c4f10411b3e8fc8c45031b26927e76940bf8b178014a56b8b27ff0f2cb4002c5e50ca1f12eaaad0dccffa2a6767abe723dc774d4a6d7f038962d080e1bc91d4b896ba179414321156281084cd8f337010d983142f7f92b804935f14aeec222b38eb6e714a2948d13dc0fc0a96200df19cd1dee45a4bc5bc33026d4295989f2f9d54327f87efb7d0b3669b179943889af3307c8c36a3c37e30de182fc1b45220e5bad4a33d24e66dc4b22d2a4d8289d85b65d26c6da007d66cc098a93a6b8e5d68914d6ccc8b46c6651ec4486a1e82e9014b5070aca9305dddb14e508e2a6f62b57f450596591044e1169c45a80907337e28e9b0f2d74f38e09ca33ffdf90235241e36ebade30b08808c6ef56984e0cd6d95cb24198dd00e67b0c20bc1c208755422df2e33ffaf7ea12185fd9bf51e96443e9a6a51eddfeb0b97b5fe10eabf03bd227ba30dcefba18c312a803c63d3214ca53265022b00fc95b232ebd04338f970a90c36cdc0c034d0253cfdc1b49e4b2b545ac8c0cffb82d15f0a136ec279659c2d3b63cf30c4a9a6400a7aa8658e1d4dbcc6a536c6c349a3ec50a7f844b5bb090b446d60c459cb929fa22da5ce2deb52d48bfa3b25303fa7a2cdf0af2ce41cd3c450a98661e6b1feecf240bcc941830a1cb6fe3d1344bc568019e3830e1e1ffa66ddbc25eab1834b76cb4ccbbf054c26d3b66510c8e7a3b447e6c5a12b6a5ccc4a4e7a765acc1966e94dbd59e8d3359ae243daba204802806daf4369e437c197e6765e69cf734f7e3770c90734ed9268c627fcf6d4b405d2de7dfdbff045e38695598eb1bc7b6ec7ea992c87495a5846d38e96077bfe8d79c28a2287184a7cec4d5baf4c0b0bdc0b494f2cce8a76ef236c12bd190c6b3a06e9fdfc67cf3edbed386ddd8309fe66e87fc843b2c9bac5cd4a80915738acc9eb66d9a210e138429a1155f0672b9acf651d4dc668b4ff63e5b0e0941a57570971c7e225335c9944a380eb62d6bbbaa525063c146077741a294f4a271fb8d47138b2008e81c043b285e390c75e8876839e8999c853b816fd5c16e58c28bd29502081145d22cc1d30a07d1b044eb5f85874b6748b689320821cbf4cd55b9ed6621bcc34dab18f906d3fbfedfa37e0eb7da1fbbd88177a53bdb936ce8f7656eaf78545ae3042bc051a93a288fcfed0130ac723e497b2cafb49a4e988a0b8e35126d9b861da81aead555b5aff47abf95e0730c7c82e3893a46391151e29f02e27c8f25d2be6fa2482a409f51224316722ffa295cf69c4da9a28c5e8087b044896bd9bdde971f363f1cc2071d3df6e52c4bc2d8386e9434f476bd0e809ac13290b517c4929187c2f2b9d6a091a5caaaf130d3e96288b007ba9f631d6447f007957e9d9b25e538c14e954843da225692563af976b17ae896c7297df5f0212a3857a4e01d9f5c972c4df5516e75e50eb8781393f2648d78fd85d713e6741e16749722baf70f8e7209370909345f30e5b466bdff50cebe96d7566c50b858f704bae09286544d353b59ef7fbd0d5341ef70357c6f629906cc23dbda86ede01c7a6b5fa709bb1084034b6ce530b4936d6f81877ed5cd88f26158f4933c380ed0d13e57b49917cd3f97ca5b1b977a7139d00d939c21b029ace4ec23c28390c14442612cc7bab90176a52ce752d9d2ff3946f888bf3c17301da54c84cb081f7b02a6c7ca84ee516bf5d3620091bc90b442b03595314878d917bbc06dc61e9a2dcf3a1abb0dc98785d1688d7f79c17a5ec4422b7d0d4c378e0f4b3488aed767f32502ac7a2033e4331e37eeeb56aa313a6fc92bd27b9d8909365a7c2a6b8525cdbbd047cabdd46088b9cdbadedf5ec04f564147186d048a8d0f0490b92e10c2f620e43b1233fbe0c8a414f0d2890f9c5e1ac0058bbb5e2271750af42d5d3a8af839a6b7a942284040f151a6081e31ad5b926028e716f8c0b30411a13ddaea50361a7ec6e585c56f3b9410a103ef894df4637f1763528a2dd5eb1299b7bcfb533ced6d6046afb7402668ccfb9348bf8b4426b4e3e2f9f04189cf9a4e51816147ab18a29c0e736fb2c77614e08fc966f45d291a7125946b5939828f97eb0740371f6ae586b4d4567196cc600c5b6160f616424f826f6122b0e4f862ac014c0bd2e9c37dd1527aba708875185f310e689c495017674a5d7365a03971fc7012d7df7385dd16c6e34ba4110457d75cc22c9d5104494fbc0a2672b302089a4777868b2fdc521dfd464128edc21aad7ec40a4a82bdec552d2f470f86d1d3125a02a0d1a411b760f414c94a0c95ae6dac8ab0a28669d86f6666ff7a2b8b4cfdfe0739ff79a82f2f0948388d17de83c31b0b3888d3d6e5ede45a91dfdc1662d4ef4f5f5a0f11a2aa9a68edc6b68535936afd9e5ce0d03720ae7f18b340833a5338dc5b0120859ad751619a0f5b7bb3acc09025edafc76b1ea9d7030f9bd0541941b69b47ec2a498641339ce883b81a24508ea58a0535cb3aee8f7a13af7ea9be7fb4e15f476ecb110eac50329f3ad4bd811bba1d10ab6a50c6ce072d5f64e3f0d656894e374f56dd9309c131a63b8107bd84b99da6d0c3890a44b76f95237c0abb15a42dfb98d04de9afe4717e4b55c329d0802b57ff6ff6063a41a4364bc4fdb54b32fd99f8f8492c5a494e7741dc4573d79bf6ac5ef7912f9a2ae4a63ff30fe872e8723f084927b79706e109216193fd87d01da002d2e45529736b3d4e103fc63f74061fefe41ab54b8cd532063d700a1d360a72c6d99431bc31322e78130fd8b3202d99e988bf1eeb8bcca50cbfac1c0063c97c91174403e33b07dc85030966e181d2fbb6f679525a2c334af93b2aaae12755464331b801422ef8d330d42cffdad6fd4a8fa67c2f838a9188a7f9e7494246c4c6e63cf23ccea27e831b8f544bdcdb294ce3a2b27b56ded89883b482d3bd134507642f6ddb29ba1a1bdb2f4a21427ac271019c36525c590b012d547e00c8bd479865644352eae340eb44f5036ff92ce3cee87fb19bccaa74d1c9a9366beac031966c95d5cfc2b02a33c83a47ef5c2146167c16ca4b52fc6fdac158af8006275bd007aa2ba74ee6d31b2c3ba0c3dbc90b6fdb8b8b54921e520694fb3169455ee25c3cc54eb75530a9bef86c2554aaa6690e46a70e8698cc8ea72e0d54908770eda862bc4d133da4869d2cc7a121aa522d8c9616a057edcadf089ae5b152c82f2956dc9c98ec616e23a11e0c95df30d0afd809c9d1b6746ba8774382022b35d3dc8805956db461c2e4f34bd79a184f3d063d7e5e48cdcb72cb8e07752e4a25d2705860501bf6f63a00dfd1aee078d49aa02715287617481c65e567f87bc1ba956c553dbe31173f4c105704dd1316f804c9352161645b48d70ad591e4af78f7718ed31fac5d0df47dc2c6bf5f2c1ac8ab79298e33ea608985d8c1c244314bc4717537820e52702d6748541d1ca97ace47adeeeab312b058df14182e067827710b9af16405b43ba1378ca6d02d26e4d134011f3b088330e63fa69f77f75e0f17022a49deef0663d2ea717e7300f7a5c70dc6acc0f681b86c231d468df190c697b85ffb01898a9a11ea4c6399be277b182ea541df9ba241f4d7fa409d3367544a2bf5ba302c1b5c784805d18b3dd9f26e5302ff5e9691873e5cbb0a0456e66920f0e93f510b1142738dc52a66cd9c12ddaca77bb077e99ec7b618d3526b7e73baabf5e90fd5e0f6a57ed00b9cf49645d086d79635f955c84ab32b2caf84cec53960b6785b025235c83be745ec87b8c8f72bee22285fb2a07d939daa1bfdd5787a0ac48fe2d55a2b04e3d17a67e65f30f524eb64883101ae386f5dfe539d39bb44f681fc4447aec1617d3e8afb1915745d55316351158af038421e92904fb0fd7c28a4122529030bce623c4fbf4044e7b3edda1e50b9c8c08a9b1df0856b043b9d3cedf7157d0c534339f0b6fd246e0e1a53d30b05de9dae08672b032aa49f58552e82fa05c2eaeba41a291c72fb013afa6a82552c24519c092195a505de2bc7f3d49709227701a6ef5ab3df172b7be5d76b8a61d1748692bdd514b1fc3f4dea0f57c1a9081a27fd874742a094631929d4ff5f98d62c7f136426031197255f8cfa8106efb00fa1e39391c3845c5096c33f07d9fd0069f0c6fd5897f359e48ea00672e395193cec916f357c5f5dde720ab4d0c9c857afd4c0b74e66e980e0d1fb276890ae81a6b04309fe049d171b1060f195a35d50f02eca43bd6a85619c05db91d07f771045f634029d3800975b7373b0d79efbca7123290461152b09f7007c45dc900d5c5746f9683591363ed5f84cd0cb72fb07047addb83fec23c1f5b26a72c9a9f47dda9b099487b0d7925b26b2e154cce9e84b8f5d063cb98de30281026d170f6415a69bd4799a41d27153c5b7b431867a9c204b065858ac90b8dd330e480e87ad86cb83019b51f5aba4f166436764e51f09e7e78eb5570f7391af042e87124366bcc456155ce16092c8ce52f7d250c378bc490090f8d35838e7e5fd3fd8b2cc5c063c7f0b8fac1fb3378065ffddc2b0db9d081c245896f0d042b0d638eb63e286e51c0c8810f45453502eec507e38fb58c9063565bdc1d9cfbd33619f34b7d84b64d50e544bbe6ea0429709a919f366e4a386a6961862a499d011c37a1f64fb9a615f9c0a928f75c0aa78251761829db48c9ca676811e4582f6cd334bafb2664e51d37ddcded9b21a80c0e10b5e8b2799551fd76a4ed2e1b430bccbfad19d02981b0fb34608ab1a5db792e38971bf145b5d4f7f80143eaecd7b706ef95c39e74042ec947771a36197541e6c6a838415444ba0c0a9f2845280bc25ad44e9a883979ae5d0e8730a6a20156be83f1736f625b3d7d3a26644f7cc14c764c43465112553ba7245df30c59bc4eef75652205c6a8c19d3efc8f3e5fbd5ece265ae62851c31ef189f5bac0efcf0453edd7c828993292013ac7aef611e559764258b6d6493af9f4906aff54040d12ff505e0807a9aac087f4b840bfc631fa543c286c2ffc13ad5bbe373dadf4821a9468cecd465db2c961f7d0ea5daade21f1224cba6df8db328ed48c93fac0a69282083ce9da89fccd182326471b90a41828547d212d60b7d44275e1f1a8465ce4f4f9314eca7c464fd2d98eb75e1a292ad9e6d393dd17df3b4fa570c806fa0ce5e9097232008bc525b594a8d05b4e3523ae7d02155189ca3b3f3e7fc92008c7e9345a3e4963e638055b7b29a13db78ab51ec165561ceabc1ab9e46dc2a90776078e15716aadc9ed66be96d98832c676e5542ba8a52c17987dbbb7dc659a8f2ef2aaf493c1371150ea5fe192bd87c219912fcdc86d2e1029017652a40ddffb0e700ba7a6d6d818681bde29c2b938edc00f848efcdc323e1c843bde809e2cd374d841ec3dc8c5bad01084e49caa6537d4fb40ae9e38c73c64db230fb53145e82b781dce7d2cd8b12441d8fc4badfc10ba76efbf9e5f9bfc098081c8e023c18daa2113073f8ba38495bbc829f0154ef8f40e9abf53cbe7d3a312922501675cd6385330d0dedc991ffa7161e7ab2d587ab881975ff99e5ea54fd143138fa209542317e86a3881069cde4e64a066f03c90bf29b78984b05e1b62201555ea84e0609b92c55f0229713b303115d65361b01e696e7ab3f017bd37a97d21061f362f590f6d6c4d70d35d89b30e84f9747edcc2dac6d4c531351eebe0efb69a371807c72faedca94ee47e45b20ef43f53bd4334e1d59e03f599baf72841338afd163046700228946317f6de0d529060e7d4b8f05ad0081eba88e57b3d35b15a9481694f53c9786d1ddcdabb35224a066f9c989b4cc78f7f9afa9f4f130952302e5f53888ba384f00755602880cd122fad93154ead9c5df4d0bae2164a90c825b595c439dc9df3e8c2860153268777ffe76c5e3cd6272dd32c8902e1a66ce25a211664935f49a90ae310b02cca1de46b66ffbba093d1ee5557f1cd54513d8b55fa05640ed666e03e608aa8881146eb35c259b3f5b066525569f36652698d155183bfb9d0c2a3ce3a4a96cb5db7c9de591cb0336990b6805b082dbc5e3d0daf9081b2e9e10d001f5596ac7cb96a8808aa49f5b9848876fa18aa13b67f1adce483994da9cb8168c771743c6b8974f78475755aa34507fd15b7a050ac62ecbbd514dcd741267e82447f51b7ad3f2c37bfb56927ce5608fc482ef9a70ba03e95ae2342d92a617afaab7e82176cd2e8169fa68453bf607612309af367c4c99ba83269afe7c26f04c7e7c0d25bfa921d265bf01add3be155d4f1c5e6268b9e56e70636ca95c217b115d252d034567c74f0507e002aeccbd8498b624955f93406c6c131c0cfc6c40531a6e81e336d12fd0b16c5f33989ef72db57a0c8b41923f5a0558c18c1b7ce34311109b248cca0b05814ec48cbed15c83e36cba424494ac11a6172d321782a4f34b23e43676742d8a3c95a591bf6c99490ef676dc6402e7cd4d877664869d99bcd51762154fa83aae7a39651f7e49a1331b050cbbe0a1b9e04112c08eaa0476360fe83ff735e495dc4730935258d58ed5c5a78f6be885310640016d557fd86aa875d88b46711490fa72788ab906939065633246cd893fbe8c4c13f670c36c2c83d984eacb2e67b9c958401ca5020806a100cf208e93ec336ae97cea6bfd27048977041a7f7cd2fa71991d4d1c78e267072b8ddd0021585d54e694326012063e688edc8bbd88e641ba3b8cc594678673a2f3e25bc4f51adf521eb2f3e9abd7611f403ff151e18d9d64ba613aac02c7d1042aa09ddb53a453da39f481f530ced1156538711b8cafc224f8b16d5da81e881595dd73458e28fd1dd433618a4d2d8314cb9f535266bf1101f34bfd19d95546211d334801eb7d11d4f24f22f62bd6228a5d3c1b72317d5a74b87b6564b8990b510b40894f0ca243a80564615872cad7ef3a336e0aa27c5060254dc014c3d1e2372a4b7ea759aca058b0fae479bc30c2beb004e6203453797de253123a6c4960b6e19f861ff5a247e6edb98e11d492f85f33b006cfc3bb31f27c77e607b4839fed44d266641b5d5b4ed51fe4b765787e24a7df592de530f182ef6c672fc821114c775fe020b4c411b817d149209142c9dd4e662a9180a333335db48e9739b8d8764e9207b1908c8443654591ab417d65d2404bed2af31160c24d2faf07308dc49d496032ad6f360d27803c024570df5673f0fdc8480655793cc2f0e268d380ee0a1ab44cf45c3f69bfc202ff46f8e8cbfadcbc71215464b6fdff745ed5deb894e6f97e286ec4eafa491df454d7d0083ae74740e670ca91ae3b0c5a195c8ae7abb95b14a65c18dc6ae84521cc1e86ad24ad9ee1e095e042f3447c38f0e5a8f28436332907b48552a4be42961f6a91c233a45acc1d53e0261bdc41038f15456da862e286a83a791c3a9c993266f95595abc934d7650a903553d825f362f806615b13e97d54059641064601bc9f7f73152886c852d28bdcaa80f9f09fd8715aa2919ef8c55580214b34e8619e5e3c5f7b90388376f2ad4f590cf5428dc189f299538ec9a8ea89130fa12fef1ed57a74872bd4a4882504038352c2e126b22609563326c5cfc41573b51afbfa53619bed4cec5f4dd220a8f2c4b1f3cf734053d19a74ca89685ec0797d40ac126ea2ce3a546f9e259afb5c2c748ec09cc3c9452922f7ba099cf90e0edbc64959777cb9289af8ed8138a9f540e52f3589b5bd55165fea93748397c905e0b1b61f07cdf6e2f27290ca8960044002ad33232e35920466f39504c4633228d3d0b73276280f695654c730736f7b74e3bd8409daad4230ef96b82b4c4eb70913e1560e1fa2c2548176df3c0473766416e2beda052d47473415cc9754e957cdb8209a7f6c8f9e1f2670b5241c66da1d835baf8b30cbe888e05201589c41475c8f78e3471933dfc07a45996fde0e78bc10ae8958c9faf53103ba3e3a1106cc4b58a9948d51934d0df9629aa4ad5a67fb38b531867835930f778075a07a1d59dc0105bdb1a3e8890c62ae755816326036967732a6a595e913c036ba70a18c03dfe9d8a7acdaed6a22a858e0d8dae45e6d949b0c0de984ab5fd371b96bf762fd64752cfc6b50381ae3e6a54a14075de16c57a2929a692b5d23085f592d59e47ff5881cb50ed6d856d09a3b9f418d5548855f7402c724ba012a1c66c33e17617afd8dcac570a04381149adc62ad993cb7cd436579913284f676c465a867e4cfa98174c99ce0e0349b5ee9f24fc9c60e9ccc35cf6c36037fefc84f6ea50a30568ef70c7875b954a3049ac66fb403221c42c96066c91b3271f7d7dc0b521b78268f3bc55042e104c6e143cc69328e6671777af8d0759d097c1ea8cc559a554cb379f462b081c5b238ca7d654f9f2b0ef02d570c1d9c71611f2a1a7c02aa63f78d5732bc329689c546f120530123ad6cb8cc7d29e44bc9f8ddd6c8a949a1ac305caeed9ef39dc6a486715d99080ab4e208cba173143628f197972da1e66a296e1e064555b0e283253f1db37c196e5f7c3a4b91edd77cf2fee3735e156ab651f66913dd8f21001240067feac4b90bc25f16d45a6105d45c94b13e936a4db821fde040a01596e9ec212260719b2ce5d9c3b3a0c5eafcaf5bcfa4b87c564340f52a4ed65e89cbc535fd20b4ee0bed1e9ce2bff0cc2b7404df3239c45048330ce27710f28c149be9262186d3d973ac44a7bcdf9a56042532ce1ce60f9170f97a7ce5fa2e2f23a67ad4b26cc9ea7af9045590d2c4d634c60d8db029cc05e36fafe62ee8ab32182141ebb12187497c40a752c19fd101384ae726a5f6531084f8a4266086b1702158e3ee9ad300dc0bb76fb59a907b5ea06b2e09cbda1d72207cae05c51738ca40b2946eed4cb487464ebf22cb96affa8957b4b31705a65f0c4bfa8aedb1c43ff9e26ddffb608327b75c8f1c3123d676de2880f12719a81fc0c5b1074a0665d5acf1d2b128992b137643fe960a58955d8d8281b838170961b043f68beab9cdbb64f6fd771ae1ada62806ed917b78a81a07607cc1d42c784aad82ba0338a90b9a646c61f6f505bb219d96e9fe3e6ab7c3133c0ef77cae804ca7e7707a04df4bc5c4a725e8c6f69e2bda63061588edb50b54f05b055f7e0caeec69b919577a6e957b18176848974b440c9182873ac8a5803553646530ad1b402bcc975d86bd5b9e92e09069548f584d08cbc5ab1bea6ab692bb70b3457ad681771fbc284f5fd8e0fca61845623ea10c6b7950184e8109de2bfdc3416a6377e2b054e7c2fbcbcf5b5aeb849168a6af361870c6540fa0d860b3c3bb3e725fbb6df2ab576ca83093b859b01bd7ab492a472828d80f18a1be5186344e7fca5f6667942dc5fadfcad548c651a69dfc933286f931930f372792f00fc0357104829999cffce1867cdd3e2ee3a524dcd95444a5c338128b00427594388ea041cb513b7d08da34ca79d36f95fb2982e6c8d0dcfe72f428d3f493ac9338fca7e590025a0683dc9d1e0a83f47a55161e9966a654ed9073bee1d56a2a72afb6503f61142e203acea4f06bd17ff28222c2205e1af0b28c04d6f7ad60778848f917786ddc01628c7f2ca0f67896f0f05faceac42a28293fb031046cc7f27626c02341eb7056ad9d08a1012448987aa8422cbd94a4ba5fc6406cb5c3cc1060336e74b0388d70db1e375a0587ce42c062e6a21345b90b228dd41c038ae3254ba2c7175d33eb51a906afa7bc55029ae5907d627fff35c9ef529a137b4bbb5216726d076bb5451c65d41a0309d7be4b8ee4c16ca5e6064b9850e2d44217f8e288e92d8e65af6a20db9afea5e7a4f2759593fdb0b2dbba52854dc7a411e02aed504481c7170322823d9adf8a88e9f137d71988e6600ad9ea7054d613ae3f970ce1bfeacd98f4a8763a8345acf9dd2bad273ada3e7c046eed852b2514cce313ae94afc95bb107b1c42836c38a4725de8cad2bf96e44e0b43628827aad1ee59a7bac01b6f351918ca28ddcbf94b15d05b471a29a156e16bd671a6395860469ac94a0259e51c7500fd529fd15aa01fc18cb7c05bddc8aee091683b50219ada20ec6099893f3e41048d7f2284d49f494f92b02088722dafd397ff67e2a3b65d3c95a9583ec86470dde66a288437d9236572a080a5088e177e3cb1d03e69601488da06c62ef61655796cabd9fd1dea9ad27834c4b38f187a7026c190ee3f4c244bc3e51d0939b52bf1e0795d4a447488db34a924f0d4cb02ef12de3c323ced9e117dda29eee7fbfd5b33fdd4b017846ce3ff64ecdf8649273801d110d89e2d4fb4e3025789d9b8f6ef20604151556650b59228e928440b05d01950493bd42d62224139d8e0b3ca18ae837871374936fff0f7ea41773408ba1f194cefa79ab293d95e5d8707ab4f5d4b975eb387615e04baf0a01fa15f854a4d09b190b9dd2a88f0f0860c19b51fcc9ddd249c9bf6de6a3a215998b603633ad13bdce04cefeb165c8b8b9efc7a0248b4942704be8f739f3af5c6e11a4c3592a73dc9c025246b91faf2788930042b1b0abb92fde66721f2d773d2b3e8961afb393053e8009f60c69cbb519d1afc7a34c3839ef581dcffaa0467f17b8a959ad6d48374bf65c7b597206007ed156b2e0869577924f1c73ba738d1deb0cb89f899b2d901a1bf01974e840a176bc5e8c3a161d024b06822ad2300278e7539b3c588aba1e7bb8493d1d3af567d49990171f87c9e6920ba321304bb58c096ce7441de4c8ae80063fc8a874867eba75e85482d8debcd00491e408c94de53948a03973f5bd32601438b0504f4b844f337a567b563fa5952bf532fa9ed5911ab3ff033a2eacb6b1ef55597fa5a3d1cc570c9bfe8a4a795c87d87767db86258cd547b6c8272bc1c7a65b656e046d670b3787d6eee2729404141f64a07f394c9e0e20a92d1307510608209df1c90a1634d53fc8635f2f2f88876c6f9663509b3706e00041c249c5d1e74dbc89283d3cd7a1adb6b7ff09b082000e18e44d7d372bbda81fffa7a3e2f682f79fae5947a6aab4a23ca840e9cb5c69f74caeaa309fa8042c5d78ba433d482c449b539e22d7e525a1e070869adfcbe9871599fdb23a5e30073f8ff8ea1149568ad774dd699aebf11948d6a3f1be867c3d05ea22e53d453936109ebd99daf20dfd6cc7a54a1c228929dfc9a250c3077a7ff843af41e87f4c51a93ac8b4e165d3b100cbb71beefa55c7eb2bbe3048a6191f00da362251181ad188b4ed1d55e81aa97318546618eacf32b0c860abb296eb13606d21249d9023667d98cd5888ac17a20dda107935be2caa5c5dfcc718e67d3ea8a71f18ca4761089edf75e7d8d028ba5bb9a77cc2c7b8d36c4a8837837a60668210bd14162d17ba78a4bbbce32b7c7057e45ec1bc20461cf4bbfa7d60b74aa03b46bbd2c9db5f350683194228c9360baff5629a4243167f392b2a3d857ce77183f2cbb3ff8cfa5eeb7ef603c2f7530f413697ea20515c04abdeca0802a326e2e3b74f6271a1506dd6499aa05ca31df8eea79a84b2d618e0b3ce10561f355384ffa0d844453ce772659b77a1c6848ac4220160c453d12d9560644f4dedbe2140a39a8a2f684e698403d12d7011d5320523544593e5402c002baabdb6e9f7c9728131557b1bc19ea1fc561c4fb80b4364de96a2f6d7ed0f0e2aeed7b66473aa74881aba9996d01a16559bbb273ff2f7ce1f2e27b5cefa489e3e262b880f8fc476cccc9d63287c900a691f385abca5595e41ff4cfa8d1ea6ccb64a676dc9aac5f1a1c3d3a4201e92c79466ec45c50b4ebf1958fe35e5e6196a748db3506503d10ba133c177445059ec8303ca45bc621739c3822360a354a102017dc54a1d2c3fb59f493f6270925d48ee0226cb9de91bf0ac76d33632c41e0b956e990016384c33f8679f6240e606795e8e10f28f0303ef482b64929d92a8e749698e034209f45643230a211cdf4f8146dacd3271b5ddca438988e9d880d606e13aeada1de9cef47918fc01fd935a1c8a451af670962d4f26a8287de4d025b910a46a97d93b2a6e4c77fd56aeea06e6a5b2aef9768544042a89afb6b307bc5982b92fe10f17ca1591cac21754cd7e9829843807491d21bd4d8e1f3300d14c66b9462407f3e605a6d00d11e51d0f868a664e92587a88fea5587f2d80a86919a7de7ed1ed54df8005868a2475e61bd4d5ad4ecac46955476bb42af50a1c3cd20a0e42e9adade2702a2df14443200c051a4f1c7c22d18755a7411487217270c8851da839d96b86df925279a1d429a15f25be2055a8cb6904fd7fc36450c327bcae02f71ae08d9ddba4d7b357c76c411558534462031758d7f9c963bdc28aaae22a28a1834895c20ce38b0cc10c654f398b9cc13908d110b3c3c54ac33137c619446ae35f7c50fdf4d81820947b750f01828088c65cc50fbdcba217dc5667d6ca8a87fab85e19b04a58ca0b6fdc498dce7eb3e69b80266e099ca319f6f476e33763344d1776d3290efd2e40094e9e49232aadd917ba749c5c1c65bb7748c9175b5829fe8420aa4dcc2e716178007a9f7aec6dbdb8e4872ee5f340975fe3b69194cbf8f87a80eba858e1b343dd37d57c7d94b30005e0ee6747a93b84b11af60dd39f4878b85e2d391437f63fe57d207e21c2c5f352622b614ad8f9d39b4a3860c077f748a715f98666f406f13f4142248604b71bb4123f79dce39f38220b41541da036ecafa39df7006f077e100f82f48f0aaa26422de2fd0923164f1cfceedaff7321b0068b76d63f467d74b4dd3b58dcd5cae777e0fc274ff0bf256218f72947010ff3356851df66b2fdacfd6cc4eb095c9fc143fbdab05d77a23f847aa98fc37eeb9bcf815d8b67b56d742143c4ab8656d20e493d92ee49a7773368b9e7f6eed6717c40caa40d17133839f4ee719b91d76fceea69cfdbdfa9015bcbad0bf5e426e4f7339d26419cc75132be9954cbad310bdeca01641e57d56a153b3ed6801b10926c09e58263e04500b6d757c59af136eb9887258211ffe0b4954738746d0a1e960361dd4ada4a27e4407b90d44620a17a0442c0ef0f528b4cd68a169e172bd1ed5ff03f74715f17d53a72eb9d1e62ef4e86cd9aa7de94a785fd34d8ec3c1678f2e4c00d8ce649c9dbc45f8fe711c97f517dc0433e4a57e239f0ed7f614a525b6cc0855d2c09313817c23c29d983c579ee551bd59ace3c0865d44329a8a1aa85bd743e523eeb12c993a6992a6dd7658c1822dbd23aa5bd2e3c9419466264f7728c71830442db7a8f10e3fd4dfdc74b8f8de1a61ec6726f46f83448cb4ae9cccd0235ef5d0545e9123c7391c1d9f95ab19097bbc69314cceccec4d89e59fdf80cb58ab7586a8d6ce85960ab3497d1f32fa7b43c89d96c16bdb77f8af5c665f72dcdb0a0aeebc59d98d98da9807583cd83efd8c348473ba4e51e348e94e0ce86ff6aeca28a1284c3a3c4da9dc1d532e0111a6debe399dd834ca87ef669d02ae843d3675c380a74f4fc72ae7d590444a159a76469ac807e63f58713bfad6142d583579f92975762039b3c8391ffb1d7f56980baaabe7d626e42b0249d233a9d1e03b9a1f2a89f7874898f1c7d47a6e453e37444c5f9e5b8a15c36627a3c2121b5f2e3c0d9786a44bfab89f08264f4a0829c9e6da3181f075593afc67e857b89d78730a6617017d0db0e038bc96bd092bd56a57aceb568074a71259c5903217968970dc0da8019fccadf10151f8359be10402db1986a00c77693ca9b4c236ea08dabb9099def80b8bf6ab604e9c9ad77bfd46981d4ee1beb36b19c6bc607ec1ee31aa5327bb372a27e91dd399671f0c0bae331790179649229759a004a6576cf20ec8b1e3663dd01fbf59a8b475e5862fe18b224ce140365bdde62791981f73834c31d7e9c6885d02dfec358a5a577440192e66730955479460cd2b19b32df8b759ee646c5bc09954b5f5a4343127cc4f90772f670777cd47b4aa913b480455aac869559cd399da1b184258d2256f458c46aa34e64636ad24881d4305a270e2e162bfca76cd479999be9e1ad62de640d6788ed28c77b9b4d2bba6503cae9f7d1206d247eddda13df250f982d6559c8a1d6ecebfdadc848229754d2531b416ea61b6ef87cb035837f2e96cc00223d8a3528b184d7354b8a9df944248f2f821c5a6c99986063adcdd2f5aa577a86397cf8eaafcc8d841be53e2fee56eb73cec0fc2038243a42fa1cb922fb50d2eb00d519f41e1fcc964d4e56073dd528749e069c40a562007d9b6f8e3db04f2beaa90ac60794456ea4f5ac9b1f36c8521a9b186337bda594b160655a542f2edadd150053b6eaa75db4f60965752ccdd2e900122d71bc7802e9bee1e4701a88d970ba08e12819fe29fd036720e6d6c9703d7db715b28b6f6e84537e8887ca3c6cb19e7959794ee6b647180b5889b5cc2e499e670c15674402a72c4df2ed10742466d4c29116df236dfbbd6e2d1135342858f8bb767e35e7da85303b5363209564b2b9f1ad2561cd50a094c926892c69fa471fb2316767591f32dd454103e891001a8f61661432e5b93aad5a2eadf296e1402ee18bba004644979f5c97acf2612db24230013612f6151ab6d0ffa8d0a5e044b30cb531d3d44594a04c4504567e2dd8c871da4a12967d3cf0e6d070d49793a414ed3759f531a34c80bf646d4c126e4057a7cdbef53830e6772a5948d0874388d11786d20f3ea1bf4e12a949087fb0d7d5bec27939b9143a0d35ce179f5992d0dfbc01cf96a6354f869e3254fe5f0867fc71c6ccdd4af6f1e9ab83453283f6dfa19559650d998f56a173b99b455624a58da5b6fca8be9ec98041e702a7e4959a5a9917a4e7013975894ce3d048f475d101d3ec1015a5d44755b5fd53674c3890aafe93bc64e93902c7d055c182f37b10153c6ff8f08ade22df21657052c5623856cfc7ace43494fcd88654d11abbc1d885f40d0aa1e7720f1b94062e4a6fecbd4ab477e4e8c09265fbd2e0762039ba3970f9afe27a458b1b09a61c0f322b078a622d96580184c0e3e5f971c4e81c099475ae5d945794494c006f002659bddbcc276308c8a40bc9934abaec69880427cb8a89eed09cc04929aa428684f1cf725ee2d99a796e8fc8450899ce43cc274d8e579f9ce238b6fe10bf26428142685442e109f1a0de4c84f57c9072d3f42dd9844c62002173ba1662995892b702bc38ddf190432c9c0f8c3d980a2403105d93fd102e66784d0b5492be2d6ae95c857ad69b54bf7fc5594f206452fd645c8ac3eb5406872235416ed256a4f17aa1a3324c6dc2ef3f19a7f60f6f8d7388003a40d9768da606c1356ce0ff1aa09930a2b4fccc952104de97f15ed3ffe00b92f94168e5d10846d6ce1ac10cf94feee3072b04332328929d87286c4edda3a55c7fb4a5ac145c782108f0806299668a022de82a9478688533ba4d109a5ce7508606e523d5b0d54043315c762dc8a3111d9a185405a42ff7bd2e88133d06089c497922caf759fe092247efbb867a377daa6fa3a3e168d19d65d428c5aa5e0aed56ac19ab4433aad2d59474b8d9c06b150b492335e34fb4131d93f40a0ba14c2ce3927c4dd9de16ad89d0f8a41b22fd604e32e6d804251889153c5269935c50bcdb23a6a0917306eeafd28ac40b909b0b40c391cd3905d46e65a64d5c7b0723c0384600f23cef147eb0d9d7d78afc5e2cdfbfcdce7c20c26f7329c05dac68bff3bf019ef54b2b3c425360bb0ce20590a7b33af1d7e00bb6917462cdf27536bef60b7c7d69cdb1ad96336b18523b5c365be44f75fe12be42555e54ce533b00e7ab6c71c476a7534ec6b952f311221cc3b14bcb0720c7bae14b88a8bfc2a1e03bc8940f3d04b8ac3587c32b8dd7262f5a01cf59eaa856565a897f97ec56a8e2ae216c95bfd73383b08cb07faeb778168575eb495208526c711205c027e74ab6bbc68090c1cd709843585d64e34867e2e7e0d9383da2db2b457eebdfdb669bd040393513ccaa3028b7bce678737597e4d37c41bed65c71fe3b848dbf566e11d8508a68eb9302ee56f7ea7d8e0063e6119f59212115b675e6e58ec38d32682d6694b932d2ea20af41956e3552545ab167836dac6c4417ac28561bb045a7ecfa6e6f90c185c9ec38af7e98ce0f7bc4d90b696491ff8371a70d5d0c1718740c87f420b9ba294b1f637c0fefb2ead455e2bc83b3246ee201725d7d13bb0ead5726e049e6c6cb9d327df294b001f360792d14538098ffb9bf11c778e4f369a7fb81cd58fffaa417ea59af7c265298fff532d765eae530d5fd22720566085ac7a19429656ff16415c3b8295f5e0d1e82079fd9615504ce117e13fb192c655f9ef9499ece9b1908e085cc0b2819ad0ad2b401040c07eea633bd46e6bac0e1cc8d3b6d01d1888e9430a56ace6387e32a1a34dd273120a1e50bd51911819b620b8304f4659f46a6151d555c55f6a8698e9a8c13e0eb0cf8e3905e5fa858b72944bc76c73c7b19418220b8bc3ac0c187892347a9be4ba7e1d8ab10e6aeef9e4575805be98e0fc5976796a914599286de881490973554e2356e861d948eff01d37dbdda82e41b4cbf78d5fce2c4b1b07d9711350a7d818557e0103e72ca7bd915d6ec4538c46f0b0871f665045b09827070c45532c73ce7792f6e3bcd87c23cc3032934e3150c8072ab6838f0e6322cc8768ef4fe7afe7b90a1a9c6cfb2be7806b9611bfa080f9bf9251b364708e91f69db7ff04868b24e70f5a84cfcd268f9b40349534ad5ea65ebc0b19f264314ef6a421a00d63847a2b4351522db2864c3b17ab4f121985f4ef885c6b09666b4ce4db9e488454d9f258cabf22457669ab8e9342b6e8a7d3446ad8e34c970a3ab090397ba21a3c53f5d6f39ab75cf421c28f104556a4215b4a295ae290ad1446bcf88d04fbade997cb08835cf4cf74182ac77b99f0d2465046287a4a4f558731b3897237e569c5614203e4ab6250eb9112829466c96822ef9f6df87e1dbf7d8be60f693898864b0933902e024e961e83a257692733db0a318564e3e6a886f0a7503f4f0db4cbb84f782f758e1b12821e31823b5e0e940b2e60070387d39226034060ada04226afd80e8bf447f3c20e45ca2dfe7e38720b87885bef84ce41e3c81e12f4119949683ced26f953bf01dda6c31b98634ee64767b070e82a0ac7773fb8fdf151de38c0e1680116d0015a8c7cec602e0d4222802805c0990aa1fed451bfdf2c09e0855345449f92ff55a5371299e2bd5462d760c963909ef21af4055f53782c17534697ee24f53599e1aade97ddf5711bc7f9cdea8ebea421910421750a0d204d2ec42679ac4b080421fc981ce34687a47525bc8d3c7b66e009463c74e4505e6d3dfa0d5257259e03612a70192d35a00338c2b0a49e5d220c0e97dbafe85e48a84a392eb74ba1cd2cdf4493997fd2b4783465e71191aff802c5a08192db268d55e0d48478ebd7385868a66f580928298739144d83572309b47728d462f267d89e85a2be7eb83aabd2de858a1eb23c46d41b70dbb8a8503bd092c821cea39cbea7a1260542fe2f517aa3bee87a3e2275ac86cc47dd0f69210bf3c6017fcacc9ccff99149229189f7c0331f64d73d8bf7e9040be194632717b7acb08272ff7163e9a819040600ec0d9569b99ec9ee18b97dda38ebacd4b7a8aec51f018bd282a6d9912cbe9bd90e26782fcc3c4b382e45334f9dfad10ffdfa2904a427d4ea63e6d5c4dda978f0ae23c3df94f3d198a7e391084ea58c698e82f1cb47553a00baf9c528e370c2e8d905fe97c6f0b42454f4c0ff0a6685017b8329a5357406615bc13db2ad42652ed0827c118bda89cfec1205f817ce086bdf741282a01e3b96f140bac98107338e4431bc847c8cadee0f4d72afa4da560dfc2bc3526a703bd21ae1f8821465968998cdc3581aca639f1e3629313bdf5ce4c78ee337cbeb6e9563989c0e921b5457130fee2c3a98d8a099befecc5b1c6298468214a2ac25e3070a12a61a478a5c198b29d5ffeaa90cd58578b715351fb6eb24e95730e0aa710eca74b2dab7773f67b03a82d2ff9d9791cc40bf77f6c577f938c754397445d26ef55c44429195606ef4084840876a0ab1be41472f01e4db8358ebe9a2b40e77fa55b27aeece0d4ebaad7317fb8a6a82b8a17cd3551a7c336f488139a44148fbe46cf02ad7126b9c5d8987d2e05105a500ad7b5607150a097303fb68fcf499f27b34200865e98d7abc8074aefc1d3e7c3d9734cdb941345a89b4e44b9cb832cfc38e9d4b640d0ca214f272323380aa12fd4ed22bee466f40ddef50fdab3456b54faea9cd7f87b7435e0c9988c37aa29446e5e6b22c48bcc1398ff3bec52b73143fae89762b5e352285ca5680424441ce0d87d069ac20a46b29477fdfde209ba9a906f5afd35c74816a644fc7402c038008e8a8b4afb4752c57e9f51e65d60f54f597f4ece78296544706e23002d2077a1b3712719a0511b6bbbc83898b3f006cbb2fd4909cd4f99301dca9b12ef4c6a17a4163e6b44d494f35c7bd25a87a2b350820b3f053b30abe63d6a0514aafc58828c37c788fc64c8f98e3e0683a1a96665f74cff21db7b44fcfd77e8a02122cf2bf305215fbf68714ad636109b17cd866d6a00185287a013955dcc94e9696bfbd49939b31c769d70f8f3e31ceacbb0ae1366da69585bb0ebba2d1b2c705a5c570c314a69de95de95f2181fdaaf58fd0980a6be71a5f79b563557a52e2afb5b728a8b43de07d7b97e9f349deaff5676eb9f079508ad4b94f9041267c854820a557f23ec30eb85a116246847e5d9c3e951ba80bb9be316d94720180433b0bf3809d160b2c748a6d0a2483e33084b135dd736d7faf62096944b92a0dbaa5199f83836eba34cecd0f57af2044fffadbbcf6111f4ec84cc098fe552e9679cb36cba9199383a1b46092b33da341cf39bf86cde768419cbf3ef4134140488f5f2c2381bcafaeb3f841295fdc8f159a075fd37c3137947fb23cd841af80addd07dc9e5a73a903947c59a64bb06e8f2b7ac20f91f2544bd117febd24bf99dedc8d13fc9f63d5e9a2cfbdfbf8a9ae789dc5f121c0cc52451f7acbac569d8df1bcc72d85393641abf90abc190924ce1d4be7e68e43a847763c3eb958b86999139fdead0edc2c05a6d53763b0ab521e17b95b1ba34b959161db630cba5935cc324e38331f955d59c98d76f9add1d0c4589adabbe86670419f4a118d532cccc0a81341c7d9627525250e9fc54ff8f3ef02a678592b220e28fe071074718e1b35e003291612a127a7c78060e0964cee5bff5ba2360b6da59b4bfd64e588f05d3fbdb467db64159d7eb27a621a124ae179a47856417110f1821d9c5cc3395866f91342033483915fc0b2379ae12756ed64a782c01fd0c46e2eee292901ab48d628773586a8a2666aefa0d2ecf22674d54454a55f9780a5b2c15adf2d8e22e097e2ba332e2eb337fd27e5f60e6e4550cd8b21ecef1690f9996605737136bb07340b3b136e309d1547cec1d01076888593ca458717dd42404193322e0dc10d575718305b6fe3a94e537d32b98edc2261c9aec15040303aac8ca915c3010c29236fa23c22b7950ffee24cb3d44a586cbf5fe30359b80b7cd2fb71cc765160bff0ca7c470d1dd48af96e9005d05a2f8e09856209630802a40fae738d4802a318803f406a6c58825adc9ab3fb6d69a484288484288447677ef26084d086a09a3d5fab3b50f7616b7a068ff1bbbf8f2e7b4afdfdacf47d70b2f053af0edd88148d0a2f8f6b3387e0f7ee2088adf43c32de9ab8baf8930c36af3db1747205668f3beb1ac3014c50f57e0f7820b4590f3f2fc7c3aeebd3872af1a3b10576d5ff8f643d0bb07ddd15e1a4208de51f57accaf2b8febebd5f38bf1bd94f7729cf6f9701d10eb8a2f3f71fcf1befbae7bf143f0b56a94f4a5f55fd7af76075fbeea5d63f8128803b1be7105937b5fc5ef3af1bb11888b23184a314b8f7e3ee2ab5e7edfeb31fc3bae7607e2f7c5518e30c2d73e9e37760fc3dbe07722e57713ff83a1fffe2b0cc1dd69f0eee55f2016cf5cde1c374e0900dd2494f8f881259350e2030b9f2dca32f2acb1cbe02c9555856198ff47bf2a1c59da5afd2ad62839e8d9d8acf06ec477b56cee87f986e1df78f9ed17feddfd049aaf0087a720887f7f5f8f5d73adbf8dc3fa1fd57fcfdadfabb44a7cd6d7f0d37af5e1abc62e83ab7e7e24e8b71b87f538acffbe6f5c95370e6b8b20f3b3f2b33e6fd6f7df8f5d86ed2ab1df5f5df1bffd233e6bffdca8c22bea9bf06685f7f74357cbc6b3b1096d42556813aa42d5ab7ea33c2cee08e2abf48aaec417370b2bfac307c16731de0904711cf07fecab1edcf6556fb7ddf759f786e178c72e03e72feb7146497558bb6f3c0c9f45f83d5565f377ec2d116ebabfa3ea459b5f85aabfaffafbddfefe66fc616d10fc705cbdcd288a23e5abb1b754ff651cd683cffa6f5cfd1dc357b1c6f0ef6acb07c79f70eb57bda812c74e83679cf07feeeb0f370b2b1ac7e7befef0f50e37f83774f54292f739ebb7e2dbfe8228507ba1ddfd5ef1ea7bb7e781deb75add7c2cd5dbb456faefebf73e6bd6f756bcaf63809eb87dc09dedebb7ef7d4fd5a3fe50f5e057bd3d2ffc4b82f776e3806f5fff1d71c0cf7f5fc401b74ffe7c5fdb17bfa78a5af53d34dc7affa81edc3f2cadf258ac9bcfa6b5fa562b6fe56530bfb7f232e8c5e8b8f777ecae8cba50fdfd4b445dacfeeef07318863fbf10f4fd7064514583aad00867e9f1eba1ac31dc7a355e22fa526ddd2171bd3bd035f2eebddebd7aec20f87a045f6b6fffdcebbd07be06ba46def5bc117c3df61744811ed035f2367865fc7bf9ed3c76af0227153cbd20caa7aef0838ccf97760593cf157e18baada98bf2f779ec32780eadbd7a7719dcee7e5ffca72ffd77cc3fdf4fabf58756bfd62fbf18a0a62fbdc56fec41f47e4085db6f2de1f6599f5f74dcfe5665f01995ffb0de92d07abbfa9bb7bbdb7c31ec66fd80ff191c7111aedf5372c4edb75ef5367cfbf78ba11f8c91ff7bf0aff8e2c609b74fdedf966fff7eaf1a7b1e61f5e2573db2a8a2c1bf7f47fbaad7f323e1bedd38e25b1cf1f3eb0fbf6f38e2f691f4953fef0fecf93511265f7d0fd563d7afda967f6f63acfedb3fab17f78ff7da8e1ddc332c5fedeb6de9da332a6ffd7dbdfbcdb6367b46e5acbfacefa1acb1d3e0167cfd598fe0383f9fea6910f05c2d09fdb3f4d56754ceda3d06dcbef7bde8de8e94cb2f46e59604705bfad2ffedbcfbfd1995ebeb43bfb7d6d2a0ad1593bf7b2536b84fc7bfd763277efd5e749fbbc7556f298fea559f5563d7dc866fb706c1efa94f5ff6c151fc3b7adfaff8aa5ad95f315aaaa36758defde4dffee93e7f97fb0c2b49e0f8f73d54bffcf42cc92c8914cfafef088e5d06075f521e16af7a4979563c087ef82c464975c2dd37f0efaf187baa38ae6072d58363ef5efbf68fa6c07ccd7a705c3d6bf4590571fdf2c10fc5b1cbe07a7f7f47f15563188e948b63eff637eab1e74f4110bf2fc407c7eff5d86570fde2e8f36d495ffac1bf639ffc7ed8f519361c3b0d1f705bfeed4e83e79fbccbbb87766305ba095d0697303ccacfde395f9e40069f315b7cda500d443ec1e42b903f8370b9b770f24c3f18b4d3e0dba5f5d6296bad967ee5747717f051f2203a672cc3907c441286bbe66763dc455ff6e7092c275bd8f1b356ca167223e1a2a4508a96b32432cb4910249720c8b2cc796db494db385cbdfbd2f2fa5d0a6c8f378d046dcd9a356a38a65f0c6dcd9a35546c2f5ddc3ee783f9fdbc79da0b3cced06d1aae2f04fa1bddb8b16ffcd2a7f8723b267c3977e4cb55de9174fe1cedf782fb9c97cec8755dc76d35ba9c83b62f7fa7eed03a7639e78e939472d1621b0b8e8796d182ca2363abf555250bbacb59fd9e7af774b9f80b0770b92d7dbdd5fefea66ddba66d1bcb929f5eefc341c37f7b7e2f3ff75ef63c2f6f6ed3f09d6876248b83ff9c974e67bb9d28e8d371f23cabfc96e8fe28b0bcbe66ddaff6eb0b2937f7dd66514573f4f3e19e7eee3a4a27e7f6b6f4654e4d820723a51a5aca63a98efd6f89ee9a5b14589edf3e8bbaf8151284fb76deefc5646145ffdcf47b28f7daf7eef3de7cbaaff525cf2304f1c9bbcded0d8f777c4a44fd2c433141dcda9ae98701edf1a681938109c33f6178cb3c98f6320bb381ffc666316061dabe2114c2f053580fd5f8a3c017c2d829aff4c30ae02d25027abd6ffba431208104993233de7deebaeefb0a3e650fa5f6b1b5f4f37cba6d3a827baaa1af4e8f42fa456bf54b51ebaddf8e77f70dbffef9baebeaae007d7533e8abb358d217deddb780be3a13e8ab03017d752325a2af8ebefde92441a0dffd04435d709b124dfbdbe38b2fbef8d679eb4fbaa94cb6e85e5342734f7fdb1b7dd91febf782e6704481bd63dfbaaf230aa61adebd36f619ff8df3cad8e513ef7ea6e9deeed9445fdde73d99e8ab7bbc8366e2dd535987657f13a80bcbbb3f81bae8befb6983bae826ef7e1ee97e2a5117db77f4bb6d870fdef5f902efa414ef3a25a36e2ee19d13decd19efa82cc1bb97f408debd943c54868377cfedd07d8777769c544665544665f8ebb669ad79d775ddcb9c6effd09976820412643e9abddece4be747b0069c3e9d8177ff7a5d1b2e7ed78a8fdb2e227c56c1affcfdbdefae4fbad85efe2679389e6fcfa43c1be9115487fe4ca2ef72d1a706680ee813a73f3f178d55978bc6fac8b107b87d7e41295b602ea90b7cf796edd326696c098d715be5e19ee3f2b9afa3312967429cca169d98ecd2224763f2e990e499495587fe4657a03d38e56652127d05d1f3fb4cea3297372de39b6dae7416804669544c215315a80a54055a6ba5447bbb9a12695a7433244b29a594926ea14e5ba4a6a4a2e8b5176b58db38b9715d965df63ee97d6028a79453ca29e99492ca39a594524a29a5a4524a2a5f6a4a2a8a0a13952d4d5498a8cce691fc3b8de494724a39259dd20439a59c524e49a7dca12ff994652f95b4566befc517634ddb366ee3b8aecbd9cb9ef77d2018ce30f4a616456faac66e592d1b1b4fde5039e594724a39259d524e2af994f20f3095a59c73778fb7204b3ae79c93e6c8f4b3941e0a6054be4d0fe6c3985864d1d736e79c617269373e67bccae653fa7acaea2841114611466493ad40954d2f5858d19f34f22ea75a50792c2075ea7b8915517fe45d364d5540b628a2eff0f95d365dc93395935650ca1693c6f8dd1b7d05a1ab7c3089ae4f6bf06cb0fa722644c7830ed30b6a4cd2410f014062638b68695e7743c77badb54a49b7ee697e4364c76d5ad6c2c46cb5b68ed6460e425db4a6a6f6a03729ba84ce62ec0fcd71a9525aa372458b5cce96945816f40a4c98a009c344096a46632e674c8eb8385cce6e8881672e674d94d8b9026695152d8b87a13701f0a7acaa2bae08dfeece02bdb103b1c0cdd39bfef4a6c3af25b272063fbf38764f0c33d087238ef8de872a95b8f37bef79de6b7995f3fed12fee9fcf1b8158fa0bbf300cbd9cbd70d3dadbb4d76d5c521e57d56185acdb5daa07c7cf557956882f2b4b73bd5a6d2f877a354afa02552aad0af9eac151f440d5287a2c2f0cdf0b41a0fb61f85ed881581e0b2b7ae31d88d5815812d0009716a69241093c7f969483d57796d6368783dba64b0045a0affba0bdf6da6befeae600e500e5782d4fc5aab67eafff1bb1ea867fbf18e2e7ffde8e3d875bd08216b4a005c59df7dfb7e0afc6feb13e7f05df3e5e9560ff6e9cf0efe7d7230ef87d7771f0fbfe1cfc247d892fee5e02d79f3f90b562e5fda302cae1a0de40399ca502552ef0c6a6d56ae9073f832d0d82593fd8d260064be0a0757356df73b87d6b800538805b17768b228863f8a0b6f4da166be7ac764e0e504e093ce739f8fc72c02f071c5c3dcbb51a5dfcb656cf1ac3115cad565cd56bbf6a3d38b2be35fab05625ac541b28a704a01ca09ca0a3a0a5123e70c208a69c0f9c3082073edf86b6b6b7e964d771dfb9bebbf9aef51dab5bc1ad68b558fb67abefb2e93aeea6c571375fffa6d5da3dc866ec9752d70dfe5e6c370070b19e039c9bd58b7935decf3467ebe5115cc158b138584170e3843b84d5e707b5d65da7573c0cee5b9e57bd15db87fbd673ad5ced082c11c40a7eadaefb9100b65e1c71ea772faa541ba7ee105aafda1d88ab3ccfd3568f5ec509c0c360f12b562bdb7d6dfd2a00db87c5af7816ad5fd1a5c08a5f4fe0f561b47607e2f9bbdd81b8f841fc136172ac17c76e9fdb2caae8fa3906ebebfe617db87f6cbebe6a6401b12a005c6fbf72b02dce9e51f9cde437df436ff2e77c13e69a6bde37dff762fb5ac1bc755c8c8e774f5ddf57bcf5a26c80373da0df6abda52e6ebef51b75b1e25bef511736df7a2d41607dcbdbadf1fbbeef9aef0ec4bfcf34e78d931fc747fcf061881f06e50f1f46fe301c65b7f563f1375f4790c5d79d378ecf09e61acefabab56c91bf7abff27caa371b609fb6bebe56aedd29ef1ea7adef9aafde8ea2f460f5756cedcee2ab5f7dbe192d7dadde66f4462d5bacde5afbf961d82d658b2d658b20fe7d0f03dcdf0ee275ec5baf2fbe1d7bfd1bd5cb2feca137e3eac571f5a16afbd87c7d9bd5d795dd383eacaf9f829ac357cfda5a7f7d18ba6e167dade6f6f9f4d4bc7933887b8e77b91b338ceef5d7aff5f21345b1b57dbad7dfe9ef0bb7ed81df5339eeb72c7e0fdaf03be8e0c10e7aaaf6b976fb677b8edb9e0b218f1d08e77b1c9fd58b0f63256e295be80ffa5e7c18df8be2a757f4ebfe1be71a2e3f954a7cabeab64f16bfef53f06d2d5b88dbcbfcd90fe2dbf63e1cf3b746f1ed086616e75e841b277c18aa2d650bd5af3e88871bc727fcef6184ff7d10b7631ebf311c57a36aecd6ab9ffefc1f8ede3edfdbbd53106e2d5be4b75bcb16df0771f9851b06f8795be6dde507f16d94db364e200dd8aa0140472eabb1cfe02b517fade283bb7b1c0c779fc1ebeee0abbaeec3f0c577d157f8e0b8fac2d761f73fe0833b0cb7b71a25578d1dc8f32ea5f66bfd5cbfc555dafafa96e6afd4e6abfe9bafbbb35e7e31ea6e859fed7841f06dea672f06f8d67bfbe1d83d1e8aa1e86d9cd5ff88effd6a7b2f7a35f4be1bbba87ff5d5dbe1df70ac33c2af1b67f538abf71e7cb1db38ab2d82e438dfff74bffaaffbd5777b7bcf1bfb8c2a3ef6ecab368b2adaf3f68ffed5feb1f93a76bb813cae776803dad4fcf6c1dd6fb665d9fab9d5aaadb08662f51efcb055df725fabb8bbada1a5767334e8fab68ee1c83d58576fa98bd6af569f5763f7f86af5a24befeeb144fbe2768de0abc6fcabd76fbf35aafea7bef8aa5d5ffc2a7a9cebbea782e14b1a862fbff07b68088edde333b8dd7d5b8160ebedd8598f9f869d0da75baf02c5b72fbe7d6e7b6f33fe88abf0e57f0f8eaa6f8d5a8f94abc6ceda5a178ebd13df1357fffdeabd51f576045f1cfb0c1efe6a04df3ee8fd37fe842188e1d8813c3d761abc0bc3b72090577b0923e833b8dcaa9d3508510397ba81bc5983103508c1e7d31bba52f2c60ec4bdefc00e9459fc6a201e03a4fa8e5e07560f88d53d2759daf7826365f1c32c8ef8b31eaff8f58b11bef83a5bb66266d36c52329bb44d52f09b4d7a06215b744468b36936cd2e92478618edfb24c3699496415f40740886520ca12d97b326494ce94e890a04a9c9d316de7fe74917a3f2755fc0eb4fac6d7c659353f97649366d139685770e090d01007c6e4e49b6a0ff91d1b2c5ad31a0754a0a5aa4d1e8ca6eccde7b639bdf9f1de0f527b67bca1694df9fb38b612cd77e2104717abf7ade3671a0baeadc23524bdd5f5acb1653f4fceda340fdfb5a52cd144ff9aaf3eb4f10578fbebc33d0937295566ce7aca0b66db6955e6be7788dbae4c944cfaf5fbd1be8f9f65fca16b2d65a3f2a3818a830fa93cf40f70934aa8c5ed15c065a53f3a4372922dd2901a6077dc24390a51e49b0507f784c4fb963d2b1b6073d9f4a296598cb8c37fc55a2e777307d0800a5944a6ac7b4e60f1987ae2b62861f929e4f69f63c8dd3dd49b035a9b56a5cce9a44995176bca7263e93d0a1c5873330f9220c5a8ae1413670e971068b902f5d78c0ba554ae24a950746105676f8a194a4a808ea4286e1f3ed150982e52578f19ffaf4bb6b465dd467e17fd5c763bf1be8c5efdba5baad127d2d51d235a916a946a80b914f8bc3b3383c1dde3d6be4756f8b4df266bc7b4c9cbe17ab3c4148a0bc3885e1c282922f44f0ee1d0173844b8fd81a23c2c0ba0786776fa462290c0d4267cae000ebde10bc7b469496784b9e1327d038a1a6e72538cd512fdef3d4540633958fe0f47352e5916b5228620d12971b4da4e9d975c41217b4d05045890db09ebdf09e7f2c9181861b6a8e489581f53ce334671e0dd6735522572572ce23efd92a75d96659e541010b434ed434a991821318ed98c6781962e3470a402c01eb5d13a79d5302c63c5143d40e33454c60bd7b1282f70eaa8beaa4b4743968e99c7447ba25cf7bb7e44475e6f72e08a7bd2b02053544ea499a28aad4b801d6b9284eb9a90f481143ac86a2288ca2c07a17e3b49329c17b67d4c17a779403e725070e0c7785dbc229e7c4e98c3ae1b47254387d2e5679645394a93242d8e84187140c08de39d90c4c489952458a2b5770c03aa78577ee06590a32cc40f6c4992658e79238e58c704a3c19d6b925d5079aea43cd12529c6e53356973aa49db534ddaa038fd2da9f204e15003151b425e9e50819285f7cd8893d49a28747c110305ac6f4a9c6e4b456288a2030a2b599a9882f50d0bef1bd3d6b46d41b3f940b305d988b62317ef1b528d4dc56a4cc6e404c5e9772d4a93f2a2e5e04573a21dd196dcf0ae2d3d69484f5a9266046a4a9359e15d33e2543ba239602f34070c065fc15b6c78c74eb3aa33a33856794200020a8a1d580822cd10ec0aef5836011dba3451d3c419239ac03a36b2c23b460a7af2c44c9021457670820bace3241f78c746a8f08e9534def112ea030df5a16609294eef54d2754a7a4a4aaa3c412818515162c214058a1a580fbc5f234143cac43065c6c4cad20cd6af1213ef77090d90188c922461831b3258bf331e78bf4c9c7ebf4d22ef770b9aeb03cd0d7289ee118bf78b446353b11beb57c6e404c569b7519c5aa91e6c0e3d38e1b4dba5267ba4c92e79b2484f36e9c948852a00d392a531b3a72f3c60bd4655a1dd1aa978b7473eaa171f6038759a49f54adda2549766538989d3afb1ca23a768d1e10488a42d368002465ff62a0b810d889862831614b45881f56ac469456241d298269204a106470bb05e9338e5bd1a5981f7aac4695dc25140c35150439790e294caaace13949125cad4b465a906e59d82b100f521b504e15403449c1e71d908a63802e46b7e9f39700438e1f4e7acf2883558618a0a4e50e18309189d4c4ef4fb8ce2744a710aebf308a74b389d4bfc8369e483aa33e96f40ba98f2359f563a8fa65114dea74c024f6e20d224c817251eb03e63bccb2933513fd820f38411300cc1ba8ce211e026549e201852484283111c8ac880048c3e75b9342041903c02429a8a78848912a4051804387d5d79829424f1218b0ad342163230fa2eeae20121ecd00413125daa009103e6004e7f87d2ef66ba5ba3ea549d6c129faf21e95e9df8fc5ea7f8fc3a455da89922050f03e0f56f7daa4e9d1135acf8fd9c57bd2fefbb38b846c47801aa742185a881db9c849e3be85e93f8fccb84ee35c6e75f27dde9139fbfd540773ae3f32d11bad3243e7f2ad19dc6f8fc8945f77945f7f9c4e7774874a7a4fb54e2d32ad9ed6efc0af17bff837b257d59abd4ad123f82d7aab4dd307f5ba2bb21f4e7c2c7e389dba69c218cba6c96090a3b6410f2b699c3a7012a94301bfdbed311404d980db05b941e8ce1f569e65cc032eaa2cbca791c127aceed4da1a3f856b935a273d3319f5a6b3ffa41dc3ef84363de9fc6a0bb8492b56f765f23d982debb4fa001a394bea0f4440a381808c2331574e5c1b15231606182cd1a36865852a2fbc6358f9ba2a7152986cca87c808d59e5d1a0605a8230a59d5fb598ef78824c628a223d6034c0a8136896a629188d9d214272c06cc0991fc4e7eeb346ed2083d1f0400a1776386142e11083d1d8412166c47555baddf10429650821180dfb032629033a8bcf4d6e600fe24d10018104b3a384d57172a5abc3921291c911980bb794854b345cd65a6bad94d65aa7984ec89c1e2671fa793ead2f274cd20bc35febd36c3f1262e08f04495f3326cfda94b4829d06f7e8ab722b5bacb8942d5c6674ef90387d7b65219204814982d0ba8084e1b7a38cd3bfb2ca83ff02132614ae59b3660d4c7bf96580c2b47d020d18deb2ea84494e4c4a299d4bf89c72f22b9c521c327d40a661e55248109e650eaf51ad73d659674c6c70faf47b41e735aa734291654ec7336a4456d1b185cb2a396c3c7159258714b746128409255bcc9f1449c4a2bb35c24b958752e1040598feabb45479c02a40f86034ab3c741663ba4d95a76ad9020495186cfe75aa3cb2291633c13ad9a7cad3495121c515a8ca33a36231d8fc8dcb6f2fa6dd1a3971bdfb7d82e2f34da83c362adc517c7ed3db79ee7e93fa34aad7089faf31f16e8df87cab64979ee65f28a3caa36aea71440c36df2245559e29c34b36e946d959e591b00660493283e1ddaf6c7eb74617a9ee7e6374773b856777cbc4520e6139e8d6be4ec22db752b0e0c02d1298b576f7ba8176b84bbb341e59372065c932c7ce406b6004225017944f1146a840976078f53c249a03c973f78b85e8827600bd41c6e56c898c2780cb99922d5c040942e5f57d2aa71f1d0103d4457f69a0f2ec2c21d180072037002105ab6f003ab9fc38f03d74867bc201a260340e1005931203771f200a464748413f973b1ce184d3ef9289474d5ac36499d3e9ec22360d35753bccaaa7079607e9923c39e4afff0f76388cbfdaaf52b6089f354d9b4991c435ad088a5a852ca97be2180bf5307223bc217df0b881a3c6aa8edc643ebace4847e4c3b843bb344beb21fd550811c92ac562b11828129751d05041ea6ec80a60450cce7105aa05ed469a1c9786180d321a8c6840a221e946a103cd10c715719c1185dab94db158cc8649a1b894126ba250bc876e5e84ba27d27965be3411830c3159114c4bb2a1426843c80bda17d1cc8e6c2305ae3d3942a88997f452858726bb1bc61a6b44d5c7d2072406a2973c9834cbd32ecdd2faaea080bb7517c618632947a88e5cb239d1545c577ecb0b0cd5d1b894233e9033de43392f44bc6ddbb6cd49cd96a31e116d1ad6344dd3a6d4501d6983a807cd91eb651072248a1c373063260a2230c8d20cd5b852a464aa82f88189920b35740c99462d1c8f694085eac82b5b603400c3e11b35051d2f4f474d5618b23485901e2c3c804c90180c8065426ef0410521596cecf063069942c8bdf75ea725a799139353939393d3d33dba12dba172c6a5488c0bf9c8402c1420b869078b51f364e3736c3832f4e385293b866c0132064a35668a1b18638c73fceb73fe8d8851a22846d4b0d8cba5418ad3a0c606d111af2188b6836f64207666e90a952764c6fcb04eaa20a2dffe8031c6b119c4a4804298353c7cf098b31f846a9031c6b88a91aa23372624deb281470733a0841962070f6498242161199274613b18b1c0246563f26147d721a5c937f45ba18e638c31862a4275e411ae076a896ba8cccb2d59d4c0e001161678e8f07a78e29a2654c4715f86d04c188491c2a1091a6411d363f6d8a1e18b31c698c8a8eac80d1f11111262c7f6ac998ac562b298d1fd0d638c311e4242959888783a4448f9f2e5cc6bce7befbd44982c91264bc4c91279b244a0ac95a24651a108d3124318636c0311d59147418ac06c3882ab100b1abe18638c9f3c511d0915c5f53c99e27a7488715c006cac31d244123d986670e107d1490c0b2d6c6194be22edd22cad8d0280796c18632c8423c0248d0d514786c8f0c2e431857de107c7693ee8b0e19a10c7417161052451d8f0030e2560da1151b6d223c78ea6699a56464675a4514f1924570b43488eba202645d840032849a84892030b378cb051e45e28472e9425178a13d711919d5a84d2e71cd9fef5396fc4e620aa4c648eae7d62aa3a72d341867310a1b09142218eab4116b2c2240fcd8638ee89982bf43b5a131d4566128ea18429a281005766d872745119693a76e8d488e25eb97173dc0d6b2840511d19c551988ac9b66ddbb6cd4b8d3443bf7367211541a82842c5112a960ced18dac18587ed304587a7324568396274c58a0a1d4820a438ed88c2400c998121c814c618afb03385ae086d1102b3090d755d91a66945bf7365b063918c3e07cd0d1ede4032238547d30a5d87e4d449411a8303862c63ca0d3041a6301242c85cc187323c868888d608cd4ef85434241b578ed061a5983fa2aa8edc4410e5c91a2a5ba20c8144851c1f901edaa5595a9ba981c98b12189c68f9318b80dc00460132a5e8354dd38e9c501d093bda340b4f608142c599a3a921269194a3a1aed3344d46c50170d1c8a5698891568d29a19890cce62856c83467cafc582303152090a68e22421d482d59c6fca837302162c66465568316660e2d53a868dce5388ee39ee3388ee3a01c4175e41250a4341435ae998d9f11511d897730c618480c5a0f5bbc231abb563796501de964e337a86897a6693a8a8a5e5fa478616289a9432be28cd0608c316e018a6b210aab91598c95ace11813d520803158641882c5860d25609838ac20b183831d9e0d66efbd37872254471e59e2848a85e570c5da1b2e2a451ca7611d986b9aa669464d54473a3d7123a8fbdd9126a4b1157ca445c886ace18b31c61863294c698e5ed091609a862072a5824815913a22b544cac90d796f6c35fef539ff02f052a3eb866e3031c72c8c593a528589264f6a7a4c99152e385e984cd528168bf9984c5c4609426932618d8f6efce3fb55e174ab78ba5540dd2aa2eefd2220dc19293e661c9410c7fd98c2421c77a609271485ec6a58a346b1586c87a6699ac6714dd3344dce8270e29a3665fc7374c82fa0108e918f232a49789802c39019ec848f1c190a90aec352e6c70d219a406a326f5828409cd8344de49aa6691a991926c384c93461324e98cc13d5c12f1c644853f4236aca86312914f1b8f7deeedea20ed20c153d859a0f6396b022f3c1e889ca282d2c79c24740868660328ac56238a494a2c314130b19f410260b133c6451326de0d0c14a8132e3a1abe0e26406863245baa4994243b38613ad88e3246084d310484e5c9c003151309ad2f0c51b8731c64d94aa8edc306eb2c489b8e81d4dd33427472eccc9125da512c590ba410b0a6654402365c69c38e996e0200a527fe722b1b122254b111e493b9448e973a20803431235a4b0658624d61459c15a5430410f323e1001a5498f1caa50539444366523fad7e7fc2bf145c99a27bee0a0426889932214c547d77d528a6cc0fda882e8773433bf5d7cefbdf7de7bef354275a4d2d28ca92788266d477312929d8ce4e8ba24b208d142181e57609052e3c4639b3939c102964dd3342937bb01317237bd8d2c2d8a13a91b2310a1820cd0645961062d6984387952841cb1428dace18b01b0652acd0f489a2832c6c8142fbc52d08c501da9b434e36033607a75d12226880e597a10e2070ca3e158490dc7332f45378ec2bb711ae5c2447564d3e6a49f5c50cfb944511dc9fb8b6b1a2722b95e6ce4d8b6ad87fef69b3dfad7e77c07c2951670c4f082111596988ae26506519ca08e7ee79ed1f0c518638c71d8c231e698be4419b204859920523c11729fc040044cc618632ca97002d2c3860f6788a81105c74335741491514fb1584c0558774919c56514190491515c93a105ae5dae0d759a025ac6d4702293210b19987603ae45918168e8868b26b32252a640622222258198d203491468b4241183820bc658c318e3b71b8bbae01e5f8e31c6786f3c3c0754d5919ce336fb3222a6cc1127453323a6c0f0131cbfce81e36745397ac231c6f86efa2b4d5f164b0dba5c692224430d489c28e229e9d02ecdd25207e11033732465cb99242451556c0f39b4d65fbbd8d776df2eadaf3d8f8581daf8630e7d4961e4e9280c932322524df430a54619aa61288b8f1b3678e28c102758986862a3dcb8522455439a5ef8b18388cc923355745042ff787ce1efcf73e8cb3efe1efa95877bcbedffe2e48a952a52506a4204d396e05a17335c7b167581b926c5071fb8a67d8eb63bd0ced3977d987db983936448594b29a55b7e0f9d5332e86b4e6d2a29a592ca6bb1c516dbce9276db13d41968d78bbad8a4a7a90bf9fde9ce0da26cdb5685ebbaf1f54cfc073b7d87762b90f327c76d4adbc603d7654fdbbcdc719bf6c28cb5d4524b35bb4917f6376dbc956f23953af7b98eab4ac03f1fcd31fd7c2cd760db486d501dfaf77b61378d8da059f7d36670bd74cacb93e86d935f988df6d8b4fe84602a2a995dc4a62e4ddd94aab59e1e582ad54a16489ee914f22ea3866653d5c964765e3a3f826bb62daba62f925ff1353199a6e4912175e8f7788db215732a0592676ea13a13480b4be8984708a5a13a6a5eb389be36252d9c13a814ab996b7bda29c5484400008000f3160020280c08888482711ec891f40114800f6a945a6048970da38120465114033114c32008628c210410438051ca599404003e0000e9406d6bd40a645a472e82956c9b68dcacd53c5e7f353ae06eb738b4ff2b555292ecdd3af108553343c8d010ae71a30c4dbc61d6d5146bf67fb202308c78fa04b7ec0da90ab4859ca8cd58d7887ba5ce1ed05a4383181260833d895c8a44d04e3fe8971a8f89d63aa9724ea3b33451321bc53da7f559616e812964dccd4554deea46ffba6b50c0b1d5e75186e8b25ddc01d8a45920a2653d859b32337d2bfb594886a0b3412636029df84f2376037c9126e04705682b1fb4bf09e7c89091d75acaba05223e8511d15803daf90dbaaca190a65e7367440f908971ad9fe1b885485a7bb84e8f00df5e8e28d77046376fa59c5cae44fdb9794bfec55b031fda8ef7f41efc949e1b829b37c55b3d07751fb893f8c6e7f6bc2e5ab12d6e2972898191b7bf6bc4a1a50e32c3d8d0e726695421d8c4749ed135a00b2d9ea94a118d9c80897f664d6399b612a7ac41babd3ea4b5cca816dd9b243d68558f9a117acfeb1220ba506345ff2ce2340613dd820c9b868823cf411dd411205906b0a3a134b5ea1483f6e168b62f2142508a6b9e95c802696c8ed81a841d2cc4c05e09f3f696400536137e39b6f6796e207c6d028bf6cc35705c844daed05e2be65e05b4d8df2bc9c930de45f18f7270593137cdcfe5fcb8d12926c76762dff57a3218f34c7643d02637ba41cbc5faf1b4ab242ac3f50930bad312fc6700d19ff27cc25d9d78c29348116bb72141c766b61de835146f2648b7193b02de2761e50c9c819b3fb3100f977a00bb404d93fee4df11a882fcd48b27dc602c47fc6b00dab01aa754c83165cc9bd3746d445d80851bffcbb39984ffe60ae15e26a1d16ae45ebfe77f8296dc7a9900510ff1b729a0b8c332fed7e759e86c75bfd548aaae2440586547c8afc8dbac69bbca0dc55b4693f683ebfc15355b962a737c59305dce43b741ffeb8e465ac5a174ab5e80d218ce3a100560c13a43f13e88bd6b393627bb0dc98a97931876211cb016997f1dfbc8eaa68a9406a2c85d27f0f2dbcc9a92bd9af4115d02d7eaed42213c8112fb2ddd8fb15b238cf1bbf0609819104b0289691c0b1e01cbb60d1109fb749404b4bfefa6c28864f774eb13e418298ac8dfcc034ccd6815f65bc26f2b5428d5576dcd53a11a34364036354d0b2b94400afc08dfccd31b9643037ea54ba91d6e5c88c4c9d03c56b7c30752dcc80fdd0db6952e854e505ca9eb0612ced928880861a481cf22e9c0f6013d14e19ffd10648920a1fe56535260da0516552b77e23f1e0eb7903945a6373e9f1bb3c9883e1b75ffc228a007d542912c2bbd5369851586c4e2f4fefc426c8b557f221788fbe085ec5b5cd5c9e5f8d17798c31cecfe83fff2092b06f24fc4d04e28290b4a8890dbdb0385e570858541bd05b0a9bf9b2f189c0b5c2dcaa2e42da9d21c261a6d1922353d46fec41ba54087a9b3e2a30b639509a920bb70e8b07ee4b8922a3a2c53d991593910b75673fa92177ee293e45846b7d6083f49bfe41591b06388c668990ca2e281c526f5d5cba2c285e217231cf7247ce6f2671a0dd504f2bb06b0fe0cbeb815a6c9e581a650574cbf8118b8a628d120bf4d7b152a5a4a54aebdc94fcc38a87d71b868d696a10780fc93e62adc140725fbd0347b913c361b96ec6cd3e3b17aad5792932168c6388607d78f78b2caaebd36352cfdfcd0e319de5e4750762cbb15beff5c60072b1151738939c8a63c0c5264974db405901c74dee756d18e58c3d0b914bc7a051c5d396473ff1433f6a8983b39103476a7b81ac1cd4fc53c496849a423f3b2464513ec3ca8d3040a345a1b3139e68f6c80f507e5bd1b3b03de3ea0f3676958ab1ceeed91fb4caf2b062219a385851e414bcfc73e7ded1198431ae7f04e2dc6d7f576304d03b60dbe617ced44e4b711b7fbda20026b253922636986365e2b5a89bc568079758dfa8e836e41502c7ab1f08f5a607669ac0485c6848f4c43eee2770f0dd0822b2f0377e21a1dd3cbb4f3140935210c84a1e13abdf0a0f904cc37d00d42f857cccd10cb805e11fb61cf04ba30bba3c789e887d84a0fe015c43c6540ff93db24aed08c89350086d8a4977a52daa926e835473bbdfe64a37d27a1f3ef76d11814b165a7b028ec43110e3b4752b6624a735c58a79bb1c36279a36a9ceeb2fe90f77ceaf8ba01719d386cfea17c6228f1dde8fe613d89ce2a0314ee957e400b67f5678f9082c212be92c62aac676da1cca189aefbc3edfa099b00fc2815e67db5894fbea58c9e999031e294aac4e6662565f3dea0578ceb8c02765b2a13f1a943c9490491ca3bee7cee187d476f5a23e3c4cb6bcb44b0ec094526ab1dce474c4f57859e84a351fdba75738ec2d9d28c12862cb1edde65b59821e5a7f9916932dc62592c0ee2e3297509e0acedd8eeeb994ee5311909617ae80a78b43a434afc59d76dd11168846789ac99a0407fc0bdc063f8d0ee1c849693899138d97cf3d1d68320cdd142f47f1330546e3042c43161d3427cc5653548632dd23dbf1fe5db4f1ba016480892c18264855bffe6c03708767961cd7019d1cda69e6220d2aa7250c57b74ac47fe40f339505d028aba050f8b02279a97cbde1f0b97e242424b3a2eb6f1695762c4f416bc19382e4523d6d63f44136d1db1131aa3ffed1faf13b12e24d60fdd73311c5116b98d3496b07be8e6c70e153f34f8f02a303af31c8d139b6024c07a017daa1c8a5faf028fc9942dc7e5c885a56012fb0f31ecdca9246d66f834392e4feb125d95bbac3bab621c0af859a9008161642981ab8b16c021c632a052e84edf09c955e07f6251fb74c92a47eb432070c7d85f4e0438365f9739d70ff68d07396cbe1ac615b36de440dcc70911516c1a090d24f45d2b39f46386ca01794ad2724341caa8c0f966933809dbc6768641ebef2902de76dc356dcd849f0386eba449d3b01a0bd972fa9a6cfa1d2d78eaee4b6a1107f4ea849b88e9847fd4cc67e640b664412ad7e55e3195b22728ea8d3b6462009d208a0e25325d048f93f968cfd40fca4d03ba3d9690066da02d944b3408306683a60f0dbd7207d0b7f1819e46d0684bdaaa3bc4cc50a40496eec496a1e4162a3a9c749b322fe922943864880e5128435eb26f70f5229b9465be7acfd44548fb520ff8f7567daa0fe151aa5700dcffc4e8f79f1bae8fa5dc425f8068cf1f2e5cc3c622217b1765e827bff6898b19252f5a9ee499b32eb469e48241992572621ab42c49fb70897f91d0d1dfec9761d66122070b4a14638939f82ae114e94dd826e692b629bd714c74a2d226f38fa91f9a0f2c1b1e5846e057a508f6a7da8a16f32bb0e9276e7a1ba33dc114082b9b99b3d4709aeed88f2cee9a60502d5ac20df0deade74c27f6168b6dd57bafe3d9ca3039d95ce92aee2bad666cee8f90dab17a8dc90c183981992614a5812c241d0fba8166f630adf9dbb5a35d603f10b389ae13582bc42785c25b5a917656d839fc2ba4fa5be01a8eedaf2c7e0362e071e3a3c21728544bfb4eb5416f919fb545861ff2eeb9ecff0a6342cf04ff84a6a25858410fe63eeb8fcd22afdb1874373da0df52e596c7142280f4ed513f6c7e144c1af9feef730dc3a4a9966b0fc35aaf10c1ef30543ce17ce57c468d09a5a7d088d7d56106b2dd62c1592133e7b9b46180d7a01051d2b23abc08ef798cc6d5be2b6ad45b9d256fa258f3a0f7628fb1f8651130505f0d8365237c275aea25254ab10811831b8e792180765e46b00d2a88114db6c42530d1dc96714710ba6a78642dd03c96da4594e94b0f241c396d5d961fd86b17df023bfae476ac70ed8a28d58e673585bee4c181403d09af14797859e735044baec4426293ab1ea7a749fa9688c7662227a97d3129956993061aa126c7e8fa11154867a38c1ea7b8f9ba7231c7502df898f95d5bcc0a645839b832324cc0de68c206e48b9433031ac84f3b58fd8fc2468f02c1a8dec6a186f79faa11609f314ae4ccb9c33c61b3a3851c50a1c3498b4434db510d05d79a5c356037a5d869c9105798cc89468c211b3a7ea3703c8af9efb8089865adbe6080e6cf8d14a083544ae472aa7409fe9eb8545261b8c8905f547d5e9406459ad9e9dd3abd20681e33c840495395cc3026515e597cadccc7e6d375c6e779a878d155ec23d482a91d3317a37d58515eb626ca811fdc2224ef7136035815ec64825331d04dfbff563667d1208896036a456777ee82a54eaa1287492e59c42a1c68330ca93e9421a187c34a74cfa652f01ad1474c1094d840042b4313cbadaa4328f23bc9c6c5a48636baea3a661253cb41621d14562e0cdb8d4736eb5e12e8bd0ce86cdc6676d8c65b88a8ef4f5164d38f3a4c1b60076e89405752980c37d0149377853b314814c35213a8dac74f8e9376d73be2d261c338ceb72c684d9e43ff63429e8839c7759c76003cc7a1a4c277a52edb51d3a84206523bf83b672fd533853beec631264432d5ffe5989e071240d8aedf887f7a8125665aacafe4c11b3d68e3f416e7305ff10e68b7ce6921af63420ab378efeb3c68824ee0d71c89ecc64537d6f0ec21f317ed2833958da5ee400478e966d68453eaa114f182482fb9414cc7c3a0d10fb7e2619b1cec5bfb74250a0a06aefda85e3e1eb4325593ef277e946e916a8435e17fc9840a6bdce2456b13ee43985e927a3f029b11296b3628fcfefd030a00ba8037c4063da86fc88df2fda14b507103c9e506ba6b3c35d2b7988f04688aaaa83b826d0f403fffc3c8018e4985a534bb67350399ca61b24d539e4205e2b1186dd5b7c2c809b4fd8123ad660efb40a5c69f183c66c8f158894250459e42c4a0a10b97a71d93621a6f91669237238445e8abf76728d78b0f580ed03b3de7724b5fa2eb9788b0456561787f96ea45bcc67c03417e4b8731bcc120048cdb7350f61f9da620c7cc8f882161c14343e93f36e3258d938fd1a8da6d30cc03438bdca712ed1caf25f824af5a3fd2dfa8297191b7e4d75a3ccecbb58aa218a065a4e32aff40b89f448abf2a7d6bb4e1d201390f17ff070565ee7d5edf6657bad0be0aaf989cdc10eb74f230c215250676e74c81ba2875cfe165a3340c996dc23c3b38dc092f98bb0f84a3c66e1435d2a873b5ce9b4d241873510f1a7587a699029791c38310c91011ffe0d00c0206ea6c80cec871a3970f4107d6c95856df2835aeed2c1c3233ce34063d99c65fb7bd03adcef0304634dfcd72127101de4e10f84a8ad893b84a979913e299b67dfeaafe892ef5636d675f179aedca4ebfc9a1251744fa63781f22f366b6b803144bc5d8abe2fea3f8ec31586010b32250b3011ca15921f89e990a9a043d2674fcbfc7080f7b0badf91cb1a006136493234ea0c9c1cd00525d3149d9c9292f49e93079bdc5dcea208cbded72441bca1ff94f195f9989d2f2b487b0eccb2cb14da161451d1f7bdaf790b781c2ec02b8ea887e0962fe8312cd7c07b1befdd02f6242c8ac80c32c616815ca98156ed3d5d84e8d482631ade825a16c9e049046adf6ba12075957dced854190a353334ef8bc5fdf52cede80652d640a6d059e19145a9bf84b880a3b7c7050005731c43c08fce79d68dccf47d0b9cb8d30352468320d7d00d7a2e99998141f33d19ab1b2efa874148144fca63286a50b618d434388406794034c38bcede814bb54c7304aefb77cab1fe7cb59e4f922303ea119e83b7f7e713d518d702c74dc19385eaaff00e2190c033c94a2e400a1c7de92d5f831438a1cc868ad7cdc5de032c04a5f0ca1e34c229609f17a2cad4b2263c884a747bff9243832700ba1be52aea4d7b0d3fef5c725ab772e487d751c7011411dee14de3286b99bdd227916eb1a54e71ed2a58d86d88464a151831b653369c83e565892eb1983b203b72092f4224829174560d90c29378e8ea50f0edd7aa5deb68766a3262a299a7b9bd2a49dd8bea76829b358835aaaac2d02cece6ddbc1fc8b39f05ebea2f0aeef54abaece03f2827ca5a00b4e27b7153162ade1acf818217790c4821432efd3c728d0b6eac9098d97602e0bf678c5e5781f5473829d0c9f1d07d1c7b27c447dbcb5d2caeba8e2df580d362efea6de1a048aca08a7620ad44d7c40b7c050a272c41d0ac1936b941088b2f0b39107cbfe2c9a790b88e236390e9b09a78e63166b01007159b17bd57cdecd47bc10b4e8ab7a6f3929f8b9258823d518e637b361aee047739af5ce44c8a28c222520c91d0f8aec06e6b46134ad99b9fa0b5e1ceefe64c8241c7b113aba5795123108a7512afb6b16d205b7d2bcc02d987f0b5e2a322d523b8ec138640bab107b010c3b76f92c1cebd67ac156c3bc60ff5e8bdb5941bbdeee925640df2d2e58ff2f0c2032c4aa9144d7c0ed92aaa812e69d9908b4a9a27c15c6147c8667a277d2f2f66faac8f7a19770d40f9e6c3144d8a10fbecf3e93f1ce11b1aa80b301ac9b139e533768667c1dc1f468e98b2e5e3135ea79c414114301c6b3d9852a5d5a917077d246d407976a776bd64a70062a9949a5ec82a3c30b7f8f6669be45f7a6487a67e702d7251bac149a29b0ce4c09e26fc5d9a3cb44ad69bf42afa7b640b4defc69dc0c952f1aa629ba7c45f2880915a67d3570b6e52066034e9b9d3530e1acea86c00b227d7831be08fd73ea3215583cbf70f8f01dfd1377110664bd5adc5e490a82d9ee5619e9171b3c46a7759a609d88bad96097701c03a6f159bedcce3e69005c838c42e8b75045486045e3a25826829e91bf07d8bb2a67eed98cad3b3ddad8ae09d1a4f74b22a6dba046f6009c2ab56d19ed5ad8034c817d5e50be7933c2dc8f3ab624553bae9a2e27e3cbd4506e902c520431f17efe3b154bd3bcf984f03f6f8cf36777e30b56e0f69e444a7c496f6b5a73ef7401818a02c02bc1774b84a3a0bb3a9e860f170c326a7e48d4acff9da05f9635f504d7818ee23fa2d52a58c513940ef8dcb42152cb5807f02725152cbcea2bdf439fa02ae5d8989fd018a2214a28adfe892801d2513f145f000a52683fbb2808e4517cb84b3d34ee207959860b482d160c82ca7e46c1391f148cb7c3064bed8834cc75505e12dca0ef9abdca0d8427dcb0c91bb7eff68d92f9d318c3a82ae4fddf1c789495abc6075b79657d8d67e5db2a6b5c7f58729455951f98560d6fbbb4b99230b24295738fd513fa33eafeda1a4228e6137be0b95d30c04697403c56ed7d48c38683f613e859213a4723e11c1eae8f479c6e594c08d3623289301a7adf458e28fb72337aedc6632fa10b78e1f223c1a9bc14192c253425144b2163f79e40c389c9c6e5862b42b4651b6aca6ec305c147675dbdd92ede01b026332211543af79e5c88781e41f02c68341cfa91c8ccbd7e0c6c938a5c0dca8a19f1a4249a74ce499c8ee7d45f6a0fd98c86c82528bc15dab23ef290016339842ca88a2c134144d3aab6201db890443befa35ac03f01685e80f5b1e8430d2b4240abce412cfd4a5bf46e11b50a60be5dcf26d3bf8948d678dc42e8d33794cbb1d363f6aba5d146c1264f1561ffe943487d2a79d312aa9aa6d3254ed9a580e22b0c4db37628c09f258d0a6557cf39e4c35db4f9f0667c271f0b7e1ddc12a0027cd771e1be09a2bbb2d298427241355aca2b8bd04a72ac15f0b8ac23937f1b4fac15b18564ec0ddf56b16b3ae468a81e00bc601c6cea56d2969edca94d5eb9e86501c98b72992006a0db9d04568ed183b85383564c92c1edb6857713668db8ae4899fd8c43071182e20061962d16f28e57e5cb1c61d7184459856545e020bd4046ca1673da63a92c3a7648fa6b881d8885a18b4e293391d276dc9990c3f6b42651e4d351c4a46c20649c685df9244aa26738adfafd9d49398ebb06635ab1c06bec80caf996224625fb7b99d3d0d3402897349f88e7c30488276daa762d56409fc86bca7970e05c2ee3ea888ad4a4bbcee25f86452f4a59ae48731dda77e319e3ef8846b4e62e463c89e758fc4f7ca2253e9d07769fa197f8c8d9f70773bceef6d6668cfb021937360b83cf59c56744b0f13fe4719ac1b2d360baf780e8e2bd18cc61b88db3b622de2cd6b3e6619dde1752ee1d1d348e894bb4b305b6aa3c4ae61349d0a5762dd32aa3cf22cd445b0b394fe46b46c8cdb0aac35f41275ec21dee6a316c64d178c05950294ca6249f56411fa55d654a7047d80163f7b4905ceafc8daebb097b013eb348d0e1656b9c70c532dd8c381d4e22aa9b78020a34e37469fdf29345b0272c505af0f762af9e24e3d90c177ed16ab2e3cc505b8cdf6dd0ac648cc55a67837c810ebf7e8f4cdf7ebe7c1e103fc37dc84deb595b8220971ff89b997bcb788c548eab25cc2af7de946af9bbc8da3385badf88a82faf36598fdad7312c466744ab44920a531babc2496ed2764dd1df6765359226fb8d75ef78213048c6599dc7b8c034e258ec57b4aff64853c56cc69473f83356ecfd7e60a7e4b332647a8039a2ca914075ee326f50f960c327f7da618a70ae1deea410bcce8a77eba5c466aeb42ee33a35fedbf09d6271fb6cb2ddaab653fdace0f097911235d353f0fab0397f30e71d9fbf13371df695897745884295a861973f590218f26e21011a04fd41cf1fb10191c83e1c01badf0fb133fde90cbf7cefb476362ff199fd95d5baffe086156481def56344a89b46c11a5d4695020d49589782c70ca6afc6867292f409ec43aab372ee4a06d31b6a329993ed98eeba52c905cf43c61c0bc9e2ae9ee061f7c82c866b8d1b5f66215e4ce4368b78a5e146e2b78ed22e76141c182d323d4604f7bed180339e2b81ac97eada3d3c22846e9992cef8b31ad366d11ac1eb081b65cf6c10fce00d5b3f8db3a72a719cb3efa3a003c720223a7264813ca9c68dd134a6ca561920f204547570ca594b652bec00604e192a24b5fa69d0d94e7dd9d0c8b8049137e8f30234703af652f2ce33c651646d4f20b9020d1b43d2e2ea79172ccf8f12639e19eb435af80763aeb2999356c949f328b5319414525572bf1c550761a92988714a72bcc416daa9ee1062ed9aba0ff12965d92e17822f117d30c3800a241a46f41e52645142253d2c069aea48f135873c5387e25063a23233ef83e0164d59c509482d7922082fb5373b376f536868535993f4d8edf0f20d27135c66aca67a15b038aab95d536e5fada11aded62c4e93acd3a3fc3a7ee9547034709732fc4a35dc43cc2ddea884ea6c2df3321454fb2397f6fa4aac9dc1e0708a7035310cd75e324f4fd42503b418400fb6be384963dda37d1dccf9162a2377dc78128b83a3104426361df54be51e560912a008c6dc7fbdf05a0a8c9069fd1c4c9ac1525d51a087c1eaad78d59a9b7018a8b406b1bd7830759a7cb915908cd7c70463030228794fe7c3b2b2c5acdcecfd27968061f7d0027452d33d40112f6703aa5287c90e19ae42540218f90ff2e870993884d4aac9431b5d9b96b54ba1d5351648f4d5fdb14f25220c630199e9c0493e45b3b6f607cf39038a6579935ef09a87754ab979b31147dec5b47bbfc2d9d8df46875c6f26cd4929dd492cee2b249dee888d9907abc5ccc46a941c0a85a0f4c6d6d7a24fb7b3867e2d4a06d316d48c6361a648f8b2f53c50eff1d89f800b56c30a079dcd76607a33d70934b120ae82a19ef829f2e033108f114187c2c8d78be8ef480a114b963abf2340fbf58bd25da774860022a7ace2c1c521b20fb7b0da58c7d777565fcae4d5dddc865b53101882d80288ee00689fc5a82101f825e79bbc62d0ef5a30ca87c6831e9d63e0a729ff6fca27ef770fcb458023374504c56347999e0da354a4d30bebcaa844703be95d42241fd2faafffbc312b8ad25c548074608a3e5a357e6299492826b28c55135207296cf630dd7cc99d701df663da2e2c6a1f45d16b4b6179b01c6c11c23606889ec13bda89038569502f8030027bcc8b1df9d844e111d3a5e869aa49f1bf70326ebb8bdd4f1bfb7867fc103a25caf2c53feed5844875357a5ec273bd4a96c4266f2b1508fa99721ff6e5587ffee2ca882c2ebe95059cab987c3f05006080fe75209aa9e584dab655deb8aaa83ba79d04939f01f0efe7704cf178279705e570c6ba7a0aec554ddad811b2c400c78e0b74e946553def4ec342578856ca270c054f91aa4a49f8f8806e2a8f3ef73dde5bf62195aef17217496640f065b18836004a4fe067e2c6fbbc96b155522c881a24ad78004f04b2ef49ee64959dfb0d28ddb4a7966452fd3929acff3e054b013bfce8a2adffbf392ff6c39f8c7c0f5712e0f9443c2d4cf2cf71854a5d2bece6a9a050f63c2f193d500454c7bdd2060a93a0620baa65afb90a11c1d72d3909b3316659446f3c1fa0f7cc7fbc6a12235f82144c719d941a2a33fb50a5d42a3b3253cd0df9b01e026fd6b3530bdaaea758c7b5bc220f1083ca7ea5bbc455e08aaf5bfe8593d9afd129ab722c8ca793276ed7b199685a66cf322c84d3886120145e0ae964aa821760a4d1c4cf261a1d0a81d2d4db7dbe94d5a99b0a2c462004815745a0b8cff13b328e19d4983857e379c09e29bd12556794adc4e460f632858ef33c5abe6df5f924d44928699f4a8b3dcf963a232d1092523b482e58465f3424a3e5a51b4372717c04b53f5291899c47157638b8b153f353c2e83107aa8e6320a00233bdea056c5d541cdc58568c50cfee325f382457b4a027b7ea52ca544260f29e1ee8efff0d0affdb015b418f58345fb5f0e5e8be4dba5773f5b068c4a0ab589f050aab04837c37d42faf3d193ce26e54f29539e9007f3c37979317e89b42a8d002b4fe9032c81f7f85134a793d7b2a720f4cd94eb5000e3b6c732989dac2bf1c9c457de212a429f100cb5f172e139b5c1db3f5b1008bd3b27e01cf06c5e09c18b3c188d5747087290d702b905ce689cfc56728cb4bb9e33739f05e29be472cc37a9e908d3299f7a2e16054186fd471ad19576378e44611a0c9843c03617f1f05a6f1245a5efe383071ac13c6958426f463bae93972344541441c487f1615deb5d28fa768873ab6747bd21c90a233cc1327a176a8b1230e86ccf4e8a7ba04348ecc593f72dd36a89fb464c7830b480190212587394e7325affa8b4a940239780fc759983236917860eb7920c4096abbec224ac0de074e991bb65c5074898b4cd467231f681ed2c66cb011fbbc8c373c7a69d384164b3bc57bd9c6da32d249252ce443bd2a456b07ce7ad05c67c73d62958b55294671774d49679504dfe66c1a7976330cb6e0e6b46d27c71238e948ec33c5d6167b227a369e883e9ae5d13512518fff3ef8284d124497e4f5638ec6976b5f254ca5ba5a4730ff01834fd0b8a64b959bbd14ba6bc4d4bdda8ae89b7e7c8aad2349f3dd7f9a37d8939f1d85bcec5c679c450e259a7d78c1391e154cff019b4dc0e38d89071012ffd7050af6f1abe9f0f58c44846ab9c8d5c4b994532486a321b83b8991b85f7b698ce8b61d84f686fdb60beb4367f8025064d2bccac9069a7cb01b61225d4bf852b6e30226bb807591735ccfb7aa5e1b7321bd615513a1914035211c061ca03bd8dc27951d373b88fa0fe5a830681730e64be715714f8a8676ddd28e722b004d1dca55f81099a46095e8750b3943a98ceaa47360cc7e71574e01e09557532896f45901431976d3d5d183f2e0ffa3c12a09ae712867017880bc69cde6a1e14c0b6d5e3be5012c58c48a2838aabde05936227e1d6f77fd53af8bba540eaa9d01b6952acf4ca5a437a00a00c9218a22eaee388089fecd2e799107021d584a158eb3f40b463b651e09ef64cb0ce4f30be706f51f4d9de4c583862d5f1de24ed691ff2cfee893eb115e3d8fe6ece0c4e2da67e52c5816f03affae788c89cbfd5d29a80e4b03e47204b09c2609cc41df91e3c4ce0d3ea6a5d3bbe9a5bb6e67581c70f677f28e0d61d894b742023ecda0ecf890a3939e63da27b04cab9bd4daddbdf7c721a074bc2a0b2e4bbe58658945039b3011d85e1a4f2b7d6b8f2f4b2c885100ab710a66f86ff68fc751115f405d46025c196722a7f10f543a0b8219158239e5c52ac62a3ac6ca31cc5021b05e96c0b918000e44c7ed11d70abf45d9d3376ed9d8f7a6171428626b2eaf3200f6b78a62e46273df89e30009e04221bbf81a06b5f76ec9c7576f6c077ad6e09c343aa39176b47cad696a9a9d5cb7898bda1a01a1f9bc10481de52f94476b08deacbafc70b93c1ed275f0b57bffe5eb977c6e688cccb8ab1a71f322d925ac196aa84079a0728f69c92aa1e2270e194f4447657ddc259feed9db269422edb1447a252d613ad3daa20e29959baf0bc4676d8d802ef25c053c08810c105fd4ba845110e797492ece6cf19100a6bd950b3a99342231b0dc4158c12c8914f80d5088bce46330e7f873801764f7393aafe08d799f392247b458a170488559ffaa5824173302d94173f94e3301ef0f7ce5a7b9ba5664cd7a606fc0d2e94402318c2675b05266a97032499330cb41c0d5e8f47908a191a891f470a456a2f2f17cb9b1828743273fdc3798add1d3b096b3f53e608b45d9a0adaa673a78fdf32f3e2ac20c376f8b7b21d5637ba37e33884ec4b46097ec353bcce4b8255f96d7489351d23d6ff966ab843d404bbe196b405890fb2b1b03f970a502646c0f8b49b2265005b14766a1ce376c464b7b7e4bcba2528878db36091a4f3a9eb2e48b3f7b718a6f0c563906b2e566900411fb696dda2d4fa6d9037440ac6bb16a0f57337c6d88287d7567d39d97059b7a0b3110643943853ac9ec2acc97f225e2a50c4985e13fa09c22891e139ae58279d689347a697fd8d02dbffbf8e9a978210e15ecee50903bba4693bbbb1bfd68c527a003351a970dcf83f6288be20a958f2ea25801c9c24a9b7ab4922b3b75b09228211be5f42a5203c0ced9503fcc8733e34c4148dbb2a9962f669eb7da240c0c211d085014f50a191b68524ab1eb516228fa32d10d2aa9a05a9688276d36f0e81432bc496b37b0a401051d4f56ff21df7ce1dbd6736698359437091de0b5d586574c8fb94483ca464f624ddc005eca4ddc55d20395edf0ca1030da729c270fae8dafa172b96f3c17ec3348680a59dcdb33de606c60100a1aa1573ed2fd138f06c1c75faca38124a1904d3f4d608ecba0159b3c7eb4d2b195f65a52f80fe27b543a6b447b54786ef339c95721c07aaa98d022340f944d4e631cd19cab90e6899006d77dd599df94ca493f2a7de7c5ae00c72c15e157c9275d8c61ccbb8058f04f99b1b1711e32275dde54b008dd38fbd28d79d6c215d8c80e695951947d2d4040e9039eb370491cf6e17b2b9217c387a8fe3497f04b8158a9f7d1dd00b31a0f8856fa0b076ae3a30e04044eb9e35e1505bf36fce31a5457d51f69582f73496162402727c5b81296bce37fe06fcea2e8e55313da48eb41edbf62517fbbf9aeac11b7afb14a4f004ef91fc0b0af4a6f4aa09b589bc27a56def15804ba4f32718e595a348c4578a28dd161e7928549e6312b26018b0e7b4e914f4cb200253373e4fead0c35d2ab4944822c9930aa73e2d282252ace741862c120ce896cd87765e339bd0dd10c88f3a592c360caa63e70cec7db2170ea6007320118f9ee880eb1ccb77a62b5d6240832331e4c4270dd4026f6caaad061e016275e010070c8841d317d1b748a3bb2cc4dd42b42d3f1dc48181c37139aaa9d18e1f46ff97d6cea70c3a2411c6df812c42831b0c5f24c820e31aeb86c2b75233db0a7a953c0333e6f8550a6a2c09825365ddf6437b81b2383c7b46d9a01baaecafac97f87328cad0f061d4a778b14d69352e26f9d1c506164247904ea12451dd35a156a2368910468078bbe4c6e831c8ab549ca0bff0e464b9981123e2870c0b0de86d68ac8183b95765eb23645542a29ffc2a69e859b5ebe87221e149fcb321d87e55d8a68021ff271ee5e15113601da41a8a498a84d439aeaf322047b7d6ca7854276c6dc476565dc86dbf1fab14030397a9c7d4db1a22d2bdfb6cfabe079f69a1e3472a7d40e1e08f63eeb834606368e2d7c931342a70323d8c679a30ff073cb5c05ac70961e6a7142e1d7b64ebf7827e7dcc05c00e30a318770ff2809464d4b47eb370336ba3b9f9f77bf77a6fc02be5ab02d6645c9b962ef0eb4fca785dc5deef905903ee75858ac3f9097d2a0c59257794795b27fcc5e58a67f01aa728dd33f4b96df97fec766ded69b0b2e732b38f73f268288cde78ba514188005bd31c4ec05885f212a1aadb4ff1cf01298b3a1d69dd36abbdfae4ae059e266793871f9ff9922b0903bbdfd7cc330d78cff726897474aa8a75cf06bf86923190ba3e67511a322126d095846a6a491bba5af430909d6c3a85e43fd7f7672b3e9c8cd43bd3f6550a7fc376205712cac8d31a74640e75ce22cf6c5e2fb85634e64f07535f7a0be759d06949dfd48400aff407346099659a9c1f83662be8d0daaddde961f5b3702adc035b42a17140a3a4b712da0a0c82869493452b27e2c2e35dd798ff4a05bce65fd017dab9e49015992b03dd19c5b0613632fe8edc4619656dc078bda1d129a8d8d6da6fbf191e0c775ca1a4e8bf2b9549a8d230ad37777593d92d401346ac44741d9c05ebf1676efc65cbbbccf5115adb5fc2c6561d6d62ef6fa30b3787c119a1540d68d25c39025f138467def5b72ec5753fefcf32c54ecc135e43e111e812c606000dfcf4937f46ef06671705902266386300ae8f76ead168dc7880f625a64a8406cacc7104e9696fd8c97caa068fd04d03fb669377ca6dee3f50031c8e86ef489185214230ee1708d28702d29a4803c5a6836ecd651ccae62275ead75ef02503d728116cf0970f7580d4686f3985fa23de5eac3f56dea9486f341276a0cb404f3dbc86cc44ee7e3d6043d8cf6ebcffc04b9515f46120618319f9a5e522112629e4d0dcbc29a992a681964dd7e57a8ca81795f9d07d591c8c5b55e90c824e095fd921fc7417d10d37534d81664c90c144359c450d125dac4398eaf9e44334f103e5b5d20889c614dc7877edbf194c098ceaae183610649e079043463389089acb74ba4d80de2f660c263f68105cb443b4c69ae26ee5d03673134a8e3a8d527bd168eb88eb67c627201e941d23252f628e0408654b1ab25486f46439a70b9d277a1b892f3378b1bf7853b79fa495e9efa578c9a82101ef667e9ffc70c39da0b99a49151893bf27c39bfbd441f85d7aaa0236ed2a82fca72b3084f7e6b3b4729d9d5bda2824175106e48121ef328e23a50d1d28de1c1116dca679ee05952a2a7a4dcebc4fa309874d7fde8db1db81d459e677dddf2d2dbe14342433b4c14b15667a8fdc8551cf4f37b0250687f715ecb3757ce13f43432c4f8b1958e45d50cdf4746be7bc9d8281d457aade8958776104e8b41c9b6d022b1e7d13dd3bee71dd68a60515c4501c4780f083d3d3b61241c6f2a408c441607b00c5ad1bee5bda184cf843e18b9394acbe5d048fe494961284b875a78291d010c6722c090ed1a7cdb84c85ef3e3d8cd49c925912d3a8db721a1eeda164edd129a1aea123ad4cb730a658a71056e5bdfd553a4f33baa977313725184c701ca54828a83a45042b9882e53ba73c0ec8281c2e5ae8c2f5a0fe04d466285088937167d6de5770137918043564c44bd24884081ba4dd2bd99883e0fc0c8005d94f6f9ce01b70f912b6c2fba3b77144633b39905576d9fcf04612b599af422adbf1e9e639d8057f37522beb59c1b5d87d293bf42e42eab17f28c5f2296bdfeabeee8a027b6dd8599bf7190689bd2bff14d9b0770d4af2d630104c5753c686243b94182b151a1dd3dd5ad693777505f30650a95db348f2d07ddf3faf2f6f50e01a79cf4c1cec5b08d16718a19d3548ed9e7429939b08fc4cb57ad4ae004dbe480ce74a8e193ef39a097046d471f4312a801d34393aba238cdb9740916906d90712163f9017941d81c9ae867fc28e3bc069fca6206eb5e4a9573c6c6a72e9f2963c44ca531f1f982a682c7540c5b0a7d9fa655e54cc5e530ee325da6f196bcda9cfcf77b9695f2c2357bcf743c41b65eda87cec5281baaf97b08754b8bbcb3d85559952d8855f1ecc9b15bda9ecc12650440871434a540c078ce407bbac0125344fde5b60ce5fd6bede8f2796ac5855a13c507ca045dc0b61dc2beac0a7cc06ff9cbb4cf401617d8d4cab5e8cda63921879c5fdceb9bf585465ca2275a7831e29324e236b9fa922fd5a3276e290e79a04fadfa3fe71925b0d12048b2da59137c56324cd841d58f9d207e27f3a22737d6a9b40e654c360846581d2f55c782ea69e07de92f0e8d54210c9441a2cb03ba238b8dabb2bd20a078dcece9b705d56722d0003295370ae24546b10dd11b0579619807737093c2ff20c92076bfbeb93810ceaf3c6c407bc1963fd7ed6c317da2d64981d62ebf326bd4abb7f04dee8f2c4546a1249edb4422e02260af24967861b13287563e977055d70a45c43e18c506b8382ffaadf441e85722cc9fc6edd9ad9fcb6d28097ca06c46bc12314f66aa3f8bf6eca11618d780d87757e730ee34f3bc60e206c47b9d37271dde5733e85c0871c2e10df5c105b79e8efe9a65d64d6c278c8750d182eaace3fe42d9f0334c04d8a988d99b37a0b05ca006a7abb8d336e9f5e995349ee264f399220e0480a58b00cb61d416132a36be04e5de4212ae64faa342a50241774830abfb2310158a75a611e1296a1a443fb55ac4174fa2bcdbd61c8677aa2c96888fbdd103591b1ee1cdf44eb126a999db5db966ba43d71d39864b19910032961078df5b6a71980153bd1bc4b73d5e15895b7645d37b5beb3c11869809f08b940edb214367becd4824b912c48541e0ab5bd15305a927d43285c921d5fe778cf60dfb1439029a6d1d0a6a3bb3495f430630780d2114c0cd0030c85fa826e29376907d7af5087512a04e7d67101ed347752f15cd7d111b49a752751a9a09db5c404ef75b54c4655f3a9404d3cd36293000f50ae8bd8773462eb403ce10ec42952ad3565235266140d3542936ce8983a57db9ec38ca0cb625ba8b7aa90d8b330aed29568e7f116c476de6ad781c4e0acf570f032410763f0ade2497d3ee4303b7372b0265500e5626c7e67fd5357c6e3529114ee0dda0cc1ac5bc02555350dd84f0d72fb7dd0e730d47be8c1ee9031ea0c9affa195b7a5730113fe8ad91f71428591b9b8d56bd710f287231ab4266da7527b8bb882ac5ea47750d0ef99181f32cc0534204245f7d99c0a40f69706a5169193982eda949b1719a366a3dee73748fe946c2b5c6d901bf972b38a8f9c5092a9d1b14a31bf579e52618b92822ac1cd267d1eeb4993e3cb1ddf6ac86874b323398a70380e5c003aa8cab7a9713aeb65a98ec1b6f9c71338fd8d31ebb2437fb90a2ac40bd331bb7e748facd4816c59592e6642925d4783c70d5e5c7a6e3d857b6f295bdbf3774643499a4ac863d37baafd3ffbd71cf92f269acc97e655482b0748c27a3a14af66f50db28fe44d6603e0e82d9b7481a0335d8a83ccb409b8a9da841cdc392fc8ceb461eeb6e5c3e862ddbd89e6a8ba67532b5cebd6be30f302c97af1480fd81d8e4eab06870078fff6ab7332e1c64e3895929ec2e539a2b0634312802f9a2bf83c140d70584c738534c7f87fb2a28b9b6910f15e3e02304b5fc675fc4f744029850b800c4286b2a8d0b0ea4505df68118e556f5d21569f29263b4a0e9932630b463d291d8a2b2ae61c072796b3d8ddcd815c415e2582397bda72f21b666a306b575c1cf67d8b92b49164f1771aab36547782b17c49dedd0e12b9447f08fa235068fa0b04807bcdaba1105dd04c3924c9d395cf0318ee0e0787513beb23d6ab379c40c8f00cb015a670b290da87a1259fe6f4780678c9058f61e9860991793582870fa67458416a5678855fee77c5548ced5f1954c501ee2914e6dc815b21cc8333b28a37ce3f8e081ba12d7de9130a32b637b4d3008831030b2a14da46d4de9619eca20b62e0d5ba9fe7eac7d6ded1a9398ed54b86ce0037a6e5ffc51211c611f1fe1189b2d852d2baee9330be1fc710b110eb6f86d49289cecf68ce1633944d7dae8197c89c0b4111cfb6a63e23d402d257a9c6660bc170df0650c299266a09e08507631787f8f19f10b6d0658cc9ad18b401f37a1d9e0e8c533020420651902fd3dbec4527e5e8687fa81315e5274034c0de62531a89fe4a350eccda28c807d36c28296452251ed89ecbe38ef8f043cd84801e1158cb6b1c88c06d2cc5d053d1f32cb055be0365621ba032401962e7d1a0c48b8e8827608043b9d68f0d1c463ae77ada45e8ba8b50ee244103fd574e0826e73f01d1950fad8e1063f236293223736e060d8b785ae6f2d9c5757b341a76816c75b7d83b803e8130839c69f35db7267e5036c075403f2df8378e213c6a9ecfcb685bce2418cfd421188f621db29a9d99ac4b96398386008009100ce9904220217e925fd2674114fbb0f847deeeeade8d65f692333d93342e02ab05d2fa6c27136d33bea5822c90ad4ae4c8b68c412fdadbb05dbbffd15462d48000591342482b725072dd0800ccf539ff21e46851b430eb5fff16278bf05ba30540b6088256ccc6fe1f13226e8b14c0a9e964a7d95bb69409c878507ae409415a2e855f8c9353c1f4797c63b533321d4779ec3b782c1cbde36c7da7fa29477be5ab7bd7472f59a654cc970215529021c9ed12e6c0db2584528a2a378bca7540a618fd84b6e239764d7e75907783aea4f3ee38aefe584c2a940cd4125f2f51f824452c5179147dd93d3ae7739a8b620d61ae62768059199a12672b7e75f15df3c99f70f44982a91abe15be42a0299ef4be6ea90ca76fc77640801cbc19d52905791480b91f187906a168a589156baec000599443236e29310d8a084ba14157f92a37e6460594720f18b862328792f7551b134dfe7cd9b89ee243bc75e2698d9c549b16e0a18a6cef9211fcb55945415816af78f39235929725c1372ecc5c5a8e8249838d3f078d8a0c2c5f178aeb11c73ac20ace35e5f1ec6707a1fac2393bbe24f3f602de8be01dd5186aa465546ab54e2b80d64c4cb45dafe03cdfa872f603723d98c778be0a2d493988a5a70a4073c91eccbc4fad0cb6a6d51470628113fbe12b48fa7aa5106e8239c18548df926ebb36e040a33403343ae000437eb8d35c4bf2149efda542543525138c54905fb94fb5734ee1f3835700b9997c6bc1ad28d6c0f7364fcf1c24d2feebc9fd81d464c233ad1886c43a3953457dc689b40193179eb338108e017bfd266c7bf4303b2af7120c576eb3de281a42ca43a0cf62fabb1fdeb145e20634fefe05bda18443feff5c0cf20bbefec3d3accf0a4e10caad901db6e4ca7bbe67feae9c7157e71f7bf26a35fc1ef3cd21fc11c8eb325cf87d5183130cbe472a03f779ed53503ed4e04da0d8c82d7b2d2f113918ddd310b8ade7c857942394a53859fb373065b020a1e70107d7fb5338af9276c84d0832a0a3af9da8320e4119cc4b4081cc193d343cc8ba743a4feb73dde0aa2926a34654941610259c969080c3e2953e34ca8e416e02fb31ef55e8684886e048435760e24ed1aca734d86868890bea2f736012ca30109a19460c65aa6d858d873d35d034d6b09254582b2027224f01dd2cae2341126050c07ca739853d950ea4427824bb804f465a9f4ff7c326f7d2553dd00af4574230a9536f19a83124343c867d22c8171cb0a8e5480941f990f84c17a5d2c331f88c235c33627331fc8d0abaef0787e27901e42e4579d7f344292d8fc662daad486b54e8a83f53ee8c861a49ad6c80f7f74408c0059ac65afe92e643cc197b8c0a49e702dca7304553f690efbe903d8e906bbd24dbefe850408a443213597f69edc9c664941065698a9f0401c535e27e2419da156c30302aad884d1529ba33cc8413a38231de1e92208345867bc067a281ed5a2558c169b083f4c063b70dade86a75a171ec5f4b72585c4ae5b784465f32f2146eb46627e485e35f14859404c511f63a75bd6dc1651efed8c7a210fad7d6455c223c993f3089ecbcb38f7e095cf72e19f25caeb72094bd7f69a7f25aa708e17b40b0840c22440e98b07cb609388d965e937166ce82e9c1c6d7f8da94efbed7833400da33e4b8b2c9999f82b250f3ffcfa77aed6d7ce92a766a38cfb80ce40c123675feed69b728fc85456071c964593dd37464b771dcc8a90e96be86102fab31db9f2e74a33b0777ded467b6a37d055871299bf9815239abd9bc419d1b9bf08e67d863b200cf5fa9d07d377038c802d009996709a75e9c7e4d813a8e71c6125fc62bd01088878e046f43c71f4dad2224803e78f9abe346e28261648ea27f7a88151fad700d1f086ac27d5374812250cbaf37fd6b4651ecb7b9c9d09b1f4db360035136e63851601de6ce9d8511402b4a2c6f9cdcfc03817ae75bb573974cb13b41a80858d9bc58739eb1026820ba61f70ed406c6758de7c0e4601d3476a23011c1256bf14d9e186328b1558331b4363579289f50b1dd01d498afd0852aa9739ccd42109f6afb419943550a241fd6d86ce06673e04d1b9a84ef595171c80b1d9cb0f672a2a90d87856eaec19881e4608ff1844be581afc98e0d8fcc7da48955b3354daa0d9d00c1434636eb3efd4f4416252b04daf80da462cf3054d2a02ae47a9a0610bf00a7679664cc63f723dc40500396ba7554606553a74f4bad9dac3ce629b114066ea4a29f3895f0f2d1a29088e633bd768de0f4a65480048cf39fa9dfe579e8212e086ae96dfbbd26de288fc693abd0792d6539fe6b02fbb9d5e0719ef768c8ed9236d1a8c400862477bd862ff9f3e917f40566d062062dfb9eae41915e80568fa61f062cf7fb0eef07f58f59052ec2a3a6bc137c89623d94283a18c164420bf0cc6e55a086123fe493e9d0208b26162981ad907041e5e8883559fef6d10fdf4f55ffc3601bd945a10a80e5e4290c03656eeab4ee237d762ad26d1303f2cd4bb80f17e1cc0f22e45bbba06d837a54b00e9f75c5cc1e62eaa03d09f1118880e1cd38adf7400072c0300f8c1763163072c9f475e20e1fa35e34fef0013cb9d4a12bf55bff006b13eee8ad665910eb0200692d0013b44ec60c2bf155e4f3dff20c95bb49598cbb948497a6b32fde8f40d1cda22cc5ce54d03e62f84ad0aeb0b026d6d718a1076cf293fa4980c08dbf4e47ed8ce20f03d021b3caf05dc963f1837b1d822143484e25ac0a9137163dde9479ed595bf9e6d14e5e5d0f65b9e808df3e0c590948ad8534cfbec30ab5cbb1888f87a885567033c895f83f0ae954d1fe6dd05f0ae1cc98afeb5956a0f23bb945923ff016e18c3f3f50b94523c796c1686655f9146163136ef7fcab1f77fe721a9b30f12a0c1635a14c6fb2333295f760550ef5f8e41076c384cdcb5c2da71076ca6d8091efc67cba805d133d0fbf07ef5e61103dec64652c24c2e3255d5204ff67ce7cf883d0ade3c54dc9574f8ea17595adf0527b969783418810e2f63c0f950df17619554f1caa57eb70182241693486e76abe397f737bf1fa1370b34a015ecce02fa2d4e6e5c40d0324a07150171283a1ac1750a5728dd21d47048627d0612e2f246e1cc8865c54774db76136b044ca2c7a173d0fdc1e780d833f48cc5e21f61f8b97deb232ac5bfd44c301538265bf6ead2137bcd12b2bbedbdc996524a99524a016807c106a8061e1425c334828a681f9a5e8007e560fbf64b5fe921ba9a93324a8924633bd7f219a976509cb2634b8934a79c72ce2991a69c718628a3f4c848edb98cddf2086908183f1b1a80c8cc80d43d2958a2aa01950827845b218c114628617c28258c90053621e028b99ae3eaed31e3e9ccfd6acc678c1173775e8781f1679c99cf542a27559dbea494e9ce6ded8cdfb9e8d1dd5dda54ef3e20d815331eef6ea612679cb119eb29a7300e7f395d72587b55267b0b45984a7b3e6374ee20e46811ca54880a6418653ba1dae84019f8ad95dadadee8670e049a9f61fb40e08fdf8f2342a7188429ac23663c1e39193336d436c526824d08385bb2f880c4a11adda7fbd421d4ed9f8ea0ca0f7500e9c88139c8c5a22e582a02ea16ad86ead518bc611d42cee91082deeb30dbde7ea71e2eb181175e55fe520edbb7493e3c060a7c0062879f8154d89c6624f679f6e91427b577b4c3f6b1cf51fb18d9529b290f9b0a3cc4b6d58777e61f91a1014f7f777c786766bb9909b8962d37e46067fe04e4d38e48113ee6cb6e665ffeee4c603e7dda75a0033d0471e9d999ddcc7627d09f9f4d65209363c99542b0752ab4c74f81b6cfc6c66f5458f64e05bf619fad619f6dbb0fb5cffeb0fbe1decdf0f8baff75ff639f13dae3a73320819111507c80055aa876befd13da4361df070a9ddaee831585255a7c51f7f97df052caabba0470c18bc4a64438d1fc63a5ffc51823a5d4a2947e2ed49d1f25cb6e1907a5dc469e01b6c03f3bebbe4ecbc975250ebc2196d457044208218450c228e3c308ab8047ce45055b96fb8ad4e5dd0a2151929f8a80ba443e3df59b93bf1cf3ccf4f34fe52a55a7afed2ce35929bba57c9d9e922b9c81716c116ea1f63327f79983ccda957f392e32390e916a9debc9a6e3371bd56450cc6d6511b8103a65d35e92ed1381883f9e20824d7be468d2d8e0f353b17d4b94fa349d1176748a7fdb97c8e2088c4da4c861552d6c4208b14e6d8ef5702f0bf30e85f6668cceef17cd7824d7cbe282ac909970653c22e45290a2890f553e204aee82706581ab777cc4ff9a7da53d1b476c489dfae897bebf933ad5df479b737d7f73b139920ba2c92f3de52e13e45b52e8d053ad97f27d2c8e7f5c722c70a5dd29c93bfb57f48e33b0caaeb330b16d7b28744a7ebf0536c70f7080ed151285c4faad516def60698c129798b410bca2a0820542402954581811c00a5ed003181d4c011424002a940842ee48e123a5944ae69c3306475eb354ceb0a136996df39f973ba8bc66e91871554f7a7a7a66f07562882cabe201c6092e5860e061890d3feccc229870c26202053820292d1459b27c018952f0c4979e3398d0218888283188881ade97e0b2849725d030c111089378b58425cba0810e6519d2328434c465c8cbd6f0c4a754fab13e0aa9e8b52979cec2a86671b4c9b93d043212e42acb08242f301aeae9e9a1c19728055e8caa0c3390a245942561fc90866a8879c35012c8d3c5861e21bea868504508249f271ec319385825194240b1f0017ad2d3d3c38402d5255255015a2d92642003366b60d2c4c84f121b268af469a40cef3dcdbf0daa4fa934e79c4a6093273f3275ce39e7ca49d7ac0f3a2b225625a5943f4690ecca0b0f1b6a93d9b6256f33031908a521c404110e41b02088264f50524a19c64fd76c904e184e640d82b6740004216d19082184d189275f2a84441d60b1a2045c5a9ec0054886781b49c651d76cd24a878c2f57194365502983e8089d72ce39271a4474cd4a41a3ca868615141a58deab41882473cea924871f8c40e28b1827c8328319653c714310ab15202de10303013465944b03105db34354882a0d5790dce03d72f16359a59fa6010a7422a4640a412191b8a064850a24781823490fd697538c110b080c88a50624503a3092c402e3678b7e5061322809b2ba41932641404ad8204a5003aa10c3cb0d0c80e4bda7792530c0e10c2aaa48638723a024f1028b4005304c152449326594524a59b4048d2a2513349c490eb248428c6c49110f9d98e2cbdb7004062171242a9be84f7a7a7a9acc39e754d575624b529d5355759afa943c60195901eb4024a594495a0a0ed70fc3c0444a29ad38d235fb13a4638513eb3fe050ac40c102250b142d509076478a0a66891574ca69c539e7a4e2354b7f9873ce241e96256698a839e7a4486c60b2c3ea4a9313eccc1fea9c464ae0003f0003548c3146f9e99a8d1244a338d9504653b8c08932bc6444013a383172440b7c60f0c18729c6f04192a4eae9e9a98193ea3a51e527898768847bc10b5fec971e25fca52e911441fba5c6152ace0802ca7b1023836521e96122043402c986da64b64dfec04063a831d48003920562c8078b53972c5db47441eac285062c35ece0d9442ab11b54e99ab582258bce0db44c1a28a594d2196a28baa68c524a292502aa94524a9982a22335a63803084a746204020f5025a51dd098203002346511086e90e10a0dac691952c2080ebc68d103f760f4f3c43f70a4e4dd8ba8e3c5bf20879e24678451444608b0f0d9509bccb6b1500ff5f4f4dcb02c54d7092952586887a49432496f510b6800467619012a40059c243983891624698203142aa825a5945390ba66b9583b53bc589609aab891313e4e392707df82dfb090d7c4bfba6fcbba0f153fcbb2c1ff9a688deafcf84d64e54aa7b68fdf2aeda3e9e3f7d1c6c9c732ae6bc62df65897fd74bffebadcb1cf858afd725b7d62d95f977fd6ad95a5cec7b08f198f4fcb0ac6313f7b9dc6baaf858acd391fc330ac5e19372113d5f8d6e4e0b7e72be0c4b5620697f8d692cd4d0c93430d8ed0c04bd5ea16cde04bdd53d1eaa75a6ff973111729758bb8f8a0aa5bb4a58a8a82df60f3b3a0e0371dd8a4266524edb8b02830220a27768af8315f7e7f0aee6373ba36eccbe2704a9c8d129bbf3524d619a40139c8410eea7ce6a2600fb928194ec6f9fc0ef67fa33dfc8fc2741f7fe9356e77338e9fbecc782eeb7948ac56e9fb6189731edfd3d353adf7cead2d896076516787d35e3fc6d9784dbf04c1f6ad910a403ac5efcfefa353303e3394cafcb746db0e9d11b86c8cf10ca3d029affd29748aabfdecd3809e0b746a8b66d0fd714f6a8bb608fa888af8f82742b7e9d40702ce0caa7e10c250fd44a8cd1dcd370fdbf7b51b844e3d29b5550221dd53d2e127a3fc46fe97feead292ed8845ff883f11ff39bfc84ea99b59fa3eacce87773310904f7f663b1ff2e98c8ff8f3e3cf223ba5bf28b73b93db9dcbb1d2922d8b00d78bbdd96166f687709dc1de87bff5d973a5dccc3e9122ae2762bd3f9122b2ce077cfa44fcad9fdccc7633580701ebfd7d58efddccfeced5f9a00f9f08ec66b643b557fadfa15f12629bb966aef913b07e3e7d22f0ad9f00fdf9b323e2a528f375baf4b4b4b914174c12def7cf224c12e8bdbb3049babbbbb73d86696c0dc3b6ee0e9b6153201c7a7fedcd38962f896db6db306cfcbb2f85e82fe4170e6394d9249cb07b043153e862427757e2edd44aa10bcb12c3dda19c130c0986b711304a0c6c913e9d1a21331e97434c8a812dd4ad3642c58b035a250c6c29d12de016b8056e815e402fa017d00b084504aa1342b1c197dca33e948d17a5558a321beb58d6012bc5fa4b190f04aab38b2aaf692130c75847eb80d91e55ced883a8ea225475717cf165c9ca7a10f1de9be59a2f5a51fbf926aab86663157cb3c36b52f18a1d1b9cd2ca78948e2c134c97524a5914032f5546547b4df4346a0632454842596494320649d153aa80376c57dd222cb29061b3ea16619184822dab5b84451725b658b7080b1cec2001ad0c9ca8eeb383ba455aa65458b748064cd4ef6da8b860af75b4aa46f509265a9eb001885ac4454f2540dda22d4820f3c4cf939aa3ee133f43950b2c2a228c3af53150e5ff5a95a553cc4595de61471a017fd1d1517555a7b6e8e8a7f27b163fead41665a1a53252e587516c9f7fad5271cfb7f10c89751ffed7af874c58181bb626a253db4591cfaaf6384b7b0c4311fbf2dda81465fb5cb5353ce84a1aa6f0828bbaeb7ddc7ba36592f8999f7bb8faf1139f2980582054190695ffc9de10da84c0279bb3358afcc845f1f91bf9dc59ba8619c86f78a755d697ed7395eaaa6be5852ff5f3a3a7bdc3d6e3374ee43790c86bf85d55f74bfd5a8546ddff5c55f92994264cc4d635f84d127ca2535f3caafef1088771204ec4c1f1c7e9deb94cb07d382ac78911bbc18575f74f0335506da2060aa37f5032a82dfbc980321b32a00ca86644195006f46591802c92f641a7dacab296916585656419d5928f656419757179807db4b11f0cfba95895eef686de32e982188e0d944285ca142a54beb8a28fdfd0efee3c8862f3b18e2a7c7a633404c2a1cd11408e9f1c3e39806a0ea21c3e3980a41817ed1bfa6d0b6b3e885d9a73f29b83edd2b3867e49e9483246e62adcee1e21ec869c7f376ce736e3811036f4eef686605c4bf3c555f5bf5000a0332afe819fb90755a316003a7486c8e9de7892e477226c1da0ca53d9a83c153d62fb56059f71f0ab54aa136855792a9b139caa3c15ed2e72d49effa564fb964867845ec938f857a71ea2cfe648e8d2ff6392bdf18f3e9d07526cf17f2037a18e20a803880419936c8dff92ea1ea8ee503e027180e8b337bcfb80c42118e79c7042ca33c2e9ce5598d91dc6e87e75e460d42154755ca93a0d391d401e23a743a8bd0825f4ca0fbdfbf6f8e90c324ac952ce266c40023b66e62db2943209addc03c695998171026b9329da22a866758bc040027ab1791a658cb2c80b3664612286166049410976a21135c608e96b418bb4a08272a48dd62dd262a87e1b11d7fa4d7f0ba61cc9b0c34475451a3ba92b868c763a9063055a78b1e34206c40ba06095e14698af482a0a2692765c6016c252980aac1f10ac81fa67db86066a202657e4309fc566c07ea6f4776354bf21b0ca07127daa7c08298431c2d83980a2c36f2ec74fed8f397c72d8c0385a72a49c03c8a3333f0958881fb96566eeb3a954a84c9132858a0ca20755b7b21f65c6d31da10741b8000f8a012578d96256757362389a4dd964fe14bd742a66734cef7f9938aed18ccd09c2ab98aff1fe26986a703538afdb1a5759c623e64d7fd5307120b4e7a61a9c3471510bc702575357427b276e6b34da98182e76d91babbd31c656e485a86e8df90bc30060aa31ff5935266627e639e389798dfbba6a1f8da2964eb507bf378db3f130e6753a1a55e994ccfb47a278c5fa56e52ba9c376fab8da9cae3e8001a050dbb6d0cea389d4a9d3bb8d13b7b50607ab8de7ac868d0e8857b77a9930d8a998a71be3d598d55fcedcee11668607ac351ecafc89e38ababe03ae398b892bbf69a1dda1a6ee4371f7fda9fbbc59653a4762623bbdccfbaa53357e1efdb607d963489d9ad5bf85fc661e798dc75aa38bab79e437dba67954fd6197edd4fd888979d39fde015c776f98624edd8755df0ac30981595c7d32f5f3161202ebe7ab2f62a9feb485847095ff3425f8a3e6cac614ecf0dba109fcb2ebf14129a2505ef75c0de116d7cb2f2ae34994f36188ea6733dffa0da3247c8dff1fa4b19b894fbdf63aca4210adf26322ecf0910290168e003901420a1116a34e21750a86eb1297bebbafabf2b3ce4ca0694fa6f3362fb6efabc71742c256fa2470855d77717cf2b947f72052af1ea5bfbaafabfc1ea58ee66381ebc755960154fbe7fc9f3c16a780bde1b30bc25e7bfeeded1c61e04b2e84f68854d8d9ec0dff21b6ef9fa653bdbcb2a45c11834adda230866adda2309ec05982d71901d5984d855e851f54f85789838994962ccbb29e862bb2edcd19d96d55f5c4059fab071287ad6fb2efc752a58f923d642cceeb7a12b65edd0cf63fe45fdd3ef6fe452a731f568754ab961ee32efa9b5945aac56d563deb2a28a533222121f5c71ebcc77a2eb6b5328551b5fe2dab542a21b5d7bca86da44e3a3263fb7ad5ab4ec18fec43bfb7b7b74b19095f2debe9c3bf2e3691108327a58c02457630cba3606f619b2aed5e0f3be3a15fb22cebb2fe82b134cbb22ccba252aebc7c597531f29ac6d2352b2f5f565d4ede53ea4c86029c506d2a3333046253f95b0540d59919ce40c8afc20a9e03e4455c8eaa03e994b343ee142ed0292681097c82dfd0f72fa153f3fd7b6c0ebf3f8fd521df7fc7e6f4fb151cbfa1dd0a5ec33a649781c5e13ff6c6b7563218b6207bb3abc2e6cc54ff15360756777ea1fa9a51fdbb53616f6cd9f8db8134b7029719d9fd9899bfb50478c576c28e4d52c13f54854de95542a13e0a147b2eb9b4ba51108551511fd8a078db288858d5fe0f3ac55114e1c39cfab0ca617ce45a9a49976e7ee3d9d8e0e834110fdc2d931ba1bd1136ac63f45f2f6eb4000af5feac7ae15a9a8f4768af5f84f6fa7d0bc7960b3b89220442f5dbd5c74e6ab3cf0efee928a00cd5fe21cd4792b841c9c7d910aea09c66fde70eafd9eae65d125b37d1f6767c162c331efef2877f9c5978eff01b147623d61e4e3fc5d170e01ff0233be914ecb6774ea6bdd3936d1a7d6566eed89dbd8d31c6c810eedef881bb5c77f7e9dec418e3945ca59d8a0d2ba4cc198faf3f1d12dd5d4ed1be2bf806634799d3858c7dc6b534123a776ed1ac87064c5be982df8303115e1726811a504c463a935a1002f76283a95b0446900bc03872c42653b7e88bd515db56b7e88ba32f8cb8246df59330f5349151b9a912b00586222fb2d4fe886262727777282380fecd06b561509b4ab1f1cb50a95c2d62644a0c4da098c0491058201144a9a88b24b597088a30a4f082892b513c21c30e1f1143f6415da64125406dab09a4d8522b3958abab0657e84093302ad5a0cb0df38827d691200944857e62123ed3072024545266400288269020910405d0114445492e58b29304105b8f8c52c6566d58dd222d9680405b8dba455a447182ed54b7480b2ca468f1050b3653dda22d8cd82c71d14eedbeb7a1e8def4c3ee8390bd8bb00bdd4dc3b57b03bdbbbb1787bb62dbff2877aa77f9059595d8f61bc2666666761bb900861ec4ccccccfe1b218cd03ba36b69beada30b29fd767f6f302f6f113d850ae3167777ffc3aabb94db098115764362ed34e4c36e8bcdff83d5b22c0b8808d57a6841082d68b97b07e1bb654dab931dce3e84b18948b1ed255309a17e43a25b56a988b56bd538bb651cd64b9b2a7f3999f12c20462b46696d8d3f392a2544619b03a1a9b08b37c485dbbbddb7bb1b61b75eddef5ed9f943d8452443257c08a2f9fc498d4054a8d84fee9a405015fba3df6c051f1054958fd444fd946e1baa899cc48c877693f3cf3898c7b8aed029c94db9550c139aafc2b48448220148b7427b4da73299ff5035fedb30acfb62baa1f6e2c698bfba8f5eb3859719cf6c2a9d1af21bde89cf42f1a3c470b07d2c6423866dfed74f6afc9a88a9ec8d189aa6699aa66951b01070e25f1b87b597bd89dbdacb607b198c46ad9a755bc6261ccc67fe52ecbed26f7bb307918b6984c887efdc10aefe90f3bffabb6dfa759c5208d3303030df913e080ef04a3bba37e24f20b6f95c359be654c8c0e6ccfe6851cb7a9b107030ac3dec4fdcd61e8665cf2dbfdf39ae5ab7b5672d9110ae19f75915eb240957c73ee7ffe8f91f733f73f7938391d761e433b394ad546a6eee17b81dbacee678f5694d482d3a7f508b5a94bef593fb41bf1f524b8775708d3f029d14ce5e96dd49098410420821a49fe781804343318f12b920a594324608a394524a29a5944be47c29e54b29a594524a29a59c52165d10429bbabb0c3b6c6536a77d7d1dc2860db9c398c86c4e8dbd91c0d6c011ba063e1441040630e0c68d0214a0c20004a0c2d8f9d81b50c7868d1f36712dcd175555fe05fbe64811becf49bbab2f72bd2a17fbb5a9920c2b96bb474333fff395af3687abfcf9de25a8534bdd0cf84295bf0b935409c204a1f2370d4d67d3e8081ef1a3ee3e2a61cfcad7bf9b990fdff3b1bc748d7ce96854f925acf39510aeb0cb46df7a6b6fda47f6932affe3aaecbe16929dc4fc8bd5037daaaf7c62106b4fbefcf6f11b5f798d7c146adb563e15e55547558714cb7828cbb7fef3950d7c69f9cac5d81c7ff93ec6a64a2fdf6d20351b03a8f4bf01c8d7b8b9be1ec5411fc646a59f6995be73957295be659550a4bae5cd653c1eb3121cf0d5f22eaa666740171952506dc2daa3ffed00000ad654b8445691192ab9adbd0580a932f366d084b58772b94e8551920936842d7e31c61f719d39c638e38cf19b4747c8ddf1ff07656ec66c6ff0c7e6667af4c78fdd0ff9fd5be7f7c79399f7467ff267bf64391b2362db9cae504619fb174e22ae3d994c9a767a4dd3344d7bd3a986a69d4c9aa6699a4933993493b671328f327135994c26ed61d5344dd334eda4994ca793763a994ca6d3c9643a99349366d238faa6983769da6f9bf6db763a6ddbe9b49d62b49366d234edaf0ceb8c4783980cf775ddfca351a77cb597e16ac4d838d530c998b6ca74f09cc97460facb74d234eda469264d93795865ba8f08571b35b816aa51c3a499344d339db493c9a4699aa6fdcc7834ed64ea18d3c7c89c64bab86acfff64ea7e689ff6a78c87f6a6bf34ce015c2fc634d3673c272e9ab8ed546bbff1c8b40d34fca15cb95242e9368ed8babf9fd7a709ee1f21e458e00a3b8ad9286263a32bf276c708b3ffc3b5216c59c07c24aaf13355fd2a7f737afe765ff6db03e663f691fbba667f4d8e055a83380ad5fae684f410ae73fe257f3df0208a530836f9032e91e4aa7cd74cebf1a59494d24e3efd205e69b75c35ae8178daf530ef01f61f0c4c13dbf530bfff03e682e1240eae86e9e6fcf9db9e942dcbb26e9b39ca87de2f6cdb5c6d0434758bbcacea51ddbab58c2114d6c802bb37588b0d2036b7c1a6d3a999ded1a9affef127fdc8f5b5d785d19ffff57713abd3f34b9903609e3ecc5ea73122b6fdef5907d7d2c2642514a92c702dfd3597360cc6f55fdc578d2bfd1086f9f992fb01f3f42f8b0ba2d5f9309462305ca40bb3b0c0b5d4d1f6c8586dee456424557f9abee11d9f52fd75b254ff115aa67e4ba43367d71fb91ff287f0673dfd617d7cff07e1c6e6ccf7bfa6351f725c3d33617e8c3f2d1ef3e34fda1e8dcc13aff5a6bc116686478d9dc3b00c0ada87bad588514c6affe7379ce435fdbc3a1a8871f477ac05b647bd8158072f8e7eda7da86d6f74bbb314b5dd7de3bd6122e727f606768a534042f7cb34b68f8988d8ca15aeb273366a8fe16355c20ef56d5fd7ab033a188971f85fddb7811aff6ba146af719e181941753e84cf447ee3cf48ac631747e9b5ee436d9e7544d54b8f3152ed546c1dbcaff1667722d0d6f80dfbf507aa5f1d27ed8d34b606924017c76d98af4815c216274d7ec90fc4eba155d8b111ff0579dd613e17fc61f5ee23c2df1a5b2758af9e3e863b39961ae3aa1af3f9518d79d65263624ecf5a62b88f57311c775b903dfd663ca70ee5452ced4555f5cfe288e9745222c8f431ef45552946e317ec93913ed53f1a88c570d10b1c633321b577e5f48e02c0665a6a79f5f4114bf680982e66e9e2151b23d87e0ce1ea5edab33182edc7e987708d791b46f817f7d29e1b81c98c841803658b89e950ed91b17dbf6a7687310f6b4cf711a9b14a7b4e3307ccca58da8be93e20bcaa31bfb517d3a1a66c318927d24cda9cd389e33abb30c1643a9de651a74cef0f73994e27d3e9d4059a7ba8b4acd844390d15a219012000a000c315000028100a06440291683c9083bc1f14000c759e4a5c46960ca38120476110c3301003300003200c6080420428a514464a4100cbc37fba7ca2ca6f84e4c63c99037932843c70fe9087c0ab3808e1272d3e65ebdc459305d20078086e6e041f44d09ff21b3df62c7a31038e2263cfd8050e855c828a66b62c926de820b512154467b33ebc2307ea59eb509032c5bd3789ed3b5c22067a5d21c4bb065cad1f16b29a487a0be1585a3671ac99b311a505935f1c8dd2a10224aaa8418399f6c532c264755368815062d2e780adbd8161336a5930063a03eeb4abd052ca52233be04319c44f20012e515f29ca11fa8a6c0fa1cf243e19c7b969ae206c7f213e6fd7d454012fb6c2035b39406fe536f7134fb50ef11a9da9cd7c2b86b2534771550c1afa40ba47afe28d59d45cb496eb033cdeb0282cbbd55da617d610e40d0d15525e9578194b422ea2c41ea7b2cf404b69a5a49c0eb204490e3ffeebd75808b3b1a7b56d7fa1477b9ef7289a78b9e20aa773f6b88709a861b257c1d0f5c11c9fb2f293eaab05506dc5a6e4d64f21e1051774b96666dea7742c0641957eba83e97f844c7495313964f2a86cae71e728bc59c60bb5f3d6105008c2b5d80dc3314a1c336ff036909e8d089af518bd20d31a60ac44931c51bc7ea920a1db90d772b6ac6fddfc5414f647a6c43778d0be5b7761cbb48679c061ec467767e2b3cad5aa4608768ca6cc60cc19328634daf09dad47daf93b94a4e268e3c9cc7f7579baa2cd91626cccdf872e924838c73060e33a1aa10d5cccc15abf6a03be0b3a93352a069641498f74ea1ca611c6fe2b318d03e99117b600114f07c53e9716ba310d3f2fa88c939b827b4fcbf05de9651c1e2c3b81a00e44fa6b90e19ef46fe85a45f2479abd378cd29b93725294d9e7b99ba46c5360a294bdb22876d74377ea0474383efdad0ee3e28fa0488ea41dca8ba8ed1667708da7db734cc265851b4c757a5287ca9a1ed10543f26aa9e4b53a5598091569d3d802977d56a80dee4b1626f427f1e8471effcf38be970cc9b2c13329251fb7b3c23df7045c195398c28c1b0e44ba6505ab6e2198fffbfcef931576947510610d34c86a904db670e05e22db6ff9a8dcb8f4634c33c131890c15035be6e3ce09212b7b5158e0a6ec212e440eeea6178cfc77297eb47006e1927efc47b0a4df64711fc8cfc35676a9d34cb95082108ff854452842859864c0c53a0d7fabb4ddaec011c1b0943aafd6a23398c825b6184d119607696255f05bc08fcfa9ef7cc1bc21e8ea5af8c6134bcde9ac6e76435765b6f9726bc0adfc28505c36b5387c6de134e704ad17c7bf99511505506a99af811c31a3aeb711a7ec362187c0690b688ff18ca7ea47a93a00bc267d86bb44e6d9a07d0d33bcfca321d7a48863b17825710d2dc774fe289cc5dd105d5632f1c9c4621b0a028e4ee134dd2f9f385f8a381203f10a29d9b6a41a1738ee37001846aef544bac0cdbe1b33ae2a50d641dfcd55c5c1ffe2016b88cb30c1aa76dec68a089b7e17909fcde5674b5fd21114805fcb49c26dcfa00e960e94f1be4dbfb4d03efaa43377f23a80e825356d85091416c012d5d38d4bf5a544e75504c07d376b9a983e13f21e585ab86650d24d01f1dd667cdfd6f94ab1a891914321dc86bf3f3feaae2214c868531597e254d3d3f31faac3f3372995c07cf1177edb53a029e5a79238fa7fafad2d42099563f529e535c232475adfac70abfe862d450989836d699670dd415e18761d38b92cfd5c25b6582928812d3a5fdc3c165481bc449db362782ecbc7ac9a2b14b6dfebc01772243eb1909ffb2b52ec92f47c0c9d7dcca239a4ea42d5841a52995c7612568e5e5f2c70b394c757026b566b2f180dccdf5ae9f44972d63e2ce71f0b46c352171e652b9569909ae4574be2e9be33111f47747df2ae0fdaa7a8cb8fa3763d429cf35eedafb7bf5aa167cbaa3e0e1214b225cff29951efd831f6ae62116dfb31b7315428500a0a201d250d5471010539278201f3b769276197efab18d2e6225c413199a5354a9403c92da594a31485da6e9cba170abdc22ba2c74541700a53dc0c63875d5f643eb5080fc1fda1963acaf731e839d79fae02577f7555e47d853b8d0230744ad955aa044b592b9d37e933516a4dc0fc7083022190e1180a630e80e26b237a7eba254da0fd34aa648185ba06a55058b4f060f8162bb48e1e38007b99e84bffac302726c3f95e1389d5d638be820500df6b8899dac675badf1a8f5e4c0f2a03f6e45230f63ae28816c53d20601731ec50639d8d9ac49a3e0b8dc3a689f11c4fafa636bb7a8319dfd16ddfd9c8247e5ec703373f39caf031275b6d82c5ac2a556e1d4e7c50766052eefa51fb303497c9265e26473bd7facbc2404874836c7a37d974cb26f0f612c7a2923e0250e2ac149f3c685f36809d7f64d0c30c54c23780068780fedb2e8a1bdec694f1f61931179489fa272a64bfd875d14a28b7064b0b676bf9c8ff26f9dd7157e20a6da50d14200436b30a2e8b6eeb44a3c35ddd06c7a7ce66f0eff2f26fb8fa4e4c54a008ff3faee4713a310958af7a7420d01fd532886862ea24d5bf17043a13d05a417586117dec5659f61b6655f610622a6a477ae0f1bc7fcffa990fb75c08a77deff51b4e51146f283e02ee19f3896e45a8c5274968bb50ba2d85ae78bd11c5c79d42aaa5556cffbe6182aed2ab2838001303e257dd4ed8ffb85948ff96ef6a75396fff0e9b924c4aa4b733f0bd70848ba5e8f789b6108d5744fe7d10cded4fe862ba24a53cacffe1fb501c593d948395c000480b8d8cb69a96076c56d328eab521c04ce07f0433a76884adc801cac13abbd78d673ab51e9382a272c56751daa3db0daa74a11244eb7544cfe75a28742300f73e8f9e9ed0de022991f91a450e32f7ae12a698ef1f1fabac44dcca59cbdf102541b66c9ff81ea760e00d0c2b80d2f98f60d8a35db714ef69eafdeee541841b6ab7bf834ab9008d631084c0d93f6a628ae8348d9dc5983d2bd53f6638d30b4fa7969030949da0c02abc6fac7aa0ab73ead45c2f055ec741840b0435a10ee299e3681b9e476d8bb08b7f85e16100ab7848218e29c0d0681ecb7d9802d531cb4e5cde241751153007f1bb6bb38ae1cd363ebfbc524dad1b8100dca74f1ae332f7f5f48807cb26d05c2609de9fc52c5b3bb6497a39865ced493fd2d75db6108d8fd427598cf85e1c7767f652bea04040bdb10aab687e10058d33cf3e3edd0a4bb28fb7f00c0b4b3b63881c0fe360513868de976d22ddd18ed9f48ff1ef995e3e023ad201d0e7e8b6bbff1a75b874f36c6cb5fe228ae37d0dcecb2ce181e0cd297734c09ae80f0b681cdf0f01c1fc91a6a34d2877e883390ba7f5cdcc966dac7bf13ce9e781e668ce40d03e4154029339720b1da130cb061db2535e0330d49d2467c11715337471a7a44c75b415e9b98407c1255037fba51958c8c7ade5fb5a71166360f5f74cbb5c5a4369349445812d724c90046d7dd9e5db089288301bb306588938a9685682b1d191c91a2128854841139dfe04bd42942d24324dd998fa8685f0956f5d4b5bc50c83b57555838c8331e3fad17c39778a41dd034afc366c8664871e8671abf23a7602dbc7ba2ae178399f41cbad6079e271f2cef60ad81d4913319b002190c744836628d3f4f6b8aa9439a31c9fc52b020003244f91b2b283a50608f7232f6aef498c26f094cf9ce503f2dfbd23d48fd43534e9b964e315e32f3e09730c680079bd5f0b07a1fb58556f7b0fb817f41236570df48498509e1eb5b371dbc58665427ae9b1c17fa0a266cada38df2f334d541b646d588e003e5797302a79428d9beed8b4cb331861f9c5937f01a1cfccd264993fbf5b8c4511827ef2570a389a7c0a713f5e7b4ff1d65a9e6ee9f7717a248fe9fad98251e4d78ea380998b3f60457dcb251771ac41b62cdb6d8179dcc603768541dd5c60679fce3e4ae58739ceee1d0d0ff82ddde747b57afdf2dccebbea9a16327be450a0d23b03909511d7b9ff8a7a152e588236aef6fbe989d1a0a37dcdc071e166a8fc505a604627ea94155bf2bf80bcf0f33c6ddf08ef73b1fc60e7f47ca2a00add07815b0dda8c11a90db3242cf8fac4b4e4191b087321a91bf98bb3cf1bfac299e3c7aa42841c2f5cc6697711b67e4022936e182846d127d09c808f47f879619f14c052fac4a207b05cff61d226e37e0b4b3fb46a4e7812476c03748e0a575929ffd6e807326efce450b097b7bc9370dd8adc4e31028bbdcc651647de8d80047cbc441a01a93a808e65a8d31028c2e9de4087b89335dc55aeb7f73249ee61eb400f77ef7e29b1f2692e61cdff7fb566268be88afe891fea828fbc487d31298dc069fd61c688cf8b3350b90ad009bd397435ae809d48cd607a340169a6386178073e75e353315b818e3f572f0408f3b462d2d9fa6794982d3fb374330868afe69180836f8171097589921cdf3271b3db48f96ae409ea7dc97fa2fe556f0d4ec47a8789faad2b1eb3aa8b79453f95c9aade23581e41a7ec75f3d5e5af041a11a8ef41370aac765e137a3b0ae61a4108a3d518afbb8038b76848edb09de6f4a80e37b772800703e4ff7fc623addf7d972d07f6f78167663695593922f5b8172694ad23486d59a8b207b792b1c7a5ad84bc2b7cd8f6a5a1afb40de5989de72b4b5fa39702830283823fde8dd5710d947398677f73035da2d91f5a98b2e4f17fc6c411a6abd2909e9e75f465b4c059a20b4396505f68452102adf554acd04b7501224ed0c2ff53de1c5834cd50b038118f4004fb8ba37da45c99b305aedeac586f18e6b101d3a8175f5b71999494e679696fd13189cb85520f5d05d859faa3557155165c014c032a4dd3a2dc0548ab0aff0cebb6b93f12de164167d932f3f0c20fed67c5a6f9324f45ba3ea0874dfc53f748c61993e4f0a429c6f6a4bc346120913d68d8ef899652bc0aaabea1a319d2d2a2753a893bd7f5d555594a3d8d979b279a3d0090bcbe507d9b1a413f1b3d6619d166ee3ae17f7f4dd5e5df62e6907d7540feaf3cae22b030e908e898bf4f3dfc39801503a49e89171c1d38c13519e55111abde6278f4d51c1410adf281bf6e2c121e7f31d0ca0bab1e6c9085dfb7c0a06b075a71aff227d06350ec7090bf8265f0bf119ce2d95bb1bd0e543a79abb22d2bb2ab9b01680d5930f5c62e81b5663fc55bdd73acece910683d732796c210873c9c14a9079c517cec5f808166df1b0d769e49ffa21426d8604b125591eed2af2c2ef79324dc0523e33c813af0ae1ff8dbc4f272dddd1d1f3fc9dfa13d17c4e2f855ba6ff8ca0ca7324ac6b4d800b856826d84a3b9bfb0e56da89a7d616a3a8f9317119c3c750d2280f0d2f0831771b26ad8458ed3b0b2c2b279bebcdc356f9e282f34fcd4a2955c41882e2592a7831b0ccbdcea9339883dcda760221fe6d228e2826535e2bd70f947fa32063eae507b8ee60cc11deecd0eed64ee140886ebd23ce0f2b6b38ee3fa64d766cbe9ced249ae5302c2a6020b7be0b79f87eaadb313341bfcb17451490fe7d04a76a00e964dd03a1d165eded0258bce082326466e92e9e82dd974a98f1b863977726affa0103146cf06b8c054e22ae31397ea87e1db669fdbbc0d5ca6c78eb83102dd4aa5b6e32bf68004207b881eece5ce562907e68d61df7f169658df84c85b77ccb3ed41c4f3616549e14d9f112d251762bdb89a2e9822b7e34cd3aa4b86d4a51b37a25cbb24b8f2d2e3531a17794f7aed290e7a56359fd3e7dc2134ed3087436070b32913291420d7809ae0aac1ad2c01d75ab75bd3ad681abcdb04227bda0364db164e2d940d86a560b05916fc166ff512ae0d11eb00c9ce341e2c1e59c3894acc71b24ddb6be813aab7be882910d96c0316ec66700bb21aa4dccc903edc988945e992c2b2618923792a90718023671448666831e46ed6d8304677ddc75459fdbba43d191416a9ce2870e2c2bf11ec58c9a87c8ba6063ed378beba80073591f0a7f24f48374f1e3d6b29208a451960b1344cd55cf521556ad73fdd63be1b264cc51491c028cfb48a3a002738a030e1c52dd14537262dceada0b9bc2c3a0bf4316597e722c1f5cbe79ed012c34449d02b026f7ab091b4c36df468b7bedd9ffd05563b55e47b51bd50583b8b495d9633fbe58cf297ce76a1b4a83f2ab27f318364c68b5569e2eb0309c48b3f6c30a7a6cbc9caf5dcb5e628cf0cfc32e1fa55c4c674181331e16796c3b1fb100a8697c49c81e1797d60c6d139a6bf0e8897ce261dc936f8ca2d1828f299aade4d7ed714600ad4a040a5ad744f36add73ee3735ac07f5e18d2a361cf4082b8153146798daec82ab487367ace6f4bd01bb0fd126b56615ddc5ba30ee68e66f191ad71e310cbb8dd03ae3878f9bd8c5a0dfcb9c542b9359024c3d714c9524b3674f0323794c0ffe255568731d6538a5758870b85343b8b165acec49913d6e70414ae7a5fc735d33541d9e1458c9c64e74128ddacc2b39dce349dec64bece0266e5f02fa841c753218b83197e347939a588d5bf2e28ccd63d6607f5b0c160b5ccc29f0b68e949ba82b1a6e2eae6420e7cdd0f01c77a305ce32a9d48341e667b5ba38177b89eb68020fe4b562a3fac28032a43bc08eb15a759d6598c308e6a8a024e90663a792324c25e9e07fe44c8e37ba495227c694f2f6be8980f197f75f926b3e031efccaf7979ada67e391abc91c8f9584adb9fcd7c65ff1105a5c32a66f831fc459ea5cc3bc312b08afc88f4e30ac171a5e935e01c558d5d7f7d62b2a46af0789074f095a3a3794623420828c519c39470324bb54d5d56a630a9e5c030e85c343cd79460808a9a6b45a3d9ad3343e8fdd77c95e58088b36250b391fb7e4215cabb1b8924cc35776d378aeb7f26ee98ce5676513e50fb1bb0054622fe61a80c05b0e2b95f69de2270e40f870d6e2fc131150458ad704a6f37ba0924d34e5058cbe9a80a1057929dd88800a3cc4936c00444d97f442f68a0357f941d8450b61ef8fb318593a302948d3c2769a32de54d9fec30d6ecb595b610473e541e819787da1a77cee793c2d721c7769881b8c3c450a29b6819d64ef201b990014fda0f52dc9dc58311902ce8b6b437f3acf40161f3344290198a73125b8c1228f9ebe8f2406165e10ba6440c7724fd86c519466dc789ba938e81a1139685361c5dcca8dba219b19868687bc10ef33a3ccab0568523d76ffb1b5de0aee0741f87baede2a07d0badadba92ab1289528c8f3dd3be1fb97beb6c58f7dcc506e79b9dce99595a26a2874b45f3017bd007671443098ed3006dc1921bb91e412f5a89e33ae88c530ee2bfbf134a73ca5b9a3ef01bd0bc2ba267d833e96716e1ee7384955e57ccaf55751d1e67d56fc6ac1d1d9eb40c61d5a9cb4f3c8228b783e3b1d3e688eecba4c97bc674f703867df35134aba15b102556aed087d13583c287280287c1075f41a5d5c837a9c30c4d1b8d035ec5446a4f1c462b35ac96ecd7a5e8aecc4747946d5142b4bac99b3a77fd1e0c5aaf54bb13cf4688d670ab11ea105e2c9f57b5510599ff816c21f9184eb062749bbcd64503083ad851de0a2752dc996dd50e38ae8a110e1917d9c5df7eaac6c8f604bc88a7645a72ce716d8edb5375afbb857b81007c928af67e90c193d77464112e1cf702b54f839d6275a8cbf70c6c6b9da761b4dd26b7b12b4866707f676c7ce41c19ee6613dbe89ae06262c4f7ec4460bc2895882a839b47c3863b3f46e501e8f46b5b465dc613522692ffb552263863a6db789a40f64c40bc5777c09e34fe04a184ed9edacc088dc123de2490a1a1496c77e8f7884f106cfd6660a65c21a7237059e4e757439948d864224a3821d89bcd00eb40d3cfad6c66b7a949f85f0afb6d9f2ef4a75741768f3a969e534ef60af242d97a6d0fe809c88733b10883181095881e7c6a248a0ab7b1c99e664b56ac31ad8788d4068ccd2b1c2b87d3d50b8aecf968b253811c2b5c6c4c0c601fa04e26f2c286921bfd0e8b3d21ad51c212458ed961f4c5feaa7f2baa31a96e4bd573360a440ee4d902ee7e83edeaff67d81b95ffd3fef1d3290e0a51651353222cc93f3e2da42b7cff8d35cee0f7bac3d7ccca015ccc50a7222b6dae3f12066f4fb28c76bcfe53fa3e9830c524679e6a346db1d30a58b4666a6f36c5fd8df792f42212e7632edcccea0e19a32d040295f2a43e244f404bf1d46bd3b7bd2bc7ec5c7500dad1eed408febb20950f9cffb048879ed7c1d9fde0a5cdfa172f8f1216788432b29e0a1fc2ae3ffb3f57e24eaf1a6baffc7e17e5824b6c3352ac949d03f2422cfbf99de109124807aee8f4390c760d107d802be880966c91d34284eb811de80d2ec087cf732cfaafe9c8c1cf32532368055f980e7ce83769e667407351f4a7910615cd030d9f42f77f1294c3a6729ad143b91b7f364ccb1db55081ed572132364450e04e263151f54122b212803d70cc41600934de21a8e23800e5f29919b50aee5641a6883d07182eb891428e3af5146f7b555b5789212e1ec061eb5b42addb1de1b57bb8438631f33db60d3f218d19880b37c1ab859599151f972dab7dbd1cfda754582b0ab6c71c470a7bc62625bb50d369046c842acc8bc84cb1c50e6e1fe45d1e445c7728674dae29ea8da686cf54cc0ec4ea717b8fcfff6716e951f9ee31f276adc312375b8a223230f0835715abea884bc8f8be9104ba0b9752c8724304e18f9fab0668e252c5b44fa933854e95e86b22bb3c52d4dbecf2f3775ab4e5c3c733debf9babba3cc85dc6f61aba44d01729dc9a40f2ae8689acda3f024ad6b97bd7691d61c724dc012e7234f17e23c3a07bd03ac690e1168de1d64634ebec018c332d5aa513df7f5b63110b7383e16044ef258d04ce8f4f7750c834126bd170d0d141b55fec5b9b2c176606d3f50f6b123aec6bc17b9c5e504584f28dfe41d8748d839a5c3279daa15843ebf52ce3c8f3f07a5888f4f06ffea6bf69aef83cc74b2dc152c2d869845301d44f1bfc46f7705cf161a52a97e03106ad503e49d945171669c5ee655f6a344fc9e2cb0c87473e59e5c22964ff718777d53b134e7a0d2a13c37e6a1f00dc3385f81ea9dd2c3cd16f24edb4e3c5647e7f3e2a3077bcf92d79b70078e9a404aa0ee583f632353819c8503789d1850ab51ce01ba76b4842497a5ce5ee4f56bec81f1ebd3cfe3db70719f205cafc32eb3a215fccda04c38fb65b7d81e8545782abb94b61d65ad96026ebec47371f3ecc0ec62905f9d28d80eaf587beb23682cd245d7bac432d39e3baf7975ced5b1ee689515bc066377331cc1030077f349331829ee9017b5af39e2ea9503409b15cccd8dcaab5c2b3f3216d3a40bf32cf1e304b42b693b06d6743954ba65e6afa8a35451b3f3c47bf50f839427d049f1d2d314985e796a8e539bb7ea12f5dd47c6d6db1f44d124b1856bbb72ee928d71cdddb163aceff2d1b9332bf6b8ed5a9de20574a5515a83ac839865260e5b5c578ec3cb8658c3076d9bdcdc424064c8b2aa807b8b6d4bcbb2d0813e79e1c562e9ba4d5344c525ae2ecb8de84676dd61e80e9f5c9675fee277d96e52a68592d3beab520b0cc426065b5ec19922dbc1c6a43870a091560c6b580354764e2335d4ba6775051d7d96521eada5615c48f91f485b59570ab8bcbc8d64a2f54ac1eff48d7bf2b2496bdc6a30e4b4e389633ab8928254efc38c9fc08d7e8971156eada43c1218b66fba80258566e0ac873a3f4fe0022ff85e9299ef8074456e6638aef45975b8b2b49d212c7654f2c5c3158a1d00cb514e42f93d984912c00f5c65243605e57220064fa785342c6cbe7a2eaee59b870dc2cc0fb0c019621f940e3d3844af5b06d14b531c27be062a36fa46d703734f951dd8b1905af21eb8a42442825d29e6e2356b621000f46e76984fce8dbd7853121061068f1f3b524faa3300fd358b8a874af0170af3d592eb6f65ab710e3c3a45d888edfb36e6ee4cd5a4c85275662678ba55b1874446787eee977e0a8ade4887bd73193c15e8a2527cc04554c92afa922cf45925463f82c17c232ffc50a9f61b4bd01d6c34694693b7408d9cd48a2d202b60827f541f9fffd88b9d742977a0ecaed91bfc690262fb895591769658c919d2c4cbb3799bb99d5f658a9aa13b4d8d85921355084e0d2c78ec554c85117ff73bdf471a7a040d5e92362214005e4445df805901020a45f2806b15e9621de1a09af57cda51d83537a9a9988a2fe923e3e9d0c8e6fe402025a0158cdb67118e2b2ac921c862c33d83f4d7d6c3a64541fd6ffaffa5ae4d4eeee7ea1201c42ed552b51aa7fe7ddf42c8ee9cbac4fce0c449f0a330c5230501006c4ad4a209fea5b569637af0f5c522e094c546dbc436d104457c640beaf63e03f8d0dcb81a60d2a9c367103b8a5a9925ca67b1f98738aa69663c0457f1548c598f20e1c689385737c2c6179b2f8db7896c34ae5283817eb09e2b541fba55b1e6f291718c93188c50c90ac9279b9f0dd2ca6b47de5c4c29cb2f9f12bff598eb604ca45056e2a6b2e17b7cdf7a9a5f3d5c37a83d61b8d1cf5f27a0c65d3481c74507110926778e087041d1b93f294ede901658bf1c29abe11f73491299b50346bb667178e1d3affbdaa5a278f8f02b1d3f06c982a0bb007e92b865b6c68aa27ddb9b3703f13e1e8d0f718b345cb70a084365c4019df4f81ab04ed9a483ad411c4945131da08bb25e33a2a495d915bda9c8c059a28404c25cf0fa5c41ce43f62da4c22a36285c4f7d48592f7506de7387890d678c4c2dd81472ba967b39a3e564ecfd245b08d759ca23f83054e4377bdb60fc332c014ee1470a5b74514361d34e44aa6137d9e800f2d721ee060d6a45cd96fddc4456a727e4e8e1f95b6c761040fdbe3e5e306ffb4aafa68845105381a412f1784875781b9b9919f03fb7ab4d24133bac64f8f562cc28166f97ea3a998126f4a31c0da36feaa00d9df8c730c9b1015dd0835a318dcb33e5e4216c9925c19c68117c1ba46fecf7ab1b426b465318653c0ba4a17ea692281f190d40d376c3bc9fd6b03710d99961e7f81bba53e031c7ca06189e51ef22283424919a84b3e45b3e2333e96b4cea06d2e6e1b0fc932a45be200860275bf9ceceb4e96f56f57eccf99dd56875237a210c449846300d583d99f7cc446485be9c3c50490d9d832525849e80b53c9deb0c0a74c7774bfb06486d8f1f9628ae707c2e10e6d7324dfd2392c718d2e5a24354e481152c14ebb5e560d0fa4ca3e10c6811e9f9f48dc2de70effbfc934b56afabab80909be525a52760326231faa48da80fbcd02729a7147d14d59eb2a14b24f52e34af27d81e60b164f88eb091f3f05bb584e0a8a8e654b7c2c78ab1af9a7c6ea225fec2a63283405a488eeac5863983c70f90624b836eba9fe59b109440a293602a5d51148378e4fc4b0a580002b8b16ddad8f1109e8f6242b696023beb28e6647ea32c1c65d23875ee0518a7ad3bfa0b2d14a29897f45c6557f0fd53d8047a4c87935a94c5521b4336208ba10b8df17955cc3070d614f25f6ced2587040203818eb245246f16908f098c1580abd5e0b31408f3bfc5f0c626ea589f414891a0d33273816f19a5834604011c06fd27a90e0a74beb362a182ca3bd38065e2b50100e400e191d88b4539e7c6f9ddb9d9db55c5466a4bacc3028354c34a1ba40b8d1fddd53b100e84e0b0a3286d8b95018961dbf3497c7a773050a929f93f8dbd03c0a48dc3cb3ebcbae33f61acf66b3532518080e6c254f417cb2f1eaeb81ef483417301ed0d3df47df3fc00823c0f40af973a414f5eaa16f7902c08f9e29a08b42d399114ce0f7cc5806a6b744f395d77c80a884977de7f23e514eda0e971c1ff54e9f9ae80f660135e2f5b93bd1f9b68d6a1979d97ec9f39fae5916e0ae163345031b5824ced552b22ab2cbe2969a22a51c224d0d5e74a8e2bbdd0b30d62782d249270acae5db66e250cae0758f72ee6e4a656aac3c8e7e95236e6f21cd1e2a632c6e750c6b5b90cb5a61e4002668875810e64009dcaacd543cbc85bad554ecc3fb6e3ad65fe1ff664fdd30ab0aec0863b5fd98785423d830edc19406d099090645f02682ec88491e843c189c571f1bcde9f9bf05f0fc67284f14c1aced138033726f490605e6dd88bf4ba47fa51dac0b7152d7c401df8b6588837810ff0058ef79508fe6d363eca568aa1f672b1832ac9239c8b44c42d738af11409852e2752f7e8966b91a9fc840b19df8e90f1ad3023f46de47b8c85ca2f7a676720d543b6882216c2a7e31402f26aa3c3b813cf5183dc9d522e32c704bbcd45199dc24f81a2420263d79ca32987d3f9c98515ff205f4ee48e6eadf09bb11750f7695acac45d8b5e839b2ae193f3e69186d6fb8fa4fa28693c6a7e4578684872ec21711193a27cac3201853dc193323b59e8e688eb7b47d5938bdaac0e653dc6cd2d0becf54031d003be1448ce113a2a017d5734f224d07e6862be509c16e524fe3f7043c5caedd8a41a5460de4ef760813d2c31621fcb76968bce28915adfc676de69a1c1cbaf6a701744353dfd63415bb7c0ecb7262f38be848f80259d12c5754f36d8217f275eaa60afa733871b4ecdc2b4c2d51f6974961b027c477a5aa04a902f94e0b013a9fa314ba67859014c1738d0ee8caa719bc94b13469624b17b43dc2da6c9e9e644b053efd8c210aeb6a4f2f85687db37cca096743070d229e015ff94557fba2db8716556f970ea3d6d8311385d255e2abf2fe18fc067ee2ea213c48bfcbe83b452b7ca257a6e8ceea4d9e5531d2d7300653047eb2197c1418268f79fd33b6cc1bf9bdd37c47b810cc5bdf952ae8a95e7cd517a337b2d0c20b1455d27f505761907bfd6d74d4c57730616eac030c5747b52ef8f7319b86d2b262ae1c1f48310f30093cfc3b5681af616fec93493948005d8ac483931bd61a459f4a05b6f6574a10a490c9968890621a0c36bed6b0be129ffde375c0b7f28b06ab6f73041048b924d965542040607dbe60814db60718bb3b531d3d5079ca68f3f4254ad890f05e30677b702d8962787da2031827f6b80c84433f7c305c30c51439129c2d8777d52e41ca8703ca567e348b7bb3507e43cd96a2c686820e457ab2ba9a6ebec88a4bc3661b5322549764334bfbb91cdf1b200105d1d394063fea6f967a215dd65289cdc8a683dcec9e1e112295c4105c7b94c66eb1c8fcefd49e581b08a2768d94b789920761a3034fd7c831e6c928b72a535410e922679d7f9870103a10475c082c688492a2351c93dcdd7237fba930ce55737b9048aa9bb9a8384cab83359e1e77f77ca8423ea248ca89d687fc88646c1870274b5bd2b1f9ba8265280e04c36a92643a2b7da9584a5918a6149d4b677051b2df4152e8a22cbe7228aa65bed62d359a730ba57d4d04c76370e09c03db78ee07e60b1901ba2b2c30e7f0ebe2ec9bc3f10fbd54f97e0c06909e0aec379cc4314a0ef70fd571d7cb554b55663a24a4c16ea98b55adb95d17f6bf802858f050c94fcc3d88030e9b3a70e11ee6c6076d242ebd4056fc9c15346e22e55fe41f97f4642f517a6402509f802e76ae1f7b8a9c80bdbc451da42c5e008b4fd013bcbf9302225908e0c34790de81379ae0e6b1e61f3fd68a829ed24b8493e8ef09d400f5414cf47d831d529536c7bf7528effded70c2b9a919225104d110cea09e184d20c2c28dfbab816989a53461a6a6473fde4d20abfe93ca7c3f212d4b3dca3fdb11676254d53e218c1cbe08c10e07d9af5f63fde2ee0ef7cba05e6389a4251be895e2bdc99371e20f1cb8d4bb382352cfe615dd2b477e041d52b416ef1492230e8e5d3ccefa45db1fea9f7d7e80a8c5dd2e73f7b87931850cc73e39e6fc4b0f15ba66026ef397dbca5346c87fb0c8412ff8631229d6022e7aded37e38a73d23b5dea417dca08bd7c7f660bcd88c66f72b045a476d1169288bc81ecea31e9394b2ba4d87353bb9b264d93689981091839e5fc4262e6e6f783f59a1c7925aa35ea0e157fa8c00086ce9a89e2adc749c01236449a5dc643892f8f3b495df89b094990ac45c84c83dc519ccdc9cd7e61a70b811bb91e622eff6a944d841998998f7fa5f8f99d9fe5607346d8caa4a9ddba3b38458636e1f0bb1f4f1fe7d6cbc0f8df57765bb03a34a07b82f1a75193d15b9b87787fc65a8fea0db185268674532735d47d7f8a57485b8b962219295757f907a22738b588d599aed117c980ad1cd8403ad422746b3c8e6fcfabec8a73bd590b9b37de0b465d5b427f4bb993050109520e158adbc292ca7a9c24b42314ac5d689bcefd3be7ab4f613d38c11a847fe152805316d8ac8c9c362ab972d0b22218bcbbcc106b37f1af8dd370b72017fac4718fa00f4eea5cea67e27db247028f79553e886a1874694e87161750660048ff0c2abb5183a09cc20313b4b678479b8a79d9d0682e81f8094b7bd22b4c84ba4fa1144a5ac2e95e02967c140ad6be9a344dc16e3adda52a5f95c0a2253655c02705a1e10f666ead9d3d4949e2b13764808e4d0431a0b8a7a81221a8a85350869c23991ebe7d517bc6b23d777789e1b20d733aa79cdd2ab0a901c0053bd2c7c4b771568ee8bd7e235e9944ce3bb2cd7ba18d5cf39800886828e41158e824475f9a6d050106329081eea615c97ff9c5f0bd7cf748a8072bef8e3781ba2ca3bc34e1f56ec0b4405bfcfdbb84f8db44c6abda9d3e98ae19eaf02114330d9d8873298e2af115a73ab3874fab2065d44242afbbee65a0cafab1d2249b7c8f21191ea6c9e7a0a0254e703e4822d848a8197ad58e242c450c4c92694a59fb16615b5d06b5182ce679206b295554dac6851a6edfb98df895cd779c21a87f4e6088d3c984af46f0f846dd6b0f3b3249599b5c1b3f56fd31cec3f31d8893fb62c6fc3bdb6a914e4917f4cf925c67290fd4e74f747450f4c73fc1154db0d758a11728b8bae35c1a760ef6fdc030190247fbdc5087048ad7b17fa17059214175e821955b2a7698c1162f7cb421057c1aaef636689d9ab45c48a8e9dc430138473365da929104ad42487ff0171b86b7f37fa072c623fdc376167ae6e80896132e4072d995e895ca155ac36e4f19011fdbcaa685e4510f721f7884643e71a7b072dede0005b1b953219d49e5c85c2dbecf6e5295768ef5690b6cc95edcf83db81a08d0ac4b7c7b40359e7cae426b8f5c84d640975821ff44729100007db1289d66f9bcc022435f75650c1024694fee664d66fa2949d32edc3cc8c981ed3277824820b7246d4837c2c8e08244fef2d707d31ece4d69b05f8ce60568069ed67e1668a11b09b2f15549418be3450eadac83405190af4a5d150503cadf9cfed4db1496dcf129c36c1c4eca87fb9a7d76a82d45fcd8f8bbe3e0feaa1483f1c9300677f9d81e6a915833840c1fdb6c6f110540d7fae437729c1dbd0eb544c190d864623381c03c5865505d2febcbeef54f7634df0e7ea9205434d72f4968690466ca3e5a292032b2c7af4f5f6ff2817562c53e428837b0848d6c06bd228648e1d9a42e420561f4762ffd2026695c87e4e62b6be77989624c262907cd6afd9a6091f809afaa4c630833c38627b97fa9a67d79cce0114ac053a6ee67aa10559cf63e7c7d281e2ffdcfb3f650a358bf5a614c4d80609255b08e23083a1ef4e1fa44288692213ba33ce2d5de0669b6dc32382b1431ad4973dfde8d0892648fcacd4e4aed08e85e79981007dd84f2b443eff4a29ccd633a5c342d016d901996c9f3485a05c08bd3bcc7f7f4458b9a00fb1515725423d21ccb0530eb5138cbfa95e08c25c81887517089e9cd7be5200dcc5a781c1d8481cd519c1e60a32e1fd78f3c2ea629c19ad08581d680c4c249eb7f4af23f9c94f42f2bfd990f1d76b98b19c7c6c0c6fc34266091c9960fe0831ec6daf6c229547d15561b23b262ceaf613d9b415fadde6feb07336e677a0d74e720250630146fe63f7ecaaefe01728ce941ccd0440f814f0d1d7ee8d4cfe5f00640093005001254038a099aac545270009ffc8b948be584736008ba09b7ef7641e80522d02c9786be47f0e9b86b5881f3e512535378222e024f4d9b227102c41433ce8ed8093341f5a4cd4d5ee982781adda9259a6c440cbd0d536c311d161dcf39881c8e433b4683ecd552630edf7110189de66abd17cc6e0bc5a2c4d6c6752fb8108b3ca629cf3af0e251dc413fff5d130a4c5a97b6f4403286d63ac4b16b0711019e22cde54ffef068b7d8268549ea89ddf4abd4f1581a7d2c8f9d007bc3fed7d03a00a2d4e5819ca1b5408a3f8245dc8d532ce5794ce40bad84462658fa3e60a041c0643899c1a9a8e5565b88c8f5e788307682e0f763846f8fb4563f6980f3026e5bdbd28543fe3b6dcfc34ce002d410c5f3eb02956bc0e06e4e7ee144fb1e7260b6836257a32a1a78d4002153567208aef59ed3c8ca172e809e447e22a510aab8a5bde5d2101c03c27952a2530e8b18addee1e3e99130a38d4bc8662f02a0001e1ac70fdc5fae32696b14b27d8830c9a70ca3bde17eaf50465a3208a3ba1c80852eaef1a275a7e31c393223511dab3b18f7542613e320d23658ad2f251c4c04543d513fc947606289993424176598c13f64b4a52e56960f278f0fe82b7bd50ed1d419a374316f03cbe3a18d069e5ae9102f7e23ad7d3d1fd2d5750f5ef8f9638e82d28a3924a33f4a163e1498a1e28889ddfd0e88238990657181459d3d0213a76c0501bfcd03064285f0681e3b4939a60a8adf17112a7b24368d00cbe245a1bb8153e98b42a4c9e95c304e7b7c6d5ea1d2636c36584cc21334b2074cc58df317d0e245d3eefc49104056493f4af0ec2cf462dd080a2b934c1619246703125161f94b0f9b3070c45df6ea6af7bc33a3481016c434cb6acc7f32402a10bd6d914a67496ae3a29ec960dbf193efa4e892c93cf284d408d2f9e48c8d52561c9bca27d86e6c1aea2d632da34010852e508f18a2bf639e01054255f3f492aa2322339566abe1fb7378447047a243d002958c7dca4d400dbc4542af2244d9a6dc60dafd34659bf441a93e8fe3ad152106854b41fd4ea1af84f02bdc2be68d6c8f48cb4a688a6ae4ecf57f85629b1479be84d176197a3f91896d89b5d51492af581694da3bd4a5edf5e1b760b8cbf9103cabbaec38060efec29d9b6b71854ab10b02db2088b05ffc37e60bafcd3d5a3aeba272fc83f49cfbdd3d5d2b2e2fb7556864f3c54ab4c6b01ad6fc630dc375cb04061c44d1d38cac3558235a5fdc575cc87aedc7ff38276a71f2f9dabe21adb0f33e6117ecb8dba4339c25a29118d1aacb9c36afef15df53678fcca8a6d8f2d2cfd039c4faa727830a0690b121dece67905a7e67380ecf1aedbe914cce388760033780f40ee880a143b1830a0e2593ed4b439f48003a5dfef9ddd2f02dc1f1bc79233fc71e5a9ceaf89ca1bc58127ea1b2a835f4dd9f30d76eb075cb0b54490f7e964cebb77920a9372694a7f7187def5e7d10fe60d83f2b1b69912a0287baeb53b621932da68fa4b70b08b5b0ddf828af861bbb84141c14ed8d37297241ad5ff52d2d2d1ee7700c5fc4b65865fea76bb0b95c972443101e3410e1044c5eb0f8a9ec2adfc0ac98a631e166e7a954f277ec0a9b133cd82c4c13a3030fefe0d1fc31119d781fb64a70026c921c411097fcb1bf94a571bd784e3996c7f0d95ae76ce78d56965f2eea89721e281564b335d88ce3cdb1ba786a3b6e647f1866937c3e68d5dcbf706362ea83aaf951a6c5ab2ec7611ac637577d7a09ca40a4c29db00a170b1aa511d49ce922af2c54b21ab5a5e4059638533f1ceaa4093e11e4438d537a771fdbcb52de6b4202be0de7b2c86a03e64908209f4dfb7ca1062c27d473134310f801b265604be0db876e4de65a3733cd5ea2d80b60f6cdb604d0383cacabd5d0a9a70b98c9c98428f3e809fd83816557b5670862f0785ae1d4d88803782e102619dc82aed453a81facbee289e0b62115c526903505621da3f0fdfae4581d7ac689667bab2c22028e36035b8398b2a66728e8592aee291766e1511044a864f019f01573be8188b3a9f4b7576cbd67f3e10e7cc251d041bf4eb66349a520c3a1309e5c5e7c90efda7083a8c684333b39bc5f6b669ca84914dfc146093af77c89ed8d9bd52f0ac527041f411fcb9ea29eaee1955d477ceb16c541081c468095d5db9cb4609f301a26a4477a35d8672a2eb865406c3a89500843d3af1d469fac0b918ed5fae6c94e043d0e74651f5ea0818b34e7aeb175037cfd10fe96cee937cf40a6830ab1ec947cb3ffead05f67bedbd2b0018e40693f87741b87a6bee3c73374aa732431bfcc3f12b8f48b6c40d84ea0472577c5154f74ffc3890065cc0c44cb66deb10de7bc8728f91a1c3fd77ae968127a19b007169003ccd599e3009deadf143ccd6a3de6fb2062811333c61da5437e914c5d36deb998225f348b53d5efd11d2fe2a374fceb23d7196d4a6c70bdba41954f1876b1be8c4cfd5bb3e7f05acfa1b32f3936e5a577d68c2ebfef8b1ec8dcf7bfcfa65d43d0a4646b442b3dc7ca76fd14428e599f8c838cc6abdc706b63baf4c4301489c3ab09627aeedb78f7852556838f3fc52e49742573e944974bc1bd044029dde8d23acb0c1f4e0b963821725efb501b59353eaf850f70ab3745b2296b87d03341f278f029fbe3cbc8f3d91a5fff2f4f96efdcf3c29e51bb7278bc0f6f78b9b27362ad421336ee88cd5f2e8221c2d2420c7fc2c50a64fc7abc77068b3ed81eb5ce64313e2656cc097163692107717bea07e2b1d2b41a7a191e2c3b360a0ce304f9a4e179bcbf892eed986caef5c14ab8fc85a2d2626c6314c578b21d74793f963aaf3bbc75792e05bb783b2e44ff1ceccaef8e75d1876ace4530aa79fb2ead3af6ec7f1fdb92cbc05f3311898eb6cd65c20725b016466f9b5b128e9daea251399273dcaa346ffe87140db7dad381b32c8d2cc1105d8b8adb8ca78c4798935a75efcd67ac6cfcb347b956998503a5a711e06f721264be62f5e03aea91838a933b2567e409d4bbc7d2dd1de4ffa982a6acefc70dd76c189571070cf76fab5d4628269fd51f389b4249d64c8c74a633e80a3be44620e348d569a733003f288760307e5b0f199d7adf3a11e82ebe4b0311c14c5d504522c7f5b69420d8958d6d738010aec6c2ab3a2d261075255e13395993156308c941ab184468d6ccb2d89d5403e59451d5050d4b382cc8480da0d3dd8080a20509082142325263685e806bc8f4cdef71f7f7eec3c11bb940a314ecd16c810a15ec28d666d4cbc1e05398224ebd40a94ddc82b50e305054d4c5921b1b546cd0c5b46fb913970fb4fb730f05b717e01407e3d57877d8af4a3d7ad6a591a4f503000c23652c559a314a24b619cb32a75ac7c06c2e9a8ee250e07974899e27d9679621066cf77e0f834a8194f888ce16627a3ff5c3dc2adec24a3027bf6b30995797e6e8aa02d2465376b3a51b00f6b936943f8549caba77412375381f60fe50b48ec1b5f025e8b184eb01a945f5c835c1064fc812fc865b47f956fe684468a97c1f942037f03a5a7de74318d48c4aa640c4e5290e377d0f3df719b142398b43bc3b49501776f2c9435c955c9e49a38e2ee216f0726f5a8790e2e3b44b573e1fbb3f413c0b00b0f6f24f30f4bf04da1252c20f8bc2e2c11871508d7cee96842ffd933e1efbd5d21959691591134345144c23d99a76570d1a0569021693d4a4e9eb8bebf72920bd7129913b68b399d3170ed96fe7e0fc66e4a9f0a3a0c1c37f1415d9b492cc080e89794cfdae5d5e1e2fa0828e0e03062fa2c4396cc0d3aa80f33e6427d91299f38c44718e264480ce7e5e517d7283de3d2be6adbb31985595cd34088a62a79675b66874530620e4c65b45c2fb4cd0119b2f627baa0924b09073a1e4280079bdf3eef06690a0ae6ed7e3a2bf4e8dc4ade24ab82ad89be1e66d470ad60d0757133d54d30872e0d1beaab797efff8185f318ef08db6aa3ac09e16a7da7286550bdef631a5e05467c48d1440647a829370c4eceffa074ebbe215ef709ec9a71c4e83947a7038264aeaeb3149a48c736f699d9664e0123261c6b660b57fc16fe46b5e92f5c1f0fa5a45f75ad7d2e6e0ddd82bca53a1241038712130c04fd90496345324f5a317170c427aac046fba57c3add2f0c455f79820db709734f31ef7520a9652e01b62db251d6a1a1b4c568452d182cedfc56015c5150149904593954373456fa91c42689a559f2604eeebdd775fa88d8af296a435db397fab44195268fbcae9b706e1ed6347a1e82cb3982b6c5fa9e42abc745f767ccb23044bf3268cb8937f6d52b1345dd554a568808a1a533ffe3ebd4568b750efe2c747d2d9062334daa1cf93ae2a90be5aa9a589608b20b930935f0f9bc0f7b7efa0b63e7521aaf63a4e7affd0057b3e7db0fd0bb5570327c931e4ac7fe18e24776ca1599613c4b8ffcb67a7141f508a4cd4ddaccddc8b79bfb338e4b14842c7e565d7898c6ee3c705fd911ec2ca254548b6442ec46959fe649e4e7a826b20e2f68c82462dfc1403b21a1717a5c170800c003a8bbb2b31301d25e86d6240ca1d80491685025b71b4d1848f47caa83ab0e288d31adcf836c522c436fbd39e9c3b1c007b6d0950234ee5b75ec3e513824925c7115a0cad607e569b30c1f3b5e7bd8e818b9ccefa105d82af18571405e8279e07b9e2e6268ab02d2d6bfa633b1f9d008002c208206b9c0fd4bbc4b979e8e7dccfe8da9018e90f7e7996737e8df2bbf84de034dab3c4da88cbf5e3a5daf888f419d022ffc48ac53de0b88b0d5e12df0896c3b138502607d7c15ebc8d5edd673c7bd494ecc63270fd08bf73bac988978d367985d574984c455d8c7ae709d8c1c4334edd890754976b009c0111379665e600fedf7d04fb3cb53ad4befb99f16343a9393f76473e3e9a482ceeb396794f8fa9632ebec6b19e8a1ff2b23862272ee14c8001c44cfaef5be0e663dacda75074853ee8b1206909100d8599a67363f9538806d70f2d8c40ff2124e51a8d540f97b6a3fbed45d775fabbc3a65e352d1349d12e3418858ac2ea1ff1023cee56d7c0d054d702fb3e165b22c2aafc410127736b429eae68f32085ab58ec3ab7ee0d0c8072a15e0178f0708b05455458f0ce450addeab60cfb262134d60abcfa86adf06df120283f72041d9c6e8cb2b2df1cad1c327e7ad1cb6592fc628528a00598de058ded34e9c01706d65a5826c8fdb9b8a0ad020260fa6c549a50cd3a5cd0cf2d761383db82cade6d4aa30c170dad4694ae18196847230827164da38880eeb21ee124a200c803f2ba9b9658d9c1c65bb02ee0769ba8c46a6cf93fcebb93223fdf326d4b643a29aac45c5349326285dfdf55475c2396a6ac5a60437a45bef9497ce3e94d391824ec50cbb10f75069278002802e679088492f3fe3986e112a760c197a156be025ffa9909797091960174cb575879480f42a95e45a6f4e01c775585bc6829db597cecc9e6a44dc387bdacae6bc1a93f4e2f9e0787eedb05ef173ecb05afe972446c84b1810320a076935a3b5455f963cf83188bbdbc01e82866dcdf341f734f06dd22bfa85f8535ae4eee5680d4735a35f50f00f09c0eedddae4cba43a77c4223d0c97a92b71737d93d1d7d310da354f6ca8c54d443aa7110c8d893d3300386c34e391041eb3cc601621951b9f7c0be2c15547d9f143cd7e0eb72d18b21fe41806ba2878936436c8adc724ad855022334d348031a749c758bd07a1a189fb51ab34002f0e9a7833af2e9eeec13f67ae59de7d3ef9a6b4820811279ff183e6654fe95f674b6f28ec95f86794868f512d45980e1c767560ed76902de86d647c8c982325f0e9b9cc648a7a38a8fb96126de1a862c33fbe78675c541188a5fbe7f0c939e5a3190244c908cf756ae9b18e7d0cd949bc2fd910d739f073a1222cb2516b3151d047ffad38cdb8a2e0d1aab5b277db2840bc2c93b32fd1dc8764d035276e2f2fa345cf6b5d2b6791335259a285472c486258b4a29c2a86bbf0375dacfe62aee06648c7399a053565de8a9f4f472f7d119cb425b8e3df9955d7b4fd41fb2eacc499ae161383595a5c0a2b536f2ba33819f47df59c04e68139e01e5e35a62595af10fdea3c520515bd28d72c626c03718d6c491d3ee63edaa5b2db64b8c91f99b25d94101b5a8ce077e9c5eea25bf55d0a3c92056980df2c94da3765ec8a0b93ae93dcc94a0b1996ad87ed0b4d2891d7a616cff4a65c0232a475fd8aff88618b941c5a21c379d06c567145aaee68e64444cf1c2d476bfa829281c777be02a3d69518930ff2b32637f3e78fa58c2b715e712043e3db3480e5f3fd2f535c430e151d8939e5c4b4cf00603e3c86e24c60487d209c2e49c5911f75cc370d9ff98c7f8f407497f05f3371edf567d847603b8021cee03ba55bbab5620562a5207a9c758778fde96d3281d9707870e7e4f64ed67cf90fb456f5c72effeba7157c06028cde519968e9ff1d8211faca8c81e2cddef4a82e8dca5dc0f8192f1046d099ef8073fc08f104bf6de4de4de52a62465780af10af40a5f5972a725c595afd2ca9dd1cfb72dabecb5e012be9edade03bfd111971b1d71b72c5d2df804e429ee4b413a9c669ee27e04c51d4fad96132a64943c3b33f29cdf5991b91f534af28f299f3cc71c66803fe608caf3739991670c4c849979eae5856c92672cc6893cbf462677c05c33cbf3c71a28799e82f2fc594c6cf2c4c8f28c61e519d352f931c695678b923cbf93c99d2ecf6f59c91d963c7f6cf1c9f34484ccbd144f3399e2e69f8420459ada898cccd9d43cb067c2b0ca3033174fb353ac5534b593175245e3c6169e662e965e34b55695624de3865495bc90288e25845962536bd57cee4f509efb154c13e429aef4729146c853b156d1144196bc28bd724d02668461663440495c9a9adc2965ee6b565f33933b5ee6be068acd4beebc64ee534072e73ef7aaa584f2890a26ad541132f7632a2873636de5134dadd54a4e54d4e7ea8f35abccd557b93594b92ff3c4a13e69844552ee87898cbe88cd9fc895395a268530408de260a0c81cee3f4ca4c8cd30449039dcc38c2163e0dec19e19c2cc6060949c665cd76a15890aa922b540a2b8eface8d6c8e3e7cadc7b1efe1ec4de93fcb927b9fb1c1d713b5054bbd9852ff2f7beb24432b9e384547dae8e2577bee75e4ad5d7829aa4b2463f62597247f463098ccc5556e6de13e1ae1e915f0b6492dccff591dc3fd2d4c612181daa8dccfd48aa652e071032f7234d2d732fc2396632e75402e3349339dcb717a24c56b86f64d113993033b9339ff3428a7d2573fa45a2cc7136c4519339dcf3e08ea759e67e849965eec7d36c86ae697e3a59260de5ed25cd0766cf3f0e8fb26c15f73d872f75da934aca8d6ca3b627656f7e6017786c76e27b838bedbffd0f2ed2df1e0810c9bd41eeace4ed13a0838b3a502326dc9147de78d8b0bde4feeac8dcebb8e8cf3d0f1787e40e8ecc75b2cc616efb4d05086d16ded0a86d9433d29037019525b7baf37d879f96cf531dd15b0bcb637db9582413d5e8c1b72816a9028044f5175617aa95e4f9fd006092e7aba5a7405cbdb0fac81c4b7f13fd047f5011f6b7b83efd59c47390c903307a30a9cbf69a4ee1b5ccb94959b78abf46d1129dd985ca1f6d785dd77dae4eef9128b4ad7bef0cab944cb9210e8bd228caa351365827dcc9639c630d7d348a3e0f1e3c5c9c3cf4e97b3307923ecc0d6efd910716dd77210f1e2633ae0d1b0472b394394468ae4e6e7f0dbd158d6c881fdb14cdb2ffe546dbb3474378ae22a0c9456872e5b0cc9e6b0444b1e4b8bbba46a8c068e7eabfab6b44cef68d43a8e9d6347505f6740966a2c91c98194c4c7e071393e10848e6b8fc49e5d3c468742055a417490612e53fd27c917108c91dee676272c7be8ae82da64f7ab513241934a160b813221ca42db2cfe860351393390e138365e7421c4232c7df64850bcbce85b2ecacdab9b2f7a8ce4c67ae14e68b46398c0c26d628bb82188d4cc405cf23b1b2fc29cbd26619cbde4fe92c42829921a8d34cfe995a6725cd344a52fa3ee79c73ce70a4df3ec46133a746cde4693dd5a33aa90b3c6ffe4044297f435079ceef5e97f33bcf70744056436e488edc0dc976644372b723950677fcecb7ad6e9dc1bdf88be2fa7b28027b821862aa52ac70e1d1196b5dfc3a35bf51d21480ecd3fd6776af6bcdc9f2b727eef8651d5f8b762cc190e5572777fcb26d558a7ad729370fe92b0056f01a48f7007177b928905a4120dbc6626d20102efb7ba42d8b4b61345a96ce7256cb5a363494c59d2f83585b37ce67fe310ac91ec264ce0e58be5ea5e97c535cd17bd2e56c3aea66a9bd249bd249bda6737650ca9850aa8f1e3ba06cbf8cbc7ddd416994ddb6b9d5914c902dd3ef4cc3d101b99b35cafac592b3a2d6a5df5866beca6f7fb1cc0cb1786f5bc1a7a013cd538d25cfc592c7abad5befdbbf71b9a8f2f66f5e2ed6b77f0373717b9aeddf28913bdf12b923fa8a4f414d83fd155ab627211e9aa78627202bee78e3339e80b21d6b62a5a14ec11d6f7c6a62a00fdbabbc047da87fc31b1f4fd91b5615772c0d592c6ed3867a68be2e2ecd8b062677beb74fb385dc11bd7d9a988b9dac9b654bf3bab30cd4dedbbf9954e6297be3f3bd714124b7e5624dcc53f63ddbbf61b9d86feac2f106168e37af6cbf26369a2a0aaef7b5c99d3f69aaa0b982f424ec2434248a2485e40488468749349963439026736c1477ec682c9963df4bc20c6664fb3304c5f052c191fbfa10589bdcba9239fefea52948d509a8242477bab72fa5ea448644d91f4b6964fb34415364fba596dca15f1a5a9942b6bf222477488f4727a0d6c1898cee8b6cdfbe680a5607a32e96d241b63fd2046594926c7f2c0da17c644e93fe6d2cdb9883d9fe0d93568d9ed6c4be26d6aa893925d7f378e3530380235b2b6eff8dcfecd147c61b56b63f41921037c2e0b2606d72e78f302e20342e9963291ad9fe88a308d93e0e20b9437a4b833cfa165564fb332eb9e30f02a1c922a16cdffb60c8f64500183b5ab6dfc9acbdb7937d3880e40e7dfb342e4bb7c8238c2bdb77f0078e4cc3544ce6d83759e1d6c480e0c8a490e6b06c9fe251c736ca3e98caf63dd10722b930b45cec6f228f35b16c9fc8cc373e72a7b3ade941f712fcc2217eccdc85289963ff878eec8558dc777aafcdf68649e7ba37ac46d9efc21b9f46a1b27dbb82db3fdef864fbf26443213b60b671b8e1c9d3d8529398b3695f1d62526bdd515ab555da8f358d4c690d6292471e6d48b1fa409a214593a782e48e976b1999d2713b92e91a99d629648ac64c8ad6cb63f541a6a3bde28e35883e35652f8a924f0b777ea5b56a0b2b2da851b406d595cca9341eada20fb3c4521ae3c51d6b50a61d85d6f6e9d7345ac53dfd3ad42afb744aabb61593566d6191997b58ad123dfdadc9e6a455321d5e1126b285b66575044f9ec6cd95fdbd1b8008026dea6076c36c183831f9c66ab58a3eca6795db9ff01fcea04acca73ec2a851dca01fbcba794fee2869536a76a3d168400041a3d180a0d168564ca137e8e0a9c959195851155b9256b58afafce1863366ddeb8e9256739126bbd1e66a818167bdef05d7df7b8e5386b651eede2d4f9e4639144312c2584dd69323b6c85ecb34aa559ee7eb9092e7ebfc90811655683b5a25c3a83d79826a57ad0bd3a3b5c1248f324a9e95fac4c9f3e7e3cc1e33cfff4eb387bb4c148f3c51797a5398b8378b43c2a4d6eeb66d4335f8d4e053038bc9f4d9b68fc9c764259bcadfa4941d8e434c503612b46f5572ee9b0ff95ca601c47bd00d6e437629dba1d3797bd48ca9513f66de3cefd9f21636933c16e1b66da399ab20cbaba237dc83d5a3559b6baed65aabacdd75dbb6ee29b72e3c79aa49f4f43bcefcf44eb4bd7c153c4d555cda8970e5da60a20926aa4082568e8b1900598eb3631ce18b15508108b5c3325d48040190c084c5230a8df074159736ea45dec4e378b7f007fdf93e9cebc289293c44745f443731042ff068e16f84c7136109f6705f44deb04c0fa20e77a18c1712f146788cf0f8f0ed0b79f274434c793e8787987986e304394993b3abb81bf57088e9eb6ca6d8e63904eb244ad6c9527644167972e18beef340dbaa21df5c327bd4efc01cbc0c769d8fee46596549902f1c67fe46fbf7693752f991e82df8742eb1200e5d06c3b90404023ef7de68c4813da35168924f9a0ffe683467373388bbf7e1acf1cbcdc47273725836ca69923b99f84fb0d2f9db199e4cbfbc5f7fac2bbae0053234309cf942e9a971fa78a1f41410909989f88072f940833cd51f93a12f4ff58f42daf254fb207dd0610462eb29e9a24c0fe07f6028657a203d6884e77bf0c19008f049a1057b20fd1712f13d29949ea2b191be72b7b2f712dc61f28c4294a724f6e129f920a69fe779d89378dc5aae2aab330fd391ce3cd572d1adbdd764fa1f5179a4addc51dcd185727f3f415d2648fdf9359431924567dc47c2441eefcc8fb46e9c11aec12d785324bd4c729b06ee91781ed934d8ef943d7d3fc1d10894d862a7b4525aa928fc48d8768afb8925be8db2dcfb68eeadb5a18ce86576b04714f2006917777ecb46a11a352dc77de638111e871022776f45ef494e148e42703f6c184a1ad256715447d6399d1a6cfb041d9fbebf10e9f2bae3cda5567da6d9a65695dac31de8a0e56b050e2b7b525c4a61c8f2c7091ce451963f4a2899487882d241461e798c918d904709f40412f22883b2cbda136264ff92c95fc745024cc1074fb8c0064aa002143cfe37b858a489377c9ab821e58c1f1e4765f9f3c40af24a963f4f30b9433a745e7ae47a963f4a20d184db59fe289164891f258c702ce896e5cf122f78f70f483b8c7c20c60f8ef084da12a05084096cc1441557004d99820b201e3880021d2ca103d816d09801114a3b9861031750018c26d0f081154320e28916ba5083284628e309637c3b4cc1460aba60e267052880412181138ec0cac2a7096450210435ca50421a3518c38d266c0481013cbc087251f1022b204101107858d9810152980c7581c4166e2034e3e1892fb2f045cb096fb4b1051bfc6087151396c0411b515e5848430c232f68420b2a6a57f00212301f6406cc275dcbe6fb5a5b4f1a0e26fc2c093289965c99209eeb7baea2ecb7df1163e451277b97023cd3287fafd9fff4ca37598a330c971bae3cdae05e5fad1a67b2f099564d5a42714a3ecff7ad07edd2b3c5bb449dc5722bad2b9f15773ead52b6c6cee5ae62379feb6ea1808311e89900c8cb4285bd75daa8d6f7893a8f65f9f3da0e8f3c4e59cabbd95651af03459f159644b9bba9a0e81d3fcbbad23267ca1cfb79e1d6535efaa4143d8b2bcb53b4bac88f0cf92d1bed5a79acad2ce574f9464b9052ba4b4b896545e59246e08ba86168893e28eece6d9febce77f9b2519486d4a935c3dd694b955377c29dff4d7b8685c29d4f1be55264b9ad76ddd1c093a7d1a394ba3bc9051cdd982e0137cc2e0cc92457248b2c4396d103f5fa438bb5566b52a8d66a4038800f215a6462642c47e7533967ac0d3c1af539c1f1d956d5aae2bfb9cb2bdc49f3551adc9a34b83484e83aeba1a323c8cc602fdd8b03d37c7506f7b66a36f5893fd0ae6a6acc3ef4da506dd6bd9e40290d699db9cdccc53a05c8c35a0b1a9addda506dd6bd648e7d422df77b4f6f25f303abb5d65ab95aab0e6f745544dd377ae96ca9ce2aacc22aacd2ca458bf7495e7d91fb7dae8430579b8e2a7279b12f5f37744d30d4043031b5862b9d95a7d3ff89685dc417a3237385fb261dbaeac01ef792f0628aa1f198afcee0e2a8b461dd1a77d6cec331e95ccd9ab972b17201cb3e3024c0baa12b612b54b8f7f4d9c6ed50f6acb57bdbbabb3b1ceb7b9db391684a299dc1f556583a0f7ce94097af653c9d729f5a24d6599df5ebecd03c75160489dab66dc534eb045f4c96cb0ef638cc1793e5d3ca4d9f319fcc67fda5d3d1485d11a17a32132482a826a5ccbeb4d274fdab833d5e2d25c39a60683c8646e6ab33b8337db797dbdc4239ebac70278e4fb6aafae406e9ac93e6ab995bff272748676bacb3aeb3327048028585fe24b0c77d729dc966b3f58326d350549339fd56caac933207e87d306785c29ddce65fbfd639e7276714eefc9eedb3576d58d98525ac262cf199724d4341d7e58c309488f1e48eb2fc5112b3819216f415942c71ddd216fa07f7a50960dc9620ac71c11d2ce10343c3678a273e4ad4e002162e4b963f49486921dc9be54f12657812d766f9930414efe28259fe24d183a1bb92e54f125af4142ecdf227091870e18ab2fc49c295440b89576581274f6369829b94db53b0a752f74aa95359bd9f39a15cfcf0fc707539f823860f8ceae3a97e2ea42d0f2b4b09a3eecf6787899ca7fb24b5c61110ea93d69822f77f69b4a8e272b04555664d644c626012d894dc2aaf8f0d1520af7d354b23f6529935a438b28acbc52ea3a3a8b414954e43a5d950e9292a346ca0963d4412e593fb19c5ad4f412038b2bf376732a73e888313296273cb9ced457e828ca7ccd9b62244b37b64432973b66d76ad1f3559f4d5d51ab9d6a730b9e35f558072addf65b448f295dca1a4d914191bb1346052481d25d7aee58974b0466eab04c8fae0191bb19787a2188723935c2e72513ad52fe595068c8d586e6e8a2c779259eeead3b55af216724145a074c769cf69a4e46271c35e6bab0bd8d34a8e605902ab85891529b4520a96a8a01163b9028afb8495afd82339604252824be5c8cf92111382ee91319880660891cc70e2f3f104a0111598f07c2c6106fe1ca929d13561d604a0ef1ab144040598b7c412364aac4bc1129c8f282c11164c6c42f60647541f67b0b82e5ad48794d6668427dc071356558a4ffb50024d8316c5074dcafd41a284abfa70c20b0997fd39020b1c4f7853a36afbe0081635e2d6acd167dc2f829371696ce0ab0b9382f6e2aa64f99344094de27259fe24418282fb92e58f1155985d52963f4644c9f387708332358011403f4620b19269963f4620c9e3fd30a634516b6bdd368eb35634f158b3e881d15c5f9de77d967e2038b2f493f9ca9c510f090442b3255d7b55e69cd25359017b56c0eeeeee9b251e82ca3d33f1b7b8b84c97d2ec796979797929b1acbcbca8dc979717d2cb087c79f9bc4e64b9971cde141e8c18f7f3e469ac5965fadb4bd797650dee480a2205b56a46a1b9e83d7d9210290dd210890d10c9ed9648147d2abb2532a5b49f648614492d990a923b2d99925840851449b316e4a0288d727247d22c88048504d42a92ac51148787492e4fd1ef30290b4c8291b820c5485f348a3ee9d528fa2d4c72d228fab34651288da24f0222cdc02dee489a9166a459a6db7c992d94623411448a3225d327d1aecf6dd2e2a4c1107d929456c99f551a99925a99fe4862a396e974638c3cde55a69749a624a14c7fab93d46ad5486a92a9ab552369366b5593568d754572d2aaf913461e495728c0c7ce894cbfe9a4a4a04cdffbc11dd2c9beb83123a909b5c99561b811d41847a6ab5cb312c1a073cdd90e02f1bcee1389baaf9bd96b6fa7b7cd721cd843a4fbd111d7b3b41da6224ecaea238ac99cf9262bdc194aeeab4fe6befa74aead8939e79c4e1ad5d5d5a8aead46f593b2d75ff7cfb006ade0fa8f35a84b51682ed62f6a6c56835ab3564d28724726cf7ee7b2122d2b87c293a71186965b466b168daab046f5d3e42f83d9ab5da7acb472a3fa6a543f295b719920d279ec62b3c7ac33c8fdb4f653dcc53a1988e47631b9c392fbbb2f5a45bf42e954ffac515d5bb96bab554e5abcd2637cb48fb6f5e5a28c0edb6f211193a786326f84c7a1b8df593e39028c4cc3b19be5e672f745a3c22e76e48e77ec6230b428229075b2dc5fbb70877432e9004f9ec6198632f7de17c5c5913d0781e0c8f6dff3306d9494bfc9f7e4d7b2ca30acb257bfd111b713edb4a86774c4b53e9e4dad5136531ac5fde8884bf369760282146166a71a6a8dcc4d21737f4223732af95484cc3d0c116c126e134c5278353217c27021730f3ae1aafccaabfccac75a32c5bdf5c2d1de091373f1e4738a650e55933bf649b52f7665a3e6c907c5fd8a0a9e3e3ead62d21c8b966bad36dd936e367640b9aa541b11d8534ba552a9b4b24232a3bea4587a798afb59f2a2499e5f9d902cdff2a59fdf751d2928cf3a2edf2e3fda5ccb2d1f539b79cdc06a663333335f43bf6d4e14192c0002917ca42cc228d0a289d58e9a970e8fd51d5b5a3a99e6c3f049abbcefa71fd3923be0770b242ac615f38299c91dffd19b5a72c7fecccb2bfd1853ab41332d312d90312ed237cb8f315665e5c7985aeeb7f8e62573da756a4c64dcf1b240ccc20a4b3299d3dfd13aa16ea8abe1ae06753ea421d2908b246bef250191d2903b6fdcee47125027e67e173cd6cc727f0b2ee1d159481f263257544678f4235b1cc1a3ed3cf39ac9026ce3ce70d128116021e41a6f50c1e5a34124770c45b52cc6bc3ad531afdc1f66d12acf430801820f78608890b103417060031ac800062e6001202a4081094820021078c00f0ef0a1013d3080871d74c861010a48000e08087203901f3d0730008f4df65100020cc0861e3b35f0105534ec98410032e8c410809cf0b10e00c0d072bd60b11c3217897c7f8e59ab48df1fbee48e938672bf943d484332867efb1e0e3efd0dae7914c6f91cf8e661c0a84fe11caf03c3f000c0a9c71800ff58c73b1e652238c98fde7b4cc3e3cdeff1c7e3f5f718e4b9ad11be4df088e7b21e9378bc268b1a5858f3aa7909819384e08d1062b55aad7844f043e0220f023cc47b0083e03f80857821d8033f047fe03b8085fc88873c0770073e083cbe0630077e033888c700d6c067006fe02d8031f017c019f80a600b3c10f8023f015c81a70006e2238027f012c014f807e0083c04b004de01f801ff0386c037003be07dc03f3c037003be07ecc3ef8019f034f8f43ce01e3e07bcc3eb80797805e01c7e015887c7012be0138017f041300e8f009c80078283fc0d1801df8381fc0f7cc31b00f73c115cf307c03fde061be079f001de07b6f98c799e00d8c71700e7b70113e007800bf03bd886ef8107f03cf0ced7807bbc0af37811d7f03bb0ea69c0e20b00eff819300daf8305f032e0193e0058e763c0327c8803f0393886c738fcc739eff8cb31531ad56318be5a35d6bc72cbac626aac3b86af31a6e622cdf7d7c05cc4df5f13ab9115c117e6a9fe10e01b6b1a2eace655f3aac9227cb938c4f787301785f8fe30e62208be3f94b9f881ef0f672e7ae0fb432017877c7f18e4a290ef0f692e8edf1f0ab9d881ef0f875c0ce2fbc39a8b1cf87e9b958b1bf87e1b1f1735f0fd362c1733f0fd362d1731f0fd362e172ff0fd362f172df0fd36301781f87e9b988b15f87e1b998b14f87e9b998b13f87e1b201725f0fd36412e46e0fb6d683642364336b5d3eae473629d5a27d7e975829d6227d96976023a059d6827a1d3d0a976b372f1c70deba675e3b209931831dfe0d1027c242c8fcdf7dfc06e6237b29bd90dd0cd0ded46e866e8a686b3c2f1c161e1e0b8705e38309c188e0c6786038413e4621826d1823e129627fc7e1c9a8b3abe1f47c845007c3fce908b307c3f4ecdc5d4f7e758b988fafe1c3e2ee6f8fe1c2c1771be3f47cbc59befcfe172f1f4fd395e2ed67c3bcdbb3b7eff772ce34ff346785a5a8e7b88799a9008f9830615433c319efd3d106341e487c0e12b8485b15016ce42a03028a48542e15058b359d9f8d8b06c5a362e9b970dcc266623b399d90045c0866623643364535bf9b05aae172c269b0105d184866a37ab1b9f1bd64debc6e5a91bd84dec467633bb01ba09baa1dd08dd0cddd47056383e382c9c168e0be78503c389e1c87066384038341c219c219c5a8e550e9f1cac1cad1cae50f452ced03d8e199286fe1a9c24026f44112b9e9ab7c13e96874878f3aa4142e47c7f15723100df5f875c8ce15be75b86efdf7c5c14c0f76f2c1767f8feade5e28eefdf5c2ed2f0fddbcb45d5f76f3017c56f1edfbfc95cace1fbb7998b3bdfbf01b9d8e3fbb720176df8fe8de6e200be7f13729100dfbf0db95880efdf6a2efaf87e6ee562fe7ecec7459eefe7582e1ae0fbb9968b07f87ecee562cff7732f177f7c3f077311c8f77331176ff87e4ee66290efe7662e22e0fb39201771f87e2ec8c5047c3f47735101dfcf09b9b880ef1cbe9fabb9a8c3f7db958b3b7cbff5719187efb72c1719f0fdb6e5620fdf80efb72f177df87e0b73d101df6f632efef0fd56e6e203bedfce5c84c0f75b20176f6e5a37ac1b9f9bd5a9761a3a099d68a7a013d06976929d6227d8e975729d5a27d6c9e7b4b2a9d90cd908d9d06c823c65036433b391d9d8c06c5e362e9b960dcbc6c766158643a150480b8342a07016cac210169ac8880036b5a40c43e01621700b0870cb07708b0770cb10dc2204b78cb8a503b82508dcc201dcb201dca201dc9201ec8201ec7201ec6201ec020476a90076a10076990076910076890076810076790076f901bb3800bbf8805d1a805d7ac02f0cc02f3ce0971df08b0ef82507fcf25a007e812900bfc412805f6438e0971902f00b5010fc1274037ea101c12f423ff0cb500f7ea91d009b5606c0261f1e6c6281d8d49239fd199b5c3eb0e955006c8211009b6203c026990dd834eb814d3bd8540336f1c026119b54d8440386d9816166c03002c0303260181d0c1303868179aa3f00182607c3e8c03000c0303060189aa7fa5318068561863cd59f03c3d43cd58f83636e70cc09c7b03cd55f83636cbc977286ef4d53481afa439c0339c3486f906180206968181a5c31ae324ff53fae334ff53bae2d2d930a46130b32bd411ec317cd810d5f630e28630ed112ee38f39ae16226e6228eeff7b86854c7b637aee771e625792658f19c9ea8e515f3fda6537e8c451c920d89480a359ea831b934343807cc539522b992f615af4639fed13a0d7e56be77e62bc29656a35a9c4040e66342991e629ee6694222260a9018e3c513f346783cae89eb99664ac2f53cd6f0950316d343c7338313247344516e4bcbc5ff9a1f2d4d4baba595fb2fcbc50fc31a6b69c2f01526b9328fe16bd4e1c03158f2cc6019bcea78c298a73a7ce5ce1e83250f0c963c222cdc966102465eda013ff0e469b42e347bd0b0c6660cfefe4e05b933c3da8537ed2acfd54cc7daeb0304cbe206824693349ac974af1b71c739f4ea2117edbb10cb7fec9abffd186e68ab0db9c83d37b4d5d82c13a179e4865ed9a5b835367b706bc818ba903b5c16648e3f37a4c51db91ab7d5b6ad56c3f151190b7227bb21c54fa686b2202717a48afe50c988ec5238cff63e3a8c3c9e5eb8792c4d149bb53a523a29fdc2954fe7386582d0d5aa669a251864ae5679be07f95a356b70fb474adcf922326eff4c923d8859e3e95a7627b39ddb449c83405c54ab10da28696d1322bb71de7522327cabf89b02d79bcb727bb541d0e40be1e295ce23f744c16c3263e8e7beeed03cdd7b5c95e26e2f830315724321b9697247f4fd44e69c597b6feb366df6984f660cfdfd24f737c1cde3755f102e3a8fcc357b01c13a68c6cac8cde10934a1346af664f698409031f4b710644eff38c5c8fd1e6dda232cbc97a00f93c70b892882a70b1be62923cc1060248bc0948b98721d42bee132ce4747e706d6eaf8e30f9cb210ffaf3f26468c71c8c9b3d87671b997b96d0e2398798634fcc0296fa110fa35fc41436f25bc6f756576ee7b1cd2c9f21797e3b6504815d2e164324d42a0d3070155a8428b35c8a8a2e585231cb182d7f646092e72ff0d6a2266f2d1842c0561ac960042ad8c2335efa70915c8e4168344bf622cb6a748b498bffdc4e2fa9473fa7079722778feb3c796e5a3668f6f9565269e49411f401f52b3bed37f130eb5d29709b27d7f8732a61f4db7d2d932b7c2eb2c4f5ed7e4ce1db8df5e823c88ded6b72e9e807b1196e9c1bee8ed8b420ecbf4b0bde8b717d9506ea1f5d49c3d95a83569030a916f95b7efc97a30ca1de90cc9933c6574ca7e3a73f1ad7593e97fbe87e3cd74962d0baea8bb74f643a77ab4e38bdedb70d4f13d178ea73cca32be86e34c1e65194d5b52286fe49997c1f10e73d1659e6a180e3cf33178cb303162dc9967799af744600fcdccdb199a99b0c2d030717fe5184c330edc92f13c83a5cc81a10965a364b0cc9d6930132562185d090c963906cf8c2394c14314b1ca33211661e871dc08e66530ccc76099b91c62e9298c5b39c3f8bce0d2bbe096d2b3bcc954faad642ab1b47d92456fc22ef3278dea2f619fb9e08d75c565f9ee5d70296f575cef5d304bdeaeb8dfbbe015599e0fbe0b56c9db1577f42ef8ca77c1a4bc5d71ef6f575c173ccadb1577be158d6482d85c7a9b4be118825c7a170ce6162c654e29940db4813d2b2bd85faaa12369ac71cac639d4ae06caa3cb3e3bc467d3800b28dcdf37594dab5451bf19f9253aeb8886251197bb336d557f4377b42d45f2bdfe7cceea93ca9c52294f6aafa5db675d34cde44d3453e2e69cd3abe7813dded50dfc31337dda54349209926b381261abb0adb2fb7b52e67410b4d62a2a873c445129ba49b3644e77ad279803cd3d6b79a4ac1d9ca78674c853bd843bf66ad5aa24ab154faf867eae4003e2d55805e143d2460e3e246de460ca32d02a8e522b32d19929ada220648e14ee38595288cc1d196815e771dbb66ddb36753a2053fd47641b720d9d20a47059d6de6b32fdb33c8fdb82274fa30e58177a5e380ee964a22feeccddf74b15ff7a72726649452a4754bc37ee073658ed02c99d0d0644863ced8f2a47ea06d3c9339491c91c2eee882323cb38abdc1d4c46165a1db09a85d590c984d2b1632679cead8bdcf3cf411f79912dd737e9c8eeccb5513cc011e585e38bc2d1d497d36995cfc809779c404976cc24adda50a69924dded3a54ee7478acf29c4a64aa1f0c1e3afd5c771553e49e4eccb63f474eb8720299803e2c48efa349a1ecd490e80730321cb4dcefd1f9dbf785de772f777067f6be5f7a78e6ede54aeeef3a18591e57f29ca21f37307277b2f01b92396edc91c53594595c7267cef01b6271e57e2efc70d0b2b431e2cd8a04cfe6ed5bdd0f74b22ca43ef56a0d472e468cdbc9f21777ec443f746a68df87bf4886e7155cbd0335e724226fef6df8bdb833d36e1b8ab8f73a9cac46f98bda863ad9f1389b1c4047a7ffd4e2e5c2d1f41bdd5cf9061783f054bfb5174f2636882c725f915b683ae9993e8ddac29d69d4947156909c070f1d1d14ca526bc1701c32245730873bb72984be3f7d2756ac5a6f94470d3a328ca911e7c9711c37b912e48d0479a3a395f50b9e3cd971b6bc8bf8329a5ab009bf60172cdb1be9cf935479dfb1cc8ec5c3a709f67024189a4d574d028d28dfb622f21c8dd8cd6e5c178e4548a05ce54c8251830cb9fe98423dcb931e7c8f0526d71f55727d299abe7e291c6b32f72ce158d3e2f22be1785f4ce14b2865ea86a470b42ea194a91118b68452a6be901ba2886c8798795a4e470f416591171268a5bb24a40049f1eb9bd7e93ea7140eff8cf5143d7d48dc6ed956f66422c5db29f9d4f137a7e47e16692679a352466b9db4d639e7cff0709f37347da72477e4c1c3c33997cc1eb3b1a951f225103d83be675f67f610bdb5a337a1792c62826243aee1b823d7702c5205307b88dc4301705f757c0ac02de6b1c36d68d4115787d952eec8f4ad84b24300b3c7ccd4b7f87ea6b8220320cb9f562bfbcbd3d8b45cb9af459a49961f85be1c699e1f176e200e5da6db734dffa3df928f49abe873d3c97439d8d3248f367f3faf48e28e73169bb319f3397fbe60924adafed3a745c9e3d999dc46999ae6a4bf491685ca9c8f33d9c753768ffbfa203e8df08ce71f16d1af9be08f4a61a044818bee22a691af3d0a1e021d329d55f4351ca58e94b213bdb5960b6bfd2d1c6fd6691b48b9494b374c379f42ed736edbb66d45ac9c59f08298a1376adbbebe8ff6e7c22d1c6d0d8798a617e656df5bce3995d45adefc5dce979609777b3bebf424744e296b9d620c194bd75f9632f5add6ad96320da960a594544a2929a5524a2946e528ad42a8bb57afefd57ee13a75f72234d3300b548eb5d61a3e27b7975fdd9da343be5c4321784e6fc9ffcb2829cbd388cfd9831f2b28a5403efbd3972fae3f9d2f232e499342d2e49c73ced944f0a47cd9547afb6814d22b6fcea651d48d524a69534a292545713f4a29a5df97aa58da2c5978b23d29d9c84050b278511f9a440a4df6853bf1568d8d328060593493f61192f244365dd3c9945a96413b74e6cf903ec952d628f9739276e8c81cd00b9776873a8d0a72037ae1caaf20901952ead4bdb9496f8ee6198e45643ad4281521cfa32eea644a2da80c2e60ce72266908cd9e5cd1ae5e4d891214e36236c99335344442b9a14eb9232a9fbc29974e397d347f861c0c481e49bea01b45ebe6de0577b75d10893acf3fd0dddd49a311a936c574dddd9dc432e79c73ce9eb3594aa59696d9c25222b5b8b4b8b8b89458565c5c54ae8b8b0bc96504bab8b87c47f0ee9cddd3c69de1489b64f9ee2e3f284bfbc61dbd1545ad1bdd2cfd5c97ab6f5c6bed675f266f65f9f58d3bda2ac59dff813dde0541b067db866cb0bcfddcbe46714933a49f2410c84cbe574565e55bd9b6af1cb73da593658545e5b2b0b0b0b0c08cc60d9665d83f6483852c32f0e877d8d475fbcbfe3dc19eece15797b87bcb0068a6060b468c4bea6443d30854ce76295c235e8c18b7fe00a170a7fb943468997586f23dfa838232b2fc91228b2c43963f51fce4eb9239fea0d0ed231dd0dc7eec8e9080648eff588f905632a73349b9f64b3edc5e57a65b908ae03bdb8fbf0abb86744aa016eaa273ce39e7ac5bf56aad75fa4b91945fe79c7386f5b99778c8ac514a8528428256d9974fc45cb5d8bdbc1d2ed2a91682c89008172141a37a00f7122104098a34aa7fc4b25dab80f22613f238936dc8e3098ad70d1463e49f2630c83f51249151507852ee4c2907c0bd10ba23cf6f2aa544356a4a29a5fc5c70e58b985cf9dfbbe45e7252ca71c837c5208d96b872ca9f949256ac9074e69d56d551ee50ca9ca986675b2559e64aabf8a5a43ada40eeb39ea8eb449efd38701b5512bdaed22b7386a5d16824d72e5cbabb7344a0dee7c5b451ae7fa5945e77774aa54bf72abced67ad3450b094d6215b4bf5fbeab3d279044f929620123dc7555a5b25fa592b88c3f6a2b7a3dbb7608fa596dbb8af6010fa5c387a11e656eb9c9392a063e094fa4b7feb9c735c7507837848e97beda994564ac38f56a1b340daea7cf9763eb5cfcdf932cfc9cd193e27a43e8d11e3d6e7c01c68adb48653f01c48afe2067b2cc77150b47ea0f0c9f2078a95a9c11e10c8cc52fee0a7052b1e11156e7f97c415bd0421207a1117ee7b1d963cdff635acb6566bdfb3d556a74e9d7a89fa5b91cd5c68a5b43fea73361c2b57caf4d7b89c0c40b93d0952faee2e3a7245df236f82384829790b857c2fb317e3df178e337f3f5055dc317ce578c940a2fa49352f7b59384172076c69dde878987bc7ded7bcfa489641fb2a7b571f04df47afb283a187237dd1fb70cf361ceb91da9960280fa92c21fe336301f3343dc6a8816c76c1615ef41e0caeb606754cee93239ce4318cd16af81269befdab94dcafd3291d3cbefb0e63cf53ee6aa851cd86fb659564de5f68f104568de9af578393d4bcbc57535363c235b0175c93454dcdab069378746802a24ba874ccf4c6494b32a566000000000000031500202814108ac58291501468c2dc0714000c7fa24c70501acab22487611cc418638c3186106008220411a099a1198100752098bf643ba9124520dc75e9cac6fe2622fcaf8e802a75d8fb8cc30149612b175614ab84742da7af034bee5ebfee10f6b6c32d8cb5314b0e761357c4188fdda93721b79b6507110e695a6ee194d670030153bcb3d4b5d48a25c85c792dca82535a4df304621d7dc64a8bbe00322a54f3cb67e4b9dd37b6dfffbdba4cb60c92ecf0031b5ad82bcce40e6eec2ef43e4bb5742918584a4ae1be50bb3f072b0ccc0e09905ab38cc8c57d27e01d2226d6120e4710a1fa7a8ac72c8f8703158f01e66fe426a8635563eab8e9882392cf7a42b9ce2a7608dff22f6be16518c5ce0767820b0a3d628c7d6599bc01174a441966160038f65c0bbd006113b95b834f30d234a11e4d30349d9fde716521034fdb3e5a85f4c63c342047ce8ab7fd306ecc6f343aa84cfc2f0fc9d4668e2513def3dddc82ccd97fa72dc8f97516b52e8dc7d2a2fd284af3bb2c5a4a4f53ea9c148fa60af93727eb16de43d5eb9d96800ae645c9e99930c7526ee7639bf1b20225b1cfe6a942980211e6150f15646b418830aa16e977fc5fb9883b5e82ab810630570bdac2664a95f875b4c7866f7d26746dbc480a5422a74b149ca662b1d1d8ab7ad7f74025902d27bb2b97be044b71cb064934096c49b34dc4d2c0b7408489d1745e0eba8d9e25a290adea43e32b6446f78c0cb5ea616e0cdfc3d77222c8302d48a7071f59c0cdbf11e6e7629c085273cbaeb0daf60188861cbfe5a3fef056878a7a08b0018a1a1b904ff29ff242279a6f89bfe070c41f791cf3d885ed5d71b3527f07d72e4d04ae25cfa0b88814666d20d2f7c8a5ecb7722ebdda4abf370551319ff6c2a59a9450ff69d8b196e55d240dee5d6bda248167408cd208e49cd1eba254a0c6afb3d53d94eb3b276dde501f5f697626994a5aad59979d757b4e77e0d8cb36d71cfd983484d82b767742a7356da2717eac7e3462036e83836410317706e358add4265553b744360256cbe524406b08f43d9ec23334de74175f0173a65c1a61a8a204d2c76df8e37d92cf178c3b407b25d11741d2fe6754d126830ddb15200b3070723f453fb3895769df7f910d688ba1db821e2731ade5aa9a2daceebe7dcf2e9f99ec0376379a551956533ae8b8152937f0c9f43d57e61e5e49a12bb938625d795880b8edc540e4a7abfef76791a29bc5d3dc3dfbad575d8df487952c0483379d2b47611eef00f9afb3b964f6030074faf4af454f39fefd56f21319e98f990e072bba381e2a1aa18da8bea9c5761a5922dc403b2f457bb5b27a52f8bca6018f8f8931922e7e75aa83446075275fe4e8eaacdc44c6802e3e7db8da837d148abe5c02196fa4f1572667eea061ab1d652a2dffcf0d3ec6bde467aba9b6be8eafc281337627c1e09f7bf9d100efdd0b7cf919db0dd0e249e29396a55dd8524560ff6b9dc51cecd3e11bb7f2c8361100dd39e0cb38070a2f4890c35db2f7a879847c69bed47a6109f3112e38d5e65066520777fbdf403d3d3fa0ab130ba9d4ac2f108f940017db467c0bd95b6dfbad7dc92c1d27962c48285ca23bafe0a97a293a732267ab10fe0c7bf4e4a2433f99ff7f391edca79de005bbdb33ac187189c72766bbdc2721ead217bfb262cff5a4034909d4f371a89250087f7194a97df2518246bc0b146678ba8a16859b1f77b36414ff809f2782254ff9339cf1ade469788adc7b94b256900740be88184e04a48b1b70c46a42ddd63a6a143773c3795eeb2c349b9c772e00059c05ed5f98cb2c34c1b4fcf84de07ac0d8f695712a5a7cb358ae80d938fca413031fccda43847a57c4458146f66c5e6920bcb0895c2f1a8842cf928131d0511c2ecac61ce1da80ff936744bfa3749165a46a3fe9b70c47ca9c455600892fa7cbdcb875644ff4e1e9c2e3b485b3ef0af68834c7f4aeed8632b2b8629994d4c4bdc3d2a6c0a1e69116eca65a64872ce91f85390a1f35216314b5951624c85e44e5ad826a2e6f52f241cd7d709b8391e4086f831ba4d9cc986a10f2724225d721ab9374620812e7647283f9f71218f23babc19aadaa06981009bb0ce2be31846c728a88a7feaca6e2283090345c0bd4f60cc7b344b8d8705cca9436715f2d5be24751a409d9d8d9b8d32f0042dcf2b3cde5822c8ccb422dc2014404255b77092d57dd177a2033f9643f29840994e26036591d826ecbe4ffbf38495f6b9fe0d1343504fcf2aa1c26d03450fadb9b72c91edbbffaeaf73a4d45d023dda721d6697559b2434b1b587f93c13ee4862975d89c8d81b17ba63fdcd0aaba2a4b7996f9f6fb844749a21cff94d40d680501eaf5b4ac1569e06dc00d6304c546fecd2eea1595cb0e7468656a52d68ecc8617f2835ebc551a80cacbd29eff8e81a947c8a0533763c407fa87889fecf415bd17f45f39d01e372f8e07ca1a8905f56c9b6a3cbc13936462270fc00f751944c1ed3d34e9c4ad744e3d0f575e985e2898b2eb286192e339f120cdf62428a8f4e5ab73f50372c2ac80ef1b32111e0f7020c552e5cb44ed28f1b428063d99a37228c4519edf353cf6f7146ae6226453a67a7b1a26e7e0043dc49770a5c88b0b97c689e43b94c443c2cb7533cedc0163c053ff1f3b596ae35bc22f89556169c4a252e6aacbdbd9f64d34fbc91917e92017aa72fa31f372596c0ade893623fd102149269379ec5b9cde0b825ae9bb48e850f3089aba3cf07865900526e705c688e7815f568fa35ad7b93ac2dbe31d7888c5eaebb23c00c93dcc830d678cbba8a75b95f27d547a2c86452a5540aa84027bb689a1ae01efdb17b31f5295c9cadc7e6b13bb39d01db09847d890355c36fdda701e10a2f779aa068d783afbaf632f4846d8916af6bbca5582e25c694f5549ba76a10c7baa50e4459db7a2da05982fa4993c998c00afaacd43a925adf0094f9370e36df7b828643dc83d10bca44beace96ca478a6a4e883a2b9f0544b4a9175831b6079da93ce2dd5ad8f08d32c62501686250d2cd154c7ba84cf464423f741c822e2715ba1c17201db4be57e86e184be88cd51011230a364cada20eda1075031c93286e223100ccfa8c66fc80fc2461a8a58bae553568e46f28b808d8a00ab344bbed5a098154af8c9c575ae82eb836768691fcf962cafd8b3e68d230d69a405f7623f39dd53e1825925bbf7fa3b92b60be05b1fcc1f462039d6b73552ff5d3fa636fa5d333d5aa829eb49f350e26618e34b454d52b0dde18e7c01b51b5647f9bfd464e61f215af5cdd26c5db6bce2a11a06118f01a5657992a5d40a153b8ba5130563c9ec8a4172722f5f43ff244b28248f674b9b5d2ad2241dbd20286bbb66cae1469c8cbe9b78835fb68983a1fb6200a51f38de56d26bb9260b8e57b10c80f22ce51fcf43c523233986eeadb8a960330522e2416f9a2e8f12f4be8865fba79be392194d76ee47841e35c33af0e65468f64f9ce4e7e61bd2f22138cbef9222686010943c8c0f5188f5199d2eae66ab323333878cc6203487ae2e88f11bc6272d1cb2a30b2e4be6ee425d694d35cc6fedd2a438431da43254064775a3a513e734a7f0756692a75f94249d8d3632965c6c52add464ff0ac139626d5696de608c59352c2691511b4a8362566d65b3df6856fc2a972af71a4045d1dd565707faa0c730f363286418041c6390fb8421a93d5f6796d5a11b9b0420054cc66e9226189a2d261e2aeed0887949d5d49da75fe1ca56243d3e396af5710dd4ba6b54f2e7f5f1dc3c46adfec1b5b90909a94017a7014a389265766ccef24172bca8cd54eb4b156f0f90d091f6e81d92fa195cc845b687f1f4375382b7ca8a9f43149aa77e5e37c631aa3affa6328c1f66b678dbdb947a4ca2edb97f6d09977dc86806a5559da8305e5452c3889c4d912eee5258df8665c7070bfab60a8350d74a9d1044a8bd559a4da28a1f391734bc2d88ed420a2ca97b5875304d57098bd05ba9494321662607a7817b8acf48c7dcbbd293167a7344a62d19da3c5edbe92c0f2055c3868d9bb34723a663ce8abda3aacc91842218651ab20b9dc7c31bc6dda796ce9647d04cda1de1dd731b48f96517c5f07975042ca7c524587e784a2f7b0bd5e63ebfd30c87b8168ca7bbb98086408f99caaf9b975cce052ddd6472026907ca56c068a4c8d2c26d6078ae2bde2993edac6978b2b663c82d7f6f6320608729bac12c4149962fa7279417b85fc2b0120d88bda32e1812b531b30bbda47ef06f78e662d3cc101fc88f1b406da8d05b0df0ea125d88125e96069092a53b6503869a1b9f34421862c669e3c217b15d6907c2a2fa8c2c3ef4100701cd913c29e105715c8ad23b6923928750e6645577d7c9a964a82048f64da2ad15fa7a766e6827a59af58d3ef00f1aee4aa480c3f3a0b3c4a30943235e9b5a17d3bbdddbd4c7edb85b923b1dbc4d6d81a3005d82a85e47809a3b4faf4f2f488ac1f0c9049209fafd70bca7d896ece3d59bc6e926d8ef17cc8b55daee3d9a4a407187f4147954adfe00dc1307ddf8d3061f7e673e7fd0904b2bfc7aff004c600f246b1db1f47a86d26ac25fd4f5452a3be3525aa9165aef7ddb4f8fe67266cbae00aba70e580c34f4c01d9cf4e95d1cdc32a1bd2517225bade8a019b2aba4dcf26a1f5a725d6d77b3d4022071450cd266b6bdee272effeaba32b78a204c172a380eb941c4c63d043c769bb84c5bbcc8221bc895afd99b74624148a4546027d3f683db5e96195ed59eb3ca053f27d9bc7026edd52c48390e916aa55f7742485f5927ab9ed0786d305419c5c983c7690b31417411c48113cf01a5804f414aee54f674fb806b5285a67a1ef2ee2c3b5ee51f6483cdeee22a31578847a028cc0950a99eed45e85267d31f531814dc25e880244b2c988d05357c921ff238b33b43a959f461cdbf3c88af8fd90ad933315878d77f44a183fd16681e2aa49dc807c1621372c09fe400643ac8ad8c456174b9ae085644db510cc84bf487a2676d115855877d1ca0389cb8d586728f782b213020fd7a546e33b3b67b6ecc0c2a938de511d1cc70b170b1ae343b41398c051788eba905954f335edd39c1bf53417a5417834bd30caa2d6a1882457e83fbce1f980dcd4c31107f798773cb1cdd63af91b8cff9469409868edc6431320a487c79fbc4e43e78a4b0a18f3db4c25953027155396d6745640fe8ac7314548e0a12b0366805f924b834a6c01097a3001b041d4067c0f27d280ab502802d425212fcd55bb2460dd43d18dc6b581ccb26bc403b448282d1eae3f9660ae0572d5262c6cfc02fa7aa7e8aaf788929a91676db1b743fb75c09351184b06276204e29ed350c253de22d23e2ea18203e29cea710c2c770004c8aa99d3a4cdd38304d78c2e9386177d7e489e469ca1e037acbd63f49e7f0817fe47c28ee45a7c9033ac411df91ebd39276c0d037843a2ba64c98c791b4f1b77a705075f9eb28f7cf001429c829b8f2128c1f222c42da6a95720078d30cd4397f29681098b67b14d0755182cdfd73a8057e69454b03bb6b7c85a378671cc5f1f37569b6544308186f38ba0567884e3c4ef6f88f60cc0233d1202e82469779b33a5ceffc51d96c876d6cec9087db1da108956255c74271c47a38e2fb35a2e611704532b9a8b88c765bfce1764d481a5232264a33456cc91cc3a031e479d642207880b8c21fb351bf65381d7e24590046216a0afe5143f1f8b8e88d17077ce7741355ed04660bf5398a54dfabc7be0acfdf95847fb350c0aaf5d7c891145047f36414839f6f37181ff6cb9c2d5e9d2aeda32e69a10e604d131c6d26cf2cd31ccab5c993c9e01d56f725d16e27bce4a4538a182da6a0028628c275d78e7f7a7cbf0f93691fa67396a95d86ac7aa814c3eccc21c07f39be5ab9bbc66180f0ce77c94c1426789913fe9c589f2ad152bd21bf968869d65e6ba067eb076313762b2043e73d69a788337c46ca571846561a995702ece6937cef9d0fae442edc52d95d746edc6b8dee0e46ce5dc34468a63e9291dd4ad0506b97f212b4329dea58e45aef15dcacdad82b241bedb98ea5fff1a250c9a8fa103ab91d2fdffe47891c0207fac2bcb47a95e7d5293d5347fac1bed9026c011cf4e01457c029528f972839868c38208f40987922420da52867525365e34295cd18536d037822fe416f7cf1ba2ec458853cbae9b89c4a9c44655555b4c1c49a66a31a21b60c5dae09354603a9f13d84d1c758042c049afb4deca7275f43cf4ed06fd991098c1d64fe2a0383f8335761bc6138fac2816a0523c8395a610fbf45470895e598b0f236932d0726c8c5b21a779def839d9aa40457d530432c4780cf1745c00de77bd475c48eeb01a45413a66e4dd8d090c4f7628fc7f33b0647a418c77fc9d99fe0f7a64462403d333480b5361284a3d0aaf85158d429a8a8215348a358d471a8b8a353488350d6195c69416a288158d6195c69336a268ac0ad4081ee718f9a83439f2b256e4e5845180d6d9031e4e01f5190c09c3fba5230b80e9174cc920b8870cfefd04d00a5063b4c05ac43be8f2799a2a8fd2e652eb03ade93f3df93aef30a019a3674fec9319e24a47fe2cebd904928a9d5b39b807a92885e91a0bdf9dd00c9fd55d60d64d60eb2a00b12e1fac9340d65120d521ffcadcefd655e0d59d09947fd6959db57569be7a9983cc45259c17f95338ad80b94f290fbd0936abcf6e9bc1ee1d31738b93a05f260cbe8471fc4e9757cb063751c2ff14f8c72e3db68be88aef8d2fd543e2ad4fed2b97d9b7dfb79edeae4676d51f719760c8684bff966b50653c9b8179cd885ea6039e6a13e2a8eefbe44159dbf1f2b3ec11082e05e263e41da128405b2612e37325414b35877daa98ad27a5daf09e875c67a8ac93baccb2dc59e0afbb20ef179183908a9693645d78172ad77ec2527cb28d87b083917bc343656956fcfc1095387d6c4a4adc1bef584a40538eb60848950ebf058c884880d70317f74e60fc9e71a17c7de03205b79c3374064d23e25f372d37b64110cd8acf688484f2eb391e7196b6fdbec723a5cc38dc23f695ccc6003cc51302b33a4435e0d1997f460faba33a521561011b097a62db9838cd0b679c10f7932b4cca7e2a3f404b1969b27ed6812e7ef0240c82a408cd61a58dcbf98b7d253370e742560ebebb4670c8f1e3b55122946f6d19abf053cb8deaa11b49e7088ab62a709e1ccf24694e93a3b9a83ded86bfb86b570e33641cc4e5e1c4f5a04e1cb87b10582923bd5e6dd53155d5854161c419488cfb044a2c29efa31c300e28f346477eed45eb8eca886d1a68e0959d22c896c27694cd75748cb926bc7a3e892ecfc7add2b48bb4adee70d63c830679c068d6d5c8dc2b2f8ce331036a20c1704d0f15a53f677dcd76d5e2b8b55212b9f7a5f65d056b3c7835fd14c6ffa4ff2ac5aec035f8531a172a5ed2a25649955561d8b24b39f894b7c5f99e6d4cf89a5b1974db7b4ef413b1cb7c71be6e7c17f20b1b10fee77faf9b0afbf9b2f87884f2aedb72a864c25702b8f982528ff6a30c05a4904560581f53cf20a16ab84b487da4dca58ae41c774e4f3df8cc9dd66a278e6f1577856819c938f6955d689cafbcea4783bc9bd6bc08da16af31073f78a9a9306e87d5ed1fc25bf1cb1f5d20d93f4a051cfab7560cfa7750ae08ad9094cfa38429a7e77e3d7a378c845454e12bd9de93889e8e96c3a5f7e5ba72e3d0dc6678d7e35ee6616c8fe03275c985af895143308184375ebc4a0c47559327b4c5ff02a543efaad653a8d53cec9e8d7b85871bb71cf77d6c5de87e9bcd9d12bc29c052b6d2c2341a0c899d1e78287b420e4a6674a073626b9270cd30c7e969b338283f196111f4a22b98b36c184b8403219b696136bf31958466acb6b2087c2e76467ac5e2b696e6eb1a6048c533b445c151aad75cedab938fcf7fd995983ebbbcf488ce0ca08cc914fdeac875a2133b9ed608b84193907551dd6365de0f0ca49cf5686f93ae155c7004cbbd34eaaf11acd64283e1ff2a0763d733a289497d49f3dcada885be41414a62534027c2b4371fbee95ac1b34510661ea82118417d0dcf328dbb4007c7bdd93683328d2620d0430142a7a820e14a91e98bec8494556aeb9964d7dab481c046625d9242ae8850265d885d6c039933d04b9a0994649e2e209a7088d78cafe311e50a93451a999583ab52e86a8ffda89334198a8410ad8d7003902c62c576344b1bdff312ae4ff9a060ce38ffcf11ff2df0b457faa7482f8cc5d3c26bda6e76dc776d4189c96574900f22c5a2e281b9abbe8aa430a8804c5b8a63801e9ed62cca6256295085921841a132120b448d8f8741b7c0bec4ef0b3899e837f09b456a0bf046215306d143b2706f81f77106a9784c6c1bec7b09cef410d943642161149d9b76dd59469cd3268b2d46debb4c6a365b6c049b04aeef0ed4d1ae49048e882ce005ac4823f0067900a60e2f1283cc55d82b5bb987740e7eb334be780cdf51b0dd866ae1a8582b58022838ef0d169ca08d5ac423b251a97d3d703f9c806b89a8ccc06546ec9f9305f5f9fe50bb9647247f55f108a2bf6a7884f607359e20f9538927a8fe54e12184bf14f184e0ef0a9e40f557058f50f47fb83ec6d0f903292413e1602de8345be0d82456406b48e620fbb5db38fa9b8541bf5fc5f0f823fe74549b578d4bf8e8cec896604e6b8a68a2cdd78960fef044a1a445091cf185198c94a3d051f3ef114aa86b7ea134060ecebb301feabbc36e9af09ccdd302b0c17cddc0eb8166a7462792cca62f7ec79c7ca3256f85518bb126c593bdda055ae36d91c6336eba8ca4f931628de781e8aa3b412684148f9a07931d867e6f608600954dad473c2a993a0947ed3e11d9137abe96fad3099cfc3419be1eac3fe23e850e162cfe5cbe738d0fd33ced39aa86428a30877eada8662f527652541fdbc44fb5226b5e9fafb4c638fd41ebd8c7fe4ae777f281abfce4bb3a4f8ed5f9425a365a4b37083000d214f8a5015c7eb7a73f09474cc107ad6e0daad5832332f50b109f7e763c725907d09f30e8571c3c2bc309f312835056fe29f9ab6e9820d7cae4b45a0cf265dc2adf01efd69e74c3dc56ac151e86e88543001b38ad0a4d51a24bedc87cd9060b1e465f6f349413088cc9aea2cafe6129c1b7e7084cf5aca04a56c300ba033e4f9754f15200962d137d2acf16cea61a33e8bc7d3418f86ec60eaa695b1eaa40d9c026ceeb859a4875717e051ef7305b9d93878bd30c51ee8210c06c70d7bb270dc328deee3cdb3ab04db66620ad2956a166be79889e7ac4acbe060e784a09ed66f1a66ab03440c6644e50d8ea2b23a4a0d508696b664f9e08e17f157f0c5f6e21f2de167c555112d4d5c565dc78d3dcb422a145569fd1dda398e32595c1c692f9e7a306ff6d9fb2db4f208ad2b5c7fb72b05b4163e181f68a74ab22505de9f779b2235c9ef1d434fce289cc7d9c0262aa7200570cfd00108702024859d480c49b9f49a10592bc466e535f7408e2dfc727ec08e9d5c1bfe898f39534d1b08c8a8dab83f65cd99e3a638ab294178d6c340bf06b3a51f060935820b93aba4c372d6e49196d250009132417c9aa99925de905c632bf69191eb0f749f6923365f76b72bf6fb8d6c1e22a7daf91418c2acec4faf995d9d388f896df4041a6c8389fbdf61b049b0c769965e84d7188404c597f7cf51768bb8fb9e34482542160ebd51f98c951e2c68900ece4fe536fbb3c4465d8da1f02ff75c6be0187b393ca804202a09f31e50ef48ba2841f696aeb760ab5638ab0c0117e4ffa4262a3c2bfa95616e68c74b3dea9ed21449a7683ce512fcf9f88b0076ab5977f05f388f56393d6f683bcf53e12568a47bc664b0c30b4305028a5325fbf321da66e4fed30d8b26edc0aa19783ba6412b32809dc5cd058ffafd1a3e5088a5e06b4bc6db158bab896a008d76ad5a78570a33acc437f62772f529a45ba2654270cf704af7ba8053ecafc2240720b8bfbc4b9cc6dd4e9fd6a034237eec06f9ef4565bdd2d8a51fa50f5ffaaaef50dd3598e1fcc3800d1d6be466048f060a7043dd13a21690754e488553540346f074c51d798a83adddf868def6c08f0c065c0daf1deb4de6863a60fe4fd2724176cfc6cbd9236b34bcb11bf73fa559a33256c5b8215060d4e93af375bb764c1bddeb0b437f1ba855e9f691a4854212ccbc1f9a79dfe8324ec906f12359a6992c46b7df2ce2b3708a99c3553cac6261f6e797d0989123792ab1943407e1636975749fc8a858d52b4faa52e7e673426230c082e1912016a4caa47408ddb7d783f2a7f09a72e74671587ec08e8b720123c2308df435c88c10f9b3516ea595787a102ac0df1693a231a75b37826725b57380cf2e0ceb49b5398aa5474a274410ae02f2cd68380a6506f672fdb2a363263432f42575153827fb7c481bc77a87a65661d305f6f0e4fc75e8861ec7e65f1032ddcd2213716d24a84643c44907e2e14d1bdde5c69b9ea580662b72f722a47876b992a585f55b03e0ffe66f90ab08c45742780afc27817d109ef8ab8c26bc195b089b191d7bf85b29772e60345ea06eef1b4604de2c219bc46e85b9549bc3a7e2969b811bce71fd5fb28a0d3c789882bc30b20422d7331a23ba5a52e411f22006fa04aa7e61a87ae45411d2f5876fe4b972dc5a9b1f9292fe54ffe5884c448cf9641e8835028bbd759a16f09ee532848eba1530117f42142efea5da34502c81858d51834e3756dae7516d35b26222d5f1db9c93c11943a1d72482f69e52c1d07349f2cc3317db3421d3cfebdeca637dcb9c7d11b41aff1edcdcf1d052afb453666e6213765bce3f443a352ecc03b23d79d3247bd866c712919cbb36488f6d116bd2418ea7e25a641f44230e441f0eee9f31f9e21da32ad522606729b4e3e06c56d6e86320355ef73357ca0f7dd7c940b6fcdfbd4cafd83aa59d57fdc4ab7bad347fc3f484fae7dc357b4fd2abd333de14abcf8cff05a5baced2259707d302aaae2175ae06c87bc81b38fb7c06a5afd1986170760ee5e23b5a6539c8b6f79298a64b2f1609c3fbd8fcb04585747ba4482cd17480b173633d944f0276f0c24869e434b9b0db173021d8c790cbc95227ba62c5ef819e48c3582dc878d451f35287c8cc5028f1d86f8d54985de8afcd61299217df182394afc1c29923098631085bdcba34ee2078a5a7b55aa904ae95c686ad5c9a44cb054397d910faa51b7124d51a1f002e95a5f2a97c7a43ab014377d6d0f2a4db7ca4c5161e24e0a42cb4a71553c2b0aa8a665292b839f423408a0c7c0a33538e6a091393034872539a03007092000990cc79b83a10f85090121100cb40221591030000090e067079e8f0684ce0cb7acff764cbc2614683c021825f10a8e4e0beb8a8b60f6a7795589c89bf390471b021907ff3d56d1934c9b2a86438fc423c473896338f4483c42e3afeb4d57216317c725bc44f54785f7b67b5e6a6e9fe56b2a7b74949c1a4fbefb76977aead57dc572b772a5a35ddcd3ac77ea16fadbc53dcd7a9ebe4be75664cee323b9adf93df915e945cb0b1c4e86aa63369d71a4f6c6c853a626959d3fe38ea4155f3e55d28f0b3af89f7a3db6b6dc546c976b36fb4abb45fd76b966b3afb45bd44f7b1345d6c037afeaa8a13496d1c7652d86d21effd858aa58daf8ab21a674e39b1a8e5e0ce6296f24d38e653267857b9a66833bbe1c047bc6b18c7dce598e6dee5cb62ddf748e76a09a31254d9cab4a6b4befcf193fd15e9fce495024f9038ae4a02633e0c4bee2cf66d9f04ee5c0ee2733396283d545d38157fabc163da6b683e8f523c5fa9755a7b018bd3a73a23bf400d4b135cf55ea4a2da1c2a115dda3c5bd35f78755586edb80393a15fe506b0ce3f031b7627b9b4c876ab123119147d762d36a2a7ae65666936ae04f5d7f814969761410be3babeeac9f919fb5c305e57530ae5cde948dbad944292d1445f3c4926cca2de16d924375c2d95e0846d5ff03899a47267a5c0ec65d77917a0ff28b9a7bba4822598c0a11984a73acbcebcd5cd49bcb446a264229ec3d648539e48eb40f2c2c1dd29ddcf586979942e44ce2446e7b88c6ddca9d00b090aa09173f2cc5f6e1264b282c23256fd4e1b90bd2f702dc546a894e9112f616e2e9610c1e6d9a204f1a5a167a4b90f7bfb3e92e1bb5c0cb2e15547de1deb71bc863df6a70388d003c0cc0534522b0bf7851ae94d20bdd2174e5242b1a68d72d28da836cdbef2ad404dfd9e69770d268e6fff5ec00a9636bdaa399aaad66bcf82f6e69a3e2a45df853ef97179f8a4f8e2c87543c9e58096a90066fe7c2fa06fb4d419976d625f884c90d4eb57b472b884f8f89345ef306e91d599515910d83ce726fa8edb493d03c13895b89a983f999e9dc74379b0b64022a4c5b60426b0543b381327be11a2697c4d100a84618d936a2106c091b08e8f72deb98d22bd810bbba610777084ef0da7ca29b93977ae68e495fe76fe50ce3b873cb116740f5a433e4c77d3db90e2ecffead743cdee44691bf5873a3887b0a2cdeec8d78db74a303ab8b508bf9cca56fad27a367d695c7d3874e66d04901c0de40cf729500071d2978018b5f1871d613c02d063b275dbe948f2acd0a6dde5293fa45186d54558f133b0e8f5413367f91d3a3eca67231d1126e48938595b07a3fcb470955e26c527408e81d09111c38afcd99d8c59738ee550031a86f332abd0965ca841fdd2f796afc7c8ad2514da5a2bc11d0eaa6dd5e18aca4167dd50182fccccc4ea6f91d03bdadf6925cd7ba481c800be37c9e4b218001ea267eb0e152132ddfd5f9e9ec8db2aa90eb6ca0fd615b0f7af81f95795ba4008c8ceb901e8403087edfa9dc9be27d9ecb0cf03de90d9c38b2961ebcbcea9b9ddcfb3209a2f486d9b3842c75412e74af50361cf0a7dcb7b62daaf514970fcfce51fe3d5e21e789324f141a5ce14f6a75dfbe98d0204d51253f8a484991abc19c670ee2ac0518ab0380e24d5132377afb9ba57190b5e887f18cbd0a28d76798a4aa4461f76ff3f6eedffaab5277d6d16eb2a4763be229ee2737307beaf18d3b6e6dd8e890805078710b60666ffc7ef06af131db86945a03dd82b06e4039f967d8a59fced39a987a210f9f0d4bbfdbfdcb0b3f99062129bd67be44b121699a03adf7cd6f3c152cd0933cf76a5d11ccc7a2798c747d6fb8122f815b1bb33f577e0e012cbd9e68108038ef2e059b0640eebc554e7b8235b23aad4a86f88ae832b7965bc6be3cfca1905f78c46fb6194d77d592553aab1d654bb2ab44ce2791b48234f43b1691bf5bd5435e2878f68591032588e2c6ec0d1ea12f7d13342d0bd61ebe378f8c40e768d72b05ea148f1a329d0d6ca909d4e90845d08272f45ecf1432abd58dd8aba8757ba2e9aaa0c02a538bd87e927c23d602789eb7cf3d213feb2fbfc6aa080a0b765ab2ce27cfc441cf06d1555600f1dd1feeb61fb41574c92879f6ee0a25b3ca5243d0e3799af9cd50791e31aed4a0eea8316adf4b63f296576fd1315bb4e6654db2f176c535b4556dc669eb9db0fed291c086b5f980d077f338ac6f62db71a79afc7f0892315f87c119414f0f550b12a036d10fb7e2ecfd7c55bea35552f827e81a51138f6aba94b501a46c77a1c5dd7829c44c8bd462ea21b5f737d43b5528739ed04437fbeeb4f1d8947d29105accbec8363234cb6a642b19f0d548e8d55488be77507fa701c4c21316cfb3de1ab88ba3af9172ecb6463cbbc9d1b422697445ec27efffb315e106536b4513af613a5ba9c307e61d5f06d2879c5945f8051e1bb3ed227880b7a8a815a25cb9242e9ce231ab3723c6ac27734560fc32061e248495529adc4adeb1808e0157aeb7f1adc9e6d00ad8734e282ed91274d17b7afaa57b2479917aa57d14dfac17d0cbd64d760b85fa7373291a41c18c717d30f15c0914748184b7f97dd72ea060e42f3135033b28f8eec6327c9bc418f20fa2e48391e6c227427fa6eb9695c95e3984af0df15e2795b25d6647183e3826deaec816059e85f03409468f8ada9caf9c765488926e2b08410db20019fd6ac6835f77d77673237b45726791daf682d77839d652373c42dbd137e5ed370097aef8217a5e558294be1337cbc190df0db5539c3ba7fee1f360a458c40a30eee38fcec2701ea573e3c2147cee59e7b7296ec459fb4aec456ea773b87ff6c55bcf2a5cfade6d286e9b115f152833005f93823acbbd9fa26d1ec47736f7981d0620256975217f928d42619494983eb4736fddb6d8360a7d8e24e8d858a8b78995efcebeabf72dd3bc292455170d7ba73a8535d63ca0216d45370980b993af1343b1c419879cce2e8c5ed28c187e40758993b28c2995af8fbb80126448d080c520e6abacc9efd2a6c383bffa45b5316bcec3c6b72b52a5c030cf29784949ad02b69dbd170674bcd7cf7bdcd8efbd1e8191e33a19569050073c13f8c5128fbd5be0a2e5437be0dfb277927ce6925cd9c6b22c306f58753dbb60be5ea3ca4231ba87a180c048700808636c5c6e198389fd09a3449aaa14d93e61e013a089d879f28d673ed2c94907a68b5d074680d02cba55733398b5156368a579b7921e34cb1cd1b7be359e7389bb418768e1dfcc96357293294a50a8cd0d2dfc826b408b91f9e04e9bde17d038b5e1bff50975e8882b56fbe993aefc82c6afaf896b8641d180117d7d51200446e6768139aacad947c63ae86e2822b3321127895ad1e3a86354522e31604604570303832a536706cc1a1765c3c6b05f77d379c630766e5f7d1569e8e7aa18428919adecb6f893daa8aa16a51161a034aa2095733e58c7b6431ec79982e947b8527cffa7cb9ab439be9e449716303e105f84073ac7560cc2d3b6bcbe17976ed339571474180a5e8800bf8f3d19be711a364ef585ffe34267b93e5a393d7538c4eaf2b6aed39590aa265f72a2b4b58d65c26a5a907ed202cca1bab098fedc4a2eae24582fa5b42b2751194af329c4854f6839b5ce518a8400819b201e44fc162bfe43c83eac5bc0fda3099b0d17c6d2a81511e9eea452c5c6b64a791ecc127b2f8d7955b62e386732eb18c855360eb2c41a1a70be2b4586c70d94fe9b3385a5f67dc31b49ab0c479a273abdcb5f753240075c241fb106e70f0ac410d30166d57fa8fef63e63dcbdcef175e6d985c94da88c25ed4272cd9f9e0cb08bfdd53b5c3497d1511f7d33fc3b356fe90be227c43cb451555c773468279e460884f75482e7c78880fd5817daea93a7caf99b63f1d41d2967a9f244f8b27ab5c62f7500454cb00f0c86f0606f0986f4bd1c4d789e17fba75937f7b1760bfc6b22c2361305eac7c0f54d46d7439376e12c971b9834199462415601b59724c340d25e827a629b38aeb1592601d58524b90c88f019e4bc2ea82a2489b54ec36e42e11bef9422eb7da648fd8c1efccbc799089727855dfb32f8892c60e13594d86e53661c1f014d4c777e0bfd2fee83ec0a9238c21d1281a6b799c029daf93a71912bdc9e602f22d1c5232002ba632537d243388137ae0695b69ee3f47c64b9309290ab4e782cf12616bdf75f070390bbb5e8ba5cfd8e2286e60a846aa39a06b3eecf961b319c68582651d622a2bd6bf0c8f35a65dec558cc3da6166c677631745f63a92a65739f85946ab957c838466ceea90e0f6e4661d0d8cacfcf7690178ba6de9a003f011e377a3ada1e6874593690b7afcbc23ec18f0d7daaaa8f3b20f11c9638b1b42878ef49aa6485c62742ae7c72b212516f1aa7a60ed616d899b7e829e5c14d5bb992cae82119ca09adcfa7031ca2fd5b4b56ae8a760e2116e0d73aade8c9c5120aef7385d51785a6824a8143fc09c1b20c086d307ca71ceccff7e9c8fef0d33dd1eb1e6e8a1ce78c901a4f18ec1ef2110e162cff2751b7a45adb39c0bd66b0b9716d60a9e4384b4e27d09e5221951525e281c8092723c532ce8679c3afc224e8991913d49575d6092d0f56ac7efb6a0bafbb9dc1cd2592b6ca8da4c7b591962fc45c91e9d51f511dc8a0bc9220d7d6a1c6f864ae3dd82b5e1c453d3854ab9a534f0b4331ab3f3e0cb50bdcbfb702f69010e7108352b7632d0d527a2d6033654ca29f7b2d15947f80b3fd18a319dd505b220d7789116bc65a6a97a576b884a1655a45222f04284f6011e9472b56c0b0c97997007a60a1745241bdda63dc7618aa94234e3f1812da97d560eae370e563579919773e3695d983cb769fa1f88a4e0fc49088935d98b7855ea7b65fc584acf21189cccdee2f1a37c63475904dc2a560b84169b6e8d95a9fb346f4fd4083a00cad4499c8aa36184f5bf5d0826cdfda58881a7235a5194f9f1030cb01d2c7ed86e6fd5435edd1e0027f1200219d2826040df02f42a585fd597841bfcf5a93f15560349f319c468825428f6d9aba9542619af97ffe19d1c0c2d927d7617bcd6c5bea71022153d0a7db478ef8869418b6ccb3f8588e67e290b4f64da2a3649a6fcae7c17c1547a335a5a4b9bb7845754dc5404c4690d6002b528e241e61fb042b146c3dccfbee80a2b2b52d8d3f4b728723ef68737591b087afe51b697c9686bfeddc84ba6f9e1cd1b06b3e246b3b2de5bb8c1c03601db0c983fe37a7d30cdddad71a93591bc6995dceb85e4d2b146586bb2811713649d30aec94c987dc0ab13e2bc67e75e2fa9e28c3901045f2341da7ab29413bf2e63e62b260dc2f6abaa8f3a9c4549b0d5399e049289ca0dd80ce4100771964d1b51a51ecf2e0d4bb379cdb2320b23e51aac00000012efc34e3bf2eac34d6e1d11fee8b0c491c46942628c806766fcd16b9a8aaca206fd61f0a93523caa85987cd8bfa82bfc0fae55d3d3957bbf7159a363f048926ffb6697f0ecdf49de984a4f39f2cb0ebd5885293074f89f6f0f307855489d5831aae731b244dcf8df9cb9cb2441333e388f19fb971e4f80add5db9c18f4624a4709013532312b6f138cf4de2d48d437ef4425cbd58fea54e428cf9391a4e9103fb969574713db618ecec0859fce31fa312e8e94464dcbcd61a1a470dfa0446babf93384c616688db3b2a70389b9c193fdd6117aa5a76bf709a133773f84386ddcc31b229f22c632ef3606d1946f9315136104e206668a2254414988ce90c044a68a4d4db57a52b530270a65743744e9fc9cb97e0c6a112382a8186a6678104b146443e16d90a5aa29b82ce730d5a12156964c4f944a21639e2901e7cd9d033a21b68edd838d79a5965bf32d4838bcbbc1328b8c8f84db09553a9dc664e821894692c3cf741ce172d7ca70d2466e8d859ec5c75dbefa8d074bff7750fc6ddf7c5936116bac44de46d96dfd62eb2fabdeb1619a84e77fbeee4b41964e91b8f3a22a2885efcd1511556c7347b535725c50069df269d79299ab1c24bb2cf479d8b7bce4e90982742f498f75a6224f149df400a6d505afa9d141abff488db2a6b0bfee16ed59a884c6711fb617d63b3d268980a5940d712ba85fb3a05e34eaf7da5e138904c953e4e1ddb7b824ec231aeb5f78c69e505925c8a8cd20fb3f27e9d3e0f701449cc210321d1bde8844e9d408be9f40399dc20ebb35e88cd28c0a000c168fd7dd79aa934209708e5bfc3cb3da9d716dbade55a6fc212aa6da952ca91f744e1ee8162283652a43c213aa96dadfada270a26126258299dacc0cdbb19fa0855633811c7eb865a9833604b6e3a61e05945068b274faf2b76818bae713f7c112101d9242136a9895caa666ff78768b2864ffd490318c9a544be127530f7a344612e56543601c683699dc26b918fd788123926713427f47b5ee22d6c2b8f4f0e94654a2ce535807e373a087b71f7727aa5e8f02591a5596d1aff2a0e074abfe05a80a0c9a2e9d52ea92b7a42352d917d210671ada41531cbee281da7bf0ec6860d47736a4cfe3a24f6412cfd6f9f6d2530040b8e815d281ab203a41ec59fc2ac9b73c77e73bef9436d773a83b6997bf2a14fff80840ee720ad88af4be1e6d33e7f2417a8a3de6f453f9f0df735ef0f366598103cf01406759d334e6c53690164457a7dae3e9447433719e0b1b2f7b76a6a6e1761d15d2ad8d2417c8eaf924a6372aca0de401fa6a8d7854da5a02cbca67f3a6508adee43546854ad6fa598facb20f6c4a93ac1298d34b0296bac12f1cdb848c818d249635f09a9ff6b247c8a71b001b04802622f40034d83ab0dae1525653a1e7f46227b7a201722cb98e37d1528b593985915674369153f0d56b4eae78fa1963dee53c4a0c05c3b23e6507ec4320aca7a76d3e53993db2333ae624d777c2538483542e3f153d923b862c174d790ae1d1fb233316e2e90c75b92540499301ddfc85bc7f38057194a349289833ac8500d6a021715b5a9f5f07391a143ec7e235dab00a503c0ce09f1617da85d85b6bbd45e4ce11f6494fe89ee472355697b258a22a6944d2fffcf6d4b28ddb0eac6f50c0c6b5df748f5c175cd42aa247fed2e432373c8e2e26c61f8efd24927428e5b6aa4af6995ab37c4d541c46cdcc443967f7f91475b74e3857b78524a03d19bc12fbad9b1c8305b0b7b2d1e650428be46b698b71ba0e05701608c359814ecfeba50ec63966569ea7c3da46a27fbcc11cfdeeaf3adee4104103482256dd2ddc0876742690a1ec45fe986689666e865fc987f95d3c3a21b7579ec8f68c979e8c3a7235e545a591cf1e86ca5bfb158562019ee47630359e62f55b48ac54984836fc045625b6f38be0ffd27b9b9a3384ebc5e199d26ca630b7dde6c4a21a443b52fe089f54679cf01f584b65b084c60d389064a31b9f38c7bf6f12c8a988983c4a71a24c04c2c96782633cd384b0562fb68df474b96949b4e97e21138f04131b4275d2f12bc6850529a1834c74bbf33fce1a8abcdeefaafd88c4eb4d48c4e73175308dec1349cbe7359b0bd8b0ecacb70d14ab5a8847c918162a8e94787ff36c0346759476a79e93902e165b243472687dbd61096e1516a59ec6c18bdd127dd9d91e9bb292419b3200c8142826bbd6dba56a5ef766663e71b613e37d19f1569ee6035b2042510aff57706741be43891b982dfd9e0114ba37bff094f45a3b5d6ba88959f5f07231f69ddba82139dc64e57cccef2403f580e2af8d1700e58bbbca6cd3f7ac0c7c9be42848e0144363f33aabf278c7acb0524cd893bf63cdcca88081114d6fca16773d188dd07bf771f3ef8c704ee52876eefa00cca3470eb596e75839b674904ff64dabcbfc2e7b3cf4475e794899d12945066c764950f4177efee031de156b706e059930ffdc4a5f72f7063004f733bc9c1e5537fd81cb164037fd0edf74aebbd37382f9be554e21c1c2d064cb2b216850bb7a2bbd519a6f1bad53d2b96eca8e565b6efcc58ae10ae93348ba12091121b87caf7bd979c73c023b7d6af756f9941b3e2b5cedf80a2ffa126974a90acf23ae56488b70cccab458c41afaa253f1c65693a2f894ba1c7fcb3f5533ed1cb12a59412599a05f36df6fc1b097c542cde0be312d5433750cee410d43e552af518bbf7975d40fdc1e4a55c911543f25ab17f5095966f476d4792dc6ab375f632cbd489d867b74f24374e633a42780467afec769f10fbb0352a9724a5966db5265894e4a55e8d05c7de4af2c0d1efc239de2d0826a02bd91d0681dfebfbdaca925dc2003600bb30d7ed040dec08d18f4a68a379f15cb8d4e68a30ab61c4badd1b0dc6b8122667fea8c9b0840fd655fae195796e5104dee4d803b83b48b7d3ded0aca60ff791105cb61a2bfd3ced82a55a471051d8fdf9d42abc6334706f30d2cc1da05afcc83f3ab448f24a86a29cc674f6154ef6d1bb9945d1f3cef1a5f66afbf07c9ebda294afc6350ae6ac459586d4ef614e6d6c869c5f87ac80ed2de211298ae15544e83e964a53ba9146f3debc6cfa444e8b497e4468f1a50d4ad8fbc4ab6a2b373aa6657f390140cd7df6d6708f1f60700903b92af6091e93d3db9d677f7b53fe83786f001923710df74a150e7533a498edaa56ff145269a04d70fa1ff4e477e27f03e7ecdfc1871039e36e9fb85474f64291afac07e5afe344767b3cf37c9c91e150060392695a9d12675e5fc85c92c40ca73b6ae74b11755c074c5308702406aac327faf724afa11c81d26060611bd25c171094e29d3950bf6252038c89fdd7306e411f876c22afec2d4b954c005acb19d155bffb81f40d92733598e3507a1ec23f9465859703a9beff5bd823098fde476d3e3f09a7abf14e436f3a6c7e750fc95357761ba818fe0e755f75e91c66404b840ab4b297d7a816e27a6dafc7141a7b637bbb59e7c1adf55efa20b9812adc97862a23dc5bdbf28917c3688d6cba1a9643b163be024016a8a9907dc8a93c57eb5762e15cc24827d039c34eae502b928a37b292554dbc116940e0065aeb53da592fc934294a9c81c5caf02c1730b5e45dc999d084957aa44542d87d842e7ff03aa25f01060f4ba3fb84e0dc806a34c7066fe481afae0b3e06be46c4e82ca83d0cf724cffc582f135bc4d78f20e948c6e9dda81531218095a06385923152f9552208a53488eaac189870aa9274b78a7a1eac7aaa91b255de68193b2b0085676704fbfab1d22ed2058cde878d3c6fb050b1776bc528d2646b41a5273938bac0ec73950173972cd2b383aec57f204d76c2dc24c94527e76c5bed3cd139421296296f326c69d63c8859bab416c1f8e6c35264e2db1ba084fd87f2708f5254c6f7fcaac3a76dd615f775277a9fc20a7edecbebc7783e1138fcd0b89c86768700074b075c3afdc0303eeeff13e93c580abe1ecc384934fae620305edd1903378acc3443ae82344632a409b47682a2c1789b21d7df6c557638a951cc9a98af09ffa8475dd2d7440a9e6adec4d39a614ac259b5c23d88985795d49ba1599793d4652580868e366012076a71a5e824aecbb9704d80fefba15f030a8e878f9c0d7cde6545869c2b5dc40ea5cc3c57bf860ad0a965b6234b9f899811fc2c1590168a285272bb6b170a4eee01046216b54a9c4657c4578406833864e91f1963f2786a6b71ada7358ac1059a6083241214de5cc6bb6423b0134bb30721a5906ab0009f431e26f1202057bf88738adad092aae2e12542c81ddededeecfe7a386f1a33c038f62efcff4391dae934ac1461c16f159d6f7439ab2fd251b66a040dd9269ce600769810a1363142c70917a0aee1152b413ff0741b03cd64fe94bfeaa0b2ab7fc6c465bc391f3599472ac7b9309ae5c28822cd908297517cc5fd5f4a13b0ed6db1a8e9c996f0d860b54beb1507de974065da4e1bc0fbd329558b7e6c5dbf85f275393067f0f32a35b9a2a57ed48288e102519d0c98efc259d93573454a2cc8a5a9b7548d5980b1824a79fc2cb88a21ffb7b906ca77265cf182ac7926f91023980265b7aea05ef46139a638734692b9334f12c06fbb664931c5d31508d94a7fdade00705df1c260e7e05cf510d60ff034a9e82ef35de9e7f246ed083fb703d7000a55255d5eed0110f83ea6fef3cdc64e73872fb9fab8eb78dc77a590ac443370f59f3fa819964780bd4d9e000413f304ca8aeee5b05d73c9f89ac2b459c128865e9159674dd68823545f1e7736988f2940b4509c9bf07fdd3ce3b4f29e359d4ba81b4c6ba1ca9e1b16edbb7d0ccc77f422d73abf05c6c3f407cfb2c23405d1ef781b19078005ff85a56cf156e9810303371aea0893f5ac9864dcc694fb9e004249e10bb38af544959d74140510ca91c878d154b030097f576b698e81a6860a47df267f29d4981a714d953624704a8061a868a22e8a7830f1b1304250b6565c5772f275f82a4679911084b5dad8a85a009f562caae58ed4104c299db9e5853dc442df7219ecb7f96849d01dd24ccd4b82519837308eb74ee3b3b5405de9b7d5074ef6727700ef1da39716f9e6faa305375cd49879859bb2d421d7aa7254aa4b333e18041a3afecb79cff360cf2731f949d2895704d0b1b47ec19e69f59347b4ca7ef44521ae905b501589c9ac1a96d41e01a427431ac346e733aee3ae40dd4df1980ca246e1b07ddb0ec5da0c22894cf98a25809fbffdb31f8454c1c6bc46e21fa6c4f38254c070ceb86697cf77ef578fea2fbf35ad9a9b0c50e8748600612619d943b1303b7de8c9c8166cfea24e822718b0eba5c0e16ce76ff5d7fefa20244cd4b747ba41b7fb2b081c4cc541d71b3166a96d1a02ade1ff84fb25153e8c08cae18bb0fc952eddc99e13978c0eff5fa2869387de1201f2bb4ad05200648d044ee07594f98ca1a414e7e912a44739cfcc164336e2d63e4e258b8f28235712dac793e9ed58b663d986ff406746a704312641f677109ddd5c31b2498a51611875ec76dfe7a4dd94f527c582e8f14328da6d864bbf75af5c468bc1f54857ec312226f72e0bd7c8091df3489f47ebfdea5e8e3ff473205510019054035dd8094e4e6a8a9b9bbe956d39a9e274fdc0bde732c126d85f9e3635e5dbe4c7e8b795d222176ce6372bbd2c6ae5adf9be2cc8798e8857ee061744a2863eed1d3d141c0bb0c6fd00cf3187d41de7ba0ece78ff29d8607755b131882a1f05d4dba3b853278ae15cf4f82d6f33d5ad1990d801f848b2af3f34b2836410b33548ff97bb49444e291b629041df947fe304c80f81c7e1ce491cc57b312f3a553d36c3300c9d82a13fdcada6a2145668d83c4b046ac62376a3d5a2facea1a1adfdae99140246bb837fcf399ea9f032dfce7b8104241702607b9a14684c7621addd03bda53250aa94e930cd4c7e05739fa7d973631ff142c9c4ff290553fb81d1b1714574878456ae22b5be1f12c5cb64e350d1350e2d4066834350c3166d1456c47dff7018c5928074f605190bf3cbdc6dd0740b03c2e95fde41422da9e3887b42e752f5c72f8299244ea7a23ade16fc3c1452514ca07213f577cc0551f9dc6ef4e6e7c5f1458046a795d9a824f5e1fe4083eea8a5d4877f9f42fb81de5ca9f9d11cd56091c945d4635834b1deaaca245bcc70569ae793ea876122c8c9b8fea15048ce210b28fc4773aa0134d676b2a242186e06a1242f97e53a3e8fc9bcb7fc42f2f1cf3cbbced552447e87b52a4bda88af38e13ea2b4fc3537e02dee95eefcc6c54543c7b17376ecdf772222b7b3d7da358edc4378425545eb0a036a7f75b967714b78dafed67b0fe1085624e1874f33724432ca20bb82b27bc2d14b82c77ee0b39f406f326be02c0f75c23762c015480e8e045b92d14131ff2d213979c34e8a408590c756f90db9e8f9a80f19d4fcc30e24b71333458febbf055966f784525e059a19665a2887c14fe03c306fa8831c9785683ca64e4f6cb54e0203bee472672a190f8acf4cccf9d905c79f498d5ac7587b2a7ad48aa0d4907e1cf87a6a50f1fe35e5a742f509cd88a48fc46f3c7726f9487cb898a9250725a47b78294e9d71bbfa8fa5e7ca2edd81193cb5109a2f90166ad7dd2bda9f161c746958d8538abdc3bbb155d2e21cde1b4f57f3b3154e5d0a7375b7804c512d8fc10d9f6c9027f9d7a9f000e11e82e331c50ac4db1bad91c915324ebf5d1a84125270fa9f49d740b2c2b50a72fffaf425c1d70850bc88919796a671882abb224c812e3857e0de577ef73fad7efb1a29fa0f27127ddd5d11193cfa7e4c309a26e225614dbc83ed2d6c53a2d7f03794c2de9807a8bfaf1cfded1538445a14af87126f4b0e93e6eba74faf23e06cdc3fa615d3fd368653a3611e81a601af1bb51e950922056631542f254481bf28f7a5c781fddf6e86e02abbf6a001276c6143ac060b0fbce97b322b968ab06d16835d988ef318c8b802a0cc28a8229d72d06612b691476da5eb5f8a5b016a77a7d4758164886fcb14d1962c71b7bc4f1df60cc0fc361f83d6d011fa644dd50b044c2a27d6817c62c6a4a1c9c0549203120809f387772e4b816cd5f2d956066a13762e90cc35d5b517d23975031804df5768e6eb54cd4e0ac9228132d2fd38dd2595ddfc2e57ce258c731a425d19145988201eb6cc0db6f96320a12859dff292294a0d9fb54125e1bae44165886f7ae1da6a25eb35f432cee6cc94bc5cf48a5f3daa69ddb4539281a08fa935eeda1d574052c35d166b742789288442ba884a6aac56b427315ac024b9e78057862c675f25e04cd4e8ec3902b3ee12542c107be03076d58dea0f5908842b087564738a6e9f02406b6c05f81260efeadcb0037ddf80b8b57063b261a5a04f3d009b9a96ab2fb911423efb19d538974aa2247103a0a748db3c437bc8fb3498c74707ba7f6cd99c370db7122190414dd44ea570a5ac1f5cd140cbabc53016d06b9974830b96be651e12a5035c3094a4056146d0d46bebf6f68bfeb9c3e3ea5a56fe209eab8c0464de015021badd069030399960c982634e33f4005bcd66617e7b79b363201c6de67063bd0ed070c15fc2dd12170ce7e57ae0b94725edcd8c6d3e4864a1c3ae40e345576915f47b8451fac010adc001d29c1c4ac2a26b17073410b9f5bc557cb85c8525582128e9338c65184e88f8d17491da8cc01764ec1f7c905c0ca42a3085e113a1ba5c9045f960f0acf9704d07321bc7ae3c733ce9f843d55fb9430cd70f4c5b2c8a9e9985f941c2fa2336e70e687788a871d1dac23950b3c6d538fd5c7b2966ebac866d6d586f2c2b2964ced672ff04f64f35f6f51ef97b1c23950d33564c84604dd553747a9e9f2d90037af987143ccdfa20822eefc72bed314e942948a1cc3042941dd599c92ceb743dc40fa1fa5621b6cda6f4f82f9033a94f3b3ce5fdd3633695d78eb1357cf89816a06608081581e620f7eed8e1b08297c47b224a037d5c2e5c63c60d8f59e423b3af33e7558718b1f06064e4544c68a06fe56a309cf1741844b63901275067aaeb246d1a30fae96fb2c5f101c9b91c265d695a5d03e2bc52b3e1634f58d337c905e38b89c39750e3c92a15365a7b00b0cf3f1e48fefef5d9da03ffcbb3cf10e480d5b7b72fdde285d2698c5a0d27dd2a080e6eb48fe70ce31d6b97a935bc0d3e509b0b61657b163d572e86bd21c0556070577403208215cac7cd6e10a5f24f1194d1e9f6de22cecf09ba8e5a1c35720ac6ce3d083464a2b8ec00a2fa409130c0f7a48c7b0cce9a1d237d1068356ac1d343c0afb17a779d289b036afd1fcfe427ff71110e0bab36a6a7c422a6b47a222e780ea8238d08b5180ce77274de1e69c9d1ba7affdb9db898022faf42e272aaef21ee7731a01ed8a2fa0b103ae17008bfa43f5558485273c97c11351f960b98a74025c50fd551579ba3381b0651cbe9c20c79d923d6482caa76a8126227eba03a189b840d3fa540631a8535af62baa5a0d4de468c81c178597272ce8ed4155d2834ca82d73e83f2845126df61cf127e8fbc991849b7ea9c5a7bb959ceefbb77942fee544aa1b1c461146c178559e9cf75bd5fdacf71d8e27c596225b0c649a7601f2be1016e5dc4b8d244d9e2bd358d21729f828b95e7028e98429182dc09509a9e3f02e376a61fb109683d1d0c84c125f3b803335c337eb136dfe4cb8f77c491ecaeb4f1ac4694e69c5154841832b04fa3fcb2c88acc0b8894a44da2083328ca24f4f3fd18e6886e5832a4ec4f1386bf9123d5a8895b49e3fdddd859b7937e49e9c3f63373cef913c1e622b6bb8938a153de04deeb8fc3a96e3f9e062cef1102ff3256cbdb213a7c8c03b272e9c45ff3e4d45183f123ea026c12844e86c2c5a5bb4780da3009fde1a05404de9c2b615da476e0019cdce14b3713eb5c6cfbb0c2791ede221971601f60632008256d4fdd45b676c7f85317e29a4cc48d769378530407889e97ab9b91ce9b915cd583cec5b5eb70a0136b1d56f4718df0f7effd80f7d752a70aab947a5f86ad50738653962d228eaad2625b266124c41ea338838181faaf04add9969a4ed54b519c833a171fc4a5562c828fb88b30c621c95fba06fce950c38131df6349921516bfef48661a5970ede7913cbaeb45a1e64e6778e9c9e69c5ea32511e783abd4bb71e074b90a893ccdeacf21ff5d52e79d1e8feb6360eb45647c37baa7b442f16cc5b91d91a80e247364d1fe80bb44eee96a955ae6c02e86cd350ca2c41d83464c008d0ec82ef3017a986e9752ece0b282665508c1f62c51a0af723b878064f44f340aed822fbaf5ce62996c54093a1560c2014459af40df6372eb041cffbbb6004da8272074e5cdd2215f935da9d26211e2fcf1a3ba228f861f1b740127564eb7cd6fb59d7ed067c4576221f99a0b7f68a7297f092ba964b8346bbecde046971925704faa46360a03370a2bbc505398485f0e01d82784de4a69c0b909e25c15b9c4f57940cc741a6a8f3fc87e98e30c20be8464a33822f615b63fd18bfb20e888b01477cf9b1b5f75d938011e3ba2f5e94baeddb43038e6e79c85b8df1e574af54fa8c5da0348e98829bd8580e0b3625c6581640fa88400f696acb542b603989a35b4a4dcccab0a38a5be83b1ba52d4b8f907e8deac1bd403783601c97590519cb2003230647d5fa0ca49b37e9648a81249fda16613feec9c07afa6dfa1e45336286beb4494834317faf8dea8ed32d467b277401fdba7e2f24836762e398a502dd755bfdf3034f8b5db8246943ed4218f6303fabc2b99f3203612468a44d85adc300f41f0fad6c210f78e4211f66662968ab6825a52b911f5d9ddb20a098f5d2d37864066203e76ac5082f64c4ec1e21765390deb7d045c252b1174871ae4f9281d4ed710300d270c2e2724c478222ee1560cfeef7abf823102b27913a7436bfe33978ed6794c74150341194cb1bb1b4bb06b02bf2fa888f9f249254cb321e982c5395e2b77fb6914f6f762d23d1afef9cd0e37a611400efa813ee9589313c00a9c5d1dd7eba2ee8b4a84fb7312399f37c48ca83b9cb47da332cdcb1f37ad82e6eeb3dec960dd65b6b17d4ab8103bb83156b6ce1964b3fd775cee91b45a145c3ca6645ce69c2120a2f38ebd5b44811905354cc3771adc67f208e8e38b20954a0ec76d3d81007f19eb34a1bdaf3c444b74eae2e9c7b9dab83aabf213bfb157e8b095c2cd583fd62fe9e8bfca5eb17433bd52072ab0f09c71f4f81149e14e5e07d116a89beedb36121cebbb42139e0d876551aa78b3b2a251a15036667df500eb8db4ac9330f0bdd1977074d8508206e4d28434550f0f0f60b383b556d5cbcf56f5ad20fe485b9b8839987f20aefce0914bd13ef2372c1dd82a0b404f50c987818495da5c950ed692228a1147582080c5030760bb19c14f701c63234b62373b46a4d8cde2bf4c900a49ffd161eda956d80da8204d1853e5c2dd41645af969e5486e300378a083593689ba701667c070755b926de7c245d868d2840ddd2348c6d69c581f6d4a54110d50a95a1e67b5f44534b9f19723a916c66b8f9dfd976206f3c5c1bb34057e5fc3dfb64ec0c2638d2f584ca28b0b9adc1b599b50149817fbc480ab071198a41c90c0b3df9bc988320733c8b01831e783402fba45b44aec41eef6af71596a25084c7c9100e0347f4edb38d02a12f39bfe30dfcdb20cf14d0aa346ad47fb71b6f3a13174c297ea0a781133c6be8e4bd93de6982879491660a5618af77b12cf3f7f0cded4129a1d402034ae6c2cc7c1a28018596c25ae4395fa2c5920fbc83225c67501a8dd8c57545572c3baba0c3dd54c876517de2dafeac88f31784ed14ca155ca79010528598889c914920748d3fd5d90fd5b2c3c8feed4bda44f3b7f5da26e269b044c0e543581cbef1bd86cea11bc5ee0c6272b1a7faa004893127e78e8ab3d87a5d430df5097d4e9e03e58d0b844889253c596e9df5ac031d9a62d31e146a3335a39bd17eb76f30bf85c2548964a46af01ac45779b9dee3aa1a749fe465e46e10cd174ad330a62e7cc79a55450f8c625a4b3822adfc94584d11cbb27b4eb3441118d72f51b7a973faed90ec24795967f25d94ed82a40a21af3c170be76ac2eea573c4fc530ef49946eeb5a9553c2b5766236b6a8278bf0f0f96f61b5c18e1dbf67ba43c965bfa58c49a3703aa85a4586fbb6295d4d43f2868772ab2dacbe7a6c11715191aa7cd3ca8ed2486a048d5e5ec302471b9e51aba28465053c864482211c98da82b9da1a8fd6ddb02f58e66d5adeb4a4fb344183a28dd83036eddd83229898b1071310f3cf6a6c33fd042acf4afe0bcf081860907b7fb67a28bc651c11e51a42ac01f3a01b676545f3771545608ae7153ca05b9545f0e5612e1c0ae1f85cc2229b510e1f0f7c45652ecc48c1602a57100a73996eafa82981e0a310f7a3ca0b9607c45230245aa94138b2e004142e226a8165f5891f5185e388408dcf6919094ce684a170d641479a29022637d50da92eb71ee1798980ba54c49206050a2db4017143cf857e438613c2935809e8c1bc53e41400f96a9f55dc938c95609d96025a1037308c32b39cd73f6299cfdecceb452586ce21b9888dd436ae7a3bd072a6de0513c161a0dc6d3290ce840ef04af0ed84f430db5342ea0403066991ff087bf6129af0ccda6dfcb668e0627a2172b30ceb5e98b1c2040ac5429718b91830af7d40d99745cb072ebc20982342ec622a6893bc1ad07e84ae0642e364304c1f4ce439a224af16e95418e2370429f955c8a7dea613e91780a0488a92188e78a3a86d4313ee1474e3582d58e90c2587f13f044650e99b74238cd4015cf8cbc4124125de5bb92581eef2272047a2ce588abe99096cd76f429563274205025cc42a93a9a406f9ef98e8b2196d373839fcfc222cecc337500e71aababd5c5462ee05f1019ba60a6458ccc11aeb2f24399b32897be0b2afb3e8aa948edc815279e750150d187f8b10202d80ec76c54b452cca49cee209226503ad7c27c9af8c01bc69f6134a0a013060ca0fb000103584c486e53bb632ab7ee0a98c42913780981c6ef23c9aa0e44a5f2a25b239901dc51b0baae262dedfb48529c58ce1792b288135283897029285e742616cc493c02ed6b934e50064be45362c6a2951a71529642e4a76d29247c46a96dc583f52a4ea6011f84b8f81d4ffb499216028c149671193c9f031ca7ca1b8178b3aa0df275456959de2c02a4863006a399eb65ca44c04c1dccab5b0f037e6f753fb1720a46f6e80cf40cfd46ef9be74a5814a9c152065a5d7b9044863319741767d2c5d7fa7e7b1bb0ff242ab3d6fd786fa9ee1f2aedc56fb92ffea7f336d5f45b07cb667d6f228aa177572661fa1c3414e914d7064d0b770a63fd0f74d7a510681e3ced74c8a57c04862f2ebdc0b7bbb8c792823e74319c11ca38a367f6f10496251740b98f6d7bd2270be3b74d1aede6004513c895768f0bdebe6b0315ae35029cf10e12d8f17a3aebd46de913b019c30aa72d4b26c9389e93a3ea1e91fdf02189a0a39fa4f61027dfa0f40c54b436688198cc4030ae58505b403c175d8e68fb704a526553b2fc810b6a9f8ad74a836449299283a48d17a2d53c15d0c32657fa4e2781cd06f2644c3ad72416cbe2da9a4e52d29a08f4ea9c9bdb746299de22530b9cac07ca78d1f15dfd380928f98efad228fb358c5a094c2cf7941f88bc49387f7a1a76d6ac4a01445406d69e1d6e4d2ba9b3d788b792d240f6626449c121f853a6e658cbce46ed00a20c06925fa0e649e2481d7aea5692a476c2ae5f97c3c9665c91d747d50f25a96147023f56d3398c4234c0d14967a74c9eb9ceba8cec9cb80cf6101ebdd9a712a48e5c79934c1c7102a713d74a83a939f37951656185125da0114a2d66e851f914d94e1f6b074b714c882d4e804d8bf13409152621896d049c4ef82e356315be915d0b0aab4b8fa70062a94681a967bd5085453b6c897dde629cdb34a32c8178166043b4771b923c39874f273c5559d3836bb360f2ff2fc5decf02f82df392ed8c18047a0c9b9657401c59a5034d6aa86b838ae808eb46c3cbcb4a8a1baf2660e6781f5041d792e00cf247d4e12027b1c02ff18fc5e3442976d4347a20f2f7ed00b6b0724b28287080bf02627b89be18ab35852e3fd95bee2df79632a59402570956095e0941a8f6f83d477bccc2384158a73d7e16de619ef6bc1b4daabbd1fc8a9b1b38243becd81d8b8dda1d4b3f90daa92595fbbf3d4e55961716992160d501a484a3bbd7ddbd1f63c7ed74c4e662c70fbb1722942b9c01a23d5662b584559a16160695413637d5c7f7e37a6c08d4471348b0aa1ba56e1350abeac3f307518acc16d752798570b89494966c7cb8c15ec31efb89410c4ac833dadbf678fbe00751aad646c3dcb5a4e8ff3ff38582b930684c8c0ae8b740324340388c7f0c7c2015761fd71cedc5c06020864a758166c4c090895d84eea9807eb2cef84207a91fa38c403fd92d5bb6e439838c0c1b26c4c0c93221064d6a3f47e99c362d138a50d2aee34522684c6b39bc1f8ae3f35ce4c82e0c3af41c7ef2e1306d6ddaa5f9cc2e1f4556a962dcb74f3e9995f964aafc2a9f371a1f40158eb042e5ef0154e1882ac06faf89a01b1729a11fe7e0c4203a3b6d8aecd3a6223fe558156d3e1b1769afebd5310fc742786708517bddd31e12daddad9395607f621ca961fc2bd6516c0df409847f3d6f97acc21155e841b5de2fefe7b782e4340c0994453e902a6770a4aaa89b04064475b62639961af2b7dfba6f7b2904fcf819801fa3e4263b33cbdf7efa46e3fedbd649c9d1d8ba3ddc6aba6e9d748bfb686cd511047c9901f8d1371a67f9d66b1c8f1e307e50e5ca4a9cf0c31d4b0d18a3b63edac14f68dcf5b34ddd75fa0764665c57ad4d9f0846d0a859b19fdcfc6c07d7f0d71aaf2ef7053fc6619c6695e80952dbc64708b900688baa0f6f8baa8f367dde0f2ffef05b72858684a6106d0c68414e769f7741644035769d6aafbbc86894d2d604ffcb94644b2a674c2a7fa4d59eb2df328e9652a846371a122dc5d49742e4a978845252eca9fc11076bfac8b331e0c329547ea8da18fe8e838de1382d710831b530fdfd31087b5a150de380cca0d0228a8d261e69af632afeb4c712d482a099ac4b299ac1382033a316d014275cf44f214a8172a4f6a714b569d67ecad3a6227dc252a2b4699910a448ed20a924d48feed4d6789810840af5a33db529aaf6432f52fbd90ab5bd489b6878a1c991fe986a137fb758274f5aa23273a6a43269958286da29440bd382ca249dca5bb4c4caaa72fb9461776e34bcd590368d995d9b19d73b2b2043ceccbc41cbb856820c2750cd4c00681957803210613533536818c772237becb1ee07087666b24e5a6f61d0fa941dc1bf361afe8c033233e7460387ca10fef3f7b7e06f8fffdb2248c2c18a13452b44fba286279542e4a898624e214a11798e4c959470d4be60981a6d3490b94925110f218528a52842879c96714066b4cdeadac7a789f639a510a510b56907147eb47840e1c714a26da361390d39826a450a068e3b8c56692dca97f3e0c11f32c228e3c26e310c0bbe8d52a84a2965b42a74d3780556200c509b8e428b9b0d7febb30c7bd8c1d8d1309048985c87d1da6d2995b699444dbea797761a8e2070cc1d3a94353c6e8cc516328682196756c402f6545a1b164c6a7c8e362c7b927198f82d6afc99056ae32799e1d009b5f824140b78f65b27137b6ca38144529cc5dd7a9b36758defc3508d7fd3a6adc6f781d3271c786eb46993102154e36f8c43352621c20c35a5061a54b74a6dfa6464da6411c163e21a3d2fad371b8c6dfd52ab2182a7f633a0df6bbcfb780514e857eb593e734b8348cecfa4742cfc3bd3d230f1fb594a4574856aac0bf403853ae1e89993c1d598465df69ffc4afd32ed45ceb0fd8d0fb936f79539584bde7d250ae5c79711b3ee9312eb829a46d6e0975922060b3572fc65ae70a3d9bfaeab8755fbd9d2593961862218e1e51bad5883406d22824a5ab54488c9aa49756ca8b67758909fa4a4b4e4a224a57ff4aea6e37f95019326d0c049857ffdb4b41a395428d49e7358940b2bc2822e28f4c3824a5851ec1a2b1a029439c929a29a507690682b1c9f251b8368246463745c03fd4ab5e58f24c52945214031a70605050505711dfdf8e867f433fa19fd348150e013089dd0f82ae427f94d1da6234b8c5d4dd7756e2b50fd4a1fc6d8928d01050bbad840b1a2367da31f27436dfab0a0daa64f6bd226abfb78095c059564e4c0f159c244427eba09aa27c89fe8c0231ba36bccc6f0df8701ab9494964aff5894f65ab5867dd1327dca5005581eb034ac0e5dd3d6cf0585609388d3a6ad2b92a090a87e50280af9097b9f120fddd1a95891105624841509614542589150ed9f2d7dda8529c1f84ad6f72990d0d8b996c208651902d6eb77a4d4abeb86e0ea2c365887afecc115624551b29e362d2472385a0120b5b5459dbdca522565e9ab37a442214180a2547e08a54ffe0389dae44f8654fff1d3a6a461fa6194fa49d50f8e0705a99f54b9aa4621f5932a177a5279c0fa49d50acaeadd06245544a0ec2b77d2275eb9af34d2ca4f9249af9834a9ed9d54b5e70495aadacc2c35dad3d23e4575afd7c235f97acbce31ff4624bfc084142a10862098801c21d114826a1b86044c1a5b7797f9889f60a359de76c0ca2af605ef33c993c84049fd34920a5ada189ed09cfc9d6a2fe5087377bb7569d2f3164208bd97f6766be1be967fa1d134d63238e784737a4f9e0b002a9bbb178ebe1f55bb2a771f067a343684c9bc0be1ee2e1f3119a7ee4fd6da856f8d1c6abb0c8cdc2318fb62c28d868cca355d93ca3d72997dc1cf705413ebfe072b3b43134ce6dfdddd7d1e730231b9951a98fd33a586bb8606fc80689d5703636220f38ccc9ec3f07b0ed35b03fc1d766e3d8dac7a036464a275913e996d5e1a6f0da0c15a6f0df07577f79855f8341ba091d5d8d1c82aec640ddfe098c004328566b71aae15db6abc9fd9728fe0be803f533ecc01eb30b00134b6ddb66ddbb8e508bedc17fcb093fb627966a3f8355617596a645c61f771a07a072432b6056b81662c908c4c4ccc27298cf1e1439aef61b15583a2502867abdd070b04b94f4685058041f1a9a8cc1b6b9592ea93ba47d1a974322ad7a74f9f761f7cb9b5b4ed4d8ee1a72208192a394a8c800e81521a3ac14a79002bc24a318f8a076ea5d8dd1948b30e6cdbf82355dfb2ff38fbcfe573f76d5eb71f8db0d1c68df148d1b29fd9b6a56853725cb36dc4f1d07e87085075b4fd7cec33f9d9dc362ee35a25c7dde70fbfca8de6f28beb7712b30164b0240cb51f921ac888ad1f6440fe1613343efbf72e910405ec406d6821a5b4ff7ffe9fe7540f52bb47f18be23f5f416595ff1ca706b15eb7fcd7515cfe6b282cfff5131cfe6b272cfeeb26b499d41bbef40c2b7fd2530ee3df7d52b2e83e4971e83ecad25597aea553c1f1d8c14f549757f11d876384c70e0e39b8488d2f69e9bd158a9129452fa646201c590e28ff481dcaf1f725462bc09297a000ea26e98952b5ba497a9ef044293681536364d9b3862b87ba497aac50b3ba497a80ea47df7188648bb258c4e8945a3c174ca4ea57eae1a99f2cb5782e586eacdf7aa35133d8533f5d7f713972c67ac9e19c4066c6fa1c3983619d7c8bbb84304018ea764458e0ff58a0190f58ef810b9aa0f73f7cc8b2ddcdf5b073c0ce5c1dec8884113c3b9b3da19ba4278911d5882223786adf68d4ccf5cb3972e672225767fd0cb77c54b83a7a7485dd105ef751d4dd6c08a06e47c403d004bdfd89279a87dd7de28919eb67f42e11eb77834002662cd8643eacccbcdb3cbaf200fff3e6aefb6d639f78a2eeb7ff7202eaba9018b8691ba669cd3cfc4b0e1a6764885e800bccc5bfe4b0c11d366e67608aa67170ebac59832e40a62c4052c8b13460f4dbe3186d1ac5d97e1d66ce8c36ba332a2a9a06d999b93789f1c298ac2f171861ee8b1149b9d6d68cecd4b0aaa2011a356e67247703f2ee1025c7d280edb5c7b17538f6572481eed8a21daa406680cc348cdd45391cedd761b2154be88e2daa3bb35b00eb5fe376e62bd58e9f082ab461807a5dfe71832fdd728fee0e37292f2b4277ac2390ce5c3f19b96ec01d206cc73a5e1808fb19e38c400819422831ffeec3c10ad0c18d0690daf01301b481a25a0cf02a35df8c0cd197bbcb3892dd101de10be6be1881f306dc010437188542cdeee17780e3562055ca3935de6cf8134fc036c1eb391c394676c8541d3dbc62ef55203333fb1dfc44bdba8fe54f0e67fe098cec90a93d0af04519a7a6fdac19f7411b28ea650463e62c8eb06e888634aa925004505bb2afb6e00f1879ab1102589b5044aafa03a9bed10072bd37b7555e3fe525ff5a40e415cc6d1364ee8757d70e7958df43561d623fd4e010adf95f7f753bbc5a9c77ac04d609eb3eb709c61afeb0fbfafd757847b7e60a37c6d67dd13098b10b40ea8c0be02758877ed81af3302f8dbf72a759431472edb831e47335200a8542799f05ad8f97f53e44f34787eca3f8d1b2de2b854198d7cb68af5d78edb53cb3ec01a1a4bb25217c3ca11fcdbe40799c6842e061ff8650a88b66f8d4fe1e96348a397272ae81b2dce872388c8d9f586e581fdfea56467bd06ae293b9212303d5ed635005e5e0097273c3c92aa877c002e523282f510579ca080a85b0b02f1aaa82b8fb7c055705d45ecac687950e4cb54fefd00faf40a140f9637c62627c66dc2006861207f88ceb388c11f4f33c1730c5861c42386ed0a4f6ff20b516270bc4a8ea9c0d0de8b74238a4ecbeb2b7c0728173bdf594f41332fce5766c0ce54ef0332516d08f961c87d2dea1df29a9e3116b0fe8797ea2eeb487ae9494963cef064a6abf0b4a7a2162bd153b87abe4a5cadcc0c77321c348fcbeae9494eec7ceeb625c7c5efddaa797997ef85297d755e27f5e75a6b104cf8a15ee34eb5a0a285c72839c35800c24b2b1818c8c5dd2d2f242499cd338d356b550efd03f474470102ae4b58a4914e8078988fcd4290a89a01316a67f0ab51f422cd4feed145ca2d4aaa07de13fa331d02fa63f0686ce11cce3a9940d98d47e12f370cf9196f6f9096a1ff6f1e998a791d49e1dc64099e3d8c8bee06ebb4eb54f917dd1df3e9e6a1f504f31ed213d3ab47d8aa0804a2d42993846a0e5befbf19d0b828bd68be91dfaad15d0fe98527bdd92a25fa9768b57656c80c4732103f680cad8786df2aa8b986f81482e607847d08fb65092ea0ca8920f9edaff83717e46febe7cbcde39bbb3b35bd6655dd6657d24f6c12324f493130af493ac533471e2177110d53bf44726e8d7a81944295cf9093eef34aa73604e9b36890d70bcc8a3c0203b38392838e427f8b917a16007fb29498b443089a5a4170d3e2cf50efdce5123e8b741362a3ef4a3dd433fda4ff0b1ee70e3c68dcbdbf5f8d104fa2d51853e7e445ed5554dd1b2113a840e1dc2e8cf6cb1c51633e4d8fd10c2478fd16ae5a44faf1d3179665fbe4e82f28eacbd931354fb3988d45a361ed25e0eed6f54fd78679f0a1b2423538354ed97d1dcd606baa46196896c429d949e3c9486d91948446998ad5f4cb743e19391b2063cb55f2bb5b82019f13fc1cfc4df1722f067f4f70efdd00a9448cecfc08ec57f67b486e9e7aed44fd400a7f6574a3224480a1a3ca9fd90af50bf171c46f96f6135d3a44d49789ed41e5d370031151a5e48b5377b89aa6ea5d105559b3609d5111a5e106a138b3f57ef687841a836f790f95242886dcfdd273ffb091bfea6bdbf3f16358c06cbb0cbb25efa46935dd7635987310d6661dad5ad18e20a64df4829e5753dbc2e79b3cb06f99765f9d8eeb386905d6d4198d9c81e7ec3ccba2c0b01ebf166c3b20182bda017205ce5d06f819c33c618082d26470c0cd7bae681339343d2bd2a391eb0e70839b164458bd4e2dff2e38493961f27be90433f599ba7bdee69987e24a5235da4f68f8ea09faf8278783ece09ea39420e5cc92f9464dafb78957886c3b48cf6188657bade2fae93d19e8c1a28a93d1995f74ca84dedca9440d900b486d41e775df282f2fb699dd9f7936086bdf512ebf6a7647975b03dcbea2474c2dc976f1255fef8cd3c290e82d7d87d18a82d44ed15df0756b5bbcf6d92403f1ed29e0f961fed71cc981ffb2c20e9eccc13b11fede1c081a33dfe6faa3255946f3a61ae2aff0a1b1f78f88d48c19a98a7bd9ca8e327ed3bee7447f8dbdb1c4b8dee1aff0a6790aaf24714d0fe9616d0cf547142959f8d984b2a3f3f0e3fcdd5e439e4dd0cb2805ebe97ca1e84bad48c8808b4e3ef4994994025e9d7a3420c426d463f18e85729ff7aa95d97aa665cc961fac140ad8ec22ca0dc3b3648742c35e25bb1639cce870fbcc347daf4d3a6edfb19499b2eedfb398897fcc0ba1f8cfafe8de31f8d6325ed45ac931de3b4d747da4302d41ea94eee6321b57985a494524aa1fac5f82765b2ce3af3ccd999a5863fac3a60072386bb9413da16002208217ab87011e339bcfbc10240e040c20ab5f7799facaacc06d843771fd5b2acee83944919bc4a15a324d8a6d39cdc4bc3f43563bd0c1af672ba7bf7612f7f4ae87ef9c5995f9957a16c21493a3babfba15acfde668345e5eda011d7c377cee6c2ded280b819f05b21dac3be078d1edabb64b46a7c643d6edae41627e5075192553e94d19256b43ab837edf5c3969a71df42a994aaa88a52d5f660a32dbcae5d19961add978152d5016580d4de6820c3a7cef9063b18ed451384511b467b0dfde35bceb9bba444e6cf8e52da149515816f1c867f7f084fcf4e8e657110c6f97685a34ddd317498f8374878db199873d92f3059eb5de6e932bbbbbbbbbbccbbbbde04235c128b3c29168afb44e0d1a9d8c318a42af62cfeb0461e87699aeb2d2350ef49f9913e451d4fb509fb8e3ca4d813797a624f2c827591c77ffe8b3c7e84f238d6c1c8e35fe4b1fef3940f0f2a03b0879127f6f86c8cb5813d7c0e72436c7b92db0b0bf3f201c5dcfdadd2336c314c5aba360500a9f0e16e0aae1ed0fed9ed0d617770fd07b30774e38fbafb823b12a45075975037890f90d479f5807e9e1292300a8c828313a43b3f827e2cd4264f499ef688403fa94a653c7eb25e731f87e925b5f31ea912aafd92499fb294c3749ba05465293ff9114f65a9da427ef2230dd3df8e04769e4a654032a80215aa4085f93dbfe75b9ed5dd1eb7c756c75f2568f6d3b266c67167cdd794d8c3f7cfde45ccc6e00254ebb97f4ede6af4e43987e03a3b179c0f9d020834be15bb90bd67ef9915e8e55dcd9bc2075409fa7958f7494969a996dc57aabcb4273f3e7cec5dc46c8cecaf9ff3bf02d4ebe3b680d86959b7f57ab8d5d0b82fd6979a759bb9f02105105eae888407456af65f336c7e96d16418f69f4ac59e3196f1edd7d7b39f32321ba32bf63f007100ec310cc3300c7b52310cc366e7b587c5ffbc8abd0cb675d8cbf9d8cc3a8c3b1a5fb3f94fc3bef900a466d9cfe89f19d6e958a228cc12104a485cd718bca442623011c03a90cdcdd63031b96b95e1dadddd5db8bb574b7982efeed8ba5f6df076771863f4eb7a6786cdee1ea165c1be76973f9afd700d6b8262959b884dd02b3641adca4dd058b9090a2b37415d7e807a13ecb109da954b40f96313942b3741b7326c79b9bbe56e41a11c77df21899250c8c018a14fdfddddddf59581b07b165f4c953c94d9bb9a55fed13ceca6ed42871ca829ac908ad913f625d2d6314aeb5028253413abdaeb8cf3b11111620c2a2a60b80140a07a2f4c7cdf6c08592d4c894b6561e2771378081b420861c76d590ea1c584c58457783171310125134c780c1331ce44ef0e1fb82ccbb2220520562a119578e4ee032237b8b808521024795930c65446310ab58c823db12aebd807b5c77059307acafdc42a0ee21f943babfa252dfda35435b3b67603caff352a25e586f8a9ba2d4410815c7d830a26b7c328377ac7cfb2b9d9421d703b8cee7366358856cca05bb05a9c0572ac820062c8abc5ddb8f901475b5c0f33381f6c64c8c86442ec0e57dc1928b1e5772ccbe6e43c2703bd813706f3d43c28068653410a8284c9cb8adae6598499bcac08b7914308633c8941c6e465655e8399552c45f3941b9ec46097dcec5aefec7238843e2d7d07304933151b14e03e8b2f985917566e40e1638b8ab6688b48751fc872f73191da3728c5801651fb774f9251e079bcba68c028f6e19e30ff01470eafcef96073e386ed66555d9d932123d30300b61930b698180b03fba21fc5b6832b10fba2dfc7d0094a33467a6c4260376c2b4328acdf16f900c0763682dd8a0a8a1b52682a546c5080abd04f18c639c11b03c5ca0aa0189820198c85b4d9d04122a1585981bd5451396ca9bcba558a4295ac6e5b0d90ae61d92bd456712515352615e3d3cd06053ae5279692d252292580fab1002af4c0c2f48f6028054445cc93f55f34a06c653565345b70d0e6c6b8a1eecf6c62d968d34a425041149e2c894218d260e4085e4802a97b200425962401832814e92c0164053a8042113de069030988e0151298eff2004d50bb3b06f56663f0c2efa14fcbd44f408a58a20b481ca1851f8001670676a1c27fad4288a24208215401cf2c0f19096ac5418a7f0688c4dfe14f44a941ac934a647f0839b25f6bde7048a05133dba1e0ef43809f98891d0a76f07906864004eb6406b54e661802bc4e2a9f0109213b60b203a28a044edd2442c0a9498ef4549b366d1224a054f83eb449257ee488a0fc45500222febed1b0dcacc36cbd413b09fb1db033ddadc340c0bb92c3582f3b961beb591cb03356f7c3c80deba57c1608f08c7c9e91dd0f230ed8199c1018b921bf3f0421909de730f0fbad7720ab5b114477664686a501fefc10e81b1cf7264c084105014806fbfeb8e3a7ecfb234fb79dd75efc11bb73d19edc885863a09fe7c5a19f2588c16a01116a7c0fd2a70be86763f4d091951711f21e950f01722144324e2c4109560b80369df6e20f15110a022222fa622a500c0c203f6d42b621415b8f6a2b2274648564088868d3f9622a500c8c181919364be2bb00f2be56be37babb717fff1b387657b5efbdbbdbe1b8b9c112facd0d1c3134c76fdc7b658961d27ecacdcd3a739fdf03f4e23a2deecbdeb2ba122565bfff61df6f751f166b765f5858d6edbed83a79e77c4aead3ec5e1ac6df03ed2ee0beb2ecbaa66565d3b22636e7fc6d53f6329b989c33c3e465b9bb630cc9009578f117ded69003c74d0efd7695c39d096bdcef7f1141bf5275254cb893cc517e8d77779f7fa5dcc8b31a754c3247a108d49eea2bc50854fd8b4b98b4c9bfb8242e69d3469ec8b3fae9c9b3930ee354f670e3faebb9cbb9be5f473fe374cecc396de28ef9732c8763547b38ed39e69864549bb8b65f1d0e9b1937edf9b70554380d440ea296ca28c6e120abd5e7f06f6953bf8e0505254a94f4d0261446502556d64b84012184b0839e7906177e0633b85f77326cc5d09cee06c2f1038410420c098b8977660495edf9e7f8539792d215ac5e6048b932dec7b4a7ba49826793a8611efafd5590f8ea314137627e68d397b341364910429b7a3db873840b4ae8d4f89308fa4917ff893971891434e9d3a59373fd384eeaf2b9782e9d91125c50630b96d874f6457ce67ea2f8ec58dd08685fc4dfc270e1502f1d3f694e1a26fe931d2835c62835c60d2755e316e4a7c6ef02aab1d356a329d0f85fa6a3b22f78a5f2c70cd4fe68d17dc1af814aeb54e1c226812354b936a93196e0c8a6e8584468d9027f777741e5829999b999a5942c999999633c25d07e777718140d52d5440fdf7f3dc6ad65611deccfba95d23febbe8cdbfecd9a6babb39199d19edf40a247e774386eda5b2901fd341524a8102b1f3d7eb4e9f31b771a87b849dd6fd9185b2164e8d7f7755d3652ca85e9bf66e46c66f48004fa75b71a392a779b187a4878321f8c1e200f0c1d7ca17ea5d5dc36c13abbbbbbbd5130e18a2428acf9ca3fadd66aef3ab38d5f491db26402d434e6c1423d56b1df3565fff56318d658cfc7a494137bc6b0cfb80f888c1b0d267f46c38a71d76b7fb5d65ddcd685d8b55b0df91660b9b969cffaad590e2810ed596fbdd4a1fddfae96480693078b8dfdebbb7a9dbca3212c0fe9938cf179a74d1fe3f05349d2d2afd0c547da8bcf3c7ee29e2ef9293228c8498d3f3316b91da9f1487b3e4a2edaf928a9f127b602c6cda7bdd855e6f47c8ecc913957d753e31c4d1d151dbb6f1b720d491ce6210b621de2974a1476d7509517b70da1dc3cf2e35910f3307fb03ac48f5355e3e7ccd40c42c72f6d355d53baeb0814fa69d37198f843b52b26d4a618bd499b38aab309e9d3013efe3664e3d97adae4699ee330f1dd7ddc73726abace999a47e64f8e9fe6921a67ce545263ceec7a1d816ad95036943dc9f827fe64bfe934025cc268eea3e3a7997298f85447c7c77ddcc753385faf7fc45dcb83ab0efd33e5a7b930fd711e0145ed99a2f175d34142e5f7c74da74ddb013e7e8a23f4237280c71e7bee78c0dd766a248016ad4d07b66f3a0480de4c8038d23a961ab06a0fabd64dae63701da561b2eee7001c236998f817c74a388897f0b6e9f8897f7e6489379dce71fcfbe3cf237d721f8749693355e3bbcf86c33f40355adda6534744309a739470f9891149229fd2134916a296169c085ab4e08cb4fc762b3ee91b0db7fc8c668e2b3677621a9cb38b442222213bed2365fb7491f6912fdba78b4427f62484b77042f8a9531b61fca1db1ec441bd2525dd185b4fbc302ddbf25f8cd2f21fa95bfeb38244abfbe8c47f6c9e36f5cb98063a821a3f2b05b5c7daa92dff5943ac8da6fb16aee59739f81847839fa566b9f2731fd716d9bdb4d7f2337a5ecb57cb6b2d5c51248a50da8b7f1581666fc5554bb7b1977dd47dd737341b8d4612cb885a7070f91be6c1faf80e78c09aae16a417922491feb2e44b8b960ca3b444d43e50da745522f92ddcd70271349803511065e5583ad64e8c6205b18458280bc7c66663715957d7365c9fa45015ae054789a48444443aacee6d6891f6e2a76a6c1f9fab87b27815bfe235b8c3d3a6151f1ffac0206dda86d4087b462f4405b290f2671049293b9b1eac2e3a89abdad326ee638b8f4f04a5e8dffa17ce670a8b05b2e9a18bb48f9f7a67194229aaf159740f6bd77d21a8d7739c0fb5f7a46152fcb744487e24d7477ac74fedf3bd73750ea57d64ccac0cc5af7cc4220ecfc222bb4884c3b3f8482464a74d380c29954abf5b7ac8b5b417bb92cbaa887050f12bd2b041291a8d88dab441291a69dfd2c26d95edc557c195381edc3eda0d9188c78582a8c65fc96e62ca0cc82d176786494fe5d25e14eb2754f994873eb7717e28ffd067ae37f7aec69f3eeda033775d17125e624fd4612c16033bc169a8d6ef053f855b0eb6171373d57971b03d2150bc46fae99ffd0dfea4bd3846b22b2a3ea55f992a3b0ec473652a3159d683987abd3b10734ed6f1a73faf2b8bd049d012c80436719212a4046834624a59c77aeb81a0cf6fb99c535be118497bd6c7f889811cc6fa2f95a8e49f1faafdd7395da44db4b350bcf52da487b4a9a74dfe29bfceab36d1b79e2d9d6abd7fbd53ade6d13ad89ef528b89b1fdae3d5ec3eb9753b299d4af795ea5c6fe5a7ddeb7186aefff87aea4e9ffeca45af1415f71c2bddc74f3b17ed5daf833b20daeb2cd09ef5dbf523cd499be45bd6e87a958f57ab8d81d3a66bdbb6dfdddebdfba13deb67744a6fd21ac1e79f26488094e804b5e96321d57a4b0849d74d29241e6c55eb85f0b7dc7358d052756a6b9726cc9f3b59a374cacdfedb209b8dd1757e103edae43fbfc6fcf9bb53a873ce39a3d429e75ce68e5852f749dd243c58d5c99bdcf6a0d4ebf9618c059badb5e4c32abb4f04f5ea20d1d4a40a29090f96d44fa6ceff3648a64d1f95d1a6f933dee6bfe427b830fc9aa4b29b6c98df6cd3de7c5afaefacee6dae9f3f7f5fa68564ee468303af58979fbef42b86d60a5ed3ca7fcdf29f55775477a52e0056f0f4e5223f05e0bff4eba71c9ef4eb283e001c2f0c7f0e1c6f6ca09f85aa316e34a41516978fdcc7220b65e1cce69f298c403f2eba2e2ee228ed45c890e322e6ae862103a94c223d17719436959ea10a6d8fc5cb467ae15e7e96b8959fcbe2b2aa7619190bb44a366897acca61c4603de021e8b597653c3454af5ff9a96931b2b8708f62059d5c7209544126500836812be844062901da36785d2b2bdd10ded5bdf0d0507bf1e3d51511aa2bcff2d6e534178b0bf728e04b1452214724877fe1727e26879f1b1be80ce60b82614d2ceff25f1403f75f6ca2c6ffa2196a24954ca42f7dfc1516178ecba9fccfa1e076bd1cb85d98aba3a4277d892baaa40e4a651a4834ea205e2acb0eae2e3f04ac2bbf23a5aeac3c4b37045797ee837f752edaf356ba97f6a2a6a53882f20b816e92224175931401aa73d31842d8d1b816ac909fe33eae1cbcf67ff76147a54acb6f92224516e5225ff1d04d9b5cbaaa67f88ce6b8ad2d1ca93d16ff1c0fae436ddaca53e397ba4f92ba2214dd43545df17ad7b370703d7e174eaec7cf71da7afccfd1f5f85170a4f5f85fb8d2c2f04fe6b5aeaf2cdebf37aad0f684d4f8445e1e151ba2282d95fe59304396874ffb14572e3f276bcf1b0d0effcc83cbc76fb126eea3ac37d01837fcee0dcf71bebb3ac0bfb81cb8170eba702b9260e1200de8ae749fa4a52257d2a6ab4216ee63799767ee1f49edfeeb1cc515179572a02a551154419d1cf85fa3e0bbc312ac17210a200adea075600c3a0716d12848825e624f10e530f173c4a05323dc4943b584d468e57c5690ff20ea2ab5e973f9527b51470fae10c705a220ca85e3fa6405854ae5e2a2727171717151712a2ab870dcbbfca368064084505c3847d25e7c8e73a0f6207c174e07f73cb8b2f85292239a54145c0effa978098009a2fc1480ce575d29870ef5d2ad78f026ac43fcafabafd7e25a98162d3e16a5204aa92d6a0b6f52bf76ce6b582ffe13db8479e022d6217e8c41511144350ed5a8867d11ff732ed4087bdab46d1ac1a25290d3821a5b47063576ffc122ddb7f88f8b5cbeab0be9068882288803736ad4ba5e0c61ebb8ba527bf149ed71ddb6c73d8bae075767d2a5d80115d2a6fff8f229ae87ae62f15cf7c9f82f9c236998f82d380fea385fb202b71aeb53ec807e74a5a3d41ec99df8ca4f3cf4d14974c83dac5cf785a0babcffb04f2dfdb7401da473b8c6692f72118baee6aa2e9d2b692f42549baef795c3c45f71213d8af795bb74ab1a5b7e05f7715d71c5ff969fffc5555c6d8cd8f251d2ffa88adf5501713898d35e7c6b5bf9e91d267e5cc515ec5a3a886a2ffee83f881203ffaa4d19bff32a3a89431b8387e067f919be5505c7834bdc578a9f82fb3400702b1e57fd9e072471ab4a5a81a812d32ed28d92da83dd272bbc58340d2466d3eccb8bb72f98617bd3990a735390589fa0da0f6d66a659a8740dd665410d15cd00000020087314002028100c874443d1683ca02aabfc14000d849e4a74589b89d328c7510a19648c414040040040000064244d40008d48744b785f85b502eb30fd78f304c9a55dbf852c07fc45c0d222c615aca0e1b66ce25620148e67f42a5c112f837fe075a087df79e319a1237e3de14f71f00b6c4f750b69a054ced477aff88e3e5fa03654279f64f5c815194c2066cb53ad7bfff369d258de32284b4e3a2103aff3345993ad293c76d09934de6e31ff67302ab39bffc450f796f0ee6609779da859932023894aaa621806b61262789d008f826691eda0b3ed0f23b2e24f8b00498d7d078954068c0e41a1f0ec5aac7e3d64a89bc2d6e8963ae14d0b89cb7620ee0b231c62d05464375a62e5661c9ee2a6fb15df2f6186b1094f31aa425978ded5380140296239b6c29d2339aca7c274a415bd48a968065600e99560102296a23d9b35d938e6191a7cd0ea30daf7b54e4f37b303d259e2e8bd70b6010f7b3bc32512652156e179eff2b8587ce00d1edc10970a616595193c188cdd1d337d874edddab6e4943c7262f3880815386f7c8a9cedbccebad0c5f666cf1363fd6801c4b1be07659b281492ef955491878cf8a38f174e8f190d765d53c0311b734bb3eb7d999dc9bf7cfd25058e3337e35fb20bf85673a657f13937fc3f99a0eb0015dc67e55a183564bceb049b7d0773d77e131d37c712dc2af255e628c2e19a38d8256704cd0f0600985431dbbaba2483fae48ff1292a8a5643be0ffb9ead944ba22a4e370e87cab210bcc2c0bb0a854f6f301de64ffb53bd2f7360bf5f0191af41268a9b0337860b4f80cb6dd385b2a1bbcf7b9fa8af56534de476a758bca93aa5c9f9a3dbe82c88f1ab537707690ea9452d73a605fb3277514564a7aab8b1fe3fc28d6a401551d7f5a9caf675fd96b2d8110549562e0f31e750d441aaadd84f45e8f5eebddda89279e939b46dae45704459d8a73a85595000a7d70d6e1964e5236676012544fec14f6d70e829a194cfedfc472581d313b1d94631dbf596a2ccd12e14905fff41e6475b31400c252b953c364a6201b3e465604eb5ecea4836595157ca23799526091a986279f09ab115230f9106533986e6f2cde969d490928e8db02840dfd2c9e85a63552451c3230dea2a9c80d343c374d6fe6a1a9d161c46e31d1c9be21a21c051c140cf0f4329459cdd8a1e15cac125baf3c65c28c570649b5a100a79e2d775336390334daf468b776086e88c9be59138ef97e2e2258702c4b847c0ef984b329d589c72c610a7fb6cb4cb25a5aec37977b238bd478ccba0b9689b6630400d44f643e73a0028a3115291c890198ba8ac25a3298fb031a68b36c40b906f4afb706925b6fed18659d3ea448dc2b451170dbaca543a6c2bf4be73655e94dc7cf3a842f2adab8d289f4825a2db7d81d9e2bede558e5f3cb6186e3606e4d769193b9d5ff0fee2095aa3ce8c44b16952e092e756e3551caf483d1be57c392122a76f1824e86e93c1d0fe02c0b7d4f7a1f04cc1118d17257d8ed28335536db7e0e76d68bf32b4a969d09372294414e10f386cb006bd054a31a4bf6b2cc735d59f63ded01a8d6c2fbdcc1ceee837c66ab069702e8238f265568e0031292e505603b2a19da06021cc4eb797992d0eac9ab0f1fca1288202b4a026e224597e9ca6cc60d181d69f4636bafa3b19e1d8e56486080b4ad6fd6ce9f018a186c8d3522e6125494e3ce67a9b1352624cd417128e4ff3f883d8bee72431935821a970dc07c3df1c1fbc2d5a28dc89206ba6696be1b5de104e2fd07a3d7786b0060831a65b1e36c02734e84072d3a69882cd0b980154e598e88b612cd3337c7e18890de24163d880b9655d7186724fc190a021eeee02aa3b18ee763eaeced968e5fa1709bacc846befd4d735f2c978b7455718c34c4dec8ca770e7c0c8a3354f0547a9f447b54d9b89048f48993835ea24be9a0b5e008928ba085db0d1528198f6165cb8b5234e639411e943b58af76ce2a6820c4db95b2783ed516c887ef0923101d85e7354191fdce4b4e42f3be0b5c9dfd886bd429fb977b67c973423cbf81bacc25f30fc4672e7363857d3e6c1f049e326fe2c544593bcdec1b2546fff6a4df36cc2cb1a0c5311cf7e29fb501c9adf172a62a4d6e04f1ac968123d5a4941a64ec1f1c7464368278de21c7d6700dcf7281700736ffabe6f11da2fc280e5b298601e215769f560e4db0d01b9b3c1fe05f05b53db28c14c4708563f87b07698a1f48a609ec1d2358fe666c1fc18383b0ad1d61238d1608135487cf357849b819d3427a870075eb78e05aa6f61223c5d348c9b29748df99edddd1d43e51fc14e297996c692f8a7c2d44b280907e0d38bb3c2317df43275e205e2bc302a40f942acf8f290336e1fd025c5cab1771818134feb6573289f1abd9a5cf5f0d82a88ed72cacbd183b8fe995c0d6a09961f90145240f40c31ce3f9216ba04d42c11602c6bc759464081d5b5d6edf217cc29dfd0769f7a3fb9e2fa664889de5d7b28d271f6bddc4dc57bd20429ce88d7810f72eaca906a0a5519055592dfcb07497ed4eafe33d4487eba3b09e1b38c4289719e9e05080b91a580ab9d98eb740fc38ea802ff4e66bec00598a8ec3506ec667ac92022e645d595f2a8b5de7cf82be4e408351590c3ff5a0f28554ec103f89207b215c22d0fba9fcd38920938d4b914423fb0564c7ad4ff2c9cf1bb5879eb828dd608f36f449a1e4f63b71b1b6e5da5c8b3ede513a47f796937794a1ec7dc07812bee414ccdef248e19cda643000fa345b9de9cc620828f963f4f96ea617ca0811dfdab5f1520dd7b2d2980bd7a238484f785c0810e80f4de9eb6b59a6f0e332bfb9d1f7a456b5fa75b8cc1f9878b655fb0b7d09c8545af52a8afe57de25bb0b6c58d0510863d20cabf36f5c4cd9590d1a1c074b2ae3fb7403ba6df3c3d173871797c8dd60afd874049c5ba96379f926381b41756558c347b1b233445fa98552c9a1e55a72be68883c20cd7264f798ea0d12ae03d6e6b989443c0b8684fc8fae55ccfff490e6cc2375b70580e8a92c013310d6a6ad9c3688244b5585a111e6d100fa620122e11042b0482a6817ebd27d9aecda07399047855b0ea8fedb5c020c773e1c21a6cd6de1bf8e81e6c4f3cb17a0cc8902acc0561b371e0ae7cc89bd9e9ca0e38ffde9140c284159d38c1ace624b07c212b799298b146ae56482092ee1630749501aa3be409727576c494fb0e508a9c2185fd0dc796dc33488f47a1ad9295212138d358bdacf3461ea7062af3306a56dfbf963e014d6a6b40c158198eb3da7134aab6b3ae1319b0d2e59452bc6af47dad0c424524a3eb1b310a2387e72a8fa2494600175d11b73366f5823eb6b841545d66f20df0658e312b6de1961169505dd5cba9f572986fb21729e894e37534a03b162c2ce31ec7efc7b5dcfe11e4e5671228ca40def8d11f387911281f2a0929b18a2172152404502a24ccdc4a0078902e1a19d4b4a77a3c4f3042655a58d87a1128435264b8a304d818600bab175072b825f407127b15b1c9d08c8c2622a59c1491ff51817fd7b8b91488d450a2ff1ebdeee1618098f31c8c8f4efb9106dd016772fd7dac0d4b55a5c8c93ed2c72c24b4d948e94848c8051074dcf658bb45458924618a54ad9cfac6fa53bbe16de15d4be173d48390cd8f34ae32801cb3cfd1a021c5e81776a7cffc1b58c240798455a62fdb0c2ad3a3bed82758cf48207e74d87567b14fd8555dd27094dec235de80bec0275929ea1bdff721ba03e81ff58297500a764f3602050ac62461163e115fe4197af4f7b6851571653f83d9dc02b4e7548ca2928076eb788982da1607c9891e7c8514454814b5445c585975b38b38801d1b3dc4a0fa12770c15ce08f21766e6eba91eced832811f15824829d3262be04e4524047dbe9d752779835333538dc00d46f8abb77d30f1c787b59d4bf4be5dd635856d12a7ac4fe36aa0b69852ae470348dd1dfe98266f9b7a763e6579c10d3e9f3cc217090d2757455dd9845e7a95d8c00abcb1dad899196c0bae7a81430b7aba315811c99e7a5470bc71152832afc24a6712fdeb28c21f1110f2158d9a713c99b370bc442fd4842b310b48e5b456168a9d4630fd7c4a853a3f12989c43f6ed501f22d9bf819cca14d1b0718a16c3c57e3475e4f7b2d791a9b2cb1f9f248fa95c5a6f7fef18e761529db479e43b52ab32cec291cea1f6cf5815d82bfc54cc6d20818782423a843ff077a646057a235221e789a3b7daaada08ee21a0d94dc202db7bb06586e44fc42075e55cacb68348252b3868c11ff51ffdf4ff5b9c69d5e6f733b2ab68b4b6f9c3682c1787a762abcc68e2ed435b85150811e4cd95d6558307980c9f84ba44cf740dd1466f96d1ea51a6331faa2f42821701409844cf7867e3ca84348e55197fd499b1f74f3ef529c3437447d5a2bf05915216618f5fe0391188f13af7d5057db550e68fdeaa97fc0750a8a601ae4a3136a6a793c0495e9d1c95324ae382cc240c841feda58b1c10f23c632246aea2e6f80562b7d10ccf94bdf9a05c76eb1971dc3bb1df6bd9e756fa0296d12e9bc50d36926daeada8086d22913301226f1c0b6bbf85f251df7c3a790a7e21f571543cbb6d56b23b3ce5e066312537ddf448070e9b736d005c641ae44fec51daa6d20d6b54b480faf7cd21f89efdd75587ed6b2b1c5b4b8906dc2fea5a8509dbd3bd4713559fea3f08ac495d21ff048c5ea652c620ce0e9402d30ebca5f7f9e255311dd03e5ec2878fb89afd0699c6109e1c09923a649b09b90c43436fdfda08b40b59f6c87a93ec9c97cb0400e6c9f681aec8bb0c16493d7e49083015d8706d8807c05070492824995efa3ee1c1e224b6227a171b8641862df053892d2260b9b52ff615995838a21c815c8e32c1b2e7488df1685c8e7ea94c1c641406dea40bafbaf8b281dacd2df56ba868c765a07fa97a0f507f853f1dbf670f2dbad0e109c71b0bda40c1f0bf8458b2550bce56e212151075a8a8f26ab0960fc5f072ceecabc43c3c042bd253652428e54e00424573236a4a92068a1b0e6b014305f2238b603a32b318264cbdee561ea7cac3ec86867b9539a8c981d795c5f3c8946bcce42e7a82d8062644cf8157b6a621ca9c00e855ea0039edc9dcafa4525a0ff21feec667276ffb66e4a2cb70acbcde443c5c1c3450e045372a8bf984fc6940ac23b8398684ff60995876c8496991f6c24d2045dd35f73566ba8f30de47fe1906081db523fd5933c02294872611d71eb39c4a7912d185601d327c3bd429ef14e065bcaa4f0d5205980a88d13b096902ecfc6378496514dd027a8011d0144b5a822e29eb95401f275faf321da38262fa834bde78ba0b9d8a3024a58e834073660f1974bb1df03dd32c05da40eda434c92eb0a0223043e099da2d4fa64a35f452dd615b5dea601425aa5b98db891c773c48dd0181a0ce6100587a7ee820405f1042c50d4d0bc99229fae5db742c507473a717d244a28761188de9b90408cc8f0c189ea7a7149e5d993a03fa896ef8d07fb4cecf26f8bd90c099e981247678ac9cb6ca5e4b5ebd443b811b9922c12b28898334e8d5d29f208565640cee10a1cfb99714b6631cbe993d83c51735dbd2ed42261b0e8c23497f313da3de4bec63a68e023ab9d5114fef52b18d2bc98e09347013747b85db46abc7294b1af56e12d0e1c0c1affd240faac04847bbd85a4e86f2606387848b148188d023ee6ca08cd526804ef671a0446aa14a84adb87ca8ca44dad20efd2e4188c6dcf505eb9c3f9739f7c2f91804be633a7627be737797a7e1fed0504504dd75d4a00ae03fedf5f588d00ba7dcf88d59dac8b06cf9e520686184f4c1fd64456b066cdf7218adbd5795030f2ac1690f25f8e728b8150158caa51dd37ad073738c9d9bcf117a17e7aa7daf2557e62a9a1d934d9096245b45c4294470637b865bca8a3064e079fe1c96098bf8c4e219574e2b8bd4ee62bb8f96a18275b0e1b154140b0105836f44f048c4bba449d4f2b3294b098770317b43886bf0a30963dd7d1ef98f7d820c9ca3654dc9b3a58dd782c698dd7b38911fb64b759c8c4cddd25f6b289fb0bfe521bab3d17bf3be37d860023233835ebc5f45c1c6abdccad4e067eef718500b5f59e43a12626fa09da58329422e7676a4b682c8d62a0fa53a116ff35c8928171b4aa1272fc2d6b9f8b23fc5a0d650e82639805ed15b086d346aa8e32f12178ccdec7aa5a8da61087f0bb674f2b41c11187081bcc35d102c8f17fc27fa9b4e984d3949b8506440a0db0e94382f27d67c280e20f111d766e144c8ee930d1c3d75e50f665531e758b1f893e0eb54535b36023a0835ac41fa4f3954804bc7b01aec54118e45d3dea920180b2a324167076323d356a730059670d965bc34f2bf8691aab7500e477287df6a699a99df17fa4bbfe109c812c7c572ef6874698b98dd9a66d78bafb006a84a78cb438d015bc729cdeb09903a4b9a62e5bde9075adee350256bd3035e106bc48d95fba8df97fa010afd69e463a0146420d73c0383ad23d18fef4e7bb9c67e9a887d7f02d4fc326762e184d4e6f847cfa685beeebd8e7b2895504f6c3f574bd198cbfcd38f1c8941f4fc31d100068105477657de2e8a1d647fa55f28e52c0ab3186b5b871b0aa9d89ef4c2f645f3ba14e4f11351cd76b5800b923d5c3fb7a8b28dab9ca17960bc02cc473af18f6a5611071494f6cbaf56852081a0a1cdba324bc2f24ae45e86f8c4247e87492ac40a2723194972d98e32f210c4a65594902dc298f38e0006d0123121bbdbf6068af5f76edb0e369cd5d4519b69c50d20c5e4f39cc898d95d05692453cb0080c95d016a5a7b5981892bcc5c4cd18abd977eadaf4a5a64d9a7a2bc2d13c6080260785ae79b58f00c80a1fe51f3e12de818006cb02360557e08811b366ea021b9847aae9a5c56530002d3856fecd73f7cbce0a66b3073b93cb6fc446d79bfc3d4e75597348605ee4ba4540a566e943be4c0e617fc06aeb41ff5463da11750e5a986a8ec75c8a35b7b8813151c8253daa027333d513537adce1d5891fa24f70b8878903d3add88028001ad22e062740c8e944f5235cdcc1d7990d481834c74f5357684d86be080d75981f0723fdea989e74a4347eb533c39532e298c0fcaa123fcc750cf156f899cccb043d9a3d346d07d09fd66f0463c823c5b0acc058a1259d0732c4c6fb5270232f21fa631caa75019f942daf8ec010631903cdf4f87ca6779e0dd76ab8cad4640e716887fc84a736e59d4d41e8e48e72cb43e640f04278dc7404d78f5cb0b6d35710e8f076470005b3cf435b11600d156cdbc9746e6d5a0afe98940f0ae084cd22702057b1b22d2f01c47f63992e2974f3fb13d27fd524faa58de879d393312df9052080a2eb5867c4e189f1446aaab994c815f8da054fad00df2116a575055d27ceda333fcdf50ae554ed80f331a130d8dfe222f4e56c536fc5dd7819a71c69fcdea3bb9ce61534bf0b0216f1e3450a5ba11b4143b53d4e64741104a17058886518b8b7c0d6f26ecc347303daa64d8181ba62446db6869ee0a8f82df1deb2d226db7a89a87de33a7cac86c2a14d8901c52beb44e3e26e19251dab3a6d017edcec466bb2c6bd0d307c4757005f214667e426ed6605ccb23b6f4a3875db55216ec60afc33ea602b8c4693fa40c51b9185c427aed788fd8116c1bf68db8e1468aa6d7287a9c81368271218b409fdd322141f47a3ec69167f0e50e36cde5ae3f644997efd0334c4c1c99147a7ddaa83bf444bef9e74a67abbdbc5c9ae8f598603c227a9ce3f2be3568891ac43579aa24914a8ca1743315bd801e44f51537caea95f1d7d766e41c1c8ba65e629b55ee03e714ea2bae9d412980db1c0760bf44f126464667f91ab26346a81d00346319ab9dfe8b8ac1b6a9700065bd8828d1c1a96cf6c2a958c526b83dfca1f38f013b4d02f7f03b7723dc05f81cb644774d0519544fb38ac67acd9ab13f9d2fe5d4adecd3fcf37dd268aabd2396814e99c39b61e3a68994d8c1e119385a1b1d1f685a4e2a0e83e30e6bbbea1eb4dc9584b392982e498777b00f6617868f3359de6fa9b10a08b704d1a7851f41a67ac102d259dc1e1094f5a61ed8db86782b783b3ddc02d65c96985de9ce194d48d9982c9c5c927564c3fa848890053b14a6ac017ac0574cd9193e0074a0ecd24e617e07c370a8983855f0ce3c81333968a8da2de3e7c92b50a80263da83a44a8562b9c2aad4c52fda6593318215699e8b2f47588b4812813582483facd501d74296d5a8e580d9a1c2ee78bdcae3fb6f38a9c8f9a53fdf4c09f187d490cc6ad7bdfa5e637a54b981e633f6b3021ad013fb36986a97b138d85599fea84199acfff80ee8f57b183a4f364bc8158e8b8102f46a55d7cf861f5e4509b5766ed9b905aff69538d52c82d6074413be2270deae4562524376b473314a670f47e8e7c0a48fe80279e8515f71adeef7b6ec9e284bb7ec621e317eb9650b8677e3e79f85dd2b0cd5ad5fb570928aa344b7187f608c7de609042908025dc8af706a375f3db8b9074d3dc8efc59e65cd0f10ee9c512a79d179a36a113d55b3e7b65db0c6547522735aebf488b64e1df1fc45874d59680684cf3fbd92753a87605d672f75067052e8c0ad806ce7bb43aad39aa987052dcd333ede7e6544906f0800f598a25f70cd5ca26c68607676aec725a74d04ce40a98dff328fb1e3a2a7c3396d6c73d141dfa0bd9507f60e1481030e7228c2f65a396703adfc124a473c4f50cf9e8fd3597b5c587169e85d47c654f55cc127341e84b8f0f2c167156d80cfd4b0f4119e47ca6f1c1d308df9ebd4a8f61911c62dd0b2fc5850d233476ef6a4c746e6ce22f6d2c4cbeb5d18c09c76e7969b7f1663bf8bb588edf595c92df0664ab8cf866ddc28943433dbfb5c52349cd7a0bf512fe6e88281cbd1b1486279c89feb4fc93406dac18959ca94947d137d97da764411d9e3b3bec8d9b9f88fdc44d6a5e1f10dc0d45fb773d6ebc00482af686473bd55c011d3d9f9797d66b89f13674306b3903f8b35bccceafceb623594fc15362fca91f6849d1966c56aeb9480b907484c43e10dc2eb0c004bacf85f6d9e2290b3c51afedf8f3a87584be5d652347be1e62757fbc7887db97e4082abc350e8b7ad52fb59e1360586f6a5900f2714edf33b06263a51b37c1b6506bfacbf15f08d0d8f83ab1997af16a26dbc6fa690c67aca94478c53e759c551b978c613c71ae0c090d2d17f40f01a2a25043e765ae15ec9695dc27247ffe25f28a01f15595ef008cc3ecdebbcf404b32775185b1552c131ea7aaac4c5f19aa43c45711d019f0467780d75fb63103c926ebc23c1143b806107bf4b91ba8f7f668f22a34b02a28506d18e690ba9601010ed9721c3683f1c0a2b40551207608cd9e5d016bdc3f6f280858c230040897c62187f9d17f8e8163ad6c00a07481db9fcdd679ee4f915c478dbfdda535c99cd39c87c8f5dcdfdaeb140578fb79f366baf949cb5ab05c0de5c3855c5b29e59a6ec5dd39e71fa49052678eaea4afa2c46e732113db80b34179bfa09a038b13a22760d3207509ed4b9adfbfce71f353140a4e11beb9cf570abdeaadbcf42fdbf187423a52a9bbfc5e8810663f87432c6358ae822d1bbd32747dce04770c640b88f2d522610bbac2cf17a4f4e49bc52060694dacf0691b8e0c73f4e94e17d49e1d0840be5161166cbcd58af685eb0c3fe748804d6d659bd769509c371ba562e8faf74df2984ba0fc25f767a6d45ef3de764362e07be37e05d1baae905e239940341d5b94ba3923d50ca5653dec0e24be6d6dd56fc464a718d070fa0a1ed15a1f9327d80f30d7474995b477a61bea6178b948916fd3be5a37269d11407d995665c1dbc4a89a0ed552fa11bd1af27aa4a88116fa0a4388bd3fca4bb9f6cb8a45dd645b8cead14c96f3fcdb649009000d4fd58c293f2806310ff539ec62a972c2e9921ad97981c4a30c139e8b12a0ba946b988c92792c081ca48e02d912d017ef1da074e2c46c27a1fe51446aa165b29511d216f25c57e33e10d71502a5f5dcb35a0c3139d66a5783fd20bbf062b74e1d737858cc40f86408ec2507518b9b570d57811c73f942477977c2128084e53c5584c1844a6d7b8300139782ea573ab30b58999b17ec256ca44aaab4f4681db8a4f5ab3e2caaef123774603d6fb674895a1c782905545bcc96c52167c682ec5ec4afcb6347791fc1bc5028d5eb812c4e79f381c385a33a57868ee299c4cac38512b78a2c4ee6324e1a439de44d86912303cd2e9302aa109603f87a8aba68220c310704570aeb9624745422299c78b4a4d050a0503d0d3778e6c5fb148dc4d4f1b91800c0ee7475ae105a3d46cf4d5c61738023ef145be521a31c827607951621821342a51bb4188eec8512920c12ae0b302a8defa6eca44e601636c27836502f870627584d162d6fd55b3b689f8bb95868ac49215a9a9bf2387a29c13216a8e0a0cc11e20baeec31d3e1dffd12343a68983ffcf1ab3782e25e089812c7c465e056ce39dc14732fe00c39b6ef060f7a3993592c7348146cd69d1e657b1f76e1e7c3687722056c251f39551fffce184016c6146fa5f3bb6ac88108d3551539b547657d98acbb8140b279d9ebdf845ab6266c3152ad8e71eced3bd758c90da09de7770a9e6159f4da7b47fe6db772e480db483e137aeba7395b0fb93dc979c733224ba701141ed12b0e6f0beca64c8476af84b5fa5760239c4390ecba733c37908f8c50883c4b5891ce38f207a5115c803b55b3bf2b198415b4cb78c35ff83ef7a58d56ea7a95d60b86329c17670b14374fbfbeac5dff64b01c4fc864541247338f39947ab9164958b8e5af7d6d81806f241984398ef1a2c8e433e3ceb1f9f106b90b8154162a071fa501a352df0c14566ac3b012b6b62a0b4ede1eedd59e0113653d4d791f8ffccb5d2c4d6e6c4c008b445e6212b425533dd88555c01ccaaca475c8b3188104e23a58fd9f246d6db0c475506eca499d7f9ebbe382a9b69ab4d242bf3e2f9c55a002e845487aec5461939f7ed4376b94e093b648fd72eed0f14864e08cbc59a378faaf67d772fa28f63d1a710ed1d24aa945d8db5c69f5c047e56a966e11d573da165ae37b31b811fed94853f3ec2670e1608bdf2260b0aae40b2245ec4487ef8181e149ad128a6bac82cced0b1b1a67a185fe8d88655308af6317129422dd9477435bdbc8c5d68a4b2fca33595c47c1403686bcb411f6234934b06dd42d93cb510d2c7ded7e0d44f283b485076372e32a6cbe1566331c68e41ac4e93fbd2bdb4a6ed2db89682e7b917d2fa0f15cb2b03e9f4f21cc899bf6b3382b9770649d08885f7bdddd3cbce664f938c9339107477f423f8400e0f161b0d4a0f556c0c841ebf7bad8d671032b8689ba6efcfa300a5b8b763c092961a67b7373f068069b00ecd19b6650d4f62333df1de606c4012eb43e53046d8a07e713957cbf030c69a1a98d3eb8a80842366d53b62def2d670092d03fd3872aa1ca1ec0cd37669df79b8ff54462a5ea88979b75b6e6c5f31aa9bc82eb103b1dec6abdfe7cf20338a17ca080e609a984a6af3e9d3a929e7bc34626c9db3e05ada9201457b270786b8cbfc6d300472a5c386d1a0f65a3aeead37ee1e9681326226c28fa4fcf2ee7a90f785d8e97ad35e22a34472a016df8f010e8d8195a4efb8041c00be67e826aa5c36b3010659b6b4d48f320f6b8460b1338ee404ec973d2f084d2fea2b9cf2b09e62fbb2abb88507fd62b7faf92fec069ea2f289268f2eef85ba680e2107fa11cd4cdfd02f4821de2d30a9fdaec9ec44f5df3e63cbc61c900632369aec92a24ca0fa6db3b11e15e04da034cd0d099e2ac99e9f270a6c73da7d2449245147eea1e025273d4466a31dff2a64192417b8710698c2932a1c9c7878b20747b3963d3b2a852ad65af5f5594c386683ecd7bc87494964b8e72d50dec03c4e82d3502ea234a554f5a4ba3e3719ac9c57f3eba2e85d06dc40da5de55225d175a2d8056724b4426896aa3fc1dc28778f2ec1602e4cc70ea7f560c75a6c17ad28611dd144b8fd86028721ba5f4d83dd62a4f1cffa29f878d638c8f0695658a1bafe6f695ea5b70e6565f79b7d677901eddbb3389259ac710b95524199b914509d02ad6fa3d4da6f5c572a4b1e7f4a77ab56e010ee9a845fb9f2c88a99db7d9b0e103cf9f5062019c391af0450a4157bab505203b5ad7d1ca82f7db1192408e657c8988ffb77efd47eb80855d04f71c38d9b29724f668e4740c0d170fce67adc83e7f8fc0c8ab69ee837715f618cbf06fe832c8b422aa0246e2904c20fd58c19b1dc6b26e4e95e3a05387468813c901bfa4a0efeb6da4dee90bcf1e3fcf86508fc54625475edafa4da1d8b927f6c3436bfd1455b95ff03e60e82a12acf9f67853a7a281e65f9caf9e6ac22c73580d7a2d3dbedac65981a30eeaa78b3736533b8f16ade00cf8a91a90f21ab44c6f626fe97b22b6d7ea5e2d4ae96dc32c3f56cbd07368027492c31e620668efc091e606122efe1b887210de013e5f022ca1281b9329b25373299296c3ac2783cfdbccb5cce4cb8fd46010e2a1e7668daad2cd403a3883a2bbf2afc02c0e0b164a17119a28f2c79082ba1738eba9967909a2e9c145b249efd001a72fe23adcf21b70b6dbfab42589d26ea346ad13f2855b2287b48716dbc8675657494a2a1194f5d1dc6ca95e4faa29a08487ab00d2e968f49edbecd1ec1dc1f3ba5ebfc39a8343470be30cee4d92bbecdc05ce0666662c3d2fd22fb3a8ee7c378e78bcd97a17a40bcc938eb4d7ea023b8f759e570fc57f87e69c0855e7189c23735256b2bacfab514e0f8475cc65731cf315c80ed6eddab0dfdca53286b7ce59f570446e9fdbbc0a221e34319f0d616a9671be3eb3ab0ecc80641ca88676f499244dd6f9dbe318c43f54f12d8e47765327e15fd4f3228f20af5e679143ff7ed1bdf5d649a6e2d37bbac311fb9600abb43c97823df0af918db34d7b22c841a7291233c1039935be4e683b3d2f57b5a353e23c3a5eb20e47e74e14f13b82b9f39e8da0775f33bb8bff26c0e1f09806d67d8e1892ec089024ad03f64ea2467e9bf1921f73ce9482a8c6b0b631a186853df74dd6e3b781950d4fdf05593726cd89a596b297c883a1d797e0622195730067e1551d78c3d18e50f311ffa9feabda8eb9d0123772a9bba4d2441f1bb12b4666a8c13ad38fa020dbcf9351b91d8bb08ab79fc3757976f6a6b743a6db9e6e004a1bfa165672923d87687ff6d3ed25feb71247ae08ecc527500699d5ff64ace1ab8f98b250ee049ba2dc158da5e26fd6687ebfc01c80b63afeddd157a4b08e4b6e2355f38cb68de5d3f00d334d0c098b5a32dc6f59ac575ab1192d6c3550a49807ea7d0b92cfdd8abc3882619f62ac36a75f8628b1cbb573aecd54901590f6213981c6557ed6dd2a3892b631bf8a87d3de76fd9c199a4b455e6ec41b7f5dcde21e8ae213eed7d0c8bb2a0010817c4c0021936e5e09e4bf35e93ef97a58c0deefa1b7b73f9c6d503f4672a551bc79108476e83b066cf60f4b761d9ab3763df6130da3d1903f73fbff2ce922400c3212126babd22bcfb32a468e0ba5ab83050d35666fbccc1fa7a1999fa897081ebd45c2c6f1d06f3b7104f8f708081bb139034392a5bc0dbe70631dca8a1ff0962a2db6d51405a35e7238f03a829ce6a96729cc6f28400726cfe058608fd0cf1459bdc9da7dd366c5e1d313d6fb7e10b17f0f0b9d28e11cc818b6b70dc8423ba4bbe7a5807926f7e899a8e48e275ee6e63b77a18e89b7961940c4e16551af82e4dc4d168e182e7003cede80455801f6cefda45cf73b9342e2aec50faa07856503eb9d51975ac85a694a2a3980672c437a070a67dc06fdf24cb01d3425715d7dbdfaf8af03b3910f75743093c8d5d26822a1bc8f74fc2063234824d65e2e89e4b42820337fe9d782714abfc20c6ecdfd6337cbbec16a23cde2b0e174a581ad62c054fbc1010d521ab70a594696f7804dcc53974eefebca820d279281f19f73b041088e7d00d057f0caded88a6c708735c2ba1a74468da19470f085e3e424be9930bc22b3bb688fb736275461800ec7aaeac6498434797fb2fa74cb03bb853738ad0449929732a664b9dd15754335b1d6febbb7c8e329e9409eb1b91acdd111747d7a035320b4c259ad78679a37a6c5ca55cff07733663456a5f2c427071786236926c93d8bccace9fad77e733d80d6455e2a52630d579dfd513833c2c7fc9630d410f9a81e161c42f2b34fd5329b74bccbdb6494d493a92e160c6f309e26ad778911798427360609dc0c15d33ab39ca9dff15196efd3fd6c6ada8ca6e798d281c4a6f0b15131091d58d7d02c852005d5db21f3bd8dc2b2b032673b96f9bb69d94f6e16be8f0f3d185fb47c0c9a79e110f56d554650f612c155f776913efcecdf51e87dbfaa5ea4ca2b4e6ba410ae7c0ffa2a316e694481e4680c0c58625d9c8b9d19cfcd198bab412013ab54a0b7243de6e2fb10d738d83342c735060d9f08d37785ede584573f0096693d615abe163b7370e177c2544660a570ceee2012e5bf6154895caa0de70902b25809d8b2fb4580af2032779ebeba07c96180f23d8a48c3fc80d08d60c8de9297d11450a7857c58a3ec3c08336d60e9c454158b8fa306be4ad6e69e7cb498b24b9f52319b07fc619cd7247966ad9a333a61caaf357101b755adf9fc9bd4e48741aaee2394c844d0095fb696d056476fbf48f1afc1481b272a75e1013ddc485dbcc3431eedf21bd42e034e193b0d3a485cd107ace94d86a370c40c9a6bc46a734c19d6c7ebe97af264db65073879332277d8b6f761633991cd8975f10e8cce512e4d69d080cb893e28bbb2648176466116d5b9db424945bbf7b02cd8d6a56056460902e3fa915ad99c3d6d05806612eaeb255dd312ea82d15206177058639063e40a9139d0ced9432f6689aa0ce7dae404da1b0e43705929f362f07743a048b0a3be837788c57ced0d8146856c1991e7ab77e64338f26f95b1a1fcce6deef4fe91301db957fbd83439d3d226b3f4e5cef82af6e1c9d8fe4e003f15d7164e203c18f4f5a249eca9009449e22afcc19119c726b5c23ef001ddc1319be9715c6bccbff4e92077a2e397efdf5ca42aa651931aa6faa861c0b8315c33405f73a5156dba512e1f738c9d6024d7366b47c9c10c4dab62daf85bd14c282c8e9d1ccc3b7d881be3144b9436ca103c712e8b00b35410dd75b2c2fa79560a40b5064e4e50e4dc5349d02b38a1bc17c6883c27617630edf8f4984c2d5b8504e48e65277778dc5b76942da55b18c85583ed8b40b60341e75266d312b42076bba8b2e44b2ef08412ce26ca5269f81e3b2738632c96257d216e76a8c0c6b46199b694e8a0c0a98f0209573ef6a1bf38439871e325313da8be4c36bf3bfa7537db1326a132228901eb473484c71b4349ea5d240a067b261a4fb95390e0f8b5e180638d678df489dfd1f011b8b7ed5139d5eb7c57a58e46ca95e949fbe7fed1c2358054b6a6502944bc2cde0ac8d08e7ef9521f302ff4774051d4300f303eed3a5750901812c62a8cdc30de4fd4d1a445577e402fa0eb9f041f57f81dfce80b59c77c8b6b4bc754ae489243a3bded49e39849939a31b2d1a23ed2adc89ebd8b8ef74c27bb954896f09f3d51db2db7bb976c626130e10e495dea5d9aca18d8b6908aae9d5eb41f3f51e2302e6c6396d9ed7c4acdf4a02502921ccbeff256349b9e31ab17d54f63aa24157ed3ba76e4af88a80f185840b600f494ef5ffb358836db1a3869e8ddd74f4b7c157f79e71208e4b9632b21f2114ceaa36364ebaf1bbcde5c073f32d6d42cf1b8d571800ef921d649193ceb6fd99128bbfa2489dd554f989de98557835eb6ec484f9327827af28728fa0f9e8205be0726650af968806cf9af325f1eb3ba13ff90f940bccac26beb11e4f44958c84075a8cb826bfec807edc1d3867f579e50ffe808c21dc2b35dcf0f0fbc66ac05caa47b8f4fdf604fd8e44dd5768f9f45802c3c9426416fab2dbbd0de9db9d79e021f2e0ddbd45ceae4fb0fef6cc63c934a22e27a216aa806feb5b267ea5de7c0a49331fcdec25a6dfb76a43fdd97d5e98ff60fe98c3b3e60b78164139bfbe1e0e62bc81f1b774ab668107138264d3a6e12ea3cddd4ad0036e17ea9d4889d28debd618ce4b2ffc0e667c5ff601da1a23741a6641b5583e6b015bffba258c4334406b88d5873ddb920e2f981ed1f800dbdd405c0bb81be8680f274e3ec2d0ccb02d7193d9eda4122e713aa93d04f6e6f77bf3c23646fb7d953d636ee06e482f3aec6f35a5a988dded12e2b1ddca35e47a04c4ca74de0466ca3a5b80ab619844d187bef82bfe7894da200fb218995a566dee3b86ce8eea0612db79098fe9280c0a33954fd74c6e5f60cd2f9eb06b1fa772bcc6ebd2c7a1c526ecb2c63903c35a13c08d59740e7851f658496bca1185a160c4e93639c1126068adf3a8e851a92dc1d0c26634d308139b12d1e3399a5ed27bd15597708f9fab7b2894b548bea26679a8ac087613ca2db09ea76ded8bb910ce279af1cb016fcca8cdb8fa1c50dfa4753c0ee314209da956c4554b5e74fb1734e115b9a8c714f0e9a0b1d6c65edeb98e23ce9e656046233fda70d04332d654182d0a8b14561620b6e60077aef3b76beba0b263224f151731df98d4cb643a444d8d981b184db237d1b0fc547ffb53c7055b2b93a0f9c51cf4beed16855d5dcb89b143e2120841e5e6cb55693c2f4f96d0b4c1c3ec86d35953c84232d18d0e51244fa25ae2cc6995204ff07be428b4593b49137315ae6500cef1fdcfca777e2a9e12263501f352af1c408788b3371e3681803a0761855da89f21cdc1e66a6d7ff982dad8db887dcf7f6ba36f227e4fbbe89d2e72269b7910b0fe4d2f02f7afb778f9e4d590cb5d8b848b7b50874362d3e66f0328ae05ceacb3c706eccd667ea1913abdad3c5a1f7e3dfb4f39f024af614b171e472a5d036a1f4aea50e629c0b925f0d5393c74891d356e087cd10c0009ae7139027f53aab0469076a6ecbbea71f66b9a905dc02be52fee6cf98fbbfc6689b26b04eb73aacef09b5552aa848e13c546759b272124c3d5dc6957877f855e4c75349409ebc5ebae2f6c2fd17bffbb9040f349d118c7d8b26ed116c70c3ea0f272378b1f2a6dbe49bd8bdda5bf7066d368cdaaae1d5eb6c8c1fcadec16345b24338c253002e494855bf7dc4e42449f795b11bb134d59e99a1c0251b0c81ea2389c43d8fa6983e152465f208ad3c7e840f0ca25f2f1bd8fab6969c1307c603906185ce7d3699fa65b1e5cee30b41801b9de8e501fe895b4986a7b0f98c9494aa32743e26419e53c76f82ea900f050f3de4d48ddb87ed26a433a9259a46cd4934ad293cd7069b09123be3fef425c063ea32b763f6eac9c448e9c08066ba2806d7a5b0ca967014590e7eb4c4210f10ee92c023ea1840b8e21f624695fd7c002d4b9d2bdcad214841a674bc7e9bc9d9758b8d942a318c8b72296a53fc439eb2b79f857b6a22e4979caa87b092a4f5d77c8f88de639aca7d8dc9618dc7dc81f6e0f7732c5cf7f62d8f6aae814f30362758cb6e2a640e317d5d2fc09293a01229c070c784ca68b406b59ff52a0ad5a79b3c3430868d6eb2f6a3d4c137ab605d1d09ef4fb3afa5494eb054a80274bb6802ee65785466b505ef774df3c800a9b5e6b00dabfccb3a7c65a2622cbeae3b02ee11c394461e45df21903a1399b9e509f6ad682711400629f575b4ac6dc44413859cb21dcec7b59c8b1a8cddbb2d5d4ec4b66b50081dadc645b687a161a17134e6a38bc3ccd3903a0bf588c723777bc95fd2af6a43aa694e4e61729a7100b3065545eec918249eee36ac7abc9b525d3174cb7ed359298ef80b9d203b4af19823006f2ab4430aef2bfcd38f69b59a0d236824d3b82f5c285f9fa15b785bd313a3fd65ebbecab58f0b74b77033c669b9b66f77ad953b1cbd5daba3255cc4458549613b320e58a4ecd291ece19e216f3e128b9befb5d18fc6839e6ad17d1fd69eac87e90dcb753b8392cbfc1cda697442af7a23b1959423d8a19e3d0eef191e9b19fb61a4f353758c0190466a4c11f6aa7f2b36f3e1dfab1131792adbbac5c12d9fb5a9ed42ac59a2ec0c05ae440dbf8bb4331d1ac666dbf43e354ff2d58a2844e146994228b320a9b790e27a1edd8980cd88b8b8be606e51a4f9d413209317da1e824b321856c9cb0c8f07e9e3eac1d62d25797120e00e2e2f47055aec5c0833b19c73bee24551bff7524a44b870e8b55aec72c0686fccb160c6b300ac9789c65e2d37f6fc4460b3d6c763d7134352e024c8d2b69390147835c75ef9786d11d0f297d52b429f2f14792e40ff610d9d8fa7713d0a94f48e7330c43696c80a2a30dc2b0035b6ea1d6d408acb322c0bbefe5a8e53a54b8bcdb9ef19734b02b5b82b90733e0893074d488024320a4ddfe7ee2d31348d62fb3865666c7c6bd73c4596f5ac8c8d706f590d0aa3c75683a6046ae9026bb87b85a75759eadd5d44275a74aad31d79db69983edc5c6b43b04ca44bfe500aa008917cb8942ff33df078e820a94088d907c210f5ba6d3281905f4210c783df49aa382d62e7ad1d344ffc1226c07e6193534a7e3957ad545264ccceb1e496a45a70571d841978805a35471ce6a6019c5ee1e5668e2af1322ef615a1e80d7c3f3b09d9ccd32609549418de458052e170053516effb9a006e80a7a80e2c4732d9a65a879352e52a94f5995b327fd657e85fc51fbe27c8d055748966b519953e13446ae3b7bcc96263d793a7a68ff991a22f7358a67aaf90c3e07601a5bb305d5f7e55073e213dd3fdf36fddc63754251d1a8f911159756aade194a97dc022639c145b66e4ddc43655bba6a7015bd6a5650d1c8f52c5df6f1f1bfb28015a3868156be70a7c1832be1786167ebc3ddc5277d860859e917d62e08eae2bc616be78e20bc4db17ee5fb3b36a97507cdc31866d7c1f97dbee58225deb3f454b2703495e57c77c4bc3900e126ed2b8e00cd4b3843bf61edb4309ff3c91a451be3a8296914e0287e215b1792ad9fdcf85b12028ca4749a46de5073c64d243f780fe150dae249dd90d6cb1a24e1817bc449b966d0e65a1449b0183374e92d093493752e31e1d13da29962bf498f74810207642300ca20c351713c1be538d0b51d2acd17a0b5f372e818ae540299fac35eef9361237d2603be1f87a11037322848868aac079d9d6e3e6fdccacf10c1d8ab5a4237ec712c7e8dde9b14a38cbc2007536e4654476a4c2f1e34729b56273247474aca6109b441b858b6583ef4e51358b95b6ff8852f6b2a5d3728c3e1601cfb860bcf05fe16abd952fc21a9971f0bb751783cafc2498cbf3cbdff266d5672f64f56215ca583d398f4cdd3a3c1916906e37f865eac1d0976b9ab2997fce39b87926da871ebf8cb8c24824959693c64b87717c8e2d41d7b0914d62051087b968379a2b8dd685f333d9ffe7affef8b414e7944c21cf84c775fe9b9117655db369604914db3661e9318e0147217ea84e64d2aecf81163069c1aa47ec7cc59273528aef9749d8790792cca986b34045a63019480b2c778e1a03a48812e243ec3fd8944b086b37cdbac8c2f54d8f1b7439c0a8477789805c40e4536cc4aebdc17355601cebf12f4c758fcb6fa7843be55f7a19e3edc436c77648c66c631a028287296ad2d6867a062b79502ea8eabfeb89d260d74cefe349c2a67168cff4b2ba07a015f2c3efd048d6eff8cba7335ef2fa2ef2785fa872c37ba00e3a79e5618277e2ebb66dca48ee03eadcaa8227aa582c9b9ff9fd350a8e7b85a6959e434b9c26cb3511e6990191cf187cd9b57519c06e6e3ba5b80b2693da81aa4d7be12dce6784d2d8a99363f9cbbcfb54fb26a089181255a8ea08128211c69908ce62e4bad7c63dbd828ced13ede6e5fe9e4651fdcc2527c6120bc9db1d1276ef78787d18874e331b05dca58498dd7621e1f2c372c0570c67952dd46a1148480010b4bda990ec722474efb19a15015f523919ee65c5141b80e93ae68c4c8d716b3052d7681b7ac3dd21008c3de452407676e294f7830148f7a554135032b7129ad73c349a6dced4ac3114a6c354e19b96d285e59911eb33c373fa6f92631d10a49262d71a7636d2611336fc3b02f6e2378bb2042544dded21413a092031e33fc59a453c6280a580fbb3b062ca682525323b001670e98804ea19f83b1f951cfe4c0c48cd9a80d3f4e6afcc2afbc04cde1b340ea38dd78b68f58c5bbc61639a04907a553f77bd84aba9088311c53c4e9a06c9ec2d5a0eacb0756d26657861832abe96a0017b915342095586151de233c87cd898955cd9b6c64d3eccbb9e535c4475d8c0559c53b6933104a700fcae7fc8569a6eed37dc8237be3040193598461303f5d0e95c3428682bd3dbcf1823e111853955a6c0281fab6553af09cf0268862ad99ab7ddf9d99fe2383d3766826a534175a73aa82b611b22b970949c41fe56221e3b5f6820a56ad85d5ed76edba024930c176ca30bd0f9d15a4f27009f37fe9ac95431108e35d4434f34d540dd2ef03e83f92a38133092ef7cc3d88ea3e6fbd07fe6a54099188c202914666bc32501fa4ee9644de62450d45a148e8f9778aa13432c88238f4fc8b785d598cd6c381d3c80f8a413d18cffb53b86f667fb5c5d05343f5b6c324712b27740a8e844e7f4ed97e29ed6c206009145d452e1dd5fdb29ca1779c93e0dc23cf16059d4239a7c2857698f5f9cecbb55e9431a92ad9b89d39fb0b4cff7f6dd07bb6aa1da605fd346cf45d2d466ffc76526675f6add32001052a68f6b44f1342a3e04efd932102dc57ccb2d5d066cfbd2281a4a4b01e0c41b4b9022dc6949cac48ec52b496a74276715a916829feb902e981e140296dc592cfd8c60873d97dfcfc86b13c4310fca6400945334bfdc19d331e7c11aa23ce4b23cbcffc30dd073a12a7a14bc505cc4cd7361097326a66c5b0f7b6f8b77d23f34272caa33b9b3f09ba78b77681be0f1483ada50b0027d09121a49ee4497ad96c1790204ec09e4be158d8bfff28f3bc9e15d62d22db26ba14a7bdb9129fa435ea179ca95950bf9f5b26086d92e5d5d3a42eae1c6d4c1bf4d8865b13e25344b802b13f399e2b1c3a6ee53975c745f434ac2b81af9ceb0b26b935daf44edf3b444bb6bf27368463910d17828efcf12e309b9e179c9e106078597e86f0756383e7c2f85bcf22fdec933bfa42745e0c32b542a0d67c81410b0faf10a2524e10f282310ed6416465787d38297b06d491ee11e4d4a4f39158e1a38ef8e71a83f08d23e542a02d21f95f16ed4695315bc0a35d338acba60ff98c6c00388cd03f7483808c29c0aa488476333b4918a7750734bbe7491f9edc5b8a5410de59d2970bf6727b6ff5bcbaa3519b0fd03746e29662b53d153285445cf72200a2b09e14b5799620544506aaafe825b42c59726c99d24950ceb301974c9c037ce03b66ac53113c8e91bdb1d5971994ef31dca7188c34a6bdacb59298bfd62e7e28aed07b13434a66b26221c1a5abbcae637c630a49f1c0949816ecb065b0f4db3620fed460e9b23294038d6531bc7abf39f2fddd0799b48068de2a58cbcc07d0b6266bd3e4f0ea4c65e19d1e6f649d950dbf1147070db61d58111cf66fedd2abd90966812fd62995db945e5f9ad2cd1e328e1d7aad0f7ff3286ae9c5c4995d81bf14b429be432e6ef11b20d43d747e78c67b695526c8211f5c64aac6a1814fc0276abc13bd891f9c662510c29c7e3bc2da42dedc23481cbaa5334890661586810972f5bf413f475ac1d32450ca988052db64941e21a19063365d7801640998502232c90ba9d8435d03a501a9f490eeef08c8ecb019b4ff5c1dd34674328ea5ef169b4b3bb2c6b4bf71b5cea27a5ec98aafa2effebd4da690b5ba2c378d08068eb5b355b680bd0d51e9d6ca2a027902ca89ade68d2e39198bf0a2fc160327ce48a37b06cf72af3b7ec5088eec65e5b123d04f140c181a4a6f056f5471504ba01055990452d6bc05d87c067d7a4f9cda6591eddf2ae7c271ad3ab5de349f221db7321a88cf44d9266dc9e9e31eb9d988d87e0c16f8b1bf52faf9155698112533f2ddca325e2a3489af94f9584e8783890cc37e6fdcdde17247defc0baf88469c0efe6bbd7df0970b49aa5f74091546a7d07a21812e49631387142741bfc263a3f5c7910aafef48f50b03234bf51943fc3d2d6e11cbdb0742b090af3e1f7c939d6d6ad68106fe1829e6454036ce8e2b83bc39c3e425e87ea791ea7e231f80b0fe0c0339d2840c968f7b39a0567955321eb6db73b4fb59a9d1bbbaab1a15ca4afd774800504d159c14f7c4a3d4656a345fd813c33fe5e81e1ff1dbf1fb5862a948782151ab40e2987ac5f39b18ca9218dd056f7ae8a2538dd28db62dde23faad65f49687d9d771e3099978d4434879675d921c01bfd87140722338627c74f297e7d974c3085eefc2c743b932b701d03c513533c0c94a801b733c73e8cfcae7e583633fca220b24758b371344ca303f91584ea970da1e088974b0cc37c7ebad779d08ef08bc476d30c5ae8d7e9f736766a02034fb5b7ccc4bfedbb679c2946d25cd02ee60f9bd5c62b71827e9fc265d1b59c0fdf7a6a092a1f34cc9113aea630ceca7c9442f446a41a5f42df23704cec0cb26511a7fca3a6b0a120825508b8ce6e207b616d3c184a7bdccc0d91613b7507a8f0b79c9a3a19e841db014971721133a8d2d292d912d682790d7a2ba22bc3cbe9742870d8fad3951a39205124c1086cd5d7f390237dcf83904700c47ec67878325e3233dc56cbc75147eae99fe837386257d8b5a5d3e5143cfc5bfcbb121246980f0bd1ed2be26adcb347792613b1ec275ad1f9b17e9621d407645fcdd59f906138bd91cd8238bd6d4d8901d4e6bf511c878473d148447b4115336a9c0e397bb464d2ba310ddc6719a2dfa8004ca96a450ca35478e053eb50c7ab45a556995b31c514f857771f4cd0d107b44abcf4413025346d2398ff457fbfb50c1bda7c0823f61523e7564a97cc2d6f531381edbf83f96b5c529a22ae1a1632a348010677b47b879c62dd131b565b3fe1e29afb01c414b22a18849193dab948ca98ec4f1978b6dd536aa2c3fa769b3772d57ad6249ac227edf90251c56da5e139c29424555dca0b9054de89512c013a45bf432d5724545c310286d3c73ea0c10f46d663bd3929cc531d3708e4e862f59c04d26f677339994b101b0d573a1fde510d50879152e3ebde2a873ccc34fc889edfed54b50ff25b7b0d636f43dbfafec22eb5e40b6f98ad59a37c6cdb99809c791e616fbd278bf8b632c824e15f53a1f81a52158b019922108adb55e0718451b99407e8ff37c65471cf61357fe88ad58c98405177324c1c3922dd99b2e88e225986f358fd5fdd29311d5d0a6cfb71a543cdf9fe9307b295f565f40d8441717da5c450d6ec4e49b7f3eca7330fa882d0aae583a43a418e67f6fd81ae20cddb9e5a8b97b4a8418ca229e8a28a47ff2e7e306bce55c73e25342bcae69ca27088a2ba449932a1eaab97eaa45a1eac586faf6a991ebf33b9a3654e3d5445de531261706cef1c671097cb88231bcc778abe4b5549a718b726db7b092e99f9bc4e731fab2ade99ca6a61cb76fedeaccb6fd467808303f53b29b4aa8310052d2eaa8a2e73bc69665643535df186658f7cc570c7a5542bcd16f10c4394dfdd47953bd351620f016e9a1de28789eb2496bf8be0b197f2b205a6fc4e90df25f4394253c79965fe0514301d8b6b3551ebc45b39990bfd4af3eb3e335aa02703dbd727f253400eb0978a86afa4a1b05fc9f75e95c9bfd831c7eb30105032e9014bf84fec58baf043973aa3a607feda51dd09d51e37a1b7f16b2d94c0dea2697214da640d94eba2301fed428b6cf83aa461e7707af53a83fa9f7bb7ffec024ba8cc6cd17b11a1ecd811a40cbbc8752bab269492e72c123be347d2fc9f69f6b08e6bad548a140d828ac4ec92376e3d6410e2f9691c7be386908debd9ce1541e3a6b0f4a1a7182711a355af38bcc9671144f8858b29afda12c919a80eb5c02a233f46bd3d2c99b5680f51fdeaaac06632d5eb721264d70eea711b50474aa17afdbbfe6304b6282bc1de837715034fa1f47f63107a0b6db149542a2cd9569dc3bbf15c452b0706532f86d0439e8de11fedd7497d9767f81f0134a9543c20307d0fb6cfda890f8196e91a26cd717459bc0b27c339ff513504b118f86b4468729458a13ade00413d9546ee50428489c074e01576813ce66f082f20586cf41b5c1b40045252faeaae7931fead07e2feede07edd6ba58c87261cdcfaaf1fb03c9d309a4b66366c61497178ed5c5d1abc17355c9a4760485623842842693841dc4f313f6ac3455fcc3e5125882488a7076fe2003de7169626ab5938e04ccc56fa3e4ed1fb4427ebfbe1219ea3c2b7a5835cd8d5960915d040b233c86bca835eb7818531fe017861628fd2a1d76bf966d8e2da05faa4f1faf10bb3d27b7a652d59bbf79bf8e8a2b0fa11a109096c1d5d783c6fc9fee02107d0ba64cc67c5f87de9b4fe465204fb36ccd299affefba8429e98da83ec5e9e7447a41778d8e8fd31e4e384e61661f22a0fa7a522f52df79e5f77edf7bcf6d6627071fad63b438ca3190bbe8824c8894c3a0dc926c43e7b041cdb4d93e9ea4ec7115b3a33ba1ef1f1819960012b0b2b176313137126cd9cf5457384085d2d1a22cb85852d1fcc74f1192ba21ed85d5df1a5c48155113781086afca346f34cbd4e7b671e73047a605bfe05f1eccbd510daf4f2055594699c9c2c15db4bb6674b40dd303e62baebd2c60a9d544399c938c2aa27ea9444996262ae410178d74e939d22119340b13854582fc58075c99e0345e47f2aa6920537cf2e635944b1776a9ebf4cac480c78ff5df20087342fdbbd156fa20367ac5deb8dfafb8869f66befc1c99b1506466e99f1b54d8cfe5c785dd9868521c536b28eea7f1848b0dfa7ba514c31c970a392cea89cbd5bdafe5e4f2fdb59a5be96de89631608675d95202287c50639b9bf5aa506d7b246c0d9d60b5472e2e2d8222e50e1a59abde00392ed1ebbd17bc32d040fa2700274a92571664a5240a800895b82d2774024a15d01ef462c1fe72abc54dce63baafe92688de9cfab118843b2c961c2946dfea0a1f58252ec660c72547808f45c807c8010eed012269cc437402ea173077270454969f610adad8159fd9cfaf9f9e8d68a75707bd89a2668261a06145f3a6a19fe5cabc4b3b3f5a8c8ceca7ba8de2f19cb053220a00381cadc247756075d36e97c5bb3494a40b81443428aed3ec6ff231960cf2cc2b6425f6b5b7cd1c8df5df8b4186157b56d267c2ad599aaec93713f041f8d7b81892b538d7e763e43519aac9eb754ba0bceb249282e9aa677a2284db0f35b04f4efa50962506792281e0523f6974bfff66207afe07f5b428f433e72cf9446fcf3384b17ec0f49c8b3765cdb277e8290e5302496a1a3675e1922cde489a0f16297efba49b10d89b521ec8dc2408ab6a1804f4510ded08003c6054a2ef1bc429548a5389863c4da2f528369e1ba7edd50eaba1f5649b0788d92fdde4a416989096b01535089e24d342e800668f6f9006469c569bc5c944007f6e972bb58b22c307a160ae72da06398f7dec564adcceeef281e9c285a19befe9db110103e66b95413a596a2031cf6dce6b6f55c11289b8c97a350145acbe3cc72a065d1611b74a3392a0bee12d4c9c95900d3c4767065a41d4828bd0a0299e8cbfc9ec70214a09e1ce58b320bae3f13801740d8f4a376289df0789dd0fa6eced05a67934f7627f16701165dc0bd67c775be155082f532485307bc8f5c3edee5e8cd44c2b21bb9185dce06bfdd1638409d6881f0768b2a806af781f3bc4b4c6b74849c38240732758bdd29809eaaa65a6ca939624d5e43b4f5ab4e1fd6041d27e3dfa76c652814d4338b62f8d1961d647df9f26889284a0d2581c2928b79fa475432b8bf30368798f7d06d48a6e587d5ede3a2c90cc126f8ebe7820159ab9451fa72339d65a0323d8d7efb3e42581dd854ee9a8e141fa39157799c4214a434f73599c03dea3d56208a4619c174b55e13625543abe59d2dc463b1fe0cb2275c5972425747500298e885948fa5f80888268b63680a69f44145e55d937fbc85404a6eb7f22379c63680011b7be1597442d10f32823cc73f94713f16211a1978b62161c9fd401ef765b85fc0f5c8505e7ae4261b8d02f389df13fed05844f3d65a9837e1fc2c99c33e3851df50a9f5ccf965d71dbf65b554215fa55eab3d5e8594c756f0a98e9d4d0e13843100aa4477da334ea16a5def73736740d88d6d10eb16db6efaeaa151f325119224b0b80be0574bfc8a3a5f6f4bf65c8ff907bc767004ca28959adcef24da05a91a18f1260e4d89d6838bbac06a794fa53009812b10093285878c30ad8f307799620e814ea120eef4ba4c68364153892622d1a28788f0bacfb5140c08a39df72e6c87722ac7f757c87b52eee7709f8f9a1b3c6e5f0296f3a04ac5044804e42321d69ac8432b9a8d8534d52ea99075a59d23ca4134c38f725b5bc33cfa43116af552174c081f6ff658d84cab174ab60292de629de8bd833207ccc2bae4df1223b6cab8f56a32f2635f3523fd39045c1b377466b490599ce384678be8803c5642a74a6523be41d02887512f8a41a7945a87627abdc3f876393a71fa6d16d73c874663f6093223096be7ee20b4f6946c25e1080592224af0d88fade9d1130e320008e3a0a638abe03aa45d57d2d0e09283489f200684ab4a71b34b5a29dfa83a79b592e9db7360c5b3e84ffe99524dc398e2977683045d32dd219b1218136bfb43ef5a913c169eb32e7cdaf75136554f94517e2bffe94c3986b82d113580240751cc3fe377a16f1b5864f612fc3eccd1b23a0f5e3086a4225026920e3e9396273ca26459cb6d7ffd155a89f4b5a3ff11fbe4de331bf164a0c315be86c6bd5837d121e7212f0b850cebba179b1ce7f44b4694b5a7192bc55f77ed565e4b86657d7f9b78ec9aa8a95ddda3b26a23f6e982781364c05dc0eb2e79f321cf06115f0cc85ff51b921db8dd168940b20bf34921eda611cc5d7741d671a0062bb1cb385ae2d152967a3e3578aa451f1d369e71965f9ecde2e3363b755bc294226df9a3f5dd94d81aab60cfcabdd1d73de6c6d07782bb51f61df8c1a7658b78158277875803077999894a980432269d0119496c7cbfa233abc2b783b362db66b1189eff146ac3f35537802bafa34ab58c7395d830991d8d5e6d8a6abc1f82152fc384c7d825a04a13a8f55dd6f6ddb58cdf732b8f846dd21e64bc64528d417f81a56364b3de00bfd7772bd66323a0811515c509ba4aeb8942d8a774aa3cfd22bb7fd7904a4604ac046895ebf52b1047cea436e63296c4cb43939048219119e1a75bff8c548c77dba80348e7708339c5eb32b1d28eb8eef6b67594411bee0b795e4ae3f6951f22060a449ed86006fefb42f4af187af1905a9956d17d8380437edb18f0071588c929a11d87a8ad304ccf62c02e02bb05467dc799b41e7833f3276ed9f12bdd803204ed5ccd6f9c982e2dc142831b6c15ee63e582118e2111f24548482d98a9f90a026ccfe341bee9d2115519749d05209986dde8ee896a1b432f18cf56b112b9465f352b60f23a730d491a376c3de496ca068784a33297d6324fdd7ad3c1123537f63cea3c963be8abfb07ad3bcdfd54abe7011702d51dbfcf0fd7650e2793dc4f4de36d29a939eafeb9d87b91714f265aaf25ec8fe5b877fecefefa717f3920db2aa0457377d57f897c5d03b2e0f86c5101c74988ebfd4d6fe785da7f825aa8faaeff6d8941827d0fc632bea6df864d3a2f47060e6e05e2c35932aaa9caac9fec3365166a2f8cfe4fe3f473edcd44829c9f9c1047e94d7294f428447652d1c402cee44ba72b2a5e552e71589c851e2370877f5d555db9e4b247bd8cb96cea57ee918d8e1db0a57486ae5d08db5f37db6dab3e89b19ac6cf53d5930852940a96adb276c648c95ffeae056b029750f9fad9cdf5eb6a057f68386b5501f10335b6f06aec7ff40bd50e94b65e3756ce695d43fc51eed4c0f8db77192361e1776c734cad7fd3da56cb3c1541252defba23346aa62c57b6a8f5c0a7a19aa0fc9976a9b7056b81193de2bfb6a7e800545a584092ed886b3e9763fb850cc614e72200c36a61172692756aae157a6fc767c8616c9317957e01d46d428358fe470249bd83b54cec561c416fac769d477229f93869c8e1a302636c26467390c8f491aee5003469e7d1081d25a1b2c8907bd64d596260990ddb01920112a92c5f38e878d62bb74e9e5ef40027a4dbd04e00f2cfe1341fdc786c44aaa76416aaba484b0d9ebe4ea170f0887f7b1c0c6206c90b7f886b7d926e5d6fe2138924dc8dfc7492f63dc6494a316b60706a6d73e3a5c9492c9619aedd0e550c27cd5300a0a89ff10d134976810a16f039ba2717da7dced63ef1c9cd3740dac5a59c8622f0e074d4a3291f2ec45b9567c5ec1058824f15a04202de5ca30f5024c43a7336b8ce2854a3dbd5a198dcb85a10aee6d5d428267c3b9ea74b713a6e1fabd952638fd5ef85518c6a518d0adf64c9478ff5e8e6db397e1dc1906218afd4601073ec83591f3e572f594611340f07ae70dd47181dbcdd4b7e65b316248e07d3fdb0ae65e12d130d4e7b2bed80103e7e6b4e004a0b643528a085a7f8b3155b67bd23fad4bb5ed3f7cb793dcac21fe126f2e3babbf2b27ce062ffd6bec278a7199400a1f4c11c901ea496198fca62ce95f2d940134f85d25dc24474b229db30da7be57b4f079ce30d40bccfa6f4dbab1e17b389bc29c812baf99636c2182702c9e3edf127baa641ced3d27763ecc984f8acb75c67a870bcb6684af2da38515260816e2aecd404b49d67e07714d3f30466f9c68d7a6741da52b7839161a9f9f25ef4095b31e739292f3e062d120c1fc6fa66827634365be7533ac58020b2b9c8c6cadc74a760d2817571be5bcebef3fc12350426b82c75f88170799adb151feea83b569e340d96fc5c93bdb8c8b573433bf80ae3e10d31ff1ee79ec59ceb9ef9ee5035e25771ebf39842c33a46ea85cd20cad73c06afa73cc113b1b0ad37dc2226b0e7e788698cd1dd97e7ecf5754851cb9dd17d26c809b2600c51f50097037e14d310c6ccb9b34eb762da62395a638373b2e1327a81e6f97adff0cfc663a1da68a59627020d6f60d6d0c43f4b6d3f31773c17d60f68d6a9530a821c3df7ba2130ccb9a90d682b490f9cca72bc1f0e9bed698f739c87501a84c9e59c2987c08c97417bfd45155f4050452061c83ddfb251b909247b6fba5935e74f697b23ea8a39b167432dd419ed8ee7e61a6ea0444b53d0aa512bcee97607fc0e4895d9d155b9036f70be7632581ca8af4d63f2d0647a42ac72ffe7949af254083850eba30035194aa19cc951362212bdebd59557cfa615d8b88f46dffdd22af9ee9e6dcb89ac90ad03661e8843b1a2b0176552dd94567c63b9764b2024f420657b22597a43f3e061449eebf1f8822616df65076728c1d2f235fbb24ea99a17507829323f850d3d20c20c0f4381bdc889b669c1bc8ba8c2f72fa80872695ffe93d0420eed916f59ab37a2d03c0ffda55de979b76400a8aa79cfea2751a71b05f18f9b7c3511204daaf3fb56dc486229dad02abfa33adf75e6db9b71d3ff3da7334aa0064a7ae64e4a08795db0e4aed52d7b77ae8ca62346854d6412abd927fce240b014a7a8ff4592b28ab6c4be3f89d9674a5f339edb6a16531ed8c925eb05089a21f8e439f86ae7ed4811c424b4bc052ed87ef8220b19a2b9cbf4226a2e66a1ae9ff8e3edad6ff92999f6b685ed011bdc7652e012637d02747cd262962602bcfb917e26c018e25e651d02eaba29c7d485cd9b918faaa5757ff5741bbe697d721033146fffc3a4b3f5909a4cdea07a5fd2205d2d270d03f67f7139d925145df61e0fff1dbb7201518f3e95f83e424c32651f0e387b13a582af96a5e5a80d5db4c0b8e5ec15dcd26b4c267792dd2fcbcfd40bf55ce23493ef3d0fd971d4bea09d45361a57bc37a99d7eeed639ff1df1175e24ba339f0a5d47d77c1e86287f82d050af175b032f771b0ab3a85ccb411048858451c48ccbdb82a02f2216aaf5127ff447cb200a8004043bc0739081fa9e9c40c033267b132a2c79665dbb22c366420d82f9962eaace186a941acc66a909ad358039bf2829f3fafa3196666d96f76bebd952965aaebc786d028745e97d452b8188a66707fa3890d13282dc51732357e4ed0f23b0b14ff115120d3faa779a2a284e90351f27b80b7d83a851dd785ac701c1524dcb0a3f1cfb6e5601493c88d071523c311f8453a6d2c70f311ce785234f9e4c46d06da73b334cd27d10bbf69997bd7c87ad07514144cc832a8973e6e0b8ebc757e1edaf66b20d99e72fd4af806ba2637ac713b8a508a38483ba248b11b8f21acb22595783f26a46247c7cc3c7d31dace98622632c69526850ed120cc543d8343df8f8e199068420d2ff808a6d48b2277a063e89c74967ed9f379c8cf758d38ff6140a214bdbbe0b7727f38ae2ea3a22c56e5e64080f170b110fdbdf5fc3cf01947df4c882a1b69985929d081c4f0ffd426e8f43922056c0719ef84b3c6eadcf14c761204ce6db0fca2d2bfede07a1df6386df39386bc64ad4bd8f65df4118d67e244a9114a3c7f712c757e359ccc75ee05e9692834f0578c0ebde80ea00e91aa89335a44926d43e868a9066c37254227da515b0ffec4da79d8146ba1eebed5ec96a4c69641f129d34979ea4a21a02677fe0471faae36760b040696dcd5a357e1cca24ebd9a766bafe8d5f4b22948793c7696828f9ef285bbed335b62de545accdba331504ff2799fed426160ca26ba90c020753af37236943e0288e316aa8c4609919f715a020d6b3e89a7add7e23380dd5c854b6d1ba69d41b76beaac6b17f114a76a54626c043d3a1e943ec71665d67351c3f3c7fa865e7492c1e0218e20ad4e7473989424c10842625628dcc608723f10c9f95fe65cd7d1b9ada9cc78a287e6d0a47a456781fadcc8c8bbbc4d57b88a1a2d00c0c63f10d8ff81973386f3f440a643417c4e469cedf76e75b32d7acc15e5e3ca8c02acec016c3e084fc29d5112cfa140c0fd75fb41de6fd0f8807057bdc503cb331beac2423ec0348e6379b0df1e231a2caca509583e7ed3921c5c405e7ea45cba78cc1db32a930fcd4bf2892a68e2e478da3e52301ac2aadcd728c78563a9f0498401238d9ae8ba202ca1bea17dd6b12f0d2af0707d5951df35b7cfa9974463173754d6add4b919b9749346093ded6296600536c66f5f4a5335c7ce7b7117a2d729a5a389bad8b98634e64cb1bc6732e7a3a576146a3fbc4802543928acda3a20ee9d25ede146e61d9e8fcae20de995dd690440503ed5d2464ab9b63bf1c762b978309647a0bdf0ce9d372e4d596356b4cf36f566678a57ab43ffa4ce42e8c14bd47cc018aa964748ff041a11d8f9f3b8a5660f656153550820ace6eb91bfd016547cd4ce204bcf173cc6d4af522dac018aa91842e6532945574ad0574fd0018206e04e5ad954ab6446a0b6cc0db34e28c8ea157c67afa5f5ff038261ae8b733e79316bce1c2b345f9bdc07d2e615606dfc2ee972bdce447eb01997785ee3a4e20045da03d67d3a8b993454d88d7de2320f70d7fafb83397404e9d8e769c20e612138ee1d6b040a1b01a48d57831401203657f4e6709cbe11c0006808f0784a85417294340ad42448225d6919d1323b7bb340e8ec7b588ebd2b3aef43e1fb9ce1abb41ab03585b47570ddbcc4033531211ec0c39f7416f7d9c00b020a5d8262dd2e0108465a752f1d98a63283e35b2073fec4f476d65dc8e8485872cc441d47906bc0ac23591378726f00004e33259ef66c2767286320c214ccfe9140362119fced515b8ff7ae9370f5d95427a7654946e803d5aab24cc8833d210d60075b24b07d9bd2bda9df3b72f4eea9eb6a43ae9a782cb4e238b14a1d979b7cba8b7f122b336f2c5de5054a9dd6f3ae01856a8631bd7b227b12cee94f5cc2e4cb6c544806552635fbab0f6cb8cab9fbf30643e39e4fc68e634ed39e506b7f1301bb56edee56a3968a049b9b4e6237525edb1ad17b55fa20b037d17db785c905c3de223dcf73077bfbfeb471bbc538c4da821092590f831e1d45c418360ef712514bf25273ee06a4ef9ed2089c7862cc3a830868dc8e17c4f00839bb1e68d588a0a8c88bd20551d5b3ccc45396c44005d53a508802acc86a51a10d22d798897de82c2cd7bcfea07a88c00d0e029e47cc4c876685fb63a06e5608796b9bd6a44804027e8b12827a50982070694c950f16928cb06e8a291744e9016e1cec47a4c6b31b6bcc263151af9228396a8a3c68f5045a5e6c47f58551009601f4d24bed82a7ce2f487a93ec095f12cc4ebcb5174499f945da15af168b37e85dc8c7181edfeadb9cb315950b5cfc9d92892d4cc82a1ddc1f18bc4741cf20b9405b7a178b8b1110024dcd12f30694151d8226e2370ed9b8e0d5f7ec09111d4c59655b8f9ce099f73da6015fe5ccc281462cc05f5ab9bc8ace1869e43a786244083ba2f53faa823e92fd00a1d3417255242fe81351416ac8e18102ccc188e58120b75e3185618b8974256694f169a1cc595558a5714a7a1eaef5e919b224943f17c78d0ea666de2ae59d187dd5e6ecbc76d50fea02cfbac8d1e4dd09918aa121564f292d08c89f3deae43ecd0d027084b22d8103807411e78b2908896c8c915b69df0be2d6ef265742ddd1d22cb9f751396a7394005ac061168d92921a00c79067274773ab229e9cc35cd748183a4a2c1cb27163b5dd638c07b331b1b183294aaf2a5dcc81a5f6292b2f2622ca023a90023bbe8caa8a1f791bbe30aa6419cd74b1bc6cbefe7214b823fb93c3db7d0aa51d64fd6912df5c144b9c75faf13ed9fdc5ae46097ef4186bfef969d58444494dffd042f50d59bd60f7822496f5704968eab142d59a59aa6d8f0a18d349996ac3a97ca78c67e0905e1936e2ac02e30b44444d7a76778537c204714e17064f9c2a50c07930d1a4879215448c7336d3beba12fc7858549018230f287ea891193c94da7f36819790cc38c3d768b8d62715b2b4bc9b8bb8e0cc074b4df303200b2efdc7086df5f8c224bac84448332a7a14de513cc3a586ac42a3ec586366c45be7e809e180e639942a90a6a6d5522e908a47dbb963c60db15fa0efff5d03c6ec6b59f5ef8b927ca70ca738a823a3de37122897ef23c38eb41245cec58562469b0fc2910ab3443a2215d66b6995fe0c70372f1b7780c2df045341f819010541f5a941eee665c9982735b53fb6c2cbfb63d0138f51b257eea9deb3d7c62fcfee571a04cc6efe9b34851312164d107ca33623499b6b8b19d8f36a50ca25fc4ce4346cfdbd1bc4dc38c96b3ce1098f856f1730567304da9e047985cc319570294003b1a005d9153afe226d731ea3cdc421048bc9e6f2f2910b6189f496a7c40ca74fd2edf735f9431386d196b34f3e30afa5d9e647fad98ebc0a4a5846b1da0472c1b3d267b623d6e4ccf207a4c202aa5b9a755d605655493af9e7fab8b5e70a448c7432f5dfeed11705a2ed7fa691d2785f148901e2dcda9fa9e72e8d80b20fb40d7f6970e80ebaf9b5fd4b9685b968f4ba3f44a06d416494f713e6429a2ca7f2aa9e8fbf95c4b609216493bdf7967b07870736071e07970d8e87c1e595588570e072bd81cb9b0d5c2e09e1780470792556d501b85c0dc0e50d73f135707925d69b0270b91280cbdb0066ea0d8e7fc1e5156b4886cb3586cb1b0da9211c0fc3e595f8f68927cbe7c4e56ae2f23643fbf8e078175c5e89efa178b2523270b90a80cb5b0c3df4d243383edec49335d382cb35005cde5c6eac191ccf82cb2bf151154ff427b608c51300b85c61e0f2d6c2e5d20f8eef54f5052ed7cd052e6f2b58b8bc82292ab6ecc478155c5e29715c2e6d97cb5b4cc1e50d85dc51e1f20a963ad72a9e664d6c894fe1f24ae904974b9b092e6f255951b85cb7125cde4eb85cca482fbcb4491e9247c9b5a3841f9f4b353454721b93b6cbe6b2c19573a5ae1b22449e0b14ba4470a1ae99a19c9cd16dbca99c00f4e31375441dcf05d69b1de8e4a456abe70245b771a60d5513d49a8aaa333c3ccfc5470a2ba09fbee99be702b5db38c3523d3b3a39478e3c1768cd582cb06cac1a0bf5f3731b633f56105a01f9f0f15c7280a0dad18135cfa531a5283a04bda136b426091ccf05026d614868f554309e0b6c4c7588e0a3dac92c98e5b9c06bf55ce2135e4b3c868a01a681d415709c028eb78e682c6f9fae556c89cf2f2acf2382774e55db4c58c85c3bb0457c9e01bfbb78315996dd5daf55cb905c6f3c5b7f05efb582c1f0f1d74e8e01c3676c06c786f1ed08e1280386cf579017141b6c5373f162fa7800f8bd23f07b48e419b246b1c1069f25b600486309407684081122448810214284081102040810204082040912244890204182040912040810204080f0284207de703f8b879758c2d183d835efbdaa690f06fc0eb690f159af9b9773ce0e4b1f3418be36572b5785d8e0230b0ca1115bca0d13bf8c4306e47264007777156716589ecac94194f5030a4921196ddf133cb0a1dbde701c6f63d7ec78d2054c9b4864fe5ea34ddb6b5475db4aa577a758f3a24da2c78e7252ab5e58a65911c936923b382b31392981523271224505458a95dffae34c856679c45881ed8eee66c6a241162da66add36ca812d431df8a3331734990b7f62cbfc762110fc017774747238b0e50c856a938e3ec9e86439590ea594ba704a61a02da79452da9d5218fa534a295d39a527ca9d524ae93da526aa724a29a529a774069ae294524a519c5217b4744a29a528a754067ae294524a4d9c52015093534a292d39a531d012a794527a724a5f28e994524a0f296d41e129a53b024029a594ba502a4f47a7db29a594b2a09452aa439bb2d3d37700a09452164a45a7d49e527a136b0355b1e2059893690617320820869716017061010017585c6081e1a4a57bc185152c2a4abe721277575fadac462a5a8a2a48a5a24a516d2950f0a8a49094502e3a6162555aa1acac492d5105a9542aad847592e23129c9483bc0b8ebc2e00eb6b9ba85c99d1da90a5251955461dce8dab64dd2ac364ea5dc761b67d51259b22d6d2c12f188e6a9e561591b991b51b165e6bc982871fa14a3ec11a58f1fd8b2dc5eaae0c9489a9667c9026c2f79bc98eef672a64f1285922894ac41499b236d7ae10a4f46e2989e2316865ecc4a913ec9542a289544cac84f9b520ce1c9489e199e231188bc98abd327a952eda854aae883eda38f36fdf6d1882723835c3cc71960fb98f362526e1f77f449ae78e0d8c79a369db87d0cc1939934323c471160fba8e3c5a010ead344a186507106155149b449e5094f66e208e0b9a1b07a312843fa34532922a922a920559b4a1cf164264f0ccfddc3f3624ca4fa3455aa1c958e2dddbe5bf06466d0cb73bb00dbf7cd8b29b97dd3f469da55efe081ad95852743695a3cc32d1c793127407da228d40a25841a2ad22693223c198a13806778046ce9ede18f3ed1540af2a486a488601b6f0f69f064280f6c315d9ea10db03df4f16248b787367da22a15bc51a5ec218b6748026c0f47f06468d00f7da2f5080d06c0f39302b69fc093b168a07d05da84dd1ec78ba928207b1efa64a162cb84e1f9fd00dbc77832160e6c31ff78b617d8feb50b6ccfa24f564a87365db787f162e4edbb3689eec2f30bd89e7b8ed87ec593b178585e4cdfbef6c952c596796b0f9f8c15747b17ac0d76074b543c418952815a81c28132590f134e2a9e32944ca5523c50264bcdc0a38a276cb552ad542b159e97415026a3712183f0bc5cc513a652c9954aae5472450365b020196850f184a552a8142a85c28132188f0070f0c450a8542ac50365309c1878f0bc562bd54ab55241198ce66506e1f9b99a2bd55cd140992ba8050d2a9eae540a9542a5503850e6e209000e9e170a954aa578a0cc85e3c283675dad542bd54a85e7691094b968e0c58206e159552aba52d1958aae68a04c0d02000d9e359542a55029140e94a93c30e0e05a2b2a65f140998a035de0c1f3962a9eacd54a65ad54962af31104652a0d6c21392e37ce56107e5c3daee2aa85cb3d1f3b9217a04e0f17b8151c8b0a8ed3c97ae0f9152ba214a8d4b3149e67b9f6ab8c66659562b5ca68f0bc8a14ed842a28457542a50ac2f31c8a4c054bf1a460a913580a4b5d14ac0486c270503054090c6531148683e76fe22aad301a945589d50aa3c1f32b25d5520595a8acca5205e1f9142796c995e229b952f64a595c8a07cfa3a0345e17ce85ba50170a07cfab90e6a8ae2e9acc67b5aaab8b06cfa7e8609338c79faa0ab254397d8d83359613d918d9ebb3ec429b0b775835b06ef5cc8b691a94f6a24f35628bc52334842d38832d93f51d18141c3be390e7623ddea8fad9e81ba897f04ef0d66fc244cc3858b0ee9a65649c96fb9b8d81bd9bbb9171d0a6727047c31a580377409bac76ad90488d7882e996fe4ef501fa7940405735e206db18f6cd01016fa817bd6dbf5ed1fd0162cbf5606fb4ebe2b9f4b37bf30cb85fd81b7b332402e766981b98a3a2c3b2d33328176c0ef57d6a73401c7356eb56fad5403d5c1b17d3ae55832d0e6993bcf5a8b25e2d0e3736edd5e2d0dc8d8cb3d19df51f20c6b81ebab35e3994176c35da84dd7a0f36da047d32ecd60c8b802d4804dec4938b6ee9bfa83cdb90129117b9c1d6a14f5fabad5262390bdcb79e99346c3e5e79d22d42be2f10f5259e3aa85bac5b9665fd08b64e832dcbea5bf741769065613646e4b6eeac5bd59239340359ffa03344033ef0c10b7cc092650d96a787f4b00f0fdfdf81a365c49619b9de112c69b0c4d12df2cfde3071bdeadf6c9cee300b89ad1f7ff409da142911d986449d36d9e0c5ac20d2e0c9340fd842561f3d544bf80217b0de87d8730fc5cb67d6ee60455ccc69530c784a278e94832cba8b907bef14735e8bbcceb5836554c113278ed86ef4fb86ebd46b6ece6c39dee8c49b36e1f449d4a62c77303dfdc3bdd33a3fda845d6647bc182d0789e534ceee000f8fd918f07d28d449f4500f5911480836ec080494852df71006fa49f428ba31a85b624e0eb8053c8428279e44dceb968edb164bf1ef9ed4c276a381ba9345bab386c8fd2369da94fb074b897a316f2709959123581e25b5e5fee9d54f9bba489b1e50bf7ead53ebb6b54e6948e4893f7e74b702471fddc118d49dcc9206cbb7a4e94e46a0e7226f85ed46fc0f3dd43af1146fe24c9b6e740ff59136d1bc18ebf2b1032f067b760c3bbd39c338abdf2b1ba33b8916fac1963b074bf91b2cdf2ba11f7127c71b60d95cf41183e821100482401af6d132e658e42c2595ad71e4fbc686b65ea17ce7f86893bc3c958f17eee84e761775624ef4f15c64fcd1cd03ca441abc16f232163991d2908d074b6983e7229f7b05583e433162cb1108b729c703bd9825bc98be11577d6a77e843f8eede016fbe604d4b58d39d7c9136b18839515e762f6df2112806bd98d70d5b66a2ee6e0c2d9c91384c5cbb9306681adc2f3bb429077d0dddc17764b36ee488b4fb9735df42c6c9ee3eb0cdcfadfea5bf783b38a01c8cab038cee68cae46eb82103f3ca08a34def265ebd98b6bc18fa3dfbb827a5944fca4b29a5949252213935f8f430e83c7d29d6ba6df4dd146b43f9b1c95b3e5ac0c10da2d05db79149a96aefbd2775a4906281363e7b355e1c1a5bdacbf09332466b12070c8e1480c137b06bcf220c93e7f7f37e7dc68ba127c18fe0377812d16b81b737a952d31e2f76d2cd2f3c974437576c7f34aea402831ff797ee45617b3141bc185833a10f3cf34b7c97f871190318fab85288a64d0ee86e762f95e0105b7e8787872ffb8556a0c82718c61618eabc16f3d96586c5f04f56edc5340c862fddbb40e510eac40b7f3ca8131f39f9a44e84b56e9b8cf576d78759b9aebb898aa713d46c143d7dc12f7d04d347fa86607a696da09abda131a5cf206cad698c3152fa3829d41d7d57ebb675d7c9e7220d304d84c46007ce1d7edd8c9f7753fa0fc399ee3a6e3d1a328494524a39a7b49173ce29a79497524a293fa5bcf5824d4a29a594734a1b216090839f1018a4f0ecf7da74fc6240839f10181cc16d21862109c31318be740c862ff174bd96f9399b7baaf9375db0c0bc38e0358c223a230a78d0d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3c383acc61384af050a51217bf2b00823f8092922099cb5562a4264c81544a66aab550d0df8dd05cc8bc1c2165e3739f05a4e2608308c5607234342dd0dc126265c96292c69f01089a47202d08fcf0fbc6d5c8e36d888f591c20ae847244af5ece8e4f4c09ac6e546e11f2b08ad808230067730e4812da02d0c09ad6ad521828f6a873e2278dabce0176c6663c1f0bb8994a9b045bcf2070f08af835208af254aa02ae078042a65c4cfca1d15bc134c039ea5100c7896452ce059d2808726bd1faff04e35643c4b0d28e05906b1c3b31c810e5d32847782a81c9e231212f01c9b10e3394601466f46bc13ccc1e139dee086e708c486e7d803047cf47e0cc13bc19f033cc71218e039aa003f47216a68d113dea9670af0dc5320c0735f6100cf51032f4e72c43b754ae6b9918879ee21d0f0dc488069edfd6ec13bb5cfe9b989303db711333cf70d5cb4cdc23bf5900ccfdd01013c77086278ee12bc34f63e2cc23bc59bd812dfe2192e2100cff0092e2c3aeb9e2191966788040ccff008003cc31ce03ea4c13b45556c892ccf30071281610b5e381cc13b45a1fabe54c00edce797855705dc9fc08b2acf6f85e21561a51fe39de40e8e94e7c7330013cf33e076c19d6f6274e1fe8a7792abd812e5fbf04d6b43c3c4da002e5706700be060ae1d195cae0ae0f2b603a70397572e9b1cb85c13c0e52d062a35ab3123dec67c3a4c4e39232631f913b16843c49edd2e9e76543e939b51650d1a113b42cdb2cbd65a8d50af5a6b663392760c236958166fecae5aaf63955eb5ebbaaeebaeab3696323b42adb5beac56aecaacfed80b672c80dd19346a40e00159b7c5530f3eaa9daefbd97e36d455a3a3676254c59868a3ea34605e0c7d3c0d2fa69d1796519b7140c09376c56337e28ea55a3b214a8913931238e7acd126c8e334605e0c76f81725d0049ec0121005960e217c09a5c48949099c179c734ed17cf6ac3db34f13659f9307b401f2c00d50847c41655c9d9cc478d4ca012171f61c24387bb4f4c22886611806836118866198bd306a310cbb628c31c618638c31c6186386c238a843ab99f1f3f3f3f343330c855118adebbaae83379a489465a28c3483e4e7e7e747478d28e3c073d1c06b81ba892da9eeacee5bcd3e27075124dab367da853550c7cf8ce762f5cc8bc1b0f5d6c08b79388d7a337e56331575040cc332ecaf5e1727b1ac56a971b006eac074d4601836e3e7e7e7a7629a8661d8ada17134347b5d540dab1a7655ecca5fd4e6703cabc42e8e06f73383468d9a6135c3aabc51255fd2333d83f57a7f803887e3793b9f6e07a683564a8c8be7b5b64091ecb1647803b7f3105bb2b0354b77f049ca3df9ecf9f08032f132de0a5bf0f0542598ed850707bc985763e9b934ee9c013c27944632eb596d5355f95b79ad2bf5585db1d12728149f106a06c3c3949fb80953e9282f71f8b7e9e4d0a4e4a4c3bfb469b41d1ec61e1e013074e0c1018fb0ad0c586bad42f1a402c20ac4930a0ed670f5722fb658299e92e229f23d0323b8849f901914c199d450dc95c75bff7b2fef10bf2ed56e767bb58baeddb693eee8259774935bf2936bf212f7e428b7c44b17e5266ee927ae89f73df194db57b90fafbc868635f10473503c97f0bdd048b7582b8739f1b7e25170b9a402735252eeca213e719160ab47f11c71523c4721b08af51eca505c8853a45ce5d2ca48f194c7144f79d61a8a1c523ce535348a0301318a77915e1949790dbd924dad2f3492d23fd0279e6ca8dc1417c5addda1b813ab5c1bea532e3462fd847513b767bab35eb28e721b65fde4f6ed92db36cde3f6769be476aa7bdcce691fadd33f6eef344f77aadf1ed24d040a3deac8aa49d997d73394f755ece26ebcc0f0f2aa734e9b854dc217d39b4911eb306ba02560eb5d64462b63befba78b3410148ad18a3b26faa426b39ec1b0de038d3e91fedab28028007e5103029e69be0ce0c974f788b1227bf668e760ec16bb865d84849a1c7b92ad1fa1bd88de40be65bd0f7cdd5e17e1e0faf878edf4063735f5fd9e120061173a991b2837506ea0991887c8d47f7254c51a8b054b0301691cc7558e65450365353496175aa4cc44cfd76c479f782a712b0ec52edf246f25b88bcbdd09f7bac5721a579f2b9659fb161ddb300c136127c1441856c230ec30188661980ac3306c8595816918869160d734ab711c76162b03b35caebfcfcae8572d5ef9eccef8721d7610762d7849a09e4105716f737061a1d11b793aa6628e0ebd5105af85f579234ebce98ec773b17edd68d341bd6201b692d8a1c308508c3e2f26e22b5e5115f1f5ebf0c944156c61fdba44cf418245ef67da655fe09769c0d692d86f9684e4fdf83c95fd8b3665b732d89e86670ff362b4772fef4ab7b7f6d6929cb3322c89b576bb406db2489eb79390dc151b63c3241ab63509d7dddddddddddd2844b746779611351806fc84e404e1cce5ba0f6771f6847996b8ad8cd8ddf301d59ee9a017ed458336c4f9cad558b131200704c493b3f156cd8425645a298b4193a6a0eeac062282a4e9ec5689c7b643eac0d663169ef578e4c5683f419f2db4a92da124ac223912a915c5c79645afd621918dcbb5468abebde1860cf7414222d0080e10bf3f23dd59ef71d047060dde88b1fba08fcf7565bfb02b43f18b4866d2e08d75db4a5775f82b2b568c29ac0cf98e286c0e92934011fa401fe8d333db067da0cf73b166b80c46fb31015259411643d87a76815ff589f2eaebba6ac57e61f5dd4be6422b82adbbb031566048a43bcb9ac196b9d0e885a40b676e8de7625d4e1f7ed8b0049e8bf508bc16962cc5138e6eb1fe931ba881544a871cac41b13122076de08eee070365de4b7790625086469be41ba8d42ba06eb11e2b561b28e35e07ad4ad8183487079f348c9e749f01e28d58564dbb6070a621c6e81355bdc1bc9867928fa4e79712931394c7d3f06464703cca8daa6eb15ee2be6e39b9af4deeeb92fb9a745fb76c97092be37ad11d54915c8fcfa2e7a8b2aed9c712368688030262122e8baefd7ac9cab86e3920206ea0eeacdc403e284254eeba1eb55f9c3d1012d7e720c1f5548bd82f21b68843d08b9488bcb01ebb9777a55b33d64e8cda4fac8cc86518fca24d395e5c1618386a7cfcc023373cbdd291438407c9da406f626554cedadcc01b78139fe9e30c4db43eb231a808468bb1fb4ba56d535945d8680653da33240293ac8cfabe813830351245bb6d9d8d16552a55bdf61c4548e0e472c86f324a294b18fa18b1f53358457f4a007a114a417840687827981811670cf090dafb7bb37bf07c7e99c10fdc023f213248a2561d9286e4d9df5f94fc99fc9df84bf963f953f933a5e81b1904b4e1fa2652abd23b923aa8c5a34d97c49129d9a34dd8678feeac246c10e7d26c13898f36272c72623ec320ccf20c57d0e69ab857137774eee6266264d10a835e4c89cfc326bc9893cb19a01f1f6b926cfc6fd52b1c1b3953391b94975e7a863657c569c5e7db47cfeba2ad87b4097b98f41b2d6592a3a2c382c45d4a15f9925479426fe8ddcbabb8bc499bb8cb97da64e2f22a679167d1a6edf22f2e605ed4808036955c1e469b4c2eaf439b4e5c9e0707b489e5f233da84e2f234fab4e2f23db4e997596249faebaef4696590a49457f98adb37b185e5aa3ce5b2fcc44db9c93df1926b72ed963cbbda49486e2ff66dfb7545b7ee65e2d273d7c4555ceea3aba2debbe2364eb7d8882df3a48951a468d3cae76b68ee0eb1e226ee1036ea2aa3370e5957714d5c742f7bb763d79ee462cf2e49bda4975cedc435f9bdf529f7c4596eca57dc28145b72695bb9ffe89a788abb721437c5ef1d5de5a238cb55b98a1b57dc68a45b2609269e6c748b54c1c9735cdee42f974bf2a47b7be84e7ee5d6681addc9a3b833ba9357b90ee84e3ee5f27075e84edee4c240400df74577f22417e6ba7861d1b1bc55a489ab09c5d3d62d528e543c234992925429894425a9e294504ac49c7c1ea200b200a6e09946d0063006f370244952922a2591a82455ab745348a7271de5a6902e5f631c428a3bf591e7c5903e1f8f78a7de6953ed1d04e92021270ea15348e079d149a29348af383c7c3db3913392467640e24815c81284a0662737470570fdb43bf8306d0ca8511b837411c48156467ddd55d1c5e580b802c1d3ddbce8c56c31a41c2458f4eb6ef524d26b3de935f4761f0602e28b6ba19bfb0a24ae8da014b10121710e28842f1423b62c671ea612f5ac0c58b9932e673064063d46a7a34b19cc6016fc84c8a00667552b41fab1031ae81481e78578313ee420c1d733e9dbb3ad925e6d209138adbb49b2dfaa7ddd2cc782e1101be9f4252ec43f487c3df2902e49249214aaff01e616c2f3928b33462c2b49a31b6ffaa4033cdf42738637df11a491b4e48c9cb9c1d026725b2471d0e6f606cd4ac2f6706e21a189c43bc10787bc98d1a14d1278c2264024e079f90c8780a70df4d138a3bfd17dcf457219c7e50cc419dabc980b878849b4be897dd337d77545d7b5d7d5ae9b5d17bbee75dd7a5debbaf4baf3ba705c24d1df7b43c0ef0f094a2dcb9a61646fc84ab49292ec0169262a2c338dd3dd7f764e71c7c51b9df499916e0f3c49b989905ce3dce86c39e69682145eccf609b1dcd1a752a9c7943353eaa891413c1917b0c53cc9a7fdd44c20682121a1ad54fa8564500477f80991810f9cbd7e0f4a110936394422d13bf12467666ee6cf8e9c215d5ebe17f3e2091ee996f9a6b9691d3b2e1cb2037974425f9532b4c9d006a7f6d87c947ee079211e3c4b94b8908deee608f2b83b4484e691cec89328056d4576545df79784261e71d04609dbc8f6e8b611246cb96f84f07cdfb409a7532f46f4f926e2c56c407ee09de20d079e6906cac41fb0c5bc0e0b724c80e7532218bd74b703fd888eacd1c8ba4a2cab64645d29a35ba467d9e8cefb3049a2d104dee985cfdbc0f162469f6741814f707e2b8bf35b411ecf659e745fe0a00a5ecbbc0b2735367259dae0c9822397250b9e49173dabc2667298dae0f461bb26175d88036d26ced0c6848336dd4d165c72730cb18d6cde8b79d86534ba0f471ca3d1e87234ba944fe61b24ff01e2941c58b0bd3d56e30ff95992ff81e7e9f6fa13d161e86bddb65289e617b2cb3b3ae966f91a84475c66c1f23858b0c4db25c150f2782ef52478bba22111deae2562f176b51c0d6f378b3a32bc5d6c752f9e0b6fb7f64dc5dbb58e5878bbf487e2ed4e1f136f57c21a89b71b71c08878e3589e4bbd8438839c6c98e7d2b7190db85f72912deecf52b791e07681a7cc4c3c2a7dde1100f283a7fb2e64c04ea2db48cb92901140f80949e9c019a2840c71045bf3756523d6ba6d3d47f582413c2c339032278e0a48c8832dbfe02050b0071c0196f00458c216c8181f1f3c0ada902395eea63c44497a75b87454ea8e06c399ebc7084640c2b66db6c447b5d37515ebae98454d66d9b5ecf6a218a376121226b559b3793be735ecd1625996657093588d59d7755dd719a1d65a6bd5ec95619abd32ecc2306e8695588d59d7759dedb4ce0828152b31392981a1d412279a892dc17e699acdb22ccbb22ccbb2ac66d95f961d26cbb22ccbb22cb399cdb2cc5a4dbbe56664194743ab81412ca18451e5633debbaaeebba4b4209ed8c533ece789b837c7cbd91fd070864d1a811a7b457e3ece62884adc71ec4246cc906b11ab3cea7ebbace08b5d65a6bb5af98bdaa56b5aa55edd2322dd3344dd3344dd3b493b41fedafb5d7d0da5fb4e9ba2683b5d3f0347b4dd3344dd3344d23699aa691368d3483b46935ab359a45a8844b592a93a0544423000000146316000030100c064422a1440bd354540f140011748e4a6a549aca83611244290c23c8304208000000000000808088d50034b8510572719f8be8b5db50a7552784556f27ea84e95867887d69683ccf8046168b068104f73fdccc581cf635fda6581211a8e16de0e23a52c7e7f60e1b325b3c809c23f67ad9a5f8fddcc5b122b003841980ae794a711fde668a4ed34fa32c909417319b2bed1f5ed9a57859409437722fd7dfbb92d094bb31e33154a8d8c231bafd3729569a993d9607f872c5136793968d1954c4cc05a0709374094f431163392a40165b517e3d8c3e3aecd9993c94cdeee3e359a926a69ecd40c4dda3f000db2bc5affb8097b060426136edd9dd5f00c162f2e975c1e606806fb8dbed7eeb2096e432e132118f821ae28847a48656e221adc15d01af7701de2c869279439a14b33458ae1fb89f502578fb3ea2327871bbb9b823645446361f03cf8d1bfeb713c40478d71cf4ef2b2d2f80c8f772ea3a05cbffc272e6da00f61becbf4ca2aa3f39964cf8f88790e2bab73884b2f315f4bc8f57d03daf38ef9ad6f7b342ad0b66695828e796be2e0484a572da08887abc3eb4ae08f12c11e88e206be909559a7d2f6fa2e26b20123fc0937d21e1cd00ea68a29cb7af010e3deff9a436059481e316c3c37d12aacd13fd78bef2667aad60e5353b0e62a250c90964931086056a6d9181567cbbf6364c177560944b512baf5eb293d3b9750ca0d664dbf52d6accf645b7b77067f5268e030e1fb2da81cfcdf162d2ab0bf1943b992a8632252ec74d9323560caeb0206748d2ceed1a768af24d982f802da8f699b7a96c3e1ba85e4f44e8f633fbcabaeb2fac2dc5e849860ce4d34fdcefdb3ebd699429b380cea731d6c90250cda68c134af3a7b9e119731e248357b598b286a2aee2c98ed5bd384b98233e898174a95a281b2f87e258a2fd774b52a5097ac49a3c02681e04899d5888818d72a96c1581f273830f00674f3db5d89e0f1f922c6323e5ea8d1a0d8a80b0f411ad9a4281bb464637d0e959d5d0e1b85562419ea547d64f860d25776c9a22d90ca68cf5bf8c0385222dd380bda685ffdb18dcf313d30032909db5ec424ca6fbf9166d7ec0aa21f0348dd19a6611c37d9fe9e2e9cfed8d7196b8949eca340a6105bb43806edd868ca043663aca8f710668d1878edac3adc34c50f2909b7e7b5bce7adff27444a3ec724f0ec07e010c53e266800f8a94e7cbe99d13fcd49e4787bf2ab1c8c7eefff1acacdb6dbab52502543013401c5248b8d054cf7015983e28419521a0aaebfc404735dd076bdf06afb00f12c7d65d8c96ef963f9909e62b46979e29ad7d9778b49a21fb675c524ba2ad7a7d1305ffcf9fe2ed61e2a4d5a3934927af5b01be6c45199e771a83bdee2cad5f29dd7fb47a1ff96229e9e30e670d7703a00b05df9f33236ac1d0bf1b1871971fc0344fe3cc06c809064647d433b9eea3c73bcf9b707dfd186bd750de724043d69465980a607d2e67806ce11914dcf4353030352969597437e1227e2a0b23bc291a61d648c54e4d75b8b56c1e13840dc6d600f19f99e4e1c83bc80f4e71901417b7e723f217cc4b01d06408c41973b1d8cbef89cded19a1cc8c8bdbd46f2fc0811ce9dd1264493437881ad00c81650b14ef93ab3c0e7cceb7f6b241e28b58612ba75b890354df975f8590c3bc578f04dfa8972269ca1170dc6a04cb0f3b68d9900ba0d50a8cbf29da8a9e91c1bbf19a83d642007daee233d10607f1ff745241b019dddda275defeb85e2c7f730965040c16f514fa0b7c74cdefc1e9ac9d363aeb7da8181445866b4152cef436c54b70348b22bd49f89c70240890053a7a29a643b006bd217caef8dee2166d3267b9b97d9328cebacbedcd2044ac009d671297c6e6d7252ca5375a667263540127d1265712cd602e181116a441a89b0bb6a6d8943f5b4142aba1533d2a14a7ae37072cd78a0bc89c77a476c7f94806d515e1e8808183bed319ea7bc76a0d141156d90dc55bc3cdf6cc2d60b0b315b946496a3dc5e8f76e8d8249da5ed3e5e749a81dfbbae715c313122992d8864388f3d758c4ce1d5ff117b14b885eb8bc5fc89f9e47a8387932b54a917fdd831119a2fcb121fa34d2538aa50c5eb666092927b9a96174e410e0c832d9eac297782d1f311dff72c34f1aba07b190098faf15328e65a2e2d033649b06b6a16e03df900243822018eb1532d4e14916ca62e0e4f0c950b00d40a471d051368ed4d790432d82ac339ccb5559bb61bf511311c7e19a298890aa66803deb6d843b0316ee0caae87794df2b83d7e8665f84a337f584d3ad92f17beddb6bebb83c043547f55a31b3d57b59e0241f4f3ca3b6321a4f617ead7eb7eb778ede30536d59913cb82225438ecec06cbaa515b3e9ae1f9c94fe07d24a09dbfe6cad696c50291c03e7c372d256f2d3ccbad8a08ee76eda7619d13b75d86765db1bd96c135cf67f160972b023e73e52919c0ee48cf66da83428c38ad38a831750afd86a8630e0d9032407a1f7096c4056d77e5d481185182f2d2a4a15b772bea284dcbfee636cdd0a77de18a88723b229b15ed44cb368320ef4d5d194154a38fc86c0fb17e43cb25ae3ef2a5ef3628890f0dbd65a25b626b584c04cdcd8681458058c77d587c7be96daaabf580db0ff696ac166f317e5eb2383a343b85e5380a714157a5566f0acab62a4951d5beab6a406f99610a3b703c101386051530f62910d6229fa63a899b088a52108d0da20e08b1121be715c2166fc9b2190bddb214e3e1c226e3f5222ae3c9c22983f90455c3b3246acb38e783462240347c01704f8d5070209bf45c289ec4dbd16eaab942fd3f8b66ea54d74a5dd9cf7f48cc1f2c5e3a41d369c821b41a3f9d99e1ac64d11c101552be4fac7fff02ee057720998eb7e4dd6c530d861806933303fb12eeb422efa436c58b25c2c900d75cfd204ac29602f865b192e2d85666fffeb6d7ebb8ddf4011850d1b8b6e1beb7b487f6f09486b345e50589beb08e2eb62c0b6c2bdbb26a698125bd7815e46578f738dd2ff6c7dc77a863bbb69de6b8e3a26449eebd704180ccf7e5111871342eccaf06bee8a7cd43c357cb7db88348bf5009299206e3955f406ea0325ee688fe8c1f03e9f8fdf33a45c22bc75fad42a77a3c44262d0ed2a45496479b6d64842402faa8f992d2187aada1316bb740f7b91959502cc31a908a877c5d4636a1b3fee7897bfa96865aba12ec9f361083a7c929ca1afdf027cdfadc7be16b5d75bb2ee17cbe8dfbc41c1a67d347797dbb2fab9826db75442d98473c3e2d00eb788d1b0317d5089bf88a9be44f0ab7ad1822581b26c3eba292b3205942969c2ed2508963220676cc443c74f44779bc7690690416d8f5dc5c59328259479b0cbee100186d14e90d7d8dd27e8bc8dc7bfd23a9a25ff431015f76aab1b1a828b19b2c399b03aeaab8f9f45301567dfe6368f7875d90492dc756b735bb240d7fececae4376b295f90d84a6389944d3822e725ac96f33e2ee35f31107eabad83075bae0015ab20d6e707c8d3dbc2d810bf553e735a75976fd6722464d8e3c56e63ac593ca21e384fdc80f313eab2898b5b9e3797e8b707521d9d9a7a9b68cfc6c8d5c62523315b6a6015a82a2531c5bd906978e68fb8ce248d77c20090ae7a57179259f81bdeb3b48c68d76a81fc8d2aa89197dca0c58bfd4c0b9c2bde0ec74314e3d600af10c4c8c79f4d747fe11081ccbce9bdf4e54f44d18ecca1ce0d68f3d669e706680ec267e6180f955b231eb080d69d1a455352500b28c0a952a277fcf03b44bff42955e56b48583b77be81b4c919341a11cb8d1d96546974b5e8554c7a43c968dc3fe44161a6aac46d6543ca3169a74d7b2e3b2adcb243850e89f10bd7d8a800321aced25930473cf9c4f273025aea15aea04887533a8d24ca7894a86489e680a0c4395e3987e4ee10f719d97b3c1dc1d7d72f9d4d79573b10ad6e6e686f851e9022674035e48957020699f66a98adce4803d4776c293bd5d4fa7a47d4375c65efb77e7f87d35fbae3197ade6fa1c7348408cb945d6cf64acf8a14626a7c9d381cb07fc913cbb494c82c481de911ce298296a5b2877c160d4e107aecb7f234a718a0e94cbe266fbf7632cba958590dd70c7bd98b0efc6d515bdf216b276ebdcecc321f4e6f6390724f2ba84c8cbc86c2064689ae6c294e6b371c8f13ea763a18c4ae2547840dc2c52745da7358a506acef6d7232c04403797cedade60af77c665488d3a8f5649bf856780bc8685a9d4ec469ad211eaa7d467d10273b1adc06ad9b39dd82d882a754fe3c397a8415414d0e552257c69538d00b8926d90bc624c9e4660c2c0e5efc82934cc3387474368d40dc5e33d1ed6b03f2a1458f6b81e876b2fae9e09cafeb84c5fb74a3742ffb8d1b3ffd7aebd9deb0baf1561309bf47c0210a47d63fdab89ce3964dd1b84291f738552f1b51bb60bee9332c9b6a66d33dd0d4736ca1e77e6b65a328ff25a93e2d62cdb93ddf49a949a66b09a17da569fe32e08a004f63aafcc584fb19a6c4d491cab19a2e6366e45f2e85e3147a3686e8a916da49248609d719084391546bda1a836cb16627782d86e9689ed197690b9ba5d70131c0f7fb1a7fab24e98f8b78a90a6c3b62741712c91c9247570f32b443262a4064c5d9d0accf8428c54f9b2f2f880116e85a90f6bcc3130f2277f97e28fe41551ce1391b8fae395ed9611855083c17fdaa1dd3f24dbc459da6e5b2733cb4b9afba285f7aa9b71f28f6d91c08f7596ac559976bc6a5cc3fd4bce713c388e20d94451e90cd3c6bb240eb96d8a2414023f783aae0d118e3cfc890979ae9957977c6e3702ee139b2b7186c98e8900285813afd6c4710d290af9eb744967cd1ed7c86e09b48ce834a40baaaa250c11756ef1b7a7dd4f76acd5824da924610448c0fa8b022206d5a12e18778fd919248639592d63ff25eb316e012ee6009e27c17286b651170054a24d35b3ced1d8c6d7f314f0c70c9a354c8527f9634aa20e81c5c32f1f1bd023a172ef90400f9b0659b8eacb29e02ea0a97f04756bc0dcc3cf13ea32abcb66942b49f1107f4755927534d8be92f3bd568eada52a382890d69e4974635aa71e62c35e022fa37497b600e1d17265298ffb150663e9c61deca22436d64765f00c30708cab0d821124f441b380a913a51fcf17ac225fc42c0bdfd8183545df783154784d1cb732772eb282a45e7e2f91ddb734d29209e4be26e0c3bb12b6928af1a27edb0d5b70ee6913f7075390ed1284801e87d1a879cb15736eb896e5f81b24fc49635c8c4bb0d2aef6beaa468298c9f4bfedbba865e7becc53624ca03d85f4b82499a9e8d2c65754029fc6b1721e0ef9ffff8a3de231fa6f76adc1669c4b7126ed0198ac7054ff0ca51422c715dc80dd7255c7212052f564c1b819184da1cf03c0120b1330b20d217dcf5bf046bdc2494b1f7a977234dc044245efd2febea044df06f15bc1c232497720f8d4530aa5345200f441a82cad029554738e08004f88842cd550bf83479967060840ae11593aca074128bb8544c284cd40e9589427cc03b3c8392832828fb37b51615820a15c211f7a05ce6ede6d0e3bff7810ea87099a4332e40b7b49236aad7796146a58073743a4202f47a8dc02582a1a08527379ea927b50aa627b1708292135130d88e22c1a6d23115124fc2ae165321b9a062b974f739fa19767fa084a28861af422c273620066ebe1da1b50cfd4c8aa78c19289a3702ab90a09506afc9025096132e51a109a2dee17bc1644af39a2553471df9c75335b0429cae66ef352776a19ec8e288baf26859213f5d0d1b556c8f778780580422c9f26793478a2c80b2897a0d58216b11033ad16078219a5edfac156221981ced9e2fd990a6eb103331a4231ddbc2c7ce440340194848f3247f297f1c10cedfebb294890a60090490d2cba805dfe2fe619538067f0e1406daf28e100bfd81970b13883793bbc2a0b24cd403e871a56b45ef2b34beb54e0440d3746b3edc02116d7cc4055bb73b005e1e809a1b4ca78c2183c6733798831b1c39c6f1c178e413a6764f901bf7b4bba61a26fdf0783e6c59bba4f32d503d8e3d111da738e70296fad8f183c85b8d80ce5185b75fa29384eff1159cb3c8531e3c9649ea411dcb43f1d8f12b985629c5922a4b9e3b124420f4909e55aadc1d28a33b0a7d1a59bf0a21d0a0df2e25ed28766653171e2d1df27eaa82405dbe80223881eb8805127683853e106ee02cc3f1b503086cd81132fa5910547273c456ef5035e91155a8d0193bee8b72e5a5920a140473b2746597e3fc001f24685f494620c54f2eb0ecaaea8f30c8d4033713d3270d1cc8622cca32bb5b48580eae6657aa924fa2fa49a8b2491fc1314f48339c103586de829f4f1c821c5ae01eacaa2996df939b0fd508ff98ac4bc36c4a5618c338dc1a1ef0185fe02fb26138000dfdd58915568ba1f51fd39cc6b4f6c61a2be917773791c368283b8b285856548e0ee6fc016a460b4d2d8ae6f844c5f40934a4f143329b186093272050ead9671ffbd9e735b6e65439b1377e2cd46dfb633d1620ab6f448a1003e82131389fd6847e509268f8bd76d064ceca4ff58901de9d8d3b6ef009d70cae67217863c01d88cb97c6b852573c2b2e28e6f6cca09430156bcd56d57e2ec3fe799a19d82db280f1a15d64831f2ca2db0c01ad68df2c72b04050dd37142a2c51d222e6891b91e9edd09d374ccce294507a90c76460b5ddf7932ca81ac81a348e4fc3c0ea7cbfbfa238d778b83e501743b43550ee4a23aec898ad348aaf14f28d7fb23c21c6a7e2ed0e0cad31669a39d243f3ccd7929af5ebba98c60ff2965b2be772da34104246606016413ae57af733bd0af97caf4d83eb3a1087770be58a62701d3353d25a3b6a5c3cc04103fb765ec03a89ec82cd845a74b1e56b7f958bc2525002b1bbb91d912504b82c33be62416d7aedd332e4037cc1dfc8aa8a0f851d271b67624252930aaca952dc594774e5ecbece476a31d360a0c823983282b928a1c30de5f44be6c33dd6d2664c28b296cb504587cb18302a9606c433fd100a0f56b14918afa9ed64739f7fab5f8c9089c610be92224f4499786534abb9614df64191d675f31eb0984cbfc1e53606d20108e696006c159ac4df63bcabee24c53a01be5000e47cb6237d1b80a703ce14caf7c5d1ec266db83e4206a9a83517aa43fc4a146677b80f7ecff4edc451b920c4e8242749c4a4ab0a661cf69a2b2067f96339f7bbabb0db122b0804e6dc35637d78300e86b3b2ad3af85642824320c12e8c3e20e910e38600cd78811410a6176fcfa529651348cdd3ae7ebb0ae03870808e0de85e9cc0e4f3ea91708fd92a599732d3d27290e8231d929b6dec53827abc54ec5bb0429df4d2a97e51749c6f1102a28c731b35e3c6772074bf87111616d98fcb3ca5c4f24e2f4cd755a4045eb159a88e9cbc398cb9a428917f438985097ed23d295b1c9b065659126b84e96d23f8a7f96c3aa99a47574c97b4c037379623a75ad5b49ab9f1bf284138cd7cadef650d81e9b60c00250c7723d01302b20c7fbed239f4a37dd6550cb39e84830ad6d395b4a442b6f042455a4663e96e4234d66d4646ba7425903a6a3d243839232d754db6a5afa79a46143b8ec80fd5c571fc6338a3632975dedc12f953ebb48d4bab5dd3eef59b2e216580fdb36f8d300f13ce8f90c89a9462894dd72f324e64998cd48dfd314d681f1b432f4396c2d540ffe7d41f56966915f95f398257d0a2dd3a29f19f73deaaa2a5b8293398862f422733fed01d63a1a1e4bbc3b224e6fa7874e539392839c935daeac3c5e3e8905e8acda475205d12d31124af24b3b872d8647f2640a812d117907080f3617d50e023c53b446305bdbf55531ae23acbf8a272cf003ced6a8a4a462cfedb8be1eb17297a28230149b719627410cb358730814a5d61f242e465a0781364e687cb6979fe0dff4c01232d65aa5944683d6bcdb42ce2ae48ccc5c5f74d452653c204da877fa1c7e486af4b1156af84c084b2006e811e012387ed17564174086721e5b18f9bc67235343faf4f1f27e43374b4f168af75bf605628ecd327d3d6f7b99ce3582cbe69f98b07f6e318b68d384e673f6f33c4a5e3be784c8528b229021f771f809d19c97c82c346149cbc3f5b5431aa70d1e919f29dfd838cc2ed42c59e4ba07c1b436488800a668aaf4b006cb554c49b5e1e42b814882e786a5e6edff64b5300972c376b39852f266d454936e574e54bb614f28ddeeec84d851eeda176ee7093dbe965d3cce06899419997bc7f61bc631888c70bbd0b8bb4eccb5c7d336e85577f03819be899b54357c5ea864e04ec12d3759ae8e91978febfa8717039dab144312875d34576c60f28b8d7a293a13dec6ea0ec58f5b8e3e4b97e48e4898888f011b4c10c604b8e5eb837f1e14df8f84d3e68ea808789136e2445dcfc2bf8228dbf618e0d0362285bc4427e6e09dc628d5e59c8237bf9322cab7fe28d520a2b468ab1ec6afb96ab719850dcd8fc3a4857493682cead722758dfca45b98fb33578bed6556d00ae4f09d9f6cec16b548a37da46e4c7860eed5867030c9561d70ecc96d4b9b69f7522d2c1570347cd647ce1644c5b98efc6c3dee89a6feddd82ee29699f06752e0ff0ee68b8104bf20a4204790aeea0e72c2bdd11eb71cc78c1ea1b0fcdfd3e6e3acf6ad4c2fc1cf35cc3ecdec0a1e7a37bab508e40ec66f53b529ff0194c519bccc3aa58a738c6a60d55b57a3da7afaa87f26c7b86613e763c76a9c0217b76b04a428a1c982e312347afc049c403523ac0cb9e74386c2152f5b1faad8e181b1d9631c831c18ca686aa9d1a16038d79424999f4cba57c03d2c3121f0b6e163f804c3631e81198b14b7d75975a69bd67f0b4e503771eb59fa096518ab5b6d21ba97d1d8c34ff2a7908561fdfd542e43d5416d7407e082797ad2ab1c100467d286b4c7172c70a8198077bab2aa8ec6c5c8a2e25e5953e5708eac8e965170239a617942dff628b137a1f13325b91853342da830dc2bc08b00d08d69044a7bfda0fea088e806e5cce9351521607419bf8ed0e186940c737ef73b054839f3a4d1bf64933749c984ca67e6f65d25118a07f78d7c5166b55c471c3954daa9c3a0c01f97228670f2456a24a9ad51838e9e5c18159fff4d85bb9e09f2c2b21b6ced8bb57c93d5f783ef6df2402bb8d80b228ebd7198161c67ede11182eedd71a5850af832644654282c3293f62a7253a7f708ec03170b3cdb0520a5cc37938056294c0741aec322340706a248922992f7920a5e12bd01fa2b2706a281b4051033d2393648a86e35d488dc18ac110514f8db2c4e385109be41891dc5fad247ef85cb8537271393485ad77a0ed3c13b2dc114c31e3556565816291cae49478db077ee294b86455f249199964e02f4290f94ba8e272f18df8bc7f85e51d6d754aba7d803cb89d427a8e478cff83140d724b925c90766b0f9d1a79ba77ece8124529e0a68f13dab2968c4040a532c9a10c088af91d0ec1c052bfe8fb774ae978c91c6e1f13eeb1e43b889190133e8844af31a0bbeb4a5b68e23552f7573ae27515724ea1cd688ddab63ee86f683045b7223e330e8bc4a1fcd2019957ea7ae09ee90d66b7b5661b7dc0129275c54009e6469a99480e689fad4e5a9bb86d18e17966d78322754521d7860f90643dbe6acb465a3a006494f05c696970b7fa434f3c8164237c1889c2a16b72b965365857183a2eb750bca56e5dabeabcd2e1fe30e105754bde9dbcb1c74bb426c077d91b50abbe480f46a1531d826368f9a355c06857836bdea2bec28b1c81d6d40476c7ed7da5b5a1b831a0372b04d836de00178d58154157112c2d3b706d822f70312cd3a1a9d1728203d5163fad201f7dae47fc7a1c0cfc40953fb1e02ccbe486f5f8d565d92adfaaf727c8a15b279fd007256924bcfd3affaa0987824f83668cdc79341567be0c5a329b72475d06c38569dfd488e9ab868e7299d08247cf44e52dc66bcd8d196eb4f8d9c85984b49de6a1744016b6e25d595102d1bfb5bab5b68280a4a4965b6285c30dfdf4bcefe927771aacafbf98281dfc9176195d42790f86d7371661ad33f5b30e110c401d35203476e23d504e2237316d4a4c61fa45ce5d59008674a6f2dcdada671ad1c48590c93ecd7743a9b122d9544ea58ca64f06edb0cdd5dac7083a758577260c5624514e2dfe6aaaa0c406baa8186e688b953acb9887b9e9aa85e67113c21ba34ee946403926ff038ec5e1c7ad8103a0e160b9c97de5a2c93c7d0fcd55820330a728ba4a10ed5eb9a44d08cd44d17cfd235f67e8353db829a346f7400ea5747adb0463d10b4203af40fee4821113fe18d829bace241a75d0d7226641218bf59c1524ca950dab871819d8c54212b629b8151d18219f8da3c7f1aa92f56437fa95d4136c15091b2c7d480f5ab1876eec26a130f339e84480bdde1b94d6636b804d131b00f93ff44271641b46caa82fd48b8e9dd4ebe1653e1240b45ded8ae84929787c94c187ec7f50cc90554f2f405d65240aeac19de5036c1fe1eb333ca9f557ca138a6dd5245fe6d10eb894710057ee020aac88a08fe121abe58dbd85ab897cbe99fe1d3aad48d0548cfb4ec4490725c5aeb0061bff29067140edca95325923d4d3ca6706d5a03a07414322b0146a330a0b0c080a787a66c5f10837cd285171382e28d6150e5fce9f643c94585787d64bd40074428379e97721f51b18b103395c6ffd489b1243d5cfe4f418fcbfa2a2ef15ed6880112c8921656de2509a7cddd010c0c86f931eccb3504a5bb8f03f08a5d30d9a30042c6a2ddf3f7eeee64266801b5ec3ebbdb090905a0ef83981af0186ce41718d37a36f2225800d9abf46649fe4b45670d2c95f65b87732f8aeb75389ec602dd1fa8ce35eff08cdfe7fd0adceaff57bb66d8c9572848000540220a45450161b5068deedbc707373a3333237ceb71eb91feaad25782e31f87e0dda7a36d5c503d17e4043bb58a9777dcbf22ad7078ec13864b3cd127d469038733cfee8d8e8fc07ce7d70c94db3893b41a0e5121f9b751ee64c17f80a2cc239fbe6e19e7f231e5025c23eb44c8251ab485ec7c2a1e79501cbe48f2bb9b3332d3ff32cb21b5eec26c0ea733b514a434703a2cd6aedc33cbabb24891135f617fed60a6e840715c2dc405bae488c6b0496fc45e92016c73942d124e230f40fada22c202deaa126b7812b1e49b8cde2829ad45c4291fe7703e320c67d66048070de67bb282faa3ba7ec608950fac24d70b23e2690108cb7cd4d4038b6f397bbee518b2353a973476cf9b8edaf5d62d88d28df0f704c9100e376039750ff65029c7668d5201a3c4753ebd4da1d44594e32dff625a376f21c016d99bb5d935f7d817cc790890360e4fc9d34979097a261a461f5bf3ccca934932de01c6c4718d62892817dd2316cfdda66bb18a8aec3528a4de4bee9289faa27075960b07d5cc7f3776467ab2e64825a99225c82f18a3903a5b0a109a114bede3ed2e7869e7ef7d1d7d12688e023d647d76a7a75544a8dd776aa765eedb9e435f528166ab1bc292152109cbaa65448291c4a0d4e616a0b43efb4749f6b41ed68e1bcd8ed3e78c2bdafa558a09d993d48de27b4a2726a263830cd82042b41d24cf25b31209a87fc211b10108b1790fea28cc22f910cf0e3f72ada7f4703eff563ef5e4173af481177e362de8196de5b7008957d61975e52ee09fcd9d179a56a09610eddd91e5ef04754e4fc60e1253f7d36ece4fc9653e19451780bbc6cfd4d83cd958c0e124706fa367c43dab83ba4b284cc5815feaf0878cdb59f276f8c50eb5c85b288110cfe46ce1d71987b46d6353fcd0a4d85f7a7d015256f137d96ae098adede59cdd1a5bcd63fe1913c99e93b0b2d7ada902cab04920a7af8812bb96c0b5ee0a829d783ff2477645c223ea709362945808755f0903aa7bc220ce06440d3022a14a32b43e322a7cb7138d376c21159889bd1938f956324609a7cd4176ed587c6c8e0c720dc5fdb8048bf288644123621f66185cccb80a8e7a0339e5d88c32b06efe8409c96de2e1209777f59a12bcca91eddc7cdc724e81b58c2159bcd6b3019556ee5460db2f76bd5c1b5e897b18a5df9da7d2c10a6a7cd97511214c606c33075274a7f854681a650e9fa490343bfd09160c00cb8ac1ba1e220a42571a747af46150e2149fbc714f4387390a0d246696a521f49c43866956203ba22d03849080f354467423104611de2f85f68683f6e0f57d11bd99daa78ba3692799b70cda72e9d9fa0107d2d42a734e0ab701acd72c1b9305c884c252099878877e4e1fbc494f006ec4e5473a310ad841d3b439694928d8cbe8baf26d406781ab04bfcdfa94add75707620ecae2332315f1692b09a052784fe3194467215ebc9b37994afd0d6ff889b853446bf7372a43edc638a4ce318b6e8f53ecae9af588f63787a2657cd56db70101868741a42462f3d8b07412f217d42e8f586f1ad931142c8802359a3989ba5a8e430575e5598f084464e6b092f5bd285aa967f6709ac166f9991437a2428e1d6b17150146878e9d20fb9b44748ddb1959fe358608f34428c5ee33d8242edea5a4caca2d614fb676c9becca3b4fc7cd11444bb54e305186a88172e9d127ee408e4a19aea96bd366823f5115730d28080f5805a71954b52fc16b4779c4d3c388edc64484997a19fcafa981833291e3f0101f680ddb0467a7ef702deaeb6d2b316260d0b8f1153f8db4c8e1b396cfa7b492340cc56d0a64dee24386a720110cd73916271e916630d0912c1fa7748f890f4aab3e80a0518907f67bd26ec4f2419c34b37f1193666c2febca427fa5421e8ea2790a3e91e494280054c91973bfa9424344429911c5f31131c949e8ac5c056424d403dd4e1bfe19c5415241d85d721ec3275763548f228ce23228c841f08a31f8c9ed457e88f3dd0879c485691d3e8ae3fc2d09855a6831c31a0b3c230c333380d2156e613168049444513ac4a7dc709a8da250e87f3d5d5a758f910ec3ba35e3fd16c6415dca4392c67e7a801f60c6165ab2990e42b024da591a084de035875b35b5976011e31ab2cacdb425b8f7c3cdb5a6c5e8e80db3dc02ca9cb09a0f5d41d2a3055b497eda870cd410213da6450045cd0538a0c31d6e813c4b574335a7f8f67cc3d8a45caa217667995a74f38a2cf6f093c2931cde8d9a66cc1001221928951812835dafc22293a01339075e0df44901705c4910096130f03c89f89a549be77fdd771f660c42da9037bde8ca9aef0a3a4fe3543cf6c0661af738670af8d842621713ae19030b0a24f858ea5c280b62d3116a66bbe341c10871fac6ce2314145724a08d0454ddaded04cd5d2fbbdd16699c8f20b4494f890021896cbe0f36a5ced3efcb3099cb43209e0ae34d889c83745a7f6fe4366f6e71406720d9418c93d0f5e323bc09874ea25c7e585344abd5c1287294ee9ccc00302d5135cc3632c91048388f0c78b534f04f5b145e0fe1e076da56bc514dc616b6931434d748721f91057aeff9059f70af07e2985b803ba630a9e683b78aa4639c72a758285e3315d448a35f04fe7691acc585e10f4c45bf569fb8b012c285033fad62bd21328022eaa969e0280240068949e01a39a3f265896b4f5c8e41ee951843cda64dd2ac4ce8d7bda285394e2e46725ae3d702a2e9e325748ca8086047bc6fee3879c2f204749d445c7f538c5064dbb69772fa57beb01024b8a2a9fe140929ce6575a92a7f1cf2533b521cf2bab80a7ccb72da8834222fee985cd7bbb248376696c5a2aa327542812667e11571f53e66c62d10b50d129ce97515db509f89529959b169390051e55b8246c8cc9c536760d008daf16bdf32f8ab51bdb73252e28a44998f89953c999eb0bc06dba3cca6f2fde1e53badd88061880538686871661b637f076c5f36680b9c5a3e55cdfc646491e58b5c03dd112955a144f205baf75385574bebaa738931bb8eb1913aaa14578d13401ffd575e4e468e0f85782e5528498255130241f8dc788f23adc6f5e539454f3c3a637586414df09a36973e24c4a1efdbb57834f56e9a937ad9223d4c98602011c88af2c085e510dc04fddf40c65c7646f316e05e5289905dd0f7d40b8a4b65285d1ec16d03f8652160d654230b76c25b9e45a216ad4f2d226d273e7cb19377cb53c86221901082cca3ceb0d5090fc158c185c168a768aed7b0506c5032808e4ca906fa613173a713c5415282f5f219f3644673a657bae23c57d824f5b73e7cb360fe599fc4c25d582c989ea8e388bc40cace6c80b98f0a9f1338b4bae29d893a86727b685c8f82c26031962bf5b5119796690228d332462a1d8bf888c1e5948f02695f789584ce80d9db1aea7dc2039d7b67c3f29191f4974e3fdf78e1722b8c48ba2efeee2cd47d348e81cc9c72050325ed0e404d63b72b1ef64e839b1519b0bd94ec3d7a1f2f966a899831aafe4b6a0a5d4fefde5dc3e2e7754939d5bd28f736f987b670568d0dacbdd1a9bd336d3db019c0703af3ade47c66fcaf09b85734264e0da80699da411e9f9e80875477a8bb566d8b556010d2b58b0ff230993d3fdd668a3c61c468cdf21c434f77bd790ce2f0ae67459df184045158432a116f8805f5eb1bc212e601c16fb4e6843a2fa2008b009a67ef0399a4aab1114689b88a1cbcba509ba001417074131ef5659a612842f66f28ca937c285a18072056690468cec80ee6326f3b741c5cc259784df4b2d928e9d7ea949218258104a55bac88aa8a140ead77eec9c1a50ab2400c0baf9da5c86d1b82449f4ede05af31885c63b25841d0c5d7503b4e5f4e4118ec0b6329b2f3fc7043826f2b802dc2a0862e67fbe091636aa120b9c9711c807445a88a2c35770a2f01a760a2af480871923e6ba049a014774bfebed6afcf3266b8f4523a032ff2df3f803dc12440fbd288b025615b26cc55b0006a515931a4356b42820b84b625c5fa007374d9442de409f45c4954570b2c0933d52e3793678a486bf0fbe89df3d1a11a137fcaf685477d4ebc68025091642faec961622b04ce662efb466d7d4af1b38d3f455e7f47212354789d97168acfee4356eb639e1bd95f3b97750d18c8d2f085461056134114405b97e7e4bbef99743bbec8906e661f928076733f1fc06352c0f9c4a00cc0102b92b6e1b4e067f3d13f4a3a719c12261067c7145d4b1186328d6cd49c50077b3b85d64dff76e5c10d846182e100eaba334eeda5087c8660fbfa6e1c6edc65e4f29356dacd0a46f554b8c8e119caa856c4038c290ea5efa0398f00da2d55508047b0bb62a0aa013767c956ac5589c318c063783328594b7fa85a075cadcf4b2af85d5abbb2251535c2862b43d3a06f81acbdbd9f0c2f6ade67c3b1da0fc06a70a29f203c6061816b11c717f342f5c58d2c46d8beb800c2ba1d82b29ea51173a37106bd1bcb3863f0a3788b33ff4b993e90afcd5dd251757ab5ce18e2d70767da2b46e3b5fa7db62582f88cb1066976bbdb743066be06645f5a3f12943164ea3b53c78527afaaa7c232a1ae2a5b844f05255f2de0121f64b205116f40cbf963a53412333804c0c12c04f7d0cfe8cd5d190b9220c65f60ef52504bad4f1c43195d50c84a0970a8161221549a02c4621f3202068ce09f34955505216d3dcc18bca6645dabab4086b4dbbd85f056a98f86b20d8886fde35140916496a665917fe4e471298b9b71cd2b3b8765b15b61667d10a61fd1d4ade44d099bc5469b5b2ba9c7d56499faa6a6eea2aba9718610b85dd5b9719742f94892a2ca2d392b8cdf2aa0817bcdf5b7d80a007aec13c00d23064007fb0470878901d0633e00dc31310074b10f59ebfdb2ea2bbdbe1f3157e9f7b988fd4aafcf47cc55fa7d2de2bd92eae33bef1551fbd5dee255c6f74f5bd65a1da5f89a51f35899959ea32633157d05a91182ee68be3c0de5e3dfdc328207ad551f414650e6a5e1fd53835761f1fb2aaf7501f1b50fb1fcf61f9e9ea3ffee04331ffd9074d7b54ca0f82a754f3b4f2f224e14dc7dd053dc0585185f5550abe8dc9dca53dc3289a80550869bb4fa95568304a99a9c4b218dd5a5dc9242e155b5c12571c55511ce0914c8ada202025921e2f15a012a67979cea143f23cc9b2ef59cc2c0434bd236181358a70c3111d92d8b4ec8075542255328d5a9b5d9adab78101547e24b81eff1df7fd7a572804f030b345aca95b27f4f9c2c55d644ce81b312dcb8af14844d62de6d7cdafffb6f552a05f832b040464ab952fe1ea28e3255fe8aa907264f55e87352524e4e60542e9ffcf3bf35a999e2c380012ea94bfe233815cfa77ef86f490a45d82165003f9cc218296a65fc75a1c3b140499d7fc5eac36b8a4c7d1f35c3e900b67aa45f15aefe4db604b42c396ac6aee662f358320a4b4247a21405a6ab6fd3a29609d42a2bdd6daa534cff37f04938d3d48c3c9bcaddf8b9884dc6f5a5b432439be48b30266f0069838d73ee98e81ffc79974ef64fc643631f6c91df0a6d69f5327c24c8d27f0b8585da92b3d51410f09405550cae152499dc0705341702835a4bd71401fbf79b8df88e0e5af11896573c5cd1c1acfedce92bc63916197575909d26e1818e2cd88b16a0e32f6d72dfdf4773f00723d76d715cea45f5ed6957b7c85d2ee2ef32305ac722cf3514782ff0220078d534b3f89fbbe3c54053fae2b8a98f7ab4470f7ef19360ccff656168edc5a72583914bda6174d07f9b720e100a3f06b3528821948c61541fd89beef1409d8ba8fd3a17383e24af2d2a2ce79476e85fe33ab565df24c633a331d2c6559df1fe4de54a4204c63e72257aa01c6c505390fcd822272b761c2daf8409e903279005316de23920b8e2de62cb4ada0510a64834aa2f20938d0dcfd446a037bc1961aa2c806f9e58f7f59ff81a23e823bb0db5d132e93b48356e7ebd6441be177f027c697319e678ef37eebdf0ea60bfe86c90de4a680b27771d3bed00e41406deb712f6966dd7c1ba217e5cb34394948ac5caf9cb8f9b0054c0db9e4b18bd41c8603e9f53f48383bed35deccbad9ef6da07afbb7d65284f8aa29019fb844f72ddafb77aea4d848fc2c17bd2f0f54e02f889c341289866640e661b7bd341f900376c09cf51e7515c5ba9a537d69e321ffbcb91f5864a1925408c3502b981b960e95bdfecd6c60acf37af9b2e43a341ed5d1ac3eea6d62ac8ae7bab490e406763ee515a6118c0201b5b53bbd5f7539f8b43892b6b1fb7c8b8901122f781be9ac4cc5e20397d29c41b7f605b2c766d9d3170e5745e0e4e8bdb0260e292477b2533732f377cf625464cfdfc59160e069a121c9bdae8df30533a063700d4dcdcb293b0e650f2b763501844d34dded7e6826a0e3d5e116e0089a7a6b839c8f117086741d208f7e659c5922fb36477f3af2077776a1d23a57ee2eeaa9a6f8c3d762001c04e1f28cc2c22539718d562c12e30e745957f3080ba95d5e6e9b85e4166fdddae6e9085558ab279cf0b1ddf81f0951cbe861ff6381336827436083869fb18f2e1486598b87ba27cc53bcf3c44427c5ad760f70d82da143a78fe95d57969e0de7eabaf41979977cfd87abb3a3f0c5cab1f136adb16bcf734bc39e9f0271c4ea62024e66dc657c3aff0134fd9a17462a20e6991e1882f2eabc97c6b12b49ffbf73905f53e0fc5c3851f408260766352f47194c1c3cd313ddfae33071ad4bed461818aebf44088fafd40a13cb469ab6ec7ac3ab8c0cc83a760939b8d1fa4c270edd549ef3562c2ad2ecf1c3167a942e75e281690365941eb67479574010c2162776e4d36ee00e1fd5db3ae9165132c948685c80b1a2570d0c3cb9a62b1f3d1947336fe1053094eb5cf455f56f4e3da3a0e51401e51d381be89fe905fab01ac829b302a8b44fc9fc3f55865afd3421644a7d09690af42242051715f681956a4fc83c4a0631a7fc5be12db6b2f8094f6a447d5003b487c21e82bee297c390a5487494cdcf57016d3fc4d48d7d2b7c8dc11a065ddf4d20ea6697932feef858df7b37b0ab28ae40ea9a64498de845a923e06d0d16a3dd1804aa8ba8d1eca1157a8c53d9f382f5b891030e76307420aae2614b1cc18b2aa6b061b62eab4d0299b0148a49ed785378ef682ebf8002c77973185b1916314c446c6148a19115b101b21d644ec017af5d06391de407a18d1ebf1bd77c47c565cd07f9f17ee3fb10bfacfc78bfb2776819e9c9b45bdf0e8dd522f1f40fcac142aa1c6e6c7e9f60a0b44803b4667f88e6b7867ae22c65b3ab7628575ecf39ae1f5326af2afc6b0f8c6fdb3d0407478cd1faaffe10ec332dd52d2ba24c50f3350684d09cf0a77c67f920494bf44c2d5ded51e55466c6df8b972f06ed734162530c324e0ed57a5abe37fc8c352d59b53f7a0aa831c769ce29f25ea096f632536efa0ea405fe5da42c2379838394422940b927f6e8d157aa127744e271af8620733e5b65d4fc1d6e78d4d9d3795c9d34c328b533663452510f1272dbb669b949a1509dd245b0543724aed593f9fabe3a85ab01ebf5935949b9b738111bbf427b04339ec82907f9807a1d29e81a3b4160cdd7921b62c90a707a1f97f0407d782ff3d12999df1e0491adec1896cce1824b7db171395d9f91a777d8187c3998f76e71f8811362c508d364311d1ac22ef2116da305667c075f94dc7887443a08170b44c16250e35b881cf1947faa8678444a7a4ab64f6284b444088b3dcfaf0d651712cdc4c89027db4639bc1e3eb4877e7b4e682afab438d780775f472eb0dc280bd0403640b51f7de96d15775547840594e14e273ef4e8d4bb6e244c4ebb64e2f9aa153b72a377d3e9c84cd0460907415e06d5eedeb981db0bcc12c818d362c96fc1368898f552ee464bdeb31900e37f4c8109d0e565ffa5940e646442cb722db9123eb828ac5679e46fba9c5b6fb4858f500612a6a1e2276403692c9dec36d0eeadfbe9f19eb09c98bf9683634eb8ceacb4c56292fc43bcea4b512529f4af92af549a9afd27d94fba5847d6a5149f62580bc40cc2725fe4afb52ea5b691f257dbd123fbeb25292355ecbed5928e85e7a30e905201446de46ff4d0379a2af40e2c355d081ab42ab3c708bc2192ccbf0c8a602a0020077e1247c672fe4d021c5e5d6ab78d8277ae2a576899f74e01f4d1456a7cbbf4127b723c7b438e7523c1b16e87e3919290fc2bab59e7fb9d301cecc796740797a8dee709fbbe8c15a68d25d69bdcd1d404e57a55e49a286a62e700c8731983061a2214c4860760512c699932840c2072a0188b144268ed8b1fd614e53469820fe0a12c633d32982c20e2c015063d40c8c70b0fcc344539390a27c2a528c31115302941d4402501c0f547ec230c601cf76acfecf14958d27a329e02edb8f67c39568b02ee7fc2b586f4a43eb6c1649546acb8486964350938c738240e5b5c942541eddbc732c0eb6cd397a920ef3e4a287a8d266ecabc224eead555689e56b89b74a2c5f4bac5562f95862ad12cbc712cbe2e66c5059341b589840389ba58e0f65c7414e770d65972d22f62d339ee1acb11da72ceb0d3a61583c34885376e93f9813888b0ac4a184eaecf111a24f0dd9141c0f38e1a16cda0829c1f5a8812f31853d1d04697c887580715fe98a604f13ca307ff06cea1aa75cee8e92ba7eb9dee594595a88c305a512c27e436e6323e43f9e0f115eca42a2769199c650366d1489e0e2d8a01a31827e0d8a4985c43b1fa0090ca0fc1e2eccf11679863e8af63231847b4ca33c64141ee4294b7a37f1314f4107e87d3241153eccee8e50869f1eccebead06d72cfa06c478360274dee1ddd77e464f703216a4005620fbf033d0106872837e518ca1ddd8a16b73eb6c3180d41cec45d38c0d2d0b1353273232d94c03f37b739ad6c740b498f8d2d5aae830444a3f008311e08f289514cda80a70be4cc641841626996edfdbd0e35604b3264111f65fe8a3514214ea67b139b8829840f90fe1b058d84b9e967ac802e3ec6b8b17e4389283bbf06b7102536fed8ed177bd857f9156243377a265d4e9696a29b2f8340287494bd5d64a01316d403bf76be64217320c6ba4ed0eb0543aeee1789377afff74ad35c27d1c6561a30b8691daba62033b7c8e7b84f5fae9f8e43a29f71f89ed80d7171df2385f4f633bf018d3d0ef991fb1d15b05e7bf03b7728e30192cf7cb1218e9160e778e1edc67b10d88ad31df2b3f46e7345ce4be1255c75b315f12fec4288c566affc22462d1613d16eaa6e5b7e730fe41620a4e059c75b7e941f20fbf8652526640138b3780b9250ff580881506e5a5ff8054b802685fbc449b776a77a37db438d7f7e4981ca85b04a0fa8894553f9c17c033fa7ce742851302e4db8939602d1d0181f4051329afd6ee5bba774d18db9a2db7607f3d2d0bd84b7646df894cdcd05679d39428d66b2db4fb4175ade400257c0386c92fb5b38e2faff13ba5f5bdd4a0400a4c047738afb5de7e22d6858d51aea15b61c5be03b7934e1117c1f9e18a4c828a8e5d95d71ee1193cb63fe3760d6303e2781c7817d7c17bc84208580bb3b7471ad5ff33888a65229586a8001b1c014d28b817a0b6598f68d1a93c301b02f3c00d5ab08950fa881bd60b75d38670711ee4e3fdd4f1fdce840c8b8f60433f70dbbbb6ae3ace1f02d8bd3cd1f0f71824bc2c619b8170ff095508442a2069ba43fa767d6214661bed3703102fb5119032375862c7368857dcb715901e78ab326a6b03e77052f177027ca02fc6c120bd3f3d300bc6ec20ee90fbec8ca25744a712d99eadcb74630f7d00406bc0c158aef0bf1bc0f6d433fada520423f45cdf83b16b96a02b123399507e2d65f5d7fbc156881465e3bc2569f132b6019b06a86aa21a9144c4fd53e6e49f076e4e9da40d80120c47ed0378e4185eb7d47db04f54ff9267efe48e2409f65ae872a403af3f7be6180fa205dd284cbb80ea7730f52b4b95d98061147d552869d411a86dc5880b27a964d2b68790d8b80d20808061a2a27c9c01206efcae9c482d1b62b63e8651988113b6e3d4cbd37b8a2343c364b42dc60001e0d02177014e087180c30f254f071a165b445c565662b80538845d9a68c857b42225b5ff1921c673f5d20d14094f571e23e75306336b54a4db01cce4eec212be41dd20e900fbea21981064c186112709c9e79b3d76cad9ec949813f8fdfa908a776604c016cda022af75d635b401852a503cae436943b928f0c909b0ad4cd4bf71265547610b92d2a12f309ce01b2d32bb3f8791899b5a369b7abc2ead6b357f038d038d84747ffb89eab1ad55703283224c1576ded256e18e2737bf2252144eebde59652a6245307062f062406ecc575e6e2ba0d3c03afe6d4a6baa8041ad1936568c42fd63a09a452dc7dd69e3af85a2781f6b4975dbbba0e6acf63188248bff08d61089eceb58d3147923dd81e796a198c28fe6c4778a622e19992e94ba6ee8371a7f28d3b7c8a2c1eeeefc9c36018a8bdd621694836f59e23dd9723b92af6f460496c4fcbb45ca5d24198034fec893b484946475d74e1afecd8b8137922ab888a9256a974efe243ce040a2969cf47849ed45e1c82c430f0157b5ae69483f6de321c8b78667bf8b10b9ea9bc951ea0bd7fda7b8fc6ed00ff629c0f284f1c96d41ef41f9fbf3efa7e8e14864301aae2cb5f20510f5f0ce2c267a8e258820b6d9ce017f850bc927cd1e8c22ab652ec7981f5e70b5fdeb4cce73d17c6a12112076a5a8ffb4c1772577bd0abb8d0952435f61a928684f45557d27ef42ea916e8421de45fafdc08f4814220fcf15eef4ac187dfab26c247d84f4df339e74bd7b48757eb72f0d73a0d1ac1a31ed2327c31978e39741c9bf6a2b3c6aeb1c698945a6703c3f0b3c8406f7f0feceee0f7df8585afc98dfedb090bedd5f787462da33d7c780491e00d17600df8f037eda471d857ae0607b4c703b8d85f0ce5695d4138e3e133c31b2729ddf72b8fd27da9d46bdd67b5195c00f845fb14a7fdca02aef632382457fb135e72b52ff5aa42fbedc997a1d52083936fea5c1846f341e5790042a3f292a3da97ba8f42adfb80b0549eafd7a0d2a9bcc6cd4e85737f1cae7153e53f48030f3ec6f99057859b3ef8b9fe917b963929cd020ab42882165a14410b2db428c2d090107eaefc8d8baee408dbc4cd83612a1c12b94dfc389a3b8f0cdbf479e032cba09eff0656a1fce0caff5c80617605945815432bcf9cf8f36f250ef2ddbc520ede13ae4b9cdf18a3bb9fde4fefa7930f39131814ffe43f58c5d54a349c3eb65ae6e483788667387dcc618bdf486823f00deb37ad4279d92c59e2da86b6174d251a3614ca8472d242e2198e392d63fae6f89676a0d7f44fc438049ed9c15e7ff92e04bee196674cf6f4db9f6c278f31614d958b98fbf52b0c2f4c150340ae690957155fb3be667dcd52f197bbfcd9531b0797705591040a27822ef6fe5b8a72f036eb36cbaf9b4ca7120da6f7194c2693dfca411e270e8738ddd4da4af64fba19f351138579abe527272ddb7d1009577ebb4f77a781d5934339de645477f696b73ce6f43c2bb5b37135dbfb472805c324e11a4d9cfef45bac281c24fab9277f8a174a91846b28e9a1548bcf95dff21b4603fb41c69036a413926dd64a12f6f3d60bba5cad568b61e4d3a8958317c5f98f7bf421fd229f088f1137826bc83771aec330de434429b85cfc00882b1d0461b4a91483bca5ae5f7c3fd87af185add832f18c5f97ae78238b1acb82489efe6b2eeea943956838bdbfe210cf70eae29fa8cbe5dd07755845a99b8d83b7e2d05e3ca131f2610e0442be7c09751846faddb0a66dfa3e70b7ae8718e6b545cbf72cf83bc9eee72e9e31fd8cfbb9ebc3de6907f9e5f4a8eef4a50e69eb90ba882b5f9a4e6f3a994e272ede58a2e1a48bfe54869394a7ce4fbe9dfc746a23ad15ddb1ac54cfb74e2c96f625aeef896b96118691ad6ea2d56a3593c662490ac995ff440c39f80f789d49e7ae96d97c9cbc9fb676e2d4b511d8822dd882ad666d5d07d91857b910f885658d40bbb0605ce95188373f7039138629fd0a1256e628751b072f4c8248a7ce5dedb1bf6cef9c8f53a9e45b74cea4bd13f7c3ded3374b3e8b45440aae7c3782615cf22b3d7225f10b49c8952aed9055a469477bf26b5f788467b42e86acfb01a577f1c7d432b03676f9fcbae7380f37bb8875ccb9528514bc8585c68cd48a0c951414d4893d994a75d332dadd3d55e05678ca75c615f9d7b4168ee59d6bf91438af10c771da3bc755fff25ba75423755afd37f7e8ee35056e851d09c1802d9802a7c305b6120d297c7c2d858f33858ff3218fcf5da123112d4369709c026d136c37613f650a1ce471ae858346600f077de0cf8a0c150e06b5273f8583421c74b5c76488a8487ee5e0114482496df35cdff48b10b84304eb4f3ba791fac86b1cfadbebae7eb929462936330ccb2836218e10b8c3924bdc9d96d96919863c90c5333c03ed22ed1c499b62946233c3b08c62d36d585a069217939707ae15911d99c5a73c736d2aa8a042b5f672dc9c1209cb8fc3b987f673bbeadcc9dd6a920dafd5bb5fe6ca324a94b932177dd19df67858467ae48b6e417de44bbe24923492afceba15225f93fd9772c4f95ca541ec275f395235c88dc4565653a35d0fd9eeeb21535774eabaaa7575874a9c9bfb49237247f22411836fe508f6171a01a8cea1cce0948800d3d0a0990fec65369de9e8e8acac70dca911da437de8cf4b95716947593aaea247321d1bbb4c67e248a469238938f9ca88b2178eab64515323576546fe62d3325916990f2c9331e1236a6439784b0230bd10a01280c5420b957275458487abacf6da6d52f78d8882542e963281cc5ca997ccb1176af39e38c83050a8b716aa732c77ab519da37135ae08ca4bae080d1a1d0d6a06d819577245503e76b400d5b995bb61d8d46a0d6a487bbd81a06f8e61e7e370d44a66ae1420b54ca65517aa7329f73574aa337a50ca416fd6653394d80fa5a3e3aa9313246a637152a81c94cef59bfb65ae1b1952d80fa583d261ddd97d54f6a0a850502a321250e98dfd64905469762b2bf9998b67ea8ca395d54a2906953bbb1946f525875a8532331d7fe95f31d9196215f51cfdb4e85016448b64d1eddf321d232b1f7b84a5e4f6eb08fddc66d2aa4359503694b9daa351772896316129d5605de6c2289555cbb603541307e98d6d29cd0ea5536fb0cc95316915ca4ee569d5ca6a6565c4faa4bcfbea91aaa475fbb7eeab42b757822a9315571dca8656ae4a29ea97fe94a39d94247bd323e4f6ca8a889596ca90a0ab42e4f67f2baedb282228154a31acdcd9a510cdc04209335bb9281c6a48bff4af50aac93a94cecb663f7fbebc5b67658625a03a67ba922bc2f291e5a550ab647c3f0bb7b2a22f7f59fd1cd9f862e44bbe52467856f7fb199c44e124925717575ffed2f2255f44358861fa295775ea905ae22a11315886b96b15ecf51f7d51ca26e53b990a97a570d9976248ddaaa17c0d5289ae568faa125050b9e01b990eacd1bf42a45528dfbfb242e13200946a6497b92a1795a865e8f7d7a26ad432b26522cf186955e5e9977e264c86868a8abecc75933ef9ea5fa11483ca8dab4ec39e727155df7255d369940b5fa77aa51afa5e2947bcd90ba09443e56e5ddd69af3f6502db52c72bc9d037fbc961997ccde6a2746e7f26396c65d5db852b37aa739902aa73745b40750ebbb732cfb4d8930945a3851a2f78c393980218e0002e20a0c5c40c037f7519001fc8809c340662a0c266208c5f01fbd1105d621110b6103f6c1b84b1695489a7219824bafc34889534089692f2b29456bad3d24294da3888edfa4d83d8987a1ac4d64c9685dda994a3c59e34fc16192dd5cdec9490cf5158296527a57448041cfec3466552b26cc6281fab4f535f7eecb6adc6fa292d33df63e90131377ba61185cdb4520d56abe4a0ac5d9a21e6c6c7b2a7512363ec56b800f1374e061720fee452608d98ca5eeb6a7bdcd9e811099e1bf43401fb02fb623ec5b626ccad9443fef69173b9f3292dfdd73732df7081353670e73cf90dfbc2727b281f0cb9b661bb09f510d569e0624fdf73813760f04c47fa7e2ed5734fb9736cd3f781ab83dfd8e9b8816d8feb8d3ee09db53dfe1e2e2c33d88bbdbd5857ca21bb68e124c11446461352613f76c91871b846ff07736100be142e7c359d13c39efbe3dbf0977e8fdc9c3c19326428a594524a291db26c394d2c324c8e65a58cfb03de22389426fb8fd6a03d8e76a1656cf0fe53a91bb822db6f1cd971de07d88426eb342162cb2cc15257dd28e103f237631d330cf6cc51cce6ca9fc15e7feefb80cdfdc17d3d5cae7f7c1ceedf8eeb4c04f39c723e1665d8d190869f32909224bc367661f83a5cc5c21d0b04e4cf9f807fec3c10df7f761e504202f17dbe07fc65c7c24cc385fdbe74f9c88d117fe147ce39d8dd4214a1bb6358dae6e12f11420af9253edc81174cae8f78230bddf85202edc58803c3c41d5bd82fe6023d72886f01bed1026b74f42e8667fcc67f178f5ba21b45156e7c99338708c2f411535cb8f3a16598e93d4f1c1866ee70d9cfded9395cc055f37b58806fdc006b4cfaf36d6acedf280771bc6e8037b2b87006ce205cf81f6b712766c3941fdff28cdff970058225b1c94e6b67e7c65ff3d75e7bc7308f91d89f30e938342dba3e7dbaecb0df4a34388639e6ef983f1331449ad086075cb590ca7f01188832f3cfb846fd21e5cc326d8799651dcd32c05e0cf4c6ab030f37ae3676d96a6cfc8f3ec09b3491ec65198832c46863835d7fc935fc69951793f47fd02b19c67f7e1cb8d8efd097b29bb22c328ccbda811bbd1443bc31ca4e0a7299d37fce87184387113af4181d0e707777ec32d09211dccfbe6073c7a68c1ea3cdc19cc2e832d092a3dbbfc265a0254297bdbb9bb9d6f638c605caf9403ffb18bbaf470c7dbe1c0f406828ede847ceb9e63e0fd8dc7eca4d976f6fc6e6645c3b9007b284a878dd0feeecb854906602d940e74e9f18ecb43779da9b7f64febcc18ca8b061b5cc0b773e9c0f5d2dc3aa9bd20f034d7173552a2f6864c89d34ded3329fafdca7652013eef495ab1c67ae3c27f6cc9751cbc4a1a396e99fdf9325762d74dbd5deb4b1e19d4054d8dc17ae776c269d63e763b3834a2c1676a79fa0e412e0f20e8c583c1dabbcb1f25d682fd674e497f82d37b2900d596766667777af91b919eef84b73f716a3bb74767608af73db27604ecafde939750e11edb9af88340bc642b5caf22cf29966eb95abaad6b1c4ce59eda52e1ff14105cd45b759a20996563ae3f2111b2637ba11ce594996d50315376662d83f6223c58d1e7fecd72b938ffd604e522a2553ed4199225326171be6c09c5ec5eb3fdb099000717319c90f49487ee0e207470748abeb52c6da32402a8ee58fd6f66c0cec4ca1915b06487c2e69adf6fa9570d45c5a90bff8c7f711c2a3a273fd831148fc21a116046387ed6441b2205990a64168102a444c6a08420873f0f5871d5966883776fdb263a9e6475f6f6f6ec89019f6d39a7299871bbf25906e76663ea10cb5f8d9f9d1f1110285cbb39dd8c51988f4aee4e2002e971ea05dd931c34420d73f966a7d81a5f8fde84a035f28945c0612327253978184865c5892016bd2644b716e0289a91a0a844f9806ac4993264d6492f6820cbbbd4629e7c4307728b87b96659ba6b9bb7bad25777737994cdba952212c33b4d6dddd4f4e5028282929100e8069102517d81feda73de8b9a4bc5c07c2320f88d073bf7f5524f087062c65c2b44113e0ddd03ce8f3036d24807a5fcbae3dcfdb6b229532d4b20842386d9e883c444c2392f4c05f0a5d62c5921b2c2982c49dd0458b61e3720bc618894ac0e250b8c225842b844460b5cb4057f4e0f24f102bf78868c4154de8c09e9090dd15460c91c2c4154314e10a10b411acf5a2b1b02b4068a0252c2b6ee035b0f532901532f020ec7619c80a1798c08a13c468851037aa228d66535daabd282c2a8c248b7284cec2ce58126d2c45b253c5125a1091a28a22b8b0322e0355018227828aba89a021c42d0807d865a0a02577bb0c14249431c1320116283f9aa01b12117537ec6e47c1c62e2c13e001268145335ffe0f9046090a602f1fd270c7d282110d0f2d18d16826b0ef978ff81084fbbd0dc2b89fbdfcc2a71938f1e304eb3290132b98cb403d46d79ef00c18146219a887e8c6677f81fd821e9f18d62931e79c514639a594724a8feece10c2ee10d81823f69bb432c56e73524ab34cd3b46d83b0a6fe562bfc0abf9e7e2b956a4abf994cf319d6d8df4e359e6cd54af4b7934a7fb0ec9151726234d350ccccbcc192e9644f66983278b7ad72f06e92ef26eb8983d756fa8385bf9d9474d874f06a727ff0c3cba5197e26118e21e285a4e68d4d9247975f16b58ad2787e49c4443bae6aa21e57cd787eff7115ca73ea79e55b0cf6fa49c0328d24c46f926cf8bba8556ee3cedfae66d2af1e6a22dfe1f8b5a87ccacb207fe993ad268e65a864b5542baaa6540e75255784a564e5108f7ca1625a9a8dbf645946e462ad3ac733eacc9c83190767adce356a084a27a351310e5ee75c1342ad7067ac885c65fd057eca08a912a5703152ce7aaacec58b615996b9ba9d9337c5d52097bfd0f8564e7b44e8d421350991f695ebf0e0589597bf0cb5d6c91746378d9eba6e6fd7d65116b5ab0b9f66285b9ddbae894b294a313a424acaa1a81f948ebff4b05644503c947229af94a194a214a394a37ee927c275502cd40e4a073504a5532fa710a1a4b2ada56a1cbcf0a254e74a9415e379ffa99494dd478dc44c9b89235f92c828f562985a6bddc287c96d8f0692d16ba828488ed4a518952b47dcce36adbd7626ed4da59afaa68d0681351bfdc96da8c91a63b2b46f2982f25bab946a309e6971ee7403ab127bad51c9e7ee6e4db3e4ee1e774c3b29539d3a974d4a2c7ce97eaaf36713a0bbadbe3133a3b2f9454af5f90556e37feeee9c9473650393024d192977776698e8ee6e9ae2996d8cee9e62c2ccd2db68cc68161a2d3c04999638ebf2b3b87b0b0b8d19a9951613005ac0d009763875601bfe1cc376bf77145b7743ef5396b68dee768163da4bda68cbf0ec98518609923fa88f8dcf3dea8531c6ea83197b8ec0c6199699ffc118e34b2c62736233e5f66ba32dc32c71c090d0348585cfdf360cc31e7b88c5332a4008fba88b2e84f05ba855588e7cf81dd4558e6bad12a7c74180c333323ed69384b18eba0fdb29c25643dd87e974776f51cae949dad131fd308c8cdedddddddddd1d1bf6074e391815ecc295a32e4c1f6ba3bdfe98e799167fc833f2b71fe0a6a30607c4a0f5c2101ba3bde0020c2ff04c0ebed8f76fdc0e1b6ec8c6b0367c5462bf66bf4108ab03f6395ac3b17fb34e6b1b68e3420a326a11fdbc6c7e705a3aae9f6f790e19320ed7381d5668d2a4c9cd7ec8796797b250b09f3db236b48cbcfd37207110101446ad1d2d637780737b82e89ff2abb0090f882c1c1b082e9d0e5ec08463a375a9064f798513946a8a97a48beb575cefc18f14455c976209b705239aee21a80dc2c8de068c0c3a4c929fdbdf71051f82e031d2387549322406c1fa6520279070d04412fe8bcf9739726d276c467262f563e1e2c0ba1db6528e314e198d9040ea45688f6018383242115c704194051334fec5f5ff520f4ea67ee681086e7f89ba4dbd8301a424894aaea51a197f1b401448a8e9ee564012382e60828916467c68da0ba02808757777c794eb2dd7efe78224e73a12d675244dae473185f73894d4a007c80b253c8187c68dc6786136ee578f0041c511d7ed9fef831625ffeaed29805e404025b8fdd136a93531b68c0a3b38bafd4da909a8890e34c76285db96052700e222f162c10f3f2f1802870645dc2246403b48727772fc85afb4a9a0d64e464404c30648467a7a68406b05c403a11bc8e0c6cb403c08badf8f415d60610d3ada6b46f2fa6fbff7c22a1ded4ac0ed21dcfe6a5a818d3d36c030fd3a5cc501f8d2df90044308e2f6c31e3619bb0bf0688f26613f7afb3356414ea5f8e4c473b0b1cbd741a5aea6155879f9bdde60ea022279ab955c7f0cb26c4e5776dbdc3ed2ad560201a699dd0e1ba02a7b7e17a8ca3a98d42f2e033b21d79fa18a766e5a81f58b746d60187f6620a48dc892f325a50d6d6c6c6e7f773ee0b581614a94b29a5c48a43d67318cff12fce29f24058575c23f7b59b80357ed5118d80fb258ddd9abfd6912d6df863b3b3bfb90c1def9b186e81089eb23fefed11dbe3f6415ec20d91b9218838585df83fbd9181f6812762486194228828eb475f0066cf41a76d6ba4afe74c1acf77d7bfd5e04e769e84bae08fda6d633316cec28773cc432fc23360cc0cf3aa4813d3229ae66967ab03cc3337ebbbb3ff6e2b6f4c12d0efaf4c0d6651efed25d0e1136c8426f77fcc4c62e6ceac2f6f37fd0e7c2873e3b782ee578070ef079b4cce9c287395087d5c3e7e642222e64e63c05798e5cbe5f8a69b4236c77963bca39f0c77d00bb6dbb942e3dbc0b5dae57c3028c5e7b2de59c2e5dda6bb9d05f5a232289acb6d3692bb0dc3a2c3198e1534aa503daeb4f3e773b24c743f2688f5f9ac78e1d38f068dec1a3061d2d2401f63c4aad4da5d8288aade95323ec676f373c4232a147ab6d082c6018850e2374c8312b1b404a5cf0d3c3c4fda8110823f37f0c0b2ce0c4987c84b64b0389e5a0c669d8419bc9cd39e7843836ddb354339da61fe2340f9b96f1225e94ca29e30ddd7e849f3ff187cf3f97bdc62d94bee4049ec4c6e2cf299ceaac11ffff0391d8f800d623c6d8a454c69f54d2965376de7fc7b80a7eb7d00bde28c11b3cb3c233f17a92eb9ec5750845edc2c68734fe38f068191fe2630bbb54e3433ef6db9c33fe609434234b9f9661201f21d74fd71f12c1a356c12072809ef0b9eeba813f29b81f7c5d0ff229723f58d4bafeec1fa12cd578c336cd239776df5f1c9a478ff63cfb94675cca5ffcb5236cecac7dfd20db2208061d2e3a70e8f8d1012594ac03070c3f3860d0814387f75f0c0cab18d8c4df9905c8ded5c02fa5ec209450be0d104aff7615a4f9cb5e0d6c0d2d03df054612509ab1570a9aa7a8448ed535412911cd000000009314000028100a07c482c16824cc1359f40314000d83964270529b0bc32cca5114850c31c618000000c00018909199c170008d97b0441567ef1c7b43755b95a29de6a172e6a2f831c643b74721c1986b11353e2be00f0c69528083a85713b6904cc0d7ed5171f7f0b48672f0ce37d68a0c25d8ed6ddf3fff2c0d0a2150107cb711c1da04c86fcfb253b65f8acfc80341026921112113423ce02e9c1510054837c02894495413dcc0fe02b1a2cfe0dbf995e523ea0544b9f1935e0b9aa031ff7903f9808e1f666f5a1784899b9e9cb74f96a7194d2985714cd85668ed21c2c5e2278a2f60cbdd428d4a52029f5641181df81f231fd75985e891202548e70b6a73b1447049bcc9ee2efb635e6eae891bf0a31b8647be9d4c053bc50b1026730f3df8b01e4d7c772c2b2e40ca87aa6d6c75cd21bedccc4b2aa3d6491a2535ac84dac961b23bee31033063a5230e0674260eb1cfb98649e15a9e10606bcb12076108985081cb7934cc38220985130be5b8449e59359155ceaf257342550b860707cc25630888727f0ac8a8f7de907bf03a67658fcc98c1e12519b669de7b530284ad2ef3314d0409a23af84866877e8bbfc783a5abb643e329868ac49d36126235365d10837e91dd19bd359b1c9d6e36da98f4cf7719aacc41eb5f0c4a01c906d4b7e72b4be2e66c04acd21f1afb5217152c35fbbd1e08e8053fb1cc9ccfc2bd876ff25a60395ee7df332414325a793552d44e626b8cd607b625dc3241fc0ace7ed8c353d8d1abf508bf952821d5c035f79f3276bcb5708feaab32b28db196300825941b7ae122937dd3f236bee696d2a6b90d2b01bb05a7ce5cfe87881c230e4157517833fb4bab7592ae9c08405eee2adc468f7cfda227fd159840f35ed37147636c8863ed6047bd16faea5d9ff37f7918875d9fe69c918442f7e89fe7f06db9ffe6ec8681d0b24c94ab56dfdd98f77acb0fc8616ccdb292e237fec6ccb4384c69773cfadf5085fc7cc919b4c7da4e651d6467cca4e3f84bb5ee2af393b1a3b7a53ccd2dd9b1866840cb51a976e5e7d997ec1e455715b78502538d30f1d6a95df1decc67880261d18f941a60ff73cb80a536d7bb066610e82fb88fc4ea3e499a59f40d5040cfd90c58aaf8460a2f33a49c2bdd192c04730caae4bcbcfdc0b22278c58ffeaea745d96fac4ebac160f15d6c9f0120727a0ba745278c18dd696efd6c5e74f91b112774523ff42769132bc9734625f1371c4d3e55e262663effe6f77667cadc469b49fe69c867ff394594a8cc4108296e6bf4eb58b68c44045c9747b36c3aa42e7f6169a09c67e5c8d285d5f399eaf341c18c1592342e90052a71e29b3c7cf197316958d8cea83634846f2889d02c05df2827f125c2c69229cdab22e21b4e4df4e2086de672fbfd2393330a72b1f3d6850dd97745b1eeef88d47942009a776f50d23bec637264a1bc3988aa3b340e083cf71b79c8c3a55ce7860fecea02c2f2100361fd7602660d7073d18e14420f38367012cd7f3b2088de8220ece91df0ee4dc72727ba6a0fc2f214650f014880d24f06c33816045a4a79a926389b162b7865a85805169a6b0e5ee682a42246d9ad2a88c0c36bae3dae294b46c98ea251a21c22991a247854544568e9a9646bd0381a44282a990e183173d9d8428dd381d56441d1c4a813ce54bf81c3c4286fcd6314936d8bed154e107746f43ca55ef4211131cc78dc8e744f4c30f47182fc84c505717c41c64d3abc033d14e5eb33a35d4a07189233a602a311b0f388626acc0c1765f93483ffe8c5db10aea0f7f408d4f8a3b95be5c8349ec6845e9814ab8441d7bf585cbd904ffd93ea3168055ac75b73c59e027b26ec7795b1b40faaa1622a7e96d0d8f54e0205858e0c79d364ebb9315edd2d49438c950a16f1f981568c7767e3ee229cb6b7a8087b0f42849e0af5d3e8e193fb03557a1d5666f47ac80c8a423d8dd3ac1f0fe5c6ee88f006906879b732110b5ec6b96ff13087528d7a79cfcf010ee353088b048887fb0506926f9642b8f115a96a8efd87ab81206daca777bd94e860702c5669d1409f301ac89ee2ac05b48c595d82dbc5b69ab8b08bf2409d930dbcea26c1ee3047679f15342e53bf27682dfc9e38a09b8dfb9ef096e246889410030bb605149ec0d7abff07dcc5f13a8d6182e2be4a00538047e9c31332c7abb5b4c62f2a8616005b8c494f56e22a9f2362ac68c2140e2fc71c8e16779ed0b1d93e1095cfb11e2ec6800134bb275b2003ad447cb846466efe0fc606127344bea6b9738e27ac9d0f205c485c78be8a5f3f7272af7dab0ac2b6ee2173e708ddab43672eeb034afdff9da8fa5a8daad3b653ebbdfc66d61e274d099b20914fdb22fb9d611f632a0ab8f20e03ebf5e5b58ba5e4b8060a0855e45fc67b99fef285b14aa79374fce07abf352c7d937dd63a29520364f8c591a3f216b454094796757268ea079351729097a0e883008b54da05aca8e083f458d23ec2e344cb4dac32c06c2d2808fd063d252c37ee012f64d3b13ad43f6aff054544f78f251ebcbf54b4d40d65ae0f85c5bcca97cec57cbfbf85c98b1a6ca50d51287428ac7e34b1995f36577adc4ba2cd96b0885ec33992d0931d021869c46d45aeaf961e0fbd7229c68aa80e1f21b9cbd99d2524b08f7581fbfa5cfd0b786dd7939e09e18a0a006eee177692a64a8f4f8c49209096deab1818ddd784959feff62e0d83353bc6a026b8600979a43b6d569dd4e84109e8f04ca053cbceb794f84085e003222d95a2ad7005752c23039eac82897a030eb10d62a8a6d328e8f5433780d6df949d81a7cb317bfd88d7fc49d86102e41efb43fe2e90169a48f486c52a7bd43b3d407dbff576eef76b6d88fc62f30cbb01ba27c5003bec04f736fefc4857f96cd0fb4ec411ff41449c100b2c966bac1ccd3f3a319da397b2a2136c830718ee0f1a487c850cc151a95221c502426e22fe8db8f9cd15d71096934ae6cd9cd3c89ea7cbac520e88a2d78bc3be9ab750708d3ca2d081b8d28fa234e46f0c57b63cd521769402c895429ed4378605b50b2f696e51c080e8f900731955f1487b60e07935aaa7dc724bd65184843d709e680dac428da26a13e524fa22fd8d2018b551283a3756c3d5c2de11cb3563cd1668868742f6d22c25fdf9d99798bbda63e14d068b44a9fb41ca89bd2aecb5eaa0abf0d280112544a1f5f8f4f09f086bdc5a91024d5b8d254e55cbce75a0e71a347d5a8a826248ab47341c6b24e631722fd4f0885e3da0aab2004c4ae5ce38661a9977c56ad3e4880534c4eaa48c09f90839bf7615831e4a3182d761fe68df2701ead18527f7b1bd6a537aabd074eeff715a6ea7c4170ee55516ccc44d95f442a3fc938599b887125f90e483a92d5d23669ed50c2c26b9848f9f806c2890b0d0582b016bd6c0ec0651acdf8bc7db3d238326a26ca12ac17baf895646dffa0643258f07c8fc3b81fe4056681ad41d58bc1e521facb8344fb8af879d7ca97ad2912c02d147eb14753e35ca5744678c20db0031a8c1386cbb1467e03de039d2f1fb6f9f0be050141956d64fe92353595f7432742e516aa0dcd7638eb75ce6b6e5a7391045dc14ebfc9b965bcb03605d3c3076e41c90b2be71f377cc08b714ab18d1f13d7b917069132e0e9673a719c189426765fc0163cf08ab90bf968d567d136c4e6502808a4e29ae3c08ac4ebea393ffdd0c28fba656e7cee464be8781e72c7acdb169aeca621decbfb8c5450e1cebffc488718897c4909da3a2806b7b9e03cbb23b6a5468c2e2fe569de91f2ee948a2a5ae7b2155d796c6268c8f262a5839f7e2fe2dd96b5d1871b575f704bb00ae293a3a223507780ae241c09e09fd50d2daf0f4910578ef11c0ce7b3db92e4e1b70012c20c4ad1fbfb7b326e07e8c1a4a93e8872344d92b4455e8c2badb0fac5dbe63fdcf8cb3a5ce48359f6b8714c3668c94c43ccfef4931c0b60603272d085538be4e26c174a030b6b545eb3eb19b6dab520d0fc6ab653a7160ed1cbd32d4e63cc4714d6a825c20fcbc12274b87b0f3d4a40af9db2abf70b626ca0f28cbe072f3087c374d98b71d5d8cee91a870871f0c34bb8ad022e809aeb320a4e7aadf80a0ca0d3afd21740b2c3b5640ed01404917f029cf7c636c84500aaf4adb8084fc938fcd6d195a2515a6f5723ce742096314db8e3a0196e91b19ae4ade9cb0a859ce3786f8fad030c374b4c58286194c1f64a4bacd4709eb822d8fa5fb8dfeb6839eb6c50b71928d4c4494fc69b8d36b7085d2586d6d681597862ca34ad540ce94a4e436ba7f9d735bbf185b04f8d075fc04995222b0f560c186a4228a7da97117aa47199919765fa2c402f5fd177e486811b2530d46a838da6990e0e97e42b195aab10209690939239374126f8b93c7c23040e2d9c02bdd8c0c46d82a1a188271191ffbaaf89c3a097f4d801571c9732ff59218c40fbc1438cb10e94423760c42eab778037593e5f9d71380f4b9638a6e3bb4f59c797ea148ddef3c9233e3bb213969bbb38676d651f553e77bf586688b5ad6a35aedcda17d34e5d3dfdb64d692a0150476f5ae859a8447cfb44940e6d805396610815043ae41b1ad124f5a53028f4cfccc538d04a9e2a7a1ac2b075c708c42b7f948ef059cebf20b883383a6883284be513fc9d60083a3ffeec9ff4bcea1bc3e2ef1c892aa660c1d14211187c7f0409c3cf0a0c8da771003d83ef74da4f05886a497e4813000e99031a6ad294046622a327d6a11813621c995aca5f4c1be1f10bc9784e153a83e716869a01efa885ba0e38fa90f4e9538487d4c02d0c835c1cc714defa17b389a08bc14b23ee8a7bdc8ccb6dd5fcc800de203a22bfb2327e3cb91b8f68cac9f876784bfa0fa51966bac46e57c58a35af08bff7c5064738a05de65b3126fb2b571e5cd37df149cd30be1a06f8e977fd4dacab56aaa34e45a4b91442fb98a45544c4bd004d00027ca810d8f2cc553e384a3b5a04435809aec2505ded89cf4260ff1987cb6fb6bc7a74041ca9a8b483a3f19a1dcfc728c3ba2a402715db5c82f999120b27190da4fb8ff0e9289aadc729c47074aa3776613405c3a77f35a8c4def20ad04b99d1d8a0043b5cae2048ab70325ac1d089d201a7bc17a6587acd0cb379381a8f436d516be11df71b636e59f1b9cb3bf740353bd74e8b674f99bcae6cce28d8ecbc4fd22f102bda363ca42e6cecaac66336cce6cc93ad97f30f84634f42c02b0c382b7b27e311a4d867c7b2ad893c4373a64584c506ab3b66739252ac9e2461499e628da210c5d1418e8cdb83330346ee339695b420c058028e869094cb88bf881e132b07fc651d79b652ea0bd93f85c594689f8abeabdfb26c96da33a0d3c3fca6b4f84cc9a07bdfacc6a79fd5e738d63128aa766351c7192a4e6753b65c4e72169f0a26715bf4cb31e6c39103ab5d31888dcd3840e4f43c2cdc8b7dae09eb8ebdc2b65fd33e595a681e032c6de90b484aca33ca2a4f26b0bac576506e3b4440636ad2c18feb6da73d87634bf3172d206043b288fa1c8abdfdf720d70e65b06a76beb46385cca3575010a028e531ef66b7a212d2f2837940735bde685ad6d881aa1d4666e0dd9bc2f01a7a64755e9d11d0212831ea00b25bd5d03ebafbb1fa8a79e353e3396ecaab6810414c6a384abe1bb01607e4686b33217c46c19fcc84980e2b0d248ecc23be550302b575a4446362b2d6d94ead252ec686efa3618c29a3cd6b953ad032facca1c239ca44b7e89555135be39761b449292b887d72f59246ab5ad5813f43e9fa3aa0fe48a1c7703ba12a1a57710d9ae6c106199e215f0a291bd2c768f585a983b3ff4c9900187a19c5d854cc0d29edce21874629250080a4c63b817142d8e7e7f550c44c5eedf476513a381891511fb5702008044a8399b1733637091374fbdd14653061a7274c96178c4705c521acc90d1e8f49d4468d7bd0e95f6b92a81225ab84fa942dd733c0189a5d14fefd4c7a8d2004bd8d7b5662b6d57b7379425156bd10c38d9aef741ee5cf9971ab444bb86acde7660dd4accc4c2640a5ce26cf288c248ad4280f9c28444c46bf1790264c8f0cc24f35ed56d2e0c0506e90d1d33329625fc9c2d6178d8f4a48944384e1b3b2a347e65cc0f4b85d4f8e43283c4fa5f40420c99cf22a7057c982dfa80606710e0757152c53df13f423b54d72af59b84ed75da8d0c55631475d30d38b1d5031cb089fba2636bda96f2bba85aa2635fd11566b6084e14014545d2279473645b7c7c4e015a7990ce44f43d8e358648849b2fae09d1e61c8dd4f7863f68f03f7794f9117b7ca37e455a5d5d8a23d643c9af47505e46e0494194d811285f4be94daf555166474d85507a8ab4eca05ac2e8ea3671116c9f06862f84f93067f9fbf68dc3b97b368232021e9fc4725959b4dbdf930b9d0fcfc5fa8aa32bcf3ce49ae2df16f467c0600d2555624687c25e05ca4d28c3f70f6d939b8080307c2625963983c221933b53b1cd6467f09ba943e3256f3a29f33eba49945b830be279e5a9b5af35575cf36b8d936cdfd741a96bca195446b6d7ca68caf6addbfdf09236d6e05a64f5d776337c2754f3c4d8ab090d45f326cd78334cbb1dea4bec01f16d61baf61e46aba470b7ce39fac8cf43f70c1288df1b8c8f144ec417ef7cb53d65db74e401d886d503decc37001bcd26667217ac1ce2abf7096550a83f524b8f30213f29f2fd19f96ac8aeec7729bbcdf9aa5b88a1ac5c6037c35364a1e8451a2701b17bd7fde7b0cb055abae3689133d660230b158b80bc52d1506bc07e144c0072701d3015ba2b07711a48b3a1d0371e0086cc24a52a121c10b7ef4c31d4fcf936300e2bf6fe4c87209ea7f843025978f4cf91b9b0071c24b3153ab66851238564c44e00147a5c6244926af4f8d40aa82019be6d3b81f02f1f894ad395499882a9d8776edb939f31674c34eb4d09879cfb173f797b6b7c7bacd656034cd1ba36f88754416a7000200cf002d123991c9d740430c5de91d923b58bd2cb98db89ddad14a72f1fa79bf7b762860d6da4c0c4172b41c685c90ac04b386700168a347472c4ceca3dbce0c9fdf94d3a6f753da4a857cb20de2aa85db82ccec11623a840aa97fcc3d275b2dcc164f044b9e49b7665fba63e9ceaba70f8201c1ba7635f6c8c32727e0d3b40e686da6eecf854b8cb880a4ce664a1f46f165ae817e87b43a976ed60afb204a8feef303d36740bb15f676d7559d5ceb95d74920eb6734407a9aa34d095155c47acdc75bfdf0b2c3186fa88318fb50d0c506d005aba4e72e4dbcb7a57231df80e8da71825e5896b70cb77c9d3f63b7f0a3462775a0e22032893e2145520067e1e84b1c4af5f0a20cc10f0b13a22c0b5ea314559dd19e9509f2502107a9910fc77d09b62b8c0bf80d63e732a62d55211b20518fa1ec1aa529470ce6863c8424867828bd7846b388481749204cca9650815beefcc49c2e13040c6fa583597f5a65d4f7280989557a665ffc6905ddd7693603a35f96e8a458113dcfdb3c71718ad7f3b4d1c0f266683730abbe07992aa15d685ac58278a908704e2c52111b58d496961cca83ef42f00ec9a92b25d0c69dac9eee0454efd293008b0743899bfe39df63de36f74bc1f16bca3cf43941220bc7113b8519fc5e8597c54f0f69d1c54bdde103c4108687877c570575e1dab9b4650d44fba5b199698c2a572bd29630671a1624f9f0fc70b84411eba3a309949c85ed37d0dc653eeeb4232c9b913f34024afb16098cf8afd9717e142d023279059f00fe8698540bbf430bcc48a6f20d3d7fe8d6d9d5acc86b716b16381704ebba24915f896eb653f50622c065b8c3fb28c6c1775e55034ed64a88dbb596119d81bbf3bbc65c3042289e7b3d2be950a32e836c9a16b3d5dcf484c60b23ebd5d24748bb7d3fc6238688e877b3be5e0b72bcb8de85b3ef1346d915d22d82f4da72818b68a7941e5ccdbe1e34646eb665cfd4eb7e8083eceb4de6914edeb7447b4fd313ff2e1274e492bb7b6e188e02fb4e81ee5289a26965459cc6217562e11c134922adbc39b82bfde652aa8c079080e653a31b9ac3a578810cb5616bf6c9fc9f5b41e36ed5da08a88283a5013327df99dd66eb72c14176daf40e3201587548e9fdde21fdcd4abd61454665db8ade3113e852044dc5ac9b2e79cf2abb551a6142ac24a34ca54e17d64a13ff71cfcb854508e6c4322594aa9575106e1b8a1ef13d2941eab6d3204671849d6442e81a6bc26d917cb4440ead4bf3b3ce682e9f98f63f8ecfdac1bb48ff8b4e26e77fb48b5d31b78e8e91e3e19bfa97030eefe89a6776696c5c769799352d207b38760e2520a9397a33d24b43eaee3ba0398b73274ca5c7036139e1865df29c9e7b227521fd70f5e90556e62028771780bcad5305efe8ac9bbb29027a0390db89db58bdbb08b7baf17a4bd3381ddfe6ce8daf5bd772980662dfced47a4918bb373b2b082b740074b93aa1d5f44d0eeab235db1c86f35d537a12c82a70a29d65036a38bd011d2332cd4d10550dfc643347680cfcca52c0633ca92e565cad16644abbbe3f6572da62145751796846b64633838c83bf9c8a659de67aa202c04e54a39e5ffb47c72962aac91c8b432af7420d9fd57ad2dfbe328afb25ead1e4d4dfbdf56d1722cc7b226c3694cfda7ad4320c3a28b64d28a933f5d31b1448d007e1b047a7bf85321f542471e47b152c09ae3687846267d9d5b0e3d9a573491f0e2d6923618635dffcf7563a7ae7fe90a3e88e5acbc9c450400c3c84548752d4073104886091556101ff633c4ec6313906e2aaa8fc11600ef156b12e064133422d415d942e964cf4c0525e496d7dd65b02e32f9e1663cd316c0900bbc943898c0beaff75bd6cc8d3abf338b0597d8ca8429c4d79aec463077c65d996f508f2008bfe613a4faeb84ea0381091298d051fa516901e01ba1c4c1761b8214ab95e445905726cf4d8c15ff1eca11845bc1903b1674a7762000008e15f773c7c34e8427aef9f53a33d29e46820e92a835fd09b0f66b83c5ac0c890b2178f1900bceeb883a10f0da7194483be15903ef90d7a82d6ab93ee8156d12d458e3096056378ec70b03a75af4addc7d1c10c611280ded7a690016d10f073343a73d0d12e82e0c8a98312a1f5edac705db749b8b1150ce2b39e2d4811942eb753df390db9c49039e62381a36a71817a57d400c28a7d07a9d2993ef9935ba0eb0152801a69f1b4ccc32714c610720fccac4a2ac25c9dcd9cb4264a087ddd33ab992b9f9321f12e9baa7c00c29328ddf531ec928e3dc2e4a37fb5e21d23ebcc19a3aad2353a523dc1832534c38ff674013350dc6ff7f8bd03b31caea671437837ecd4004303dbe56e4efddc605770188333281683d4c4f56936cfcd2cb80c58a759dacb3510d5960fa837a0e0d11dc0939a1c5da005e5c1c8c4ef0f72ab1898d20d25d7d0b60711ccc8e8c348cc8fbd5b9706feccf1223603637a85f8ed9f20201c1e738b551c7f55c225a4de6a2825a34c88003d0c2c70294f6cce8e18e14da9b7ec466a0e193f8d09314e94500fbd401fb599d5c90844aa6b6250331dc9b0c8524d0dbabaab865e504c8562e206df315e2b7a38887bd814036230833723e337955574f11eaddddde2419442793175ec2564cd3ae92243f97837cc7ad2cc938480f4eef0646816151eb3b61cd65222b503b268c20c1d00f1eeb3fc5079c9361dcb8f2a7173d51732db971aaeea6fd84a4f7356d002fe016fa78c7f079af838bce590335165152a44f6c0e88f885b9cbbdd2c244c22c3a4676c6f913405dfd5b9b9d958741f5b3791ffb1987ab414317a1109114d46e52b6575046742ce660620d3808dc21e2c5f97c99afa4a485e9b23c918ad93f079299651ac9a08753b0793748d548f8bdf50e51d1986fe30c6993fc7c70cbb3f5419cea5a2799285351993de9879574ea92f616764219405487e8c374fc3bb2481254e27ac7aca9de08adb6a665b2b81ebad14b8fa5e926894b547a43ad6774f777d4a473f259902b4d7559808ee37e51a032db6c8b555e19b8cd204267a44e308de1b9fac8aeb9215e8fa7e2b4d2b4754bfe39cfa52168c8bc75a0776cef948edcd62d1cc1dd27102e4f9685cda74126fa4d599914f2a7968fa497a277dd63f0a606ad742f6709c0237bf3e2c20750aa6c7639e8c8163250e2db9a3d3e63dc491f6f5dbfd5f2efdcccbef62a1e409125c8e5a96e8b7fdd583dad833c35aa80a4831e64cbd383055230fe9090e6e7087d1206c5e24ca6f5b3006abf962cfafadc467a5e59f868397acda42025ac69bb7d65f8dbbd76a6c58cd9c77ae0ca75e720650fafb93fb78f949ef3648bceb233d1bf46925d28e808706f276302a78731157dceed6ebd7275c6495f28ae10238149f17217f60ba90e3bc25c993f83236296b02be867bb117a93c7180c7c69dfbcc9be28ef020e4f5ece0121ab3dca1fa170c89e428546aa1dbe82b97f820fa4c14fe0b28140e6d1bd97b9e4d9d04020b1df269c846417c0817c9294740d5e65a4a5830c7fae7ad65791d40d02c89084882409892ed8f698d0243e6fd0294aa001b37e0d33d0905d293055f2aadf8b61d4e1645678b309d4197e0f7ef950b2e3df400f73b12056f8f9a67ae28532111849e6f9d6c50277c53bc861186f833e9504072a56cd0d519858cc5ae862217f0c288c353a91e75c60ccf9a0e9ab3675a885f8709cdf16dd003e65cba030b7d1b110e82ca7e716a3472f1917c62e4e020fbb6eb72303bd7027c4accbef5e8773dfc4a51b2f314b7278e0a8ec71b473777554eef78c10645899fdd6ac6eee948a6704729210a5d6a3b48c3c80996f43facf9f65892ac75c7fb8b7e05e3993be44b0dca227cf5877c8ad1af02edad0fe129e1340e045b6c54eed8849e58f7bbbaa380e659aac951b0fbd023b735dc3ac9e039d9ce40d1ce9648820269cd1944afba41fd18c05613dc1ab15f06e19c50b1e40dd5ad06b7fb8a3f8eb9cc41ccda03fef452a01cf599534275e811fba48cb99156b2d31bf03f15d6eb4a5117a6f9d653d9f6bfab641716f3c678f307f2cb0cf780536d93d27693bb68d1fa0ad4f69798f3ab130e6c195a1772486379493ececae6c0f5acfdb25232e0e9e890c5b140eea5f10c96e46d15d57d222f5d338b7b009cdcdb71eacc2e55a7218022d60b1a41729c649c6f26c229e27cb1797b0d47b14fb99d75a9886cc707151480fcaaf3e7c600bc4b6ab45b05eb958c9e501ebcd06d7d95b87a0545f617e3dacbdcf6dbdf11481b38046f4ea378411d8f29e420103cc65ed35e3b5082e2055f10eaad188e8eb4cde1e5e20f3fa58244d1355ee0ea3632ca714e4a6c5989685120543dd9a1e02e8440ac1a667f940c6a9753b2ac11b7b21a85fe1c2137c21b1a539b54462bbc846411c27dc840b6a2b6ab7c34289786cfcd443565fca4f4bdf3ec27a0639c92d7ef12463ea2884049d14203a04e84237bcf458d96e1709859d6338c8a00c1d25ce083a44a59ee82049d09ea9c541d81a13b9ecf3627b5a701199dc2b627c26de19eacb6c0837fc8b5b392991eff97ea23858670dcf64546bae66c74cbbadad9a5b1b4038f8a01f8143ee689933fb7d2cbc0faa634bf8cb84707b28d1b205f2da39abad5321c53511643b8e299473a0ba7c91bcd5646a0d40f7855860481b72a4ca7af487ade4da5c2767f652b7e2b0b3ca6c4b86937d582e12d1ec3a9e87c3a571813559297360f356b26599c01ff7a3d66890377ad8db401807422d751dd3e76c070259ce91e458731c2fdd9ebbf29d024bc18edd730abbf6a4cdda01b49290d62bcebae5edbfad8df708690277ba138fb722d57f4ac862c91a66c0caa27586102c36e66a3bfb03793605b932c9eeec24f9d4e3a196f388a30cc6d9819e34ce778f3c204112d6bac1aad1d9b56f99d861abac60abc8b46cacd4e47b63ba3edb5ac1c82608624db01852dc5a92a843bdb6c44bcb586bad3d778a3607d18ed7384d2ef18e17f8aa0d4e55949bb7b3ba0ca8bacba51a085191b3fa6e534dc5a7c1662f05a56899db19833f2ed892315fa256dc312116ffd162c8031ca9d2e9641c6f8298f37ae429dd0606e84d3831dc6637a1154cb059337abd40e804ae6844a5ca77730f1864e71c0720adf0e752cb8a076ed187889b7359db43ebac8d94396eff9a084f15b086cf08f5ff9d4a0544b81d07660a6ffde7bad410ca84487b9b201d54ac86343d510f2a80bfa51183699b11f3e824c75e9f7a402bd49a5f635ccf71106578acec351b41108464cf299f618728e50c485e19568fe3c578fed4057151985ed058e7c44e5c9017065294fbe47528bee0a0cc2ce4a93a278d93bc4fb29a77f08d1e7a8550ff4509758dd25eb9d69348bf7f1e4a62afa31d114d91771e8a9fc56cc87805c3b6aadf0f543b21075162da02a047d622e19e5f4b45df251ce4a9cce4dacd3ae80a3f8e505706e833c35d59cd3a0c4af9a45e8e8c591961945332931fac003c8b8653a712c82c034478d65cc114169041b42f8783b815e019dc6c4439c11390805481af2d150deda84a52882ce2711d7fca5079930e07a6dad3b6a692c549712d8ae304c3484c97cfe97fe40038d63ae7883fe433afa421170302d3e3f05d43231981049d17d22d4128829392b482a4d066ec78072c07448e443237c8e180cc30d93f30c22079ec748264422a2d33d1ae5147b054ac1004d645970a111c09bb596bd01ce04c4bd35a185e15aba52afc96f10a713b65b29238b86e3f9e8277756b64c8c4838fc02c368e8e392fe7debb184a067fe992fff5aef487a64be32da0ddf334bfcdfd4049da03272fb35585b077a750c1976e1df1f90bafb29acd7a40de40a91cc71654628086b3a05ae22b4c2cd2d35733ff08b8c3bcadf589fa3fcce38caaec2dd1ec910877e9b894d452bb8054d3d246ba99829ff5b0099c2757c23ed5564c72df02f2824c9d3e60b551c5dccb07bd9b4f94d3ae451a33292e3bba8bd4852de107cd6ba01daaf8f45c928a777445b92a5dd5aaaa8d721192fc53645685060ada14282a9a236224c27c8036cd4491fe4a641a62593ba91b4001ed8d705726049edcb2c50c0ec6664bd67deffb98549f27636811c17fa65951345da13ab46bf37608d4cada603edad23373a28e89b1406c051057918e9816d9b42f88817eb7504797dab8b42b910b48f2225438f48acf2b21c6c415cad861d4b9ce6c9ccb579101ee14b5568245326ec43226808ed9d6c05ed13ac87c774770e7d59d44c2dcc2392db1c1920050d084638230fc948a8f33cc927766921b4cab1b98518e079929996a72b582887e19c06a669beb26b5374c8841d10ff40d0b947504c17b406f112241cd68d7e3053bf8a4ae4b1fe2fdc1ba293daf012a96f8d40c7deaa8f356390f076fa774dccac6354d1e7e5ab0a3c770899f486dd0133ce08f511d9a1bbabc5b6d1a8b41dd31bb8f1360d2842336496baa93e894470ca98371640ca4683252e09bdeb5bd74a979dd59b0d2857923a6693522d86560d13d345cd80f9de7c09ae239371766b9651c5047c9507b4ba86476c574ca5ccc6d9d187bd17942ec3c4530450c3bef3143beafec57af245d5822d483ecd1cb0b45f33598dcb8e990f47098e98a676e704cf0c0fbfd7f231b5a3ce032322f8463cee52de0830e373b1aec2c8f11282df1355ae9979278ae7b08b0744a9a61f32af9cf07e9f5a6b84af49330f625f656a545e1dff30934165ef890eb3d5bf8ea092db0519880378d7231d20534b9052f76d14abb22cda6f0960f79d659cccd7fc666730f1c512cea0366a1d41bdd15b3e77257c6ace1526e78098aed1b1f3c85049585af14640e452b26911b897fec80b457dcb54f1d0157299674de10b8cd6feea2dbc91c61c18e1edffb3047fd876d7b6af6f07bee46b4ae837758ff08eae1f01f1842c68e2ef82f44887e0897c0604bb58adf1f40491ee275b552f7ef0a831ed07dd10a3fd3f1e55549606f934744432762a8ff1405e9547e425723d3c954187180ec9b4006be837556ee891a8ea02bf2ad582e5bab5455c0507631e7af44e9873c4c83be72d4b6bfcd0f029bb11b348a6965360c83a585115c17d1bfe23918352fa24da6a6543af93dd0bc38a18466e62ba252e468528d30cc69234c064722146507eb8d6491d387469adeac059275bb650c319a8a21ef0b2a1a4b7bb3c794a599d1f2e54d0f2abd71737f94a28388a1c9d742af432542a3f9cfa09ed7e2137896020f76beef476f49e65ea9ca8cf5d454d2e5c6019218219ca5c44d9094599584078781f684c8b4073b1ce14550952878f536d481502904c9331417446c3eed355d6a851b5465180ecf0d1d27b4221816238612bbac818d788aa2d03ed9a5b5c27835fa74695e0ec19cbc538a1590d9ee370d33894cea07a4ff2641a7449b71960c8fb3b0431e322483dddfb616ee1c6312cd91da9249c012b63ee90265d23864abaf2bd477103807c7f7a76d790204f6a7b7fa11af0078a79d4649d212f7d5dbac95f39e5ba2711bcfdbb800f9a8f81a099d5090402fbe430ce8f88506dab03a8c44271b907e2894df53e9ad97c7a93ebfc50191f8844389a1147098bf880aac377c3864a2340e446a4159d6536f1a9815fcc8601ba2accde23e12577f72c9648f3a330d90c672ae0eb91863f5730340b60d7b7baee53c5d4c99c4e91a14b3e707756e5228ff51bd7f0d250fe29bc6c05deab535c5bd59cc774c7f933f377a1d620b64f2903a0750c11bca9de244701b81e84a51ab8e277a87fec4ca964772347f18c21425b4282d81bb9bc94cace95b5f3595ce213e3a63c32b600e028d05225e36f0d7906c43083092eef31643125d04e7326c0a57b31f907d8fb85f0f673e447536ab56b2ac47649e0376d661081d9f6407ca3548625ba899d25c90e46a818206be7b17203d0c07bcbbe3d64f6f8c6ec1b2198a0403abe78fcd83c9719675a702d8922d85736d74a73361369227352d90dd08049c7e6be5c3e4be57c46e2fe2078e8038f507493a35b6d129a3f9d915bda35487554302b101df412863b2f1baadc4a6609dcc7c90a0cb4c2afa6ece0a5191f3c748d0bbb93841a2b2e545f0a87cb815c631929a87865d1745fcfb23ca0e699ada445fc8d641687c6823e1dcfec7fd0a1c15c001896a2e19a740955f2c39810e414776d11583d03cf9511fd4ba07450a0b2ad91492a08ab8aa59666b1f63c4459ea8da6e335302d64c7618b696607fafb0ccd8f45498d9ff73f10ab2827e61171ca8759ef8875c6e794dcc2692a113de3e4fb9f000a41e4698d4c0d3a6011198388bd8a393268b201864f96a2a8bfddfea81d6db602300b1c72dcc031bd8ce9bf099346ccc2c2cd9856fd2b6b46a6f02d85773ea624f01334dfbf41b5d95444af4b5b7cd3f60a286e86632fa1c634dd11c8762d5e4360d0a7ffcfa160abfd02a114711fab3fb59aed52958cbb91c461662006ce0e81f449ea9c6e40a891e6f962427877b7879856a7a989589deb14babf8a1549d74f1f681aa8f9a795736b856ed2bf8993a54dda8be26621a4714630e1a7230288a84d24054cea497fa40762be6a81267d55618ea4de72788fed6055559d77dae71e76a34e7f857c8296207eb2f61a5bf13e54843a7356a5f62d668b26f0f47edfb286fa6b906703422cafc3064f436d32abc09da3da58a904f0465420f9df7a5aadc8aad9b967c9e9d7429bb9c308bad4ede25121159865dc88961878d4174f2a22044e95c1c6a7546f3b246b29eb349a5c4940c7ea4c5ecf8ecf337e0dc4fc2393902e58ef33748a2648bc002e039f848091427a428b7c7dd5ae1d85d4f30afe8cbd6a6a295103cbf4e5007fbd4a2434f5710fa8e7cea747a9da946027010ca1fed4a3dc9744225370ba0550516d43fbf655599022a22143067887469160113aa8782ddb7a6357cbf0fe4494a940e64f67dc38444cdb088b9dcfff9a705ddb164db7760ad873fbd4484889113c88d90095e6220030594a0fc29434c820366981b4737bc284b6a6becedd622e42ae9426d4a934a6ae7bc135df162f48d8c1603ab4bb28a44c875eb2db057c505dc4089047c4d83a4f0a80cc6425edd8b78765b9e1096a3f81dbb9e143d2c5fafc2e23710c4f514b3fc06e1de21e3e71b8c7b8152725c280d17948acb4ae126a5e0a2d271a334dca144dc560a9794822b958e0ba5e182127177280dc21d878ef43bbf0a7102b55f62f9401c1f22aecf88f301f17c94583e11c367c4f529e27c0289f93e25968f9f7eddfd546e3888bf2bb050de7189813406935ff09cb0698457ad492c8cff8942035ff6e80363db0a39c0e83d72be32d0e3c506eff3c1b276bab928f87412ef069df634d39eab2da654170cebfc4dda0090c7e1b7303c499787a19ab3db6173a24f68ff3f974d19140d1c43134c766e32ba02b7142249f20f3555f03a3485c60a6f5698aa21b515f45629d4edd178c2b5b3f29d9dd1009df6a0a077fb38594a17fec3c094beadfe80886bf4aa9ec7eb359e8e1b91e7f0aa84485b9015f714552035e4c829657928deced3b2ef740665a41927a0643f03d1806d2574a00903f250829a34059d87724746878395d00e9d2ab1544e71e47f462fb0b119913eee2c36d00a898ef937b9d006cfa60e7da0f756ecd144a3251fa37316061690a5619dd8c387301b5c07f2669ca2629fd92742d2a44e6c96d0a7cdb6718df23a9d4d51383f5e2a7c6cd9e56295dfcaaf9d0e916b312b7623a89d165def80ac03726d6016baa6a76313775a848ea0aca60ed870a7f7618388a3fe1eedcd8ac405b8d32158a4339c7cd00b201e8aa562bac307ff5e36a050cf9744c7bfc9ccfd0150cb3bfded30f1ad7fdf2edd69a41072718e9ce55917119d4235cbd0460a2ab43fd9131e5ce9d7346c85bd0acd0a4b1302451bb8139def840c1236c8b6bca2b77f10bf0266949a6ca70b77db791f03b68dc8e13bc086501c0c7a2d2429ca8f89969553ddbb0150f79f7ef0cbb68cd3d8ac92b8de7fd22e1c2aa61b8501a0f3f1297a30ddd1de9f945f9361521207cf214d34c5d1b88a6f18b06adc7735df2c10f6c97e9b9158139e165c1da23cfbea9577361d2c677b7c3aee9ac53e418733aa3a4e54f540c6a49236aad34009eda6507051691ad8ea4dd15ec495435af0497d2e5619e818c91300af06cd3c335e4afa06d7ea99f82b6854a0534d2ab4b29f36bfac81823089d27b3bf71b4e14b82737629a267e5ce63cb26f2437994f74fa997037355ded6fab490870d35e4325142dd84680b712c01a6fe48f17ec1df5c819c59cf606388bf49b207b2624af00d7aaee87bf957b6530722264f46e90fa4e38378fa90e28cdaf224260b0fe2ff2d308a6a840434d151ca8338c121c05f81e5f05b85bb66ec83a0a701d02fcb9d26ca54ff85b88a1a76456cad8ac9bbbbab0218603e89c9469c880f9d2992c80f293876cd189d60bfcbdbfa33a124f2d14dccdc12e0b982650a764b3cde95c2fbbab123af054298384ebe22a0f67bc77833c38b72909a90993e83b0df2d7111067d37b47623a9ab98fed93ebe3b2d08c687c135ac6bdab90f2ef954efe784f9047810908d1b7f9cfdf50675fb55ebcdf38f2fda76070860a78f427c734ea6cd3bb86f798ffa23403dd14088af08d63183f7f16907783fc0150d9f62b4817f62f4eedf113752affe48023b7b898b89145c4e67b947dcc469b88984d8da3fc13e221f36391152190dd78b54c228305e31c7276b60cbf96155482d6f5f4c33c151bb331111435d23cb38060fa75a6e893f616ac7ed94c0f528f8f2a5f0f7739fd77667492537153133c74964d81f6dee544317b9c65dd9e271879542047817c343987cfa2cb54a12df051e45c59fe3cd83943d2eb9a153a018c00dd9fd1baa01a7c2f6e865efc3a9312778c7cc7261d4c042219eabe129ab238a3ce07c1e17359ccc47f088dcc1095ef62b4deef52c7337c460bf0777de58f5b3d670736201847e6021709ce4e1f938e12f70857c384c5ca6504d252be10577d41f87bf05a8783ea6f6015bcc485dc0583cc6429087ce227a6a848eea48d9735578f936bf672bb5362d642a9bc982b85b00a1cbde93a1c50005f7c7a908859b179e345d510819654f753d6700a18529e2a5515c7f9ec8a8439d6ceef90787ff35a89ec1e86908a29ce2511a8a0dedc276ade7e22858b41476efd41058f1a18746b624257fd85589f3c7ad1d363e98d7ea3fed4f8306cbc4b1b458a20dcf982ce02ce169dcb97e0f175dd6cf5688b50f7a827ce3227a59e532c69916925483969e944f9caad7e2da923bf3c0f01c9188b2194d0df0f2fc26667b5335c4392ffe3c39003f25497366de1ce15b3b37eed44906046b00ec26ed6061c580fdd47d830ee5099e0f3b2ade0a3f9a15a039b2aa5d79ffd9960639328f24986c933574efce2655e65af9cbf36c15b46f99bd58ccf9b4cfd5966588311712275059aaff82ad96a2bae147d1e119e1708a531a6b76c0cf4a3d3208eb672c38b1260a57e78a49427607f16b7893dcf9ab01596aa9d662c171cfaf5c9a20f1665bdd6e83a08c8fc987acbb3e019e1a341ba8e41f4a439ea1633e899447a58d19fe36871c121debde6168f29aebf7e61774d4b07b7480647cf5ce10e07530b4e177be12f9ada0a7f18e732779044fd3f02a5b7ea5b42124897feb7e8d2bcf083507705b7495479406ad33ae39920b4f6dd5b48842b49e6af03bdeb24b7b3c583d611bf815491064be61cc0df52703b56aeda8ebc22080a500fa83d8c6d18649b0a639b8f9153cf9068377731e7a3c76a46a78e0605c38d89dd8301a53e02377350a6ae20b7794252c1f956692b8b02c0a2026eb9afd1830312501870e903fee2f077fbe00b7f4745120e8df395815c07adc36c32a9a1943f8b1e5ae4c3093afbf76315e5decb1bf5e608478d62825f4cca1e96f8e9cdd1978b58f9314ba92de28474debc5b6f2a5b00e2a6c5160ee3f68496f492a1bc9f0dda09d0d6508a6578ed386ef45cf02b03cb78735e78bea21cabd509da2ea7f429a90249d1b92cf31053f982bae9ea908c693d2b03c670932ff156d6685965309d0e2ef979f3ceb2dc75eb6cccfe5e0cf3f99a3f24ba0633b2e4393c28203b7f290a6588abef13cf5f5a78b4fc0408c2f5aee40594ec5bf30731db8e71b5b572c0137075638481e1db0119e8aca6f083660ae0ba36c93f7aa0a23d1a3605fcf3ca2222823039d23f0f6f804e7b371daa756a62658def2c202d2629637fa4d292c66e42f9626d5481c5e0c39320bfb2ebcc01797014170c8086c753ed75696fab7871cfd3888fd8dd8b62ed5edad0c82a83275499276b0205c4ab10dd98add5970b31f8f6afc5ad2edb070ca0d03a88a2420e91b306786878cfa9dc6d7c0a756078b18066a49aaa991534f734727c99f4941a4a2e793ad516653358078134eb15ae26c72c2ca6cb229381c9bd9bf78bb7065a7572471d9fdb3a3cb8292911305b7a3760d6f26734f75109129d6af8433d149e7888dd2ada2c5a739616c6dd83db2d5ae3459e259a2d456697ef9b56e5924da31d281ce676c22edfe75cc06bdd7e3631fc3c6380adb27586cacd719a7698f7a52c1434d10e9ed6495a5aa3647a469175ecb4a12198112df7c4100dfd79d4ac74c93525fcfa1bc210d7180e6caa25411bad98f7fb1129608cea2ff801605a630b9001c4cf892601626f2c3301b9de73a448b694d6888bf59f17869e13105ac80157a78b7fba98d5e2ff8b8ce80d10f3df615b33489323b912f47df35d324619c0bf1a8af4461d813ffcf98b38b64708c12bc95f997ff1dfae94ebcf7f9702dc5070d2e394d2f2f50b2865c7fa968c3f5b90cf49f4708acb6eae0afcc5e632bdd2f92c2e5e2c240784ef457de550c30fe16b76450ae92615f9db519289e760b6820cd35aefc71047ab0208ca12aa3d7500c14de2726c43c946449bd87ae17f89361a1bf7c7b7ccddf95f3f4526293cca6b09c2894797c2ce7c2271498c54da1f63c4c4f5e60fff914d8350b7efb56f886b16a7470aa455dcaebb8ae14a3336b93b73b61224409b86379597514c6b81baa1adf19210dec8fd64f2419af7177be5e84ffdbc82600804e95cbcc010432bceb43747612c5d84dcf6caf87998d4a00050b91a32bc575aafd05fd6ee2dfbffae58e4fae18e6a882e4ba375a47f3063bea38e8a8ca88535231f8117cddf374c2a91626b95b2a01d11291faf2dc405977a73950768ed1bcdf88c050619fe9c9ff84acee5eca766521508dfb294413937c9cbf31353c621ab8002d475032269c2ef6f54c9aaa645aa89c34fc8741403de3bff8e9004f15aee9a209f60346ab4c451546c95f75a1e01b6504c40c7a27afcca14263b856c46faad587a7ce89512f5abb19ed2f5aeacfe70453f58d4d7d0fa7efc7938f4646b7a31f99f95580bd767c89a4c1da2954a83fbd406cc47fd9f984c6260ce5b6deb08006b6cacc0baa51325783051a649ff65cae08b0c363cd80c74cdf4f2f47842633e46572e80a442162ee65619b0fbb5755ccbe71c7069dc85dff97e93bb1ff65ea0c4adc9ac0b3327369e32a918bd10272ab61fb041c5c4e588bb43653c409e84ef630a45b697ecbe036bed8634c4743721cf899b3b2a2647d0c4a130a87e8fbc4fd04d54afd557ade36856798cc62cab68d48ce40faa0a767c66ba4c444dba595ac3abaf93299eca776a8761ec70ce1e2ec44d72291a1fdd8c8e8b913387220b418ef78782e7f1e4b7e939713723023740b9b07b9f34ca9866db20f89ff1898d94a574a2b08d323203060e66f35b993fa68b6813100e5c3feed29b1542b3e579634ad2f986947ef4883f08fb26ea74918aa66edf999a776feb62b597a36ea2577fc2ebfdddfa8078417e546eeda6297fa4d27bd18c40e23ef8da0d209131f92dd9f50244ff241439203c9f8ef1e63502af1608a4583840723e58c262802409a95b52d2a5716e75f2a9c370762807b0417f0c963a862384e37814d8b2d144c3348feb03121e55486a6ec82ce305948e8a20bc2086d028c9f21b6210c67314423b76acdd44b7c0d85ac6c95a442652cda2457623b71707c2be00d84bf8a4dda1c555d0b4cf074ead9676d301308f5dd3e4a40f7315be8ad558dec59277e7c7786758b19524175d1e9420207dbf84a8b677ea326334138fc16f0ffdd47d15085b40c40b101957e096c39ca8510484e526b42435cf1f1de70b4529f0cbff5f0865da56592b17a702167a31ee8c734061a6ef76ad858de4954c7b705ca4efe2044434c4dd65a6427f550375e662db8ed00ad0530dadf4b0d154cb49d5a693467f427aad7db670831c4ad3f685586a13915e6b7fe79bd6b9e8b765188fcedd45caaf5995b533204fcbb135b83a5abb474e7118520f968cd905027e7ab70b9b96923e3230d674ff2c030d8b380d7f1707fdd83dfcf0c41d1e588c3d469ac25e8690d3d9b87ee8f222489101914bc278d6deb31d6c6037110e2454e23e3a906de937fc1f546f4f1416b2e8d9dd7125120b9e20123cb6aca0988a7d948c58b82fae9caa91f6a5d25d01a389516f1d3c68f678898aa9e50be4529fa62fa7dd476f0ca7e20186d282e2daae1229cc6442569aeb3d2c75c1ab02be42901d43c5b01198f1f6c8b5c907efc9095ee4d922e19da90d3da2690aee4c6bf8c80d385a26520f5254f0515be5d0288ac6d1281d905b44834eb64dd0200fc12f8b8cef7831e84a6e2ad0d920d568519ba3ef9dbc0b0fe2e5121078c76f0c5ac351c17b989deed7f88299f8ae2538ef526e401cdbeb67666b84bb17f6174354dc5c3443f0d663ce74a04ca84b4ffaaf88e1d3764b4e809028bf2d3e46878f4076091c99f4e76cc568ed35a26d1f45ef41c4ab267864b12766ff0929538c0b7d31e0a7c9435132be1298ae780c3104b708c84d16e32b0ab836482981e8367a5a3dcf605f92899d43facfd793ab2f201dd6541c52e747ae925c5c4d6a03f4bbb11bd88d387cf9e47e1aca39371dc4e27b0c6efa1df1c8cd86e10c7717137d23b8a8f753ba928431a3ff2b8e66dbef99f82d13b75ba5c14801090590a7145f7897c96610689fb542d1bd4f7a3367ae2022cee7c25b1c3dc28736499f0fb0a4fbf808099abe9c4d401886f32f41a9f664a5ec064078a32f764ff9cbf7c912905f2447781dd208874330d25dbeea0c949217e99e5a3ff82c1e6d2b158e6bcf15b837814f4988425355eecb77f9f1b927d858e16639a73b60ebd50d680b220d039eb37f78d4b9720ddeff13d50892f43d03c39f4b07f8ab0bfc894be3e54f8067febf4f96bc8f8eac692d9468120309b6202910c5074dd6d1e0207497bfdedb7d75e409b7b46148ccdf32598d37de8e34efb688fb43253016b3e9886660a484a87e4f1839b61045a5fd4fa126cda8f1373143e67865fd54a980e168d281c719d9a3dbd4b3c1cf54f9e4352182e9a11ccbb64d16b74433bdee8bdaa0039751ce722ce12789f37f7c73d002935a8526060b2eec5bc7da63269cb4a29bf8487da203723dfe1b644b9e06e6a84141dc0f111e29e8f8af4404937ed4ac24c3fc7349e847d1378c413ca717e6fe09f675048734ddeb4cbd6249e7fb76bf1b29e1306fa20cc0c5c4d10529377c08038005f97f08e816265091f6233ac172b2196c7eab58042cae08285fec08325a1be05bf543b27c524b56c2e5abfb69533d982c857c326aeee73a72035220a6609fa2c7326ba2870c92542c6cc07bd2b7ed2089c2f2b5507ee752f4e8982c322b614ece88836181ad945b65f75102635513682abb23398917cfad45eae65009d5f429b896f973dcfeac151fa20a776a902cadaaec1023a74963d358afa2f4d77cfd21ce396427093ea3d224d71eaef65e10ff9a835081998458cee39f403421380ea5e871277a2ccc3d7e5876d2176152202cb362986408d3bdc303475ccb5c4a320e0c1329a4cf3ca364a2df047dda312969b68d2e66b792e5620af916fab1338480ccee0e0221833524b902921489d7ede3f140aa46581ddada5ba94e099d3dafc97429e9c81879af46866776c8d418b5f26dd93b01536426cff101e13e82fedb24702cb6b239725c90f94e8128ffc3c5d20bdd327bdb352c7575a864bf507a07bff2cf31bdd4e396cc5639763d3b2c9d6ba5c991c76ac502143963a2281d6b2f2c50fbcf0aa6bec309567c8d06efddb2997c008dc30538aad62bb7f4c562099fec83d6c583ab345a8162d38c1c19511bc8598d7c3a461ce81a9b3ab0fb7160b83690bc087c099c5bf58493c18e4229548cb3358ffdf2792b218a7b4b0363a30e35db32b0ba3e353c65dd6d42bc403c75b3c085fe9b61f3164855a4d904a0171c083cda170d709034f2e08ff8925ee538b8714f0162549796928cae60f61d92add157bfdb65295a3b6afac87a37df34c0cddaa34cd6aa7565e6c66fa679d756a13f4f99b615dd00c2c764443d1cf19eca22bd55085bde740b3f0e9ba3b887a3e9305778fae0ee6c946e3409d9de7867ebad0e341f8b033fa3d64f87e6903a7380959823eda7929ea71200a0e91ae3a2276c0b9f86f228fc04e1ba1ee3810fcd043f640bfc907a47e2cf7e3ba6da9ee1e00fd841056fb41c3db219a92db43eea7498cffdfe0b7890f6a2c261f407f1f92a7ee60d1a85d67df5eb3ff7044b6bd873d8f6869060d2a27bbc10998e81815767b9bde04c3f8aae67a1821b934dff00fee82f4c5a4f83c94f1e9848c87bfcb90410e500c64a60acb04a364bd30a9f1e1650288273fa8b6a78cf1459a112421be48d65e3645dba2d1c725bac8a6fd8ae74fae056c96b9c8304d4c93c1193d93f5251ad016ed6294c04b06c4019bb0e07db39b37bc2c561eca114b6c6801afb30b8856f4022e477d2d864dbf204bf9eff7a5cfb0fe42bd78a88e4d4cb357dd176fecb3cbfaece679c131cf2021a0f8a6a5920d8594d0772159363ad32123d3344f9c0a813478668c67e064ab53f8b20c5777eb4d5d1a120fa3d11c2e499d77d658fc7faf8e5ab76b3c30b550095af2084be0b3a3cc25eedda4b4724d8050e33b525bbdb965b4a99529201000761068906ae347b2091249244924812492221d1b9d527481cbc5ae96870c771fc3f07e4fca64139276b31a7c736aeadc518e5ec628c917a8c55e8da49b9c54871b05d2a1989eb689785669d6e4042132335299591656691513367969a1a9b1ba7e254b0b9999165068d2c346afca4744e81e689948c6f529a250a0d953993a5c6a605f72c5466a2dcccc071cf4265264a0b38ee54988952e33d0078162aae3413c5fb00e0545c69268a0d004c4ab3cc5099325900003601aaa4db50923694dc86d20b37dc956e485729499592ab947274a6f314286ad0d47825410d521ebcf7514da35ca49ca8b1c1a19a86a5285585c6c07233c305662d556214d1a86183594b9518452ed8605e8a51e47d2da8a4962a122946510b382a594522c528025554d3b0c4a84269b0a85e98bd70c32588e42092049172749891745cde40f21b48f20652006090b48a27852041b8c6a605181c4b3f4e2bb0da69b194a3936464e45270ab93c98ca450e96456863fda03fb9a01d52816cbed7235f370b11396b788b3077c202561668e00923b71339392514335cd060bc562734329969b9b19346415b93483460d2d355ecb7b1fd534ca45ca891a1b1caa69588a5255680c2c37335c60d6522546118d1a3698b5548951e4820de6a51845ded7824a6aa922916214b580a3925524528c225045350d4b8c2a94068bea85d90b375c82480e2249102947c7470fd24cc7f986df903752dea2334486219c44b7834c416c04b3e98633a843e204b5c15223b708000c31c8a0a5cad26a15830cb28a5c8a4106aab9d4b0b8bca902b5c12283009604806309c70096065083461042269d746661239c4d0f79e3897932a0c446b8bb6b4009a841240df6047ad5d9eb3569121f1d6de1a5a5c946339ed5d4d8dca466d0cca0315397ea4cf6839858d1fc583605d9cbec89d76bd2179190502a8a9358965894a012bc265010952841af0a459dd52762ab5f758ad72b4ad02be855674a80fa45e5a5244829e86516e5f50aa2129404a6040b7a694951825ef3e5030f7169e695e51554673068e2b5d990366c541f0df6dc909a8a474986830d4a453328e88915989282e53a0b2ac1abce941889ad09047482d7eb95e535bbfd32eb009c76d4290d769d95e06524b6eaec04415a12953af31a4485d7a4b2d619245f412f212c963f9c41325631740c32b000260c665054f53c22b6bad76b06dd8b0a2f54ec6301171d28c69e35d801f9d3c57167135deda252b0b1fb25bae20f3108101cd7dd5c9ec2c596b5cb0d36a9b699b8eef482b2303736295bd34432760cb59093584d573ba86135353637a9460204641363064dfff46b068d9969c565990b6f8951b0e10673272efb414c8c975cd5f4e3a4aa9414a399d2a5bafaf3c198f169888b8a609d2c85049aa3d3101b718d4d0b30371d0cb5845a322282a285aefe589ccd051b2caa7a5b416cf5ec88db3d33aa428d9e25b9e13472225851852293a1605e7782c29d3881a590c0d9e8ea110b804e7bcb421c34c3b1d310133100c012dc701a71af2a5ed1091bffbc5e48806c9c18c6b0176e74b20e69d087f852871f472a21aa130f395d5c8271a7114391434fea74835fff52395d3d62753a24379c460d45c7df60566e7f3f115b2d6bd914b76549963fec642858cb1a0a6a0bd45207a5939d0270da31449fc660e8ba2474b2a8eaee49ec9670fb89a0b0dca25f4fe9d906db605b12a7810786ae22d9b093c58f0f763257f5831fbeb7a691512733b2b7e654438d3b8f76649c8656ab550c7d934ac52003cb582b8300bab82569556fb04e266b16946e4d2bd3c801d328c61c37336e64b7c0055504f78a59f8cbddddddb909cb47903ae829ddddddfdcdac46652ce6a06103f6c8cc9c002466e608207de1eeae002577770d28b513cc482cb0d282ed770bc7ca012b2d9a09dd850c5aa5a814a28809b66f7c3263e282383327b325fd44646657c2f2c7f696e9d8a6c7f52fbc802b81c68ddc5e6bb0b9b6c116d81a373746194fd870d5ea5af539c04a9b1bbfc6f466c95c3cf10408eeeededfeeb69bd8e0c3c7c5438b205a7c8162660012330f48ee9d830d6480f902b6bb2523c47a873f48231cb7cbfa17bcf1c3d5ce8d9db77295ab7ac01eb00beb52f0d350aa46b063704e1fae47f7d9be83f92ea9a4140047702510e642f2fc387b2021e78a175d1cb1050fac68d24517b3daa155ac3c33e80113445784187a8115701e0a3b574590128513ffabe0095bc76ae7e792b181604db589115c0cf1a3a465092eac4c10d84bbfb0ddcf5609b1c695ff4d70c2946a908a4c10b82ef1628294c38077dc77c0e204533451c20ab440c225b790d2a40e619b712059feb0959f7af960b34c526600c392496408ec949123478e1c39728c31728c314a8c31c618636cc1932729183cf16405e3031bfeed07fdf9e3627e3fe7e819ceab2c21b0929f06365686cbd40ddddd638c917ea4d122a5ee2e73c318636497b9131943b54c4d0b0ccd0b2d25aa9c09a6e33a39653ef2438d8646bef6309ebe369fd2cc87313f9ffa0dd1d0781107a61ff511c60b83f87fa0c84585a6d73efae2f5f093174a1fcf67c8f5377940fc8bdcedab498295afd1d07cb17e3de453d7b4e7e91fb8088cd6a2e07ef650a70c05eb1ff6dc9e72cad9fdd1ed977255fcd8b97d0a2e0a8046caaa4182adcf5d6ea8fdd643f3d142fa0d7d3f3091cfa46d7a5c79e79cb3870c84452e07b42bc4e389877c1ff61870f2656d1610fbf216060c183060c030996c970bf31c5b09f39cbc9b7b7e6bed2b4f5fc83de705e9d9bc9edba71ab8cbdd38d3fb4cc9499ff91f00b2bd7d209b699ae6d7376d2f63b6376d9f0fd7759fea7e26f5138667dff49d673f5e7e5dfbc937991ee5853d9d8949f7a63f9d764c7965bc906b905556596ba57ffa40912b7f7b1fee431faefc7a907179939f0ff761ddb8f7785cf2372444cdd77c4c4ccd47f33132e4c7f823a93f32433fde974f3d47ff445331bc2334332f5ed8734f5f9fb88fdf79d5eb64bc94abda8bf34d9cece8576f0df9895f7471c5bc1120cd55bfb0be69fbefd38eedeb415f9e14407b68574ab97df5aeaa36e917f2fdbe1681695b834e75cf8d39d7df677ee8c3e5af0719977e185fbad4344dd3b4cf87fefca4b7c0bab30f47c9f1f391f3bdb086b1f2e743bfa1faf3df5bb1bb56c5ef88e31309b702e203a47ebc61911b0efdc084c9f6f5fd994041931b5a29ec1a2276bb081b6797b17043f6d30ef66a903fff034edf47f3af071997fb909f52ed433f3dd5de9fba9ffcf3e1be21214e7f7aed2902620cfca78fa71e54ca558dfa628c218c52180a36ecb92fa7eff42f27fb2f8f3abdf83c7dbf4d790bf5bd7cd655de3ad9106f8c39456eabfbb8795626e5c9d0efa64117589b1be8f3d37ae34c7e7fbdc26dbfd5d40f8bc46e1824ce6ece8ddafb6c1ffa703f9fd8e50ecd3c08bebcbcbcbcbc7c355b121b3f7cd0477eaed270c809f993925fde98eff331fdf69aef905ed8757ffa9679991b70aefd981f52c415239f8b3a13e65f1ef5f1c403c6c33cf7e2c1f05ee67df1402f07c6b35fa4ffe2857fe5c7d905e2b37d78fa988fb77e3cf5c47c317fa4882be63b42f332a7cf677bf92e3dd3775daedc3c9a990f48862be61322e6636257fb5cf08c70171713f9313d3f29973fe68bae8a4cb8fc0c05dbef9f4c4ccccb44fe2331317544e68fc4c87c2998ee8eb8e82dbec1c9b13231861bad4cea46193dab0bc4c7f461fd1efc0ec98f7733e23fa488cb5f7a22f090fbeafb69470f09d8a5bde64686fcd0a508554ca18b2c78d1c5e57fa488cbbf23f4b5eff3317dfded79dce4e10ccda7de0fec3212bbb88064b8e62784bf747f79c4bf212618c4a00745b0a0084b1072c93fe27fe44bcd1f664f24aefc2353ce775505ad1442fb2354fb28937ef9853837320cc3742de594feb8a4e4f647e661c59406e39545bce515ee8dd0d762a41f2ffd6e4a3f7af28b9152d95fc76c05ee62b76dd8d6a4e4a45182ce481977e22d7722bb0ef3201722326a222e9d22c8a8594e4404a7882c4f12c1a64436f424971f368b28220631b84a2871fb6511453811d28920e2b20779ab85a8f6b29984e8c76d69d6cceda744d6a95326a244aee2af4272d2192d92398911512321a29813192da2336a747d52a794cee9f47320130c910d821d5921148c0641b0a36a8966ca9bf2cfaa792e3435396590d4a6fc38b511c13aa29883fd999f5ed12d6a4483620eede56b4049b417922df467894b123da246dee2b8fcd0a30e094d4a429794d02d4968af25400ea344967eb811715b1aec0d0573e6469a4b6960698c5b3b0f72159b2a0c8c980625373843539e3aed983178323579298fa6b3ddda882655c286f68562380cb611a1c086d665cc04ba8a7f237255fbf6d41be2dee419e1e1f5da88bce5302298374e0d8d4b3d4b031bde105dceb9a3cfef3bbff002577e269bbb795546d7b0ec96c3822ea5817558177b410b6e1bc2863d938981016351ab971b7f1bc2f6ac59a74d4e09410f56878b3892fea95f3677238143bf00b4b6aabbae4167cb9e468f704fdd342be660af6b294db21a986493e9173416bbdf2715114c4ecb8c3c64e6b1a75f442070e0a72cd5f23bd371789e1b91923d7fc9510789d4cde3bcc691a75083c68c1b9b1a19a9183433323130602ceae5d471a6ad6a2de09af3d8c603bb048ade98042448893a0c34c302ae88220b2e7ea0e8e20a46520f5802952a30418425495170cd2d4a480112358acfe99d94b19d0492bd658c51566719639c32059c2bb9922bb9922bb992073d5c93ac6af5f52ac11552eb17a38e875a426dd160e55ab57a74059699aaf1cc0c8b51b342d4d2d14c52b342149799293333f551589ac5c30a2bac2d9a6532714159411d352b7ee1d3475dd1acf901e19ff30895d4acfe706890c7dbf1560dd2e9e1a8f5f217f22ce60012bfde391f051475682ac98633a928c4d38e9412b7cb49b56e7ae134bad4041475e85f9351cc2173e99b8e620ea29883bbf4b92528a09823c6a53fbded0a6b028a39682e9589451dfa73c9cecc2ee7c26d9b1e370c629281f4a480c9452fa7c19edd7106c625a9e3cc59ed4429392b1c3b3cde92a76984b5a961c65dbab57ebcd555f57778b8c9a8416ab2d2e02784246b22a7ef88989efbd33763e42afadd77f2617a6e1a79333357d1df5e97becdb6d5b72ffb23bbf42d50cc2ed1adb96491342b3e994228bcb9a17d095ddab3299870434b7469279bc28a1bda2697861676e96f55f378543163853b26a31fcd0a6766973e9d463e9ac54f8edc305af9b961bce2522337bcb9f24d9eff8ec9c86465663663348d407ffa94be9569567fcdcc9371feb2a90da5b3bbbbbbbbbbe9dce98e1fceefe0af3ce0a885ddd98922c6a2b9dc82813d8128356567e9c9138a6e188f9e5861e286110b8b67908ee372c8ba1ce3f2e3e019fc716ece66857d19112fb8bd73d9360b7504a574d219ed90a661c144144aae8c1b9988e275395434bd9a9b9bfbab75f1c753e5edc8eeac1afc70652b0bac7f43363e505dba74e9e29a1e9120e6d31fa23dfd6c1c40bf7efd88689f7526d1c5a79e195db549613fe555e84cd6435926a3b22e8216a17d6e51849883a30e1fc179106b81ade2254950253d92ce1ad830ce90c0bc355fe31d701667741261c3380ba92ca95bc20192796bbe3f2df2e9cd648e40615566259604455674b4b40517293327cd0a2950acc9124437ac4ea20e8e6cd5550beee8a04126258322d355994c8aacb35da5b08a026e294ea170c26651129368cae6ac5953a695b9643305352b9c49b79334ab95c0684c2150c6fa2b1c3abacd34bda3adee9b424b344d5659a3c645562b63ffeb16b5ab5bfce3fce7fc0d382ea7417f305e4eb3d1341e1a9a159f64f173fd7918d22d976181e5fa47776b43b3ecf523f94ae2a758164dae46e56a0747b33a88eb1f431dd7b9bd1841c669d07fa8fedfccf865e2b637719ca9ad209484f37858b1793caa903263bd1a88fb848aa3cb69dd69c7b41526f5f581989efbd0f4dd733798bec8357d365cbcb19bc2ccb7d93e329102d9353d0e36db5743dfeda771244173fb7b7ee8d0ad9feeca96db1fa45b718bd8ebf502c2d5afa359f1491557dc7e9ecd345b767eba893afc3a9ee3bea1eeb4c3d4a6eeabaed2fa8780ded5fd6cd377385ad5dfa637d595cce54d085c5c8a5330c01890c2edcf406cc925dc307a0182a88a3a7d25e946266e7c7245e8f2d0840db9a888a5348b8706fb4ad0959c844ca33f281061f077edeb8182e9fac73d5167053664a0da44c65353bfe2d8084d665bac80d32acee9816790da5386e1f1d66a47c6e37d0c033ff55a498c3aa142cda249749325dafbe7e02dfafe3e78cb6e79afbd9b5aada5da03456bdd418e0ad125cd92ef94284a2a7bb901a7dd50be40b1f5b6606eb4a1fa6fb1056e3da28e83de3a00abe8171a408a6ba313e1aa4b1237b471e99ae051dd174686d7a71dcda72a36766f31830f9c209262064d381105774162e40a23a86e7c724590143ba8f59389514a29d9dd9d39c6984ad55aa710cccc412ebff32767bbcfa0f4328a04322333db7dab1440e239a9698b338a192790ebb3dd617ab5e22ab93969cc2195ac48a0c40d7f077613ea2ca440e286bf849d373e9122e886d6b1b07de313295a70c1a11bbe1426b8f58914405cf74fada2508ae20a13b89414950a194968205246bda45ef92272298210164b9a0c01450b177ff11264e3478d8b93111c141abcae10bfd146752abad955412d9dce4e7077777e776e777777e73e727777776e2a70dcdd9ddf9de71429777777e7ae42c6ddd99bddddddb9fbddb98968c439210841d1c8273f153356678c5a1a858c94b1128f4cf1888a09e32420fd4c1815d557dd9d4a0971217e059ca0958e4a7785c62653f1a31d7181fdc8344b888c3279650746124a58c10e0ece9294322062890a21937bfcebf51232a358cdd880ca0d563aa40e2bbc45c28e20046fa16233a2274fe14e5e845907eebfa686098fcfa7af36e856a01edd1ef5268f72dc695e18c6bc946f250d510fe3397f9897f1097db8a8a7afa15ea37ea95fadaf3633f3cdf9f2659edae7f197973bbc0b8cf791b4bef6305ec60b63be20fe30e47f00084761d02f3e8614f131a4082ba1566b53a97f10ac111492f47afdc49640a2e4052444d4645604f47abd5e1f035fa723581f8634abbf200d7a4bfb7248d261e523ca56332c702758906a6d6a158f24117ff9d538bfe8fae6e696e294d24967d5fe06b6f1bfb1735285306b9c33bc300cfca1e9c6f8cd21eb2f3c83fdd91f1ba435c4209de965f99bfb0a5cc48995db0b6d8d3a3c9586c8ca7c34abe3f6d12c0f7cd5566b1423339b5060c3da813939150736bcd9b6f04d1cc75c57db64922693b7894d91e685ff8f781c1111c1c6d8831ba26637a264377e354c5894ec46a1c3ca2d121694c46a07273a605980a63df1628a4c0af7394798d0ddee1b7051001cca43fecbe07d1cf9c48b2c6e6857b4e7a494524dd368fc3c20effc640fa1c6679ec09413acab9d2f8c73ce8fbf7e321442e9953e84c7f9cbf48b1ef89aa669524a7f49a7d49ab8fcb1b3904bf0ffcb1fcff97d83208ec77f0f6cf0793a7668b9284a21cbbfc2b1b39a810d573b2b1c1d6347284020c902375960e3c718c8ff9745b07427ecc6af40b0139673df5bece20739f69206eca07350f472c5fe7ab4df5ebe5eaea8c3ebf5135b02899217901051131e643e1409e1ca43964ac18631698720cdea4f020d7aab7e36f868909f861adc70f5334904c6418302e4bb6b4f8f04dcdddddddddddddddddd1bf4df61bb1dff86b4f7d7d1acfe721cc7ca085d816b88d5a86a1cfac4a35e1f1fae7ff45ec974403142851ae06810890472e81f5650fbe80a58f9e14ef7ce0e7f39600a4746e80a1cfdfee872293d46da1f0d1c81c8229780456ce2e0971e51fa4307989220b3c86507667e3a7320f261a53982fe5c8465f4971ed29e67b59239e77c91035e41ff48aab456ad6af487b77890ddb65d915ab8f811c7eb38253333333333f34f1979887ef12b4c073b4009e205a828704f3a67cfa6be8365bfdc1c9a154ac0e3cbc9979ef21bd25c3b71551c217bd8ae41a6d2a4566b53a97f10e4f87ab942f00e21e4faf8abd8a33dff34c8408cc409144e4214a3535623d9d99ab29f025a315075c2863cbb3cd39e9fa70cf97670956f11a2033ff1e28b1b6553c4568d7523001078d201b4e3aa1fa26e015aba4bafb3ae92dfd0f69c9ffc296defee5a6bbf0c692b0d6c8fc755f2d9c3b101c8e2e0cc1868a9548ae2a0dfeac8f4f5e9a65e466c5120aafa3b95baf141ffc70bd00d5f80aee7d0b36a198f8ee477145361eada5aad4da5fe79899df3060de9cea7f4fb1175a6607d5eae7ae18a7a61cfa59ef6d50eb2baf3b35e8588f473ef1e11263efab98f887f7415c73903712f4a2c37699d0ca39e8de0dc9ea7679d73d65a67736ec4fefcd4d7fec7d4c3c91c5c25dfe4fdd83c1e6a927c930cec7fa906a5abbd6713b5ca671e842c19c23e30075dd6e8fce144079642fa00f6062de9caaf63fe86eaf34b80bf7ef62f5bede37982fdab4387ecbd50e286f1a855bf94abba8231c7e9f6e74c1a6cf8781aecd996c5d6df9eb5fe9a9a24d8f9e14a6bf074c12796f6dc15fb873d37c8eaca546a26d1de0eaa850d772ef798b77fdefe3afe5594bdab7ad1b579d1c5aecdab9e6b37ef4f488f2e8ebb172520882d99a8e2ffe11359f3e5cba7406c6d2f6fbcb8326498679f3b056129f023e688577e0e31878c2bdfe4c598929bf7ae92fd32b43d4f6fdf9022ae94abe4ca5552ca77cf065749793a6243ce41460232fe38d28bb8d85fdf01fcda47647b261253ef2aff4efd0fff1dfaf97df0378449fc7cf0d76fc8f65c7f087f7f36b188ab6e4a567e36f185f8a87f795a3e91fefa4498d0cf87f6fc44aa4dfc6ce6b780fefa3efaebe7835f7b22dab7da926cff4ab6a4828bdef296ce64074fa0a8c3ae22fc833707c1459c501392f1708c8d78bcc54e3cd6ddb1c811b6bdc9412cc446b0502361438e15358b47d61375fc5968013c4fc8e0fae73c4d6cc8315ad4cd62b1548cc562312636e49896a45b8c4403e2244aae03512edd12d22ae7f2e3ddcc6fe8110e4dca59c2b14513ea8cc08d4383919b3673ea10a3078931ee1063fcd9cc443ee20ef9d13044bf95abe249c747b0599fd3acbf310823956354e0b48f3861cdacb32930c6c87cb99eddd18a580c5db2022665563c7911b202a9e3b4723493fa5443cdf529c08d5107b5341f85a56777742106852d1de7cccccc8c2708988eaaab60b8f1432d35c8c363b4af577b451d7e1496195838f102e8cee72357d1675795da0902a6a3a25beb4f8e23bf50bdf08597ac21ab21f39957d4d1c299d7d5d8f412069cf5a8f46c5a4952ead48c040040001316000018100a864342a15816c6a11cfc14000d708e4468583815c6023992e4300aa2208a210619030c018618834c110d9500a4f521d19d574a986d0054dbacdfca10dad604ffb644cecb907f04c87a0df533898974be16030523efe95f439eb1a000413829fc4ac4036c9b86151cc8d60edc4e5a9b9d8ded5b73f147237e7583d3082a608434b2a5cf49fa315f69cd16304c5c6d74bdce2a799c9ec68c913667d91e3ab21d097c3b85976d5fd5865de98f42249ff4046cc36339ad90fdc18ce59dd16230e59fd91444f501c347307bf3dc410d34c001d537d828cef9c402373c0c0dca981285fbee996b5f52e6a9e1a12980c52e2a4266c143efffd278a89dd096a1e1541af47d88cfc47a1f30e378d9ee99bf69c4cfef4ead4299d1237e62886e1b6d99acad2b80cf614614855c98441bae482462485ba51cc161d5442be1efa015908894e4982358c689fe26488cda1ca72e0473c41b7cb04cdad332cce53c7030e432c54419dacf7d64ae22e3a68dca98a5f264c73ccf9ac6fa5452321751b5915963924d2914901e85189cdba91878d8006dc7a89267cace6f84aa183ef9f3fa982b149e13cfcd2e60c6078584ad9c938e6d8ea95126af7c521ea89f58d238e36af1bc05af37c90d32a4cf35080dd381eb9aabb5c7de02f0bda03474389e30b6c020cc3c2ce3ca259667c29425969543dd62c887a7fb8d87dd4f44f60a8dfc740e919c1102a8e753240e48d647f55be15072e9edce82126fb04d778b0857079faad92ed9ac27b68742efaaaa0d3d0244c469efb2160409106f51136a3e7a783cb7918c6485a2781be6b1bed8e4ae020c0f213d554728a7b050a12d5f241b160c657c8a98963012a0f8328c4c5d7fffd53a1dd0b22251bf90bc6f30277b162ecc3b2684edbb952dba5b0d72aeef4ee956a2ddb089910e3f6b660dc3bb9ca2263fc50479f5a2dd91be20e25fc779ae25100f22c05df75f387c22de7617a157269fd386e2c9b2608bb7092c0c5efa79a38369e833c48ad72d0e650f06267483dff590c2d37193a84694a2396f99ce3e3a9f5bf1558a8c3616784ce298e507c9e441636d5d2a19941bbae497601a382fabf82074ca0c190261c963775ac54f07242ea27f2b442d6006417415035625025dc8a4f10e940138ae1dbda3e9bb51c325e6066bd1133902d48f84aac634e4ba8f1f582b3bd8f495c76dfbf3df95aff9c1c7397f7d68b9def28bfd5a90afc986bc0844a50de2433ec3bf0d36da2e5525ebd43bf7381acf1ecfd6561625efc0460ee846ada578c3192e3d22ca0715ea9e8e4091211349a8b69a203ee72e45136c2ab813657326dcf44c24934905c235c41270a603aca9c25a735852907c13296f479f1a9f84a34c33b697a6bf253b71f7c39ea8c3a8ad95499dd9cb97d9c183e51fc80d89b70fb358eaddd9366c55a6f03e0f3bb2a4f0f8e0c49e8c51e59661cd24aaa92421b3ff36873640e5180ff5c78c10599036a6060ff9fd1691c0aac8f9c6036e2416e22f0e86529300c435c0fb9a9336278d833b94d0cf032c2de1fb597278d52e0d838edb0d701e38066c8775cc44f91c2e1357369dbaf648ae117567565040fd22a5585b48a2a717b6dc4531ab654b11b27d1d76d0e28f96f6c28ecbcd850bed31cda584673b45840ae8a3e9575b9aab45d3eca960380dd857349ca7ef75400dfadf742477222d39e67a97bc631600eb1efc26821fe519d5fbdf3137e419213d45d573bf5bb51709605627d38b32df13ac01d2aa91d4b6c83285e25892d277fa058b3415fb1fabea47183c70773f68b9e1f4dce1b42d5a6db264dc03e4b61327d71a95df354f2742eec6cd48fa04aa2b94c4a92c18aa88ca81956a103f4e71430dae5d049d407e4704b4e72973d1a2f3c7d892ed46e8bea35dee3983e2da8ce5d15c2bdc50bc108d3b3a5e5c328343f42fbcb0918962cf9d5de702accb6f1756ab30ccc29bc800825a75469ff14a163815aa4e999f5f9eeddc6dd7b6b05b8265e0e4e662f76c63eddc26f66a7e0295ee14bd90b04357210078212c4ad21a69b7891b5ac25a0905077112607a91471fc5cc3506b6feb7e6c9bcf202804d5b99c8d30f27e1934de7f3ad9922cc91cd4b59614c53f1232ea23308816b8a2d2dd38f177a1a675d43131d70d86df04b14cec2abc2e673f683402e7a56a21deda09257813458cb35169798355ac5365e9ac03a8c7e167730da80b646b728cba9d2bc57a1b1b18146a28eac5a1ffcbca3a06dd26f429b7b4f841ae056269ce8264b476d30a5ff6a48349747b990a1a5178588d8195031240ded2e89e22915c67f49fdf0a95161f3819c92cae2bd0b59c4a246c715439cb9e9080b4f3cc354356977ac8abaa79e0ae99ebc0bc038d91cc8e4c2bd1556527a8b1367fa6d9e7759a9c92cb8827d54caf427092aa267c5664a12f8958400ca72852ec5a876f37b32855f27340fbd593bc984555ae9cddc9d75363b37f4592eef9728079ad8452f73b048ccc1acfcbeae59984b0a27636c2ed4568cf30e3401df40e232e1c59d859029e67cbdf3d73d03c59cb1c1a8f4e8a1084d815a899e57b621047490abc2dc989d14e34154f6c94f84b5e63dd1e314045ff94928985b04c6164a0179800923d4a8a2db3368d80d3f41ba49fa102c473752950f4cfb5279588e17c0c4ff5e813f976496bd9ff5eb5cf81c7179fb7e3a9f8ff98acecc888817d0abb28514c2f741271b275e1d307e6f47068371121b189b8334f06d52dde010e08ea37c67a7429b27559e836c1c6bd2731f302870f50b52c8368b4c4b3917fc69c4a72decb32b670582e6e73fb75efd0175953fbb0c4d9ee6ee50d862e3aab7ba8f5a92bfa2a44fe5ab5ea9d8e1b477e54a8b9771ff740e1458d581da6b8a09d731a24f100074a58ba91e7d2c38eb9695bab70ca7340c4687124d5bae8e4a82e8eb6a0423bedb4890be1da210755f0094b000cc85dd4e7e1ae0aa336cb4839ff95f176f4c67549641f481f8d8a40701d524d3da168ec2cf429d8514d33662932b8c59b7811ca4d9073724a6b5af68d77b78996d8e5a5018dfc1b9fa35f726b8ed62e361384bef83f8a3255b7ebfa2b10e13b9718432f00380129646b0a94beac416fb979de0c65eb4776befc3b57c533f9611ed26014fa8c7bc1708c3b71f41b8c3e2c2d3e687c2b25ccffb8b50f3a54efbb0334091764cff6f881dabf8c4415a00ccd76e37ae878cc75b66f55f27da5f1bd04561ed8d02e16104f3a723803e43a27a76b8580b6782f92da96b051682a16eb0c9884639963682fea262bf77ddfda64e6e4c87c5e9269e9c504f25e0975e4ac86b44f35f0cf6157182a079be104a1db6a2a3b8816099970439578fa5824fbf9646829264221bac1cd40c4493628a1b0f2dc863c7456f0534b1ca54675e83b16660035fadf8f9507e4b14575bb1e345b857a70f13addfa253ac1b4d47117969ba4052b245a4d9d1535b344766dac1d33b6c432b49ed26db88834e6865ce62e2c29610daebe45c9466c9158851a271033760255c7ffa9c6c2258feb40c7bdd243611fde03a78eb73d1a24f03d1bb8eb44503398f7dfbf741e9e5192268e76ca1071da5cb9052d3c372d2a75cac02bfbbc23d342db082cdc3b927157e7b1e2fe05210a0a66b92fa235f9af3bbdd554446bd379a2179650421398536cd0cc8de5d9bc2c2b63ada485e9a64802f1f35a7112686b46267a7a616eb1e1354add93f5cd4e311033da665c43d452471e9d70e975c16be330529f7c0c60e99176ce2d3f55ac3138932a0971fe84b8eb82348a40ca40a62d25b560234da595d66dbaad08e05eb23d3d9dbc8d03d8833c12a55ef8c29ecb6f85ef7c7f83be49ff5d922658790c05bd12ff8c62adfabbb281833d8e5f0b0fd5c0fcb7b3b26c8a09768fafb20200b1a0df1159c9740746762484873fd0554019b9185e42a237bdd27d6a3e44343ffb79a03026ccf04b38d631c4590b686824fbb321f1c6c92446c5a52aacd597b19d8d42155a7aaba08383eba01fd7eb3431fd1759f65f1e8fdd96bc96d02fd61d9d1c8c6a094c5ea9f527228712673b65c0585c590c7049534bba132c1cab91754f86b5ad0b5ac0cbe73b2922828ad279762418a94029897fb68ed05b202b968097a954a9cb06291625849de81b7f9a070d81ec31174c697f41dd878538c0c8267340a6457bca39e0a8e48ff2bcdba2f8f209499c3b5e82bbcd3ccd5d2b02ef27f8228eac0eab3386a12ffb0b80a276b9201a061e78874d941d1c8d62ff1a02a2df616a861f59da12b4c58af0480c2cb35b8cf7c1a2e53a6788a758bd4213092301941d9308f5f623cfc6033cb3b17a8bb6f7460f762d23f72c5c5f7bcba7a35101ba106024dd64aebc91e2c32c512bd2f0aaeb67d9546e31e93477c429ae44d48c9a44e90f59c7f25ad8cf0ad2eda71104f1e0276f7c1b4cbdb5c84ae6fdd4e734958b45632dbb388581ad2df35472b3ae0eb3ea89d50fb7e77e117370980fc3990902b49cc6e814eae9f47262d23ea920f95a66f38f59b69744db3b4682ef6ba1630fe03dcfc9121f053cbdebe74d6ac428d786549c5c8e4ea6732b9a977fa959a336d480bbe956c637112790bb0c3e3aac3f0ab97862c7c51c04e5f80a5e61fa78c8cdf68985fade4dc28acb879caf84e75c3db19decc5a1cf9e799cbe4f33862381d40253d68e7fb6230eddd4df6feb49ffb9633c5c1281967d65305d78e8b7547eb41f05d9f36a635ed2b1dd69d98d70b10e8196cc62e276bbf5203c742a38c15161670bd65482f45990d915db5bc9d02473283487fce236c07efa931035e5f079b3938b06386982d708f2b85a0d94f8255323c12f76c1a53ca85589833043fb77e00c87648ef5f15a8e0193d4ab9b1425bfc3fecbd591648542107623f3aaf7706797ca203d1f2ce020066bed84672f3d9a65825f20062759709909edba28b911b28c5f7b12987ac0e77718d4dd059fa75daedb8fedec68359799be4237524238569fdaca697d11250a8e07752770b16deef88bff35a5c1d346df3917c696485fa2085f4391395aa18f251957a3881114f5dd960d45cf11959074dc2ba96ab3ae0acac12488b7d36c110ced67a9cbb6391c4d218ffa5b62c400032a37138818dfd4236b6bafdfafde4a3e867a66ba673015163037a1bfd3140c05e7a508017d34f916b81e100d320402161f71f02e1b9639560d26dbbb9395a6d64e0c076f051c22f20ab98e5011bb65a6fb08ca7e1c4d6e9749e831f35bb43c486a78eb9050046998747498e32710f432eb0bb2c338a2082334000dca9a548cd86c4b5260b3f665363fd6487d097234b02ac0796728f35f3d21216f9deb62ae2b5b46cceaa2f88d04ea55cbc09d0fe93b7f3d488eee501bff791e9977ecc17b3ce9eb037c9b2c30b272623b4624886b77b0db334cd39d2a3d01f3c06380813fbe916ec9bb91647a6293e902c94254f01d439ad3b50ebdbdc1b025ecff3583d963b9cc54b5a2747e73e37df3fbc2121b75cbb022bce7bfc6976bfeb5a2f77d8604e76100e1e02b4debf052f13e2e775c2f213c1a4a9189a53ce71c3f823e87bf602db727201439e421df2c18ee98875a4632810dadaaaae8dd1a26d0c2178e84c98017d6d0b1c3a583a98a8cf9ed275cdc345371235fade8bd641072dbb019e022406241416f1baaef18b5c8e8ac4118a1ce928e861fc9a605a203e3235981a4bb41195d880272ef5a45b6d13cf05de5a26cb714c274d647648248a604b9fad521b376f8e10a78b47dabde3e3d94d886e193f42579de4324f4083f810e32dc37f0fe2deb0cb0ae103192e02e0e421b886396cd3b187867d57c4f1b34983ece8029a5012226df3422a3796dc8898ff442cfd6eb6e0a4433fe534b986c3bef8489e1f5eee49c128b275b09fd9c540ad1ce6af58a700e681a2a0d6f3d493d994d23fca234cbee14cbd5465f2dac15194da084e17e880f4f4ca084fc5d3730db733649ec6968df0b32e203dcad5a310fe33b5d2bd9dbee02350f9457c8d9ba6e5bf03246ae193c691c74a3bb6bfbf3ab759c7fe762c6a9c9484e70fb8f769f19ccf7d22c48cabb379b03a3558e8ac1dc560e6007435e0e18ec7c830c233906a592118b718172acc82bfcfb8617cbad21ba717701653b03a73f84898afb12e4f5ba8e1b7e85edf0029fab1726e21a734bbe9d34f9c86b7f40fb6375b08c63f8be6891e94574d88c5cb0cb02087908dfbcd0858cf1b8ccb013ae92cdbf979a55cbc014bfd2e59d63a4a2129fd45e6de78f987cb2510fb9ee69a32b0323dc7c361a3e9714ffda74f1e47ccc71db018ce1a40e3c9878e32da8159ee7576a2cc34e3823d70ec8421ba7585636887c966049a7a0964e8951f4dd540e692e8723c7498e376838c86c17f63e47f4bdf6961cc36cb0b232a22c8d3ba0a148a374b7e5987c38522437a73c58214a3d842c749c3e8d5bdf7fdf9ac8349114cd4177ce058a9857b356e361a9a91d1b256adf59da3bfa1168ef4ea2b0267cffcbcb4dd3f122218211812ba546f2a7b69bb9d163861884fb799258e3d6259b04795c73a33e6b780849ff0722beea81cc2b25ca3e8da558a1033b19bd65483fd8c0acb7fb2d38527258f09167b8dae9e841fa1f0ebd0d0e2338b9a31ca74a01f2791a8e61508f3b24d7e5d192e7ecc4253d41a3a994a0344efbab53aea3fbfeb2473985d86d5664b01d52116c9b6a36d4caf796974deb65e321e1b8e4527737858ddd277af69ac5222e9c51b4a03add055b012822bcf866232b71196329b3b69370ed9b043199b7f2742967a3541389ce50a177b274169fcc98d746370e031da9557fa7ac6e122d4d7ff04b95a92988ab820e270d99ac89256766dadc3b7000fb7d5a47f43ba8a2a34c44bb9916bd914c80e8856407c4a73c07356d0afa732b150f6c52dfad00c70751fb5951fd69a4cd53711c5727e64e7f6b8feefd504b56a5495f489dd5ee61aecc48a39da72bc26732cecd794079344e9f4bc7f79f95a51dbaee144f03d90786dbc905328059d0df092fa0ef2d4dcec57397aa3bc491406ea42962c81cb01b8780b29b0d2bacc0002b0bd5aad0c0333caf2230e0dc7c75bed38e46f46446606dd0f76ada5388415dc99b9e55db565b01d40585ffcb979e26a91012dcbb2d8438663d7d3e056923b41293e20e658bcab87a316c466852b263fabcb46376b715a47c6357596481e6ad89d748007c257a24437a8574561ba5b8b59b1ff75bdc2430f8660254dbf2b290a7706859dc2d18599b1023139bf067f45609db464eb98670ad4233c1fb3572c38f14b3e47415b3d3bcf22a6f4a48ae4ce6334b71eeb27f65bccfd23d15ddae75af5619a79963bda545fe5632dc4fd412eaab9a8375ddc1f393af65e74aa7bab0345e003ba69c304c62e578d7f3561c360a3a95950b07df4eddb5da817bf1db1eacf2e288d1fdebec2f4d9f3c05a4fa72b690f02cf57293a60d0fe3972c586ff96c018ab585aecf14e9419599a8f4c589f7bee747629863639f4578c070e7277e00b6e4e0dbda6bafa8cb5cc0d942ebbdaf9484d76cd53932ebe7bcbdd17b5b2f116a134fa9a2b9ff3817f0c6462e5512a987bc0ecca46a915bb1184af2b9852acc9567971862fa6d2344a49a8854c65cfb70f8907aa58353638f7d249720e999cc0239cb729d0c0e52c8a9cdbc5b3489ac690441d5f82dbfc15f43585a57a464cf074a059192b11dcb13ee6082eeb6f8e52ac7ced71916f016fa50f28a2dd594e0cb681c0d70ab54f2e4cb387d26ac3d5c99062febdb17c9c7e6a94603d7af49f9c8ed3e118ecb03af68590c0004e1e461ca09ea2ffc4411a2f9bc56c60b00afa4f1adb9bba35b84032f3596f5639a3468709041835ca03702ed5e7f64f9ca6c22cb34c28f23340616c6964693a8b84da451838c12a3175805800ceb679389c1fe718acbc7c562b848eab0bca3e5d05eaf6dcf047f4248ccc9a13f70c13f70249002ea3b5736945bf105f64752172af0d70cb58a67fc848c4ca7cce4de321d1d4d4f228d8fca476d44b4d4ac265a86f8c53791c03e5f34c6a8d23a6c31b88493cdb654dbdcee6601baf36538e661597ad921c611a01f5d6edfe8539cac277e4086d21338acc2b096045cd1dafb437ad6e01d14c4b6f0875253d5afe78fdc94b62bf4af35c99080c25641a48a93c63f0e30b96ee4078eed5b2eb7627b2a38129a9288d4318bfd55700269ebea10d19c272a2377c6aa25271d8abe5159a1abe4bd6c4718c30626706a917271af345c478aae64c4c98c518f14e6e212cd94f9d4db96d462e40ceaf5a7c1a8fc4a9d542c07d62407988e2eff4ea986e78857b22cd41cfca7ea50980ba063ffe916ffe324b6662040bb59b0614710419c070815563a11931688c8763b0714b41fea3dadbe2d88979fb43209803b70937fce72af0333380cb831a66b713c5f26cbf7ac6c7a76237af32bed3e3d9172737bfa13894f24c13e3f0b9e95b26509fe0fbd36dd4a303b2d24b100c12c4860e40cc24d09e0901a6e915a66d3cdd464bbb4a689b8805cd70a33cfc222945f4a659a19ac58553bb8ae9449800195fcff87881a367ba16288384dcdb2228cc2872ffed253522f6acec2118071ae01e10edaf5581eb34c9fbc65973dfc4529842c11eb97dc4ef121bd78b0f0894d5e39bae0780812c02fabc4e864c5c07f051cce74862423555f56ad3e1d8f4489860630aa2a63a89f238ec4528ef97cf12142877e593c453a768a99ba0c69c9413d356dc24e13051c70103134c30ecb877f81bfb963094c54de9026047915f7a9787a02dc7e62a83b20d002c2350214790856464b16c28a88eeca7d0c25083e5e7896c28e820b0c09f32733edeb7dfda9337c83c7ccacd91568015b400203818bc9185d73b46b3f786431e3826ead34e45c83ca0a1ff57e5c9701f60e47c574b0f0b235114a8cde9d449d93caf20af972c904f3edb0254ddd484d082ef9f9bdc545aa45c651825689c7dd2e87834cd755cbd664bfc1a48d76ecbd3c041a004cd19202b0dbb2bde13504d1c3d5f89cddb5e0770c51d9ce0e81ff48e943d324f33a2a60916e348b4ed3b14507313d45c74613175fc78aec7eb67b869b9612ab713393afbe2022bf9f1988dbbb952230b7aa08539642a9968462310925d911ac9a7282b13690c264e0a953be040b0eec310d93d45b1733836b689830df54e9d3687e1cd903d66897750efad33853c691f0e1d2e226c49c999051d4c47cd2e7245494e03f0e6e883f689f070d126dab198d40bccd8bfc1888c92e5ca024db083e7c2524d7904f8657db3ea2019c4dc08c8a1b94359427dd867caa5cc33e1d650fe62359cc8c19dd1002c522e0f452db4a0592b1fa57670cb88b1ecd6c4924e4fb349b093d1fdc0d25616363094a4b2b38eb87bb4289db9ac24686f71e8dc76519888a6648a69cc548479dac66b2e9c565a51d3e78259fcb0c0204c1738012b30122f4f38f59948a8340a538b4b436dc7435e868f3b3338d3f52d87fe39064738e0a29520da84d181ec5f2876d251b57c3e69373425aea784f1e6c9d8eeff3678048b2b9f138dcdca23ae7de550d83242f58b9aeb5fc43c8d7417d9bb58462d2ca832103e1e5fca51d3e908802773e6460db9b84d15f126caa06a1246920fbc326731efe0d828c07d54832592a1daa5ce1d3d84f8ee010dd131141a6aefba87374d79a7870d2e7579daf93910e1479c58c26bb0e226ba3a17994209c2023230a1e791ecb29fe64b5c616c71102e819a9510cd7789cc14708352b3157eb307dea7d72ad86354991e8f825340f9c9ac051a20b80cad231bfb6801feb3b846b7ca08e0208a69b4f041dd985e511447d56d617a26893fea74040872ef7d19405b01f357b752fe56c37c11a820886f2f2131db939894035084c710f7a82665752f867d39bebf50e57f63eecfef00101a025a7bab5e64026b5d6a4f0c81240197074ecc126597752ddc7987efe0a19b07840612a109f8c36c02d1a9368f098cddf0dd0e35208636606fe360ded006c41c1c364f6ecd85f5d85be361c51a297c64d4cccef84833e8c8f0222916f0643e2206cd02d20140c4b3b50899caf9581d73b900977bd66879a31c711bd2c6ce6e3c3abf541bf6a701ad6dfd00b23a6374e57b5f9e9f2cb16a1002b69827842ecb502909e1cb10fdb44e6c7d29f9e97b3ff319318e78a87980c4528c5d2a0852906f8357a8fdc378394d13832dce7167be032043791cfb86c446edc2f9382dc08ca68f59c5d304da6ddafca8bc2cae5d4b10fea13c640877a9f8a06b98543432c416b0f3888fc84e172e52f0db6c5404810016d341576809700021aff4944857ca947160dd986bb7f6972a2a12dc1b7055a8049e1671cf23a68107dbe9b70043d25b3dfef00e4a24f7fa736b33c86550d87269094948c32a78f12c32655feaff8508a0e0035712d348a838bd9fa42949c5b78c7ed5d19e78178df9a2a473c3a1fa9eb8344354321751393a1328c6f4a7c5763a4cf24aadf305009ba2d833f9ce21ae5cad2469afdf8679ae2b93e0ab01db1164048903db5b424bd69ce0ffef175d93e32c70fe132d74cafc31687d72ccc74c31d5f7373a3c1bb68ef340c540b092539d99fbf98d1b607199e8f71006f6e628293d39c9d9dd11dabb63e160bb6696ab83225aa587c05268aa9a4c3ee8d3cca0dde02bb8417c99c5af078b9829d0e9877c3b79de44698f9de689f204942a877d14c12f5b017be7ca96a1e1e654bcbd4e7dfbf817967b370a17906f73085302c4b3380093a052a75f5d3ed93d91509189e56239cf3b674071b276a2f6ea4c25c8fb1116e5b190e0251d998071a5c50efb464af3fea3b40f0d58790dd1a7ffa2b6692f75991629e2a40b8f0419073c97b7e1af38974e7f13685df5675b21a91b87ccc236fd91a23556430f1f197864af5a3ef04d90fd5a0dc1a3243073b0c310c8d9d53e883dcdfcc0b4d8afdbb6b10b314a76422bfa7d6013ddfba9d3cb3f3e5016d822abec6b33bd7bb0072ae85fcd575b1a5f203a04f30af0cdd495af0937dfc0eb8f9340a8bd41e61691bb733eec2d1e1b034bc666496cf2f3cc24023bdfd713f4bb36fde33767b93705ad94f52e76fde731d18495ec2b04f8cbd0f5ffea3e52f78dbd4c3befcbf1ffd6bf5b0e703b7a2cdf330d2cd9f08460431bcfc3a0bcd790f9c825882c64dafc1cb7ecf4a2f9ab90d46c24a1eee48e72be7da9e7d47e0f81e1fe493057dee7fc51d8e608b28bc3babaa3e735659ad3827257488d4fd6a977904b3fa1e5413ccc58b5429e2ed784985f5152ea45c0bdc398fd69b399ad65a95ffeb3cbbaab66a4e1204701e103fa5675f21f17958d9d772bfa2a38723ec3d01e865d12561800072e8cada6e8f0adc1ad348827af90ef445c58cb9408e85a0850775f793ed625495c70a0d745031267e0b4eb9723be7b173eda2ff51eaeffa8f58ab958adeb3336dcb0b988492559a7f79d79c3985308463beb672d25fc37d58659029816a4b5eab279c7eadeba3c9a091ed39efb2b0cd26982384aced52107af84bab6045985004b9ff85ac664d3e1413e39f778c3fe5d5c53b43c350ecbcab36ecc9dbf9ce7c2f03ccd0b84c38af91d22dc2cd70761738126d6644bcd10e132f92011f6d636e5764c7544736ec7a9d5b72d53b52f9f24ebd21765a2bb4b1745a5c11bf786bee120c4ac68f085bee68453b9c45fd184e9ebe6d8d37fbd466c05bad3b552c5e7c00532dc5ab7fa0fb577059a58bf41d1dc44cfce6ab9ed6cd00b0c98f639d194ad68b384c3cc19b108ea6a45c56b7941a7c2d919b60551bfde6b2d873645d75aa8ba058bef1a61b0b340aff5021e7b16b378d0203af52a99045eb1a69a76e99a78862cedd3a37e9a40bb01f223b46ed987062a3a514b9b6ef29b94dce86d985977da4ca779dfb2d109b41b88da635ad84b88b870f8b9625a99b5a99549bdc7473a548f384cbc1e65ef204d3bef58059c4bba7176de9139d8e092d4dcf27c0105f811bf8d1794c3aef31660d70f43a95e44cf62b13412e5728eb89453148032c90561c3ece7ee907f4c4fcf2d552aef238c5da713d47e0c371ca8221d98b1cb05deeda50dbf57d578fa680e48d30585d32aa9f2c08b10e2ba98b1e8279597a5e4ec67a4e24b7adf9f6e68591799da8e3862d294f61622b8ccf0905e67bf8d8ad1acb92dd75ffdefae9bb82a1d37adaad050dca7981447f3062917a1eba9d0360a6917820a54bc9c317749b82e927ee66ce3162c0ba1a5e3926501426eb80d0fa6fd49867dd42f7126526b86b0f4719b13aec83a9e7674238be899c5195a16bf70e8567ad764f93c1dc64031be4a827c5aca97b5134a66fa91afa1bf733610feeca9ba6bcc5fcae45f849651ce90a4e70a65704c13141d618eb26bf23ad5b463821104817d92218876f4ccac06c4ac50c736d1be08e48e4210bd2c171f2a99862a023f177a4d732eb8872288b99b23af94be90d8ce61eae56609f51bd972b0ff3002d6a021a6622a2e1ef42c1360738cb91fdb9820f228dc0a6223f94da3b89dc50ab6046012647d26daa7d88913dccbdcfddb6c8904f065dbe89af4d484b93dfbf9c383acdc856074993b815edb29c6045cf81282291d3e78af92818c76aa0a9597ed5beb72501bc0c57af34f89bff3a48fe8e0c02453a389d590a0c4c70c6226919a130c9011359d86002b7e9854a82227cbe8395bc35156097ec8b8b2d019d74c38290258331449c00399f63a29c0bb4f4b7194f9296004a5558afe14988097ac7a8e8364f1fde80355b6029abf3d0e72d9e8510ccf961a058d0c36238e03708ba408816f802dc30ed08660b390f7fcc72d622f2b0c3e9053ed5b55b2f3a5e2d0999e659c329b3db81f24a1ef5a1b629a5d098002bee5b1fc142cd7abb516ca9418cedebbd7e670a2d3941da27afc29912bdf42964581263bb9a6e92ed1d525f4c5630c6e407760c0504e521ec50d1c7ab6311e931a0dbf50b6480a3fc0e973e019f75f37d283b9298a63d7814853724572136d760e941e0f69f84c76e287e9a99b2a05a29e85b6e05598691c84b2d62b29bffcd57b729eaf8fad8544154d110170469b115a31119098b497e5f068ce86ec99b6d0899b607c4142dd010e441e7081330ff978b0e06fb3ea99f7d882b5d4454dd037ce04c7a1f74718745325364bb7877f91355cd2211dba0996361a2b13c732fef5d3c57b22614f2547c533b9c94d1a7db80b78ec1290cc885bc4aa32f91c2984636600a932c75e267a492a0ba5cf18d4c91a4c1adfd998a2a11a89931097b03d1679bc88d30a7a4d7a1397b9ddd04260ddbe0eeeb980e588b9062f332f3296bea235d89237e69152a7ae4ef8ecd3b10d1d365d01f0fa92db3919b5878eda41fc118efd5032b9555c81d21cfc823af40b58b49cbbbb789051321136a3434f2ca464ba86b844f781016f5d58e51d803a2aa3828ad10cd037dba81a28c8164b68ae273776f62de6893e74a9ac25487c269fc800e9a6f542b30596e30a6e1d9bf5224394a4a444e12780954c4d7188cbeb311980abbb0ad169a715d9eac580f1575ac535c9c2a8fd81a1fa529f558e7b4e11c4c3a8f1720a3e3b73aae9bc7700aa4dcbfa4e242e99c50468d779135112211d014ca63c63cae9d1fc1021bd9840f2d6fa6ee9b80d85d7a40c115015dd22dbd4c794afe036b9955ad62c6c138d4fead1662886bedb1dcc8c4104866f5ab0413e3f89fb27b8b18e11764ae40fcc7e6822ef38907bf1c2124cc00b380a17b086e8692e83eb8c310ac27ab7435646a686e8dcd66889353c550f4726dc77e4c5a68e8fd9da05f6c84d6fffc03d52059b6bff29d0f8ed3db9b36b2f2f105d8ca4e99cfb504401ba9b66b1852cf69216565f60c3847e856b80a5f17fef489d2205b3401089b731891f132051188e98a68854806fc424892b319f811f4fc8f0b9e7c7e77944546d8632fbbd55a55040d5c9ecfd147bef2c8b40349a48e3b26f8d1a3dde06688830bc9ef94a94a45649099a326665d14e7fb773f01e06bb31d7c26880354a9b4564d54b0cd2ce5797979d26fbe1641bc8bd03a67415827424253db35bf87d637514e43eb085a4ed6fe63d1d61c3346b3174e083b9500ac4270fc0111e7b40498dae43f78056769e25b05b5447c3c524ed82534a8d125341c8a2d4588b94ec3dd3f8b063b8c2c0678181c5138a03a0a32c3ad7d7c8fc8b19c46adefcc4d711bfcd2497ffc2ecab8ca3798dbc485f58859fe1acb172990f4a0d7b17b2c779a546068248d08344d0d7c42d7eea687a320edd7f8f348faadca5d85436e174f60e13573857c0c83f73893c543357c78b00aa67c86d0896db39b81961188b7e0395c38d29fcab1b106e897af257e7c620c281a7023991e4f4e628ce5877b07d290499e3aa8281ed2de51b97b4b1b5a9c458b7658686d9983b1c25c40fa74c429f464bbb9d8f9ce25579703064848e390f8ec0f3b6d612ee6e1a33b3cd7f4ab16e033d022d290c3104944dc09257c7fa27e5514de9a8bc2fb2a9238039b3d8f5643ba24ec22b915a73f4d51a33d938c850782b601712ebec49a177e8925e5eb421e6c58938cdf11ec56c894c97e7421bee8bce2858c77a12bd485d5e70672efdede28f771016070eecf5bc196c570268409e2952ba15720cf66e1cbac737047bc294ebfa2dea2e103283989212f66e802310203bb4377c5b0643258fa52a6a10a9ce4ca55d2ba01b28f1f70d7a2fc4e18fa0dd35604b95e3d40a28e4885f3ff8063ba38ec6af1099a0375ee232930784d399a4c0d97002e99ce43674ec6c68b5e7905bbe70abf7fb18ed313200dc044402ec8bfbc94e126005a83ee5e044090e3c27b7a48111b379aa2fb3810929fce0a60691f09cacd79f0603fec989e1178492b9b5c87f4ac8e60b2794b2e1c5ff93d3f21ed1e317c7750257c6d0e8e1526620757bf6b81664a6fc3a577cf9bfc66dcb405d2757cd9adf218eb87350f6a32872d31c271128afcb6362c22f7b11d4a6871a34d9f0306b36043a82347cc9fbe4e1cd91dbe6dfe74a2f82cd25e858e1fdbc042a42dd745f01e3354d51dd22d0cd3ab985a1fe01ca3bbac87ca106d0eba7694c761a1121df0539fff0616d7397adc0509809c7a3166a82a58960f3a189cf19bbe39cac02671bd420b3b8145a6583a1a30d1a381caae9721fb1a67404e0d6365673fce6cacb330ae2ed07065afbf5c3fd6275d9ba1076ccb2aefd72ddcdf033bca519d77e4535652bdc02446f5287a32b3f98a83d1c158ef10ac4437585a608e6cd62d2830f007085130709812dce4ced012502b5999e2fab74a1114adb88218a298b5f8f0bc25372d6e6f414f6649e91916b107027270b3f95d1053652a8c60d97bcba881b26e7361c5009a181f507a7f14a28cb71a6197ffd616fa56157ba1c3e6ffe925f438d3ee95b6bf78198e6317b906bb30db46828fe5c7e3fba4b8f322fb6ea3855ee6838c0a12f691942595afaae6a1f1c8d19742468c5eb31177751ccbd2cb23afaf4ecaea7f0cf6837315b45e28413e506b1d690666aeca03aa6a286dd433c134d193921782fb801a043000028bc1714a5fa191dcddd7d141af3ee4e640727e147a1c7f719e7e47e18e89e68fde36dd0038ea895e9893ed5bf410f9264145a565a2aa7a0eb3470e8bfed234040e4f8320cfed135da76840808e2bbcbf0b13c2a2f2ff9b92d589174b987ad37e56f1cca0a32100204c3a11f3bb70e29cdc8249417774353a26d2c5f54158ce82b81b55a698a7be814f008c3faaac2f285dfb5d0fa3c970fca9e25b3b7edc3a01002d304306df0628340411cdb3a84b941e6193f3ad95367eae3790c6e18dbb4a41afd2fbc2182cda94a024639791820580756457c121fca544a931bd1635d604bac579e0876e25f0a269ffd2c723910855166f2deaeb94d745344266e6c93776f48075e925831ccde7f5db7335a8ead86cb01b3da1800b0719e0bfe4160939b8d67632c3a44de3ec1e7ad6da881a558331f3238c7d14ee8d8992f75045b4484c712efecba721655be4d98aaebe0c00d4474a10e0e66790f9dc9eed9770435178e53eb4ac8cda196e07079ae1420ad9114c2c3658fadcb851358f89da0b95fccf5279ba68f15272a2b52df5e7f50292d04f3748e35040065120cc7c1b9776bdd996c9774e290ea27eb08ed676e2b14cc02c71693e10bd20dcd4604697a843d5b08fb8ece89888c50cd7eb847064cee49252399228f62a12d1128a51f2ee95243e19ed16319d60f9a76f108882c44515d888c93ed6ed94a4b2aa56c99071a18929011652e6c856fc03910b389982eea56ef20499be99a3df783a3d5c8a4254a37b0a51a9ad68750cc861a0d5b5d694d3980f5988a0091aae9ae8738ea2698c72227dbc6b068878d8bf2b65787d60b41ead2f18de714180521ca22b38888d8756f76730818e67f7d45545e34f92dc8e30ef49f6cab0105dd5b42cb67d2f39a1c93471637770ab7892993636f0ac8148026fd279d83cc553bd822b28d4bec70555d8c1e8d244f92e5a103f50b716095f4acc934e4386b5fd38cc13487d36c0176b68b3f1d0cd71f7b2c952c4003bd37b9ac541a61a8bf7e6f812c4bf05d383e178c42967b2c7ec15462aa6ab066a7c3ff8f10041f7b479ada6d54dd380e88febc13524e01f7b3006979c991d042bd91c40842bb21e6d7c3fc4a348496ab15679f83f78f5533d05bac8f2c5d0fe9295370ad46b1b778a987c89c1b9035918b9832bff3f6028d5f7a7125ba7511624b12805f18c6c82ff361825f05f32594e5b2f3c4f0ae8ddc8ec8292c652cd83d8ec41935ed00d860ca9dbafd03bf5b029b0fbe8d313a83facaacb3a0ee4e8fa7010c428fcd0d15b410d0e2a295108bf34ea8732a0744110fbf7fc9f74d6746b43e13d86cd25538c0da29d2e89c4d9b25e184206e99b5e8af8013ccad5a2839edcd8c445d9c3e5b0e76ee417b681dd3f0c0637596bbe3ab13d06d7967dfe7a0830cae82063929b08add295cefca2448bab0a38702297fc7e5fd387108f948c0501550760e52e5f5272d0faa4b089ac441544468025db3fb366350ed2cc69d478a63ea2b02d320201c89766f474364be456ba8af6e4862f1c152bd7c5853f3d75d77b19b1a608a39538fd85187bbbffb321e721bb3783113f33562f39da5017d05b8428ffe2e7ab5dc02186782af209df9f2c6bb7941201047353fdee1c4c54822ef463f8567df112a224cd175d8d26f0b5aa72325c8a254d393cb6a868c70352180935e07eecb0cc7ca210530a12619cac45a892bc620e951fa1434c797b2c5a4fbf3e6172b173a25cf825e20a3b04b1d5eb81c47ef82031f7cb8c1850317dc70c1850f3ef8f0c1096f3353bef8d5aaa73e6aae37c44b3b5cbd63dc6c9d14b750002a1b528db82f56322e4cd5e93f70631b40b744ec1439c41aa3115a413d86d5bcae9108af99560a0e51aa40db12d1e53d074525db5924db1108f2b9bebebcceb83e3c70cde7ca16bafe84023ecbfe11c5a02a869b6da183e46222f042f74728214ca5373844d80637a126198a2445cff34d714249b01a7ac5e3d9f4d2d4b0607db7173c5ff557e1ba62776420d7a0b77f7540254a06c69ad4bd21bfaa4581bdecf8be434887933b653480fc15f0fc80882a88564e0a6d01194d00a61f7a8e4b291ce6c4dc5472139e711d02d0fca186c79431726acdb52751e4416da30619b03b5cffc73f7195c12794620288f828c2327a2452add02da80ab5869133f693e7dad5296e5414adc6f8603481bea5015880fcf43001a070beef3ab107fce1232d1716c571c6eea059b1d613f640b707697821d56015c026dd84a1d70e67a69c69690a4f2c3431ee99dada45578e6facd8501d745b200ca4f548bb56d3141d6617037a6c19f15a33e0e86e106aedd4399dbd1314e1b85d689a544c02546eae2a9ee6492a3a15d1615283f474cc478fbf3adb912755e19d45de1fac2001605ed8a12af1aba026111248e0caa12f0490ed3b25f34fbfc96922805ae4afbe1efc1004f14ffe7957b7b76dd4c37982c262d43c1b6cd5076c42588cf74d5cda25e9d7654d33f483638350e145de08acbd6a53da11c1f103558d8c988d34e22e4485e739076b66b9d7f202ebbed8555d30107c4c7ea9146f23841921458c4f908d47bfab99733ff9353051fd1bf379dd6dca4e33a0e5106a6228e5a1557c98123babb461bb47d9e46e2332f118b5b1c2de7f5f68fff44359f835f27a3457cf21cd6e7c934b3f9a3a8931284562c9125d62929971ad4f0cab57afaf063493f1aa570cac29b79493b8cd28b6e53cd92b478e9bb9fb58a94d21ad3599f47e0d46d92de7d10e60365d140648549ef7e6b67ad2e0116f17e534658b581964bb8f5728c6e7e235da715caf809a9522af4e56e206d289440c8cf1678bc3d0c853b241cfe385c73dd02155cc13588cc1f4ab8b20083ee8c6e59ce091666c150af76a88c4ce7852277b98e2aa1bdc15a7103327eb9072a7a3b8d4e648656d43346e239abd04257a9503e71e772796ea194a354d4ea5bfc188cc255ca4c398a710c2302ac1f2be597b472230c41db51c1a2d19570a71e7e20d0b325474da1b12ebdbd4caca46801bc7d418c11aca831af5d0b73fa162a392f59b21bf86f13f180dee82da010a28fc58f6400a1254d05d673737150742fe1e0d5117c4d8aefd0290bdabff3c25f872b218e05d4cfaae9fe092307554aff705cc6900d723154796ca7674347c0490a7998c1217bc40a3b7e7272376a166a8e78206e584399d9aa2e047a7fdbe05c2d76a428d85b2b70dd4d6964e421947a9611cf719eb55046a56a9f4282acab0bb794915e935c8a16f0ab287dd35f78bdd2597cf31f8abb7806d9eee572db040c3ad2aadf2a5edc39cf11e56f7702a8865048b76a70f969bc87d8282b02814a4a56809c014ad1c5aaa3fd9c2305a7032ef341ab94b44fc9fe8af545a16908ce40b9a586e82e8340dea627430cd1cb9dfd15895cbe26e4df78ae961ffeec108383dae0369726395a98eddfb9fd0deff0b6db86be8e76ba6364594bd78264feb68eb89c3309ac01a17b58869066355af185c57b5be8d54e6c6539f18a8be7c9425e21b212dcb7199571d19f7f1f7615d4dc23aeb64a8fa0e0a6d2dc7a539cc6c3a3106a4685cef8d5dba48c362ce56e7f2b40e4c7d9a3d291ab0f1c1d82007b8161287374a6534b6d4221a748c4ecb89d2bf85140d8ac81a73556516342aeb1617f9837446c56c8d900a80a6a820b50231c27c6c01218f2c76c37651fb51892cf18ed1e66a5e0d2e0f417fac140a9fa0a1873d50261f4735968f76751e21411034563f8d3430af96f79ed0bdf70bed1ffb861f65e5e00036d4d159a668ee8d7aad4579f7e63e132fa284b136052e1a7d0d6082d510be4704c415fdc5b351538a646f0ab9568feecd604b3f153e92c6947565e9feb86cdcb9d9d915a4d4856b3f6e214cdaf7d6ce534081d9e14da2147fec61b45a2659b3156998e7c63bd8ca3a680bd49c754d800169be889ceda1befed2e63a467c37a5cb813a178badc9eeb2a30568133ad339353db7068626d45dddb503fb1219a74fa77e7c803536d4b1dec2041c93c3a232a6415508a8c05d13dfdca19a46041c374e693886ecc1f1711d24d2da6602ec4c3b0d37cbe26a2bcf8f21616d2557be163725d792a6ea7958654849582806c2bac258aa5a8b51c6c39ab845811501ae0b4a2ce3df7b8a1b21a94cc2c22c5b9af1c4fb7123a5e45afc610aea8d1b2b2f1a912947c976bc36d1173da46a8ec041d90c79e38d9b09db98cd3be326247e06d31ac9f3e4ab836f7b0e10be3aca8899cc7fb7f3b184cae26fc02cf7215a91c42ab3933834d826190a61f2784aad17d6aa9eb1a9713371c736d69abd89d05618c654c6f6bae09522a275f9b6b4295747ec251ed99f253e5a488873e328c98fa28689ed8161ec24cb1ebdcc9bdef2ce586acb2168a994b8406a91209d7f5a42b6f5d92302f7ca399b4140b0a0bbe288dec8e6d9db8b3d339d8a389e80c7e3a4da21b9af49aac101b640e5553052f9bb2bc881b5e9a84fbe610748229553b35a3d8eb425f49757fa7dc831f28c6e65a38f44e6d4d5ce3f3d5bf04cbf2518f76e4a7100e4c94e4cd017b4cf9dc08abaf629f53d1b131f58eb4cd7e23fb55a176646b10c0bc64d9cd8cfeda64bee22e95764a3e73f0d3163e4b4798cdff358407f74ea807f1d5abce915aa556508e38012e6aaaa265ff4a210f8d906947d6be8bfbaf0f19cc063a2da5ff1be71faa2d60d59e0f4ff77a9aec848555c9ab017f1dfec15ae457e5dd0ca47d7409da72b09cfe9153d5f715dd14d988486b191e4f415a44ee056c9ba2ffe4c5b07c5b9585e327361a8f44964b371604709b98a27a47a8a8c014dbf803a1afbbd2d11b5e505960678baff8fd0caf66eeec03a08bcf759bcc5aa9464821ef9a355225747fcde4b499bdb803635515706b747e7f53ab6a3eaff908688b0e6510df7131af25e5c961fe2bcb6b8856b285d8cc3a06a86f50f5dc57678f93950e96c389d98e9738cb33c84bcc2dc3394d7502a1eaabd9d42578918b6fd3a21f33d174ab8d55453417afd95d5195b0aee703eb7789a7e4e3313d518e7b7306b3df3b1f593a6ed916aaec918fff023d233cc01ff175568afdf410f13768a0cc7abeb10bf1024e0fb7223fc47a0e9a9826e6c674412a76c3599d207e9661db0243e174b774bf4ee687315c88c976286a0dee8da8c1b82da8225061b7c8f9b82b412992b3177bbd79c887c256805e4164b9277c107fc03a20b8a13983decefd1ef9c835fb0ac67223752691e6a2e7807bf7fdcf79e2655274783e6a4137103244e2f2874d41cd8f4839c8850530fa4ea8ab382f97c488bcbacb7fa6e1b1a90cd50fa8848793dbd3dfbbab76cca6e5825bb42c92fd452fb42244427698fcede54f34284954f62e6e0882df130416d317699ea881ae95b2301b997f0e254cbd4e9c8c6587fa14ceb680066346888d0fd7eb551c1a6b06c13912ad26d41adee9d04d30287b6c94745a649239fbe6d01f5e281943e6dd04dc5f462113e120916a3c0d4ca03b046b840f000df47efc1fdb688239051e16aba174db9874016c7027067ce7b052d0716598b5298b71f061be3e6822805e42d9be55a54c44c7f3b134e2911656e2a3150960f62da67776ed8ac534b5a6453dcc6c77080be6dbab6e2988a1393824f721c6dbd8d382083cb7a3020ea803a317634f36f913bec87bb47355b4ff1b29d0171a13389d335aa460a86dbbd584307283589bd1c3c7a7378aa106e39086ff4080af9aaaa897189021a7ae5f7193c20a57259f543c8d8d9283f6fc80497e53e8baa1db59cf5e27e8b99668a0ac13556fea89042605897720082765488479532d338a785cc2163c083cf83a775a2c668fbde5eb93b1d06e3b4fd77aab7dfe6e5a2354d9f7b1769ffff3f47b65adc3130778bdbe111138a439973fe1a3e64f312b1f55fdec7c3954fe51e9d03b7acec1f281d7af823ae740b989004c325f73284d9af021ea04b0ae2fde47dfc13fe2817af09c4e52cbee7e48a693966f437c826106dd806558fb008eedaf00e9cf5409972150f0158560161183e0212007953c72326724f8c0ddb8c71abdd74f64533d1f64a0dc962e357faad000da61b98b825d99b700b7b42380e466da4c91583875ccec5b6da74991626c12abcfd2a54650881b40165767391876f27c726d877ad0ddc249c336e3e7713dd6b34c5067b134fbb94ed2a842cb89a42dae4ab5304a191f1110bdffbaf5fae90498736592a36f98557def28bddf1d8e5f99e5fde98835cf4abc0918b638332075d139b26fb3414d58d2a67db35355e1e021a0428287fd0e0d86ce21335e01d83006b38349b2cd75ffcc0529139aa97dd599635f527e49a61214c1d839a8678d35d41f706c48b637dbb1dcb9e7d2e9bd06a15bea28a496015ef2b299f5706ebad58ce72e53f951e564fd05342906d2682686eacbcde5642dbaa7dbf0e619b2acc20756869a9bc3d3cc20b2b7d85008f90f5c8d5818e5ae1c1041d46d53912e4b30f29646050d99c9e95ae35a8c7620741336afe1a5801fb1e82a4e0b87520ad72fffa2977bc7bf50c3904deb2c7e6b6b064663341c37e0291c4a044fb4b12e2dd1befd863645b58725733e10b10d5383c2765211e993c1f67be2f78fcbf80ff7ffd4f13e87e0ed81d74c1211f7b41b5edee82f5e6e10deccd4c8da3135ce0b576de4fc10358d29be241479885d4f4ab98faf492331c028572622081c2e98b44e2f433ae8335b4373b9a001445aedc8a2ae03851ee4b090b31cd8181f06dcbd7427143e64a7f0be8dd1e3c25c24a191f88b09b231e5e6d06ccde262fb870f93c2b24c01ecc3a558e6978718eb105d21484546fb6f77c963836c28bb01904a112a2c5cc0084149ff0715271f21756fc52da05c1448f52d34be459b5f2258b9dc7453a3e685abf59b27e154b0e307444412970708c88bfbc3560de13b668a734ba3cef2e694f728038cceff86a280b6761c1e0fe06aa452435afa14037bf480bec31c153beb3ab6f0b91a7d8ca2113d342b3d2d2ba51d28d36dfcb88977e22278902ba9fd5ee9b3fe4e2fc1a93532298861ee4803a49cede178d02937da8a465ec395bdee13f376bbfa529c2daefa3919200cdf4a49151256e20faa024994de4c981a805bb5267c3ccb48b096dbf4bb884a6ba04b11e26329039cabc370ecfa0eefcb1a5a6dc98f25dd40e806f3ddf36050c6d6c552989107cf812b3c09fd0cd013ff87d8901d978b1ae9d172ba4a24f15ffbccdc15c1c625e189f1039965849ea0fd01c2f84e5fe13bd8ec9f0e3c0622e271dfd2eaf48e977f6af0185c418f1a7db5dfd0d70ec2035c04081bf0590b9300af0b9192a11647f0f062c6dd799b5adc02414a396ba0dc66ad92579a794e240083752e5a2867dbe3fc8c206fdb06cb26c187354304068df01a71dc40d8149cb29433804847f054cf9e971fe844d6891c1c1cf0ffc21a411e69490d232572a495543ae351194450c368d5c7b853628a9666fe3e21c93ebf466fa1de984880545d99a484fb207e5d9073403e195665e1be31fc5ce7b09c53854fbe020011f02f5859375a8eaaa81ec4a59f78f2ac2af0c78762c9fc7ed7d32a9073f988b5a3d32e1fc005b3f027351c3e5ab8703288991ef3876e4799c9216b713f29db360c02e688d10255e68e44db0b84b052b1801e051d0eb7d87caceff2a12299827dbf0ea7875220981189af23ccb0ed5e4498d16f33a48290fe0ccbd5e6adcd00e82fdd6409aacfad077a646f064c5993bfe98be18738d1785e885ce0b410b8f32eddf0c5fdcba1dc6fb89e047af806ebcec67583db6fa2bd65cde3c7818f36fc3932a08f7269d6ef1df68b8fe56bc8e8b80efa7b47d27b573ad0e39b815aaf0b2d148dc681edf78cf60a4bdfb3ddbc05173f20cfccacba0f8a2527ab0aa27c16f83a8ca2166ea744dee323fb39c0a582ca04982221c0d188751f5f0b14120bead013871401c0368a8cb0e6818498fff586db2130898e668bafc848ba0af0119ced190de52574906f36d0def19d98286324e48a66ee97556681c6151c96f997554562f0a0de638d9ab238c802426a034b75ebe69de182b34cae2445b9cb6dd74f16b732dfa417ae9c3d8686fcc19d1121c520352e31e959833273c7c664dab2c3bf8718890f65efc8155c9ffa5a5e4326738bf35ae26bc2e0e1639fca7cdecbcac15b09665821bb27623506141178872cd71d11031235bfbc598f2628da1c5e2cab13e55c2fa0c1df26135d78a2feb9f95628dd0278a909e2e0a7112101e546e75cbcc19e4b9d1e9dda0a2a120391cbbd446e909d7dcd92014b69d66b0f839ced2a7a8c2982478924a3bf32dd39ff6732442f441b0d8ce2250bdf787b741900a3456d7aabb9230f8513fe49542d24f50c3297f820964c36a67fcb6045316b56b20e86499bbf54a47004c7240df396de9d1db23adf8f88125475a09085ab06010b72115336b78a45e71e27b3859d1e31669a4da737a04d91ff3f8927c8c237b9a63c49b64072dc0449583a232fb17b0a07143fbc29314e0cfea5bd1b608fc8e5ded9213d9d206e35919fca0f032b6808225e7a4f6e1a5408ea8d34b6b9ca5d3123b01b0820f824a43291c311f90d6c20c09c1710d4e1ffd459c23595540abd3171e8707f94971fb1783e7f9bb9031e60d85f971873cec50aa21b1deaf04b9da938fafe66b89cebe843797cd3f47389211d514352ab481d41377b261998f015711f30c0c8bbb6e869cf1ec728a6e63f37e0f8067f63d04211a54cbcfdd821f95c3a66d921b470c344162e6d4769d8fefedaba7b4837884fa03ea096f9a5b3054b24a078e941c1ca59f546b3b09c4afe6b21ba0716dca46f2657a0464ec29a9da957033de88507a9c8f9eb13e9805cc9145060c20b2f9821e8cd491bd05d7e0a424d45cda696faf8c9521aecfa32f09d97bef2db794522699027109e10996099a179a13cd895665ce2e082d42776a7faa1ffced3b30b849e8d72fa4de01253fbd6f47bdde522f08efe0b314eff0773e7ae3d9e9342fe91c611dd6914a9004124364465290805b42289515f0134f039b8af0760ee1ad7f911a015f1f38079e5edafaecd2acf835490e8179f0932696cb5b32debaf6c4bd27cdd278341f0d170d4f3524c5a34aa15dd5699c86a73e9ed87314650c170f0cb7896d8b2c5c543257e2daa68b87ada082831d5c3c309c825c544c0e835d01142e2a9953213b97a4cf49694bb360b8c743fa4a05dd702259c79cf44fc768b2ab5c6ce33ef4e72a37eca4ee43f7d8353b1d212ae9d5693e692457d6314f259dc6278fe4caba44922b3b91e88fb4d4e829100d7a4b270fb885f9f7d62796665db7306e7d6ae19c76ea636b7e7ef116fb26d2cc17dad3a3bef0f4a1f46412eb90597865dd2ef9e0ad176f9d4a22affb36e28613c97aff7043492405b76e2411e744992f4c6d91c5dbef8ab79e947d71fba70a0f98cf24b9b2ce9d0ad567d849b1ca95f1b0856417d4e90b6f0ad3aadc70223de0e4618ce768d07a7b2ab041ebfc404e1f1289446a4edc1e7aeb2d040a35687b89b745dc13ccb773bf0ef2b6df26e79cd3ce6ea7d2db2dbcac931ff6f150198279f5faf1604f80c1c4cb22452a825e2e76cd20bf7c7151b1274ffbd87183f3e8e7ad5283d6e7ab41eba74f7669d05ac77a6eacdf538cd742fc234930f69e6c2751cf94def6d25bce3947739b5fd22beb610ee9a557b60cde6189c03aac8700301571e9873e3f745311377edbd0bc89c43a6417b9b29e4a5d6bade973a141eb471a6c196ec84b6f5d389284d46943b79ddb3af7492f0d5adfbc2e3b9d75ad891bca2e6f7d22496bef8d486fbd93ec0358cb67b6c17e2412f532f58d281bdbd81ba3b738569f3e69d6c42ce246e713ece7ef61cf9d03e2d7e70e0525ef4ea9d72454ca26a1c4d39c0ef6633ebd233853a97b31f70641cc6db07ac69df767c02b7eac32600837e015d3e89b1b2d56be5c5b24a35cec09e9c38d31c1f4a1881e03880fbdcbd574f8f0fa088650c3877e03972f53062e5db82c717955d9b6acbb2df6aca3d2c9dd12e323d9dd2da594922953f6426fced9eddcdd92d5ddddadd15c112f75d6c1524a295b82b2f9684e1a411c2ed90c38073bbbe5acd362956a61a79dd36a61a79d58a5604c8b55aa45a5989d956260d05a29a6c5b4956a61a79d608031ad1676da89550ac6b458a55ac8cc20953c8661961914f2ec8b5d03826820bc40ee17a9330b9b4d6d9b9546c73c0e82b98db4ce2ca46b73e326955a66b1aa6561486ab13ab3d0aa6b76eb4c934a2dc3aad5b2302a86559b85a4589d5970934a2de3366eeb4c3ad24d330c2d0b43d29945a723bd9ba6d3a452cb2c56b52c0c492d56671658a39e6c6c63bbe5ac996b1e67473e03723f7b499a43636459178a2919bee303fae33727a5b46213e875840847bb9dfeea5208522b0201f58032801c372be611a1c41dedd55f3f2bf4d2a440508080da637dfdd0ef353bbe7eb0de248e771ec879964971cf078e0ea7b9750fb167bf9479c457dce15dbb7463248a45bdeac8233661c509d6d13ebfb05f7e71283b1aa235c9760c9779a7bd61e71b6f708e6c34b2c28292108458f231f67c18488f51616beb43ee69029e8601c4532c945580032c4979e9ddea8bc5c94524fa7b4fd61a9db1fa89c58d1eaff89003a30602fc0463053f6fc846dd29f9015a42841de8408907545c4c62a0c363dfdddd5b0d2ebb2c91918ca89f363922930f4be8f1b3c88a0b3ee42b587e7ac85a2673c931e784f23346f919a7fc8c4b1ccd17fcf4e9f6a61cfc01163f1dc7c70f2140c0f2d35760a1c94f277244043fdd851f1cf1da52440f0d7c8080f4530323a02d5004f1f0d3a350b3988a2fbef8190416fcf449140316775e2fe26b0910ddb457004a5d7cb3902dd2300cf341920e1896a1cc0760e050b740b23e30831a61acb403173d4a41f07003a5293d6049528ac2072c2fa52b4eb8e89212833e5321c6ebc3eb5d1465204921b7b8dcd10f57060b0b90c02802a908465bf43040085d8450821c1817443f9fa91002125b3653e721c79e61ae79d4b60ddb26c7cd6e7257ae24f7f12871f9fc31bdd21a58586102537aa9dc86d9acb2808459d36badb5d6596be5bcd615b4aa69b57af45038f2875cd52e86ead5ab4fa07a8d21526bad2e13c33933f69cb2b14d08e3f3d5b7299d4dbef50edc8a3e2727f1b58bf8da407c8c65349195abca79e72e57d53baf5e2bd799a0dc935fef64a081636016f57a7dd60a64721f5d8fa4aed7ead78b272f857699be282457d58b434264dd96b44f49495acb5109fb849864b86170ce4f9551a9baac27efa97efa7894b8e24bae6afc91abead4e369b07ae74520b9aadd921b46a5afded5e39666d51047e4d2ac90a312cf74e91607e750189fcc49940ae8cd997b6b37cf326db398ac4cbae70d1bdb98806e77aa14aa4b5781bacadb53a5207d93bea95468dfbc3d4e75427c1592d8cfaf72498f5d9ca7726dd2623e6ee40af3e8099198c5308c9750d07daa1430c7dcf4bd406548f7a95c98bfa08a9f4a88c921c02e93776efa5ee0a1a242f7bd80b9c94d9f2a7ae64a5c2f0c3179e7d1bb8f874afc86749e7d3c9b77cec3b9c995b8d8c52eebecda62a7d3029220f1a743805d99b7a0535d48e6aae8276797f554d13167d710550a26c75c059363df0b548660def90baae89a5b37b90a9d9fbe1730ebaaf8a9a0b955a99039e69963de399d5bb765de8d5c4976718659b99244e6c7829d3d9d88208828b0164f4ea71d6becae0274a280921032a1bbbbbbbbbbbbbbb16ea31f28f4c0014b00592e24cd486118865d94e69cd9704b886742af240a383fbe5d62de83c8fce6b536554f90baa00f6916c7607b3baf64cb07af7a52cb603b777884fbf9d399e7e3e47c7e6027e5aa37ad0b737e760a1b0773ac70811234a3a21ba91935eba859a186a45991da95973f7c0bf1419ac40d358d482baa4959899a5a52d29cd279f668973d7f90534aaf724e593f3aa79453c6a51898885f800f3e71430bdea4da9bbca29e793528e67845a9c70e48eac3242794807d4796401e49c6f4e67ce04c1470e6270573eadbfc6c70a409369e8b6670e28b686bdd821a9ca2093518bd560cd38234a166319671f4871aa13e9f51b9ed6d45952e0f3e5be18497df24a7396157f2fc8531a43df46784cf8c8064d700dec1cff06ed4277525763aa91a5c1fd6111df3b9d1cceedcf8ec9b44ac233ae6ed49d15cf3a84de955f42d5eab0535d8e4865a50a43f27a127e49cbe79a1929f61922fc26e847bcc31e7b8239cd48d70cc3960a7977e8b6630e3637e70a2c415fd0775e9435c4a9f1fcf741ee94a6ee8f1063318c0873948f0c18b086cf043097c80c1cdd2ebf5aa41f2f082970c637021030aa2b8641145e8412a7237632415961ca90f4bc0410f36f490a5a8072f4f907c5041110f53bedde2fcbddddd5f70a8c156f0e0a5d7eeeea6f2d2a7952ca48348a0650545a8a0c90d505c0df4dddddddd7d05065d115fc24bb73478b903d0a7a290170c60626a434a8db0c587351b3b69b7447c77910e4f7c17f988e0ef8ddc1533f6c6949054cdd28728207c58631303962d6a32e5bb280728dfee454e6af8ee6b49c87235228c0aa0ccca0e55c9e280624537783182e9221aaa4c8290ae298228109396e2c82505525f249e14bd8a7068410f454729315242483ad82246d21231927c902289ca83424865313aea31faf6d964fe4c28df6e54f35cc4248aa21ab63c53310499e7a21a90de053f4bb8e0678a0b6e88f2feec021b9e644911e8238d9119f5d4a59c72ca2965888a5064fb1c9ad371c86fcacf25821aec2635355d3c51a9b0d8b0b1a5468da254ca0a0d8d171a34aacccc7041a1b4c8c864b9121353040393b42549a959f76659723a613199a6745d158ee3b26d4b689a952cbb62ad972ebf93a4e57792929e39871b5a244622222a32b21225a8c1a636371f8da49ebaa4f2c3a2208998969a446da84915a9a75ea9568e72a8460d56a25ab4c5fafaf6c219e1a8976fcca859f1b1a14897be1d1bc2aa6044cd8a4e95302bdfbd05dbf2ed23f80dc7e1cd80c33d461c8ec36bc581c3a3273f1c1e531c371cc78d1b5a7e840f436ab06f7c18162737b456e8e0ca5ba2a3a2667590d151b3428b7405a959210dea496a56880dbd96c883bf1dc3d2ac1fce61a12122a32321ce6128df40dfd890956fc7aa748b5ded58946e4d175634a51685744b1dfaaef2ed3b5df434ab8978fe1a6fa78b9e264dbaf069560ff1fc2a6fa70b9f2e9e74f104a9593d82e7b7e1ed6441c28245a9590de5f96b783b5994b66c216a560bf1fc296f270b51519151b33a88e7a7f176b21859b1d2a5590dc4f3d3f076b274f1e265a859fdf3fc33de4e96a12a55969ad53f3c3fcadbc9b2c4854b52b35a04cf2fe3ed6449d2a225cb51b3da87e78ff176b21c65b992e50a51b3fac9f3c3783b49444545494acdea1e9eff7a3b494a495b92b6647935ab7978fe93b793e5956549962548cdea1d9edfe4ed242161c112d4acf679fecedb490a9a3265a859adc3f373de4ed250952a4bcd6a27cfbf793b494b5cb80835ab73f824a12596306a5637f924232b568e9ad5383cbff576928eae5ce9d2acbee193ba78f1b29394d4acb6e1f9a7b793a48573e22769611dfc3e5ac92ecd2edf419ea494d2ca18463dac1b4aff34d856b4dcf985d1e8da70c3d9337bacedf9f9900671518fcfd3a12a5f7483d0eb782ebae1f59476e94e881f6d84c08f08f4f287b6931bc69feea15f0779f7c8160e6fe7afe55f8dd2b38b6ce1f8ea8f5cf592e77b69fc31f96043d479c27083dc109d4f9af450306e3869cf4fe4ec462fc004f294c4ec8a2dcbabc8a399d42f4c71f1ed389c93fada39f20b7c248c751c10db490a6261d42998e3a6db461597ca181a60e5714e497487a99af38790166319f2f32d97a8143101f23231399b5504736bb901b341ccc3f8d8e7757a45a4679d3fd54ef4f9f578fb85d23b1095fc74cfa6c1ab1dddd04e15582e15e3771b6c7bafe579e996bb96bbdf9798df4e61bf87d22777b4893b6a3e4e5ed1cfdeef6e6e236227a70de76cce4ee4880bb2c5dd53c84601c8a17d2dc4eb9d3c8e26e73e18542a4417e7d1c57d3d9ccbe43dd3b5847326d6159904577743a6cbf43199e1e4e2bc5ddcacaae964dcc74c02e69a14aff914503c0684a5884098e887c4c1b9b90141f754eadeea5148bb555b23e858175b8c91120189c49e296c18f5458f5f0bf1e5b383b21583301b0f92ad483414bf380404164c3724f568b071e41830f088410a885c54a4d31cb25143744a4c39811006172f979c5582f879b9b83ba1332eb7e5e4a26b6cb68861d813222b50a6f8fc080d6195da1b51d1277ab41263fcd172c3d8336d9206a3d378a6e20b18cf4449d48c6abb1adeb26dd3362dbb284e31285df36a18949e79ce9c6719944e4323dd1f121e2926538e2f39f8306585e80d5d87807b2aa2a1c99fbc8b9678f9f072f178d2b19ad3ee6edaf9a4becdfbf40b8f4c4b74fd2b821a82b657efbceebaebba7aaaa8ae8647be487b3d7d1e1ef9da9dc72f6c9f1d765f92f9279f9e9adf45497155405ad5397f77de33154550c153304eef6ad7755ebd1584d070fdb1d06f02ad2554ea49ca9d5d77dd3d3ba75c373d1b55dcce4323dcb79b7c7af54e4e976cb6d3e97ef0771f769a45da4fd79be1fa8651af73eebab36d69ad355cff214236d9053979272952bdf3f6c2f8f563cebd30fec9a96784fb934faff35441e8e6d4f9394f0564769f2a48f5cebbaf08e73aa7fba93a67d7905e453779aacee777978f6210a2c6463bbad5732f627163d041df32bebf53c3fc385727662421a4a4430a64d033c30aaa12352d9d8fac100f3350a20652c040010e5cb28697727b29a59472d28ab96d0bdee03c13f9e0524abf2b90524a894d4b6db5d8fc586e41819726aa24a18317209a7871b24929773aeec15d23bbbbe51529a56cd93dbba5941125a56cb73695ea696d2a3557cfd93392f8e55540667f7f610b6f616010638cd1c33cac4ebf196b7579d3580e9b9b4f4a59c5a88972a35bc963b60c373a0bfe3295b2d6717c91ea35099d52ce6ecb494a2975b8ec41ec73a595ce39e70da7553a3517322dd378b059934a65daacd46e5d172cd32686f9bc959bb3335d394fa64aedc69d4c5db42a6efc4ed37c725aa665da172ab15eeca135673ac340ab573a27d63a549ae385290a2a5262da45d1ccd098367b98e8937d5aec89afce48f6a06a505d2a150323532355c3c68de9ec3e7e700db60173dc9480f38a8172fdc3e8e2bed06e1ff6a164625031ddbda6ee6403c35435234cccd4c9ac5a5337865674a3f5e2929711167b4c9d4e955d043a1fbcf014486f355ccd8d29332a32be26cfd3121b7be4384616d8434e8a343467352c6b1cb8c26430f36d9b9ce59827cf56934a7d91876c9d9cfd876c999c616cba73ccd94bc03999fc0b5372f3b869d967dc866d1d86c2ba7b2ba755b9b563139f4ca8d4c93309892f32b4296ef44da30c66ce9907be3a83196721b0dac7ac23cb94607509e56ce41d6fea74a89f224bde4e27c6579fe0b5c48b3d2f14e2a99570dd5591ba3766e8b07152f49b1711863a2f2f13115cc083b550d4539fd42df56b06186604c1dc9a6ee595362f73bcacc14bb75da678e95776d9c1cb328e78590618646cb9c19e008309ba833b042e397436009d62d081a301c9e4d3c3c604a83bc289d6b3c48da1040ed9cf3646951ecba48b364651cfcf18567a70f5fc8ca1031f5c358cc18507970d486430d9c185c311193fece0bac1888c201d5c4b96c860818f8b869f94183350a4a40d6c20454eb1011348d8a00a59860d64804a6d510512f33e17dd20898fde9107cd0bcd8b53c8d643c6e78c31c668313b8534383df6dce8d3e0b4445c19173265361b63b4d6312c625eb18d63bced070e0f2df5f98549e6cff80feaf98872677666be1f0dcec81ded64f078a26b046c04a0a0aeeb3a8f544688387cf6708effacaee9f9fc7cba4f8f339532994ceea3593434c099f219a7de0c9da194a6525e63662635e3353c249c72ee7452df8f191d1a1a6ebb200bf8f2e5cbd370ee1a1043e3cda7e1a9826445623cf31680604aafc30d4e1b0e005741e5eeaa2137dcc66d6ecc53ec892fb99aee9e0b7275c3e3b9e12bf0d4380b723585c4e77c7bdd1997f1ef53a9206b5c3abbbc4fa542bbbb7f2fdcf07619c73a1d29387cc78d6c8de0a3c1ec91c42fcff95c1433c3e87067707cb657d465fcca7c13731f32268c535a98276f0efdbc0dd61dac63fa08decde6a34df831c3785b711a9cdee386676bbcdb81f9f62b827daf7db9e18e9f1edefc5479291b9e7fb965dcf0e6a7efe01c7ea14d098d8e09224211a4251595a0e70545265454821cb0228ff8435cecd2b7fbb6f1c791992373a594d658a9df970462f4a92f1daac8213449441c028ab9444a1be20f51f40bb808189d945eb9f3b928091c2aada1155fd4515f68c4e68d983224c1a4288917516d287ed8413a79293d25514a70e182f10d6a0e6f90025110d1608b123ba8a106ad850db01cd0cfc8cdd75a6b85a2a7b28b526b3f97abe8b16504082cd081972f39107185ab6601850f0dc5154e1c93452920e2f45ca4c4971428f1838d73e4d112d1d26f1997a3599c639d7d88fddb730aa5aeb82cc583ee429f1009dc9a4927e7669dbe307e4c9a72660680754cd96a1fd03de52374f2ead5dba759bc552fe59da69d945229a56a3abf7c9ed67d349bbadbdddb5d538df1faad17c620a69f404e3f51fde10bfd2a20f243181ef5f1373965f4847c68e4e6e7a771ad300029b7b65bedd3ab76fb765a22ae756a23a685f2e9a8b9f45a966541491f47f05c2405e837d9edcc9f0dced83ca749054482e04f6e7d262d2dc1f8a9f3d3d29ffc36f1c4fac441e7f6e8ad9f8e2842e2c9dfbfbec9c0a066604e26934d8e19eee4d9a7a172f931df3ad3f4909c3a3f79262ffea96bc09cfc276f3a9f4e9f5bafb3ce75404e56368d1237ecf07a8cb7f74fb38a5c87f1f6f6e91d38e7e421395d192f7ed735e0e4303fbc1ec64f2718f7d13237c60baf9b1cc62b72fde45b17a4f3936b1d90fb9dbe2dc595f19b9fbc86e2758cd73e66dcf8e14c02faf6eb53cb54e21ceb3dbd38797b03527ef26a7c49cd3a01999eaaf9dcdaaf4783313ccda0661539b9f5ceba20d18a2392beebdc76404e6e9dbb793d21d9b23e63ad07e0adcb16bbec6d8e86cabd8e39cd092e960a8d707f3d4cd227cf3eed829cfea5f83c03e1b9088928bfa9381a14dc307e0d4773828b797893c42f828d404dd89bc2171ee6433538fd7a15a3a8113af208d3341bb45edfe475e18d0fdb27bc1fb64f18913e4485423e9cf918d36ee586562979d80a112710810b063b8420b8befaa8560441c6112e18b0339eb8a8d78f87919a8c81c505434684858b7edc0750e2da9a73b952813ae6b4aa54b08eb9fd2a75ecabdc9d29d6d15ebd3b845ac9c34551683002170c74898bba12d701ba881b89a083537f6c9f429cc5c7c6da766bbdc53efa5e867ec916f692abe836b43785bd3e3af685e087fd8a4ac8f0b18b218beee5056df9e989261f5489bd648bbbd2abe8587ab4f87c8c1128c6283fce94c5659f2ce7e9b564e32b999965161eb4d7c796f1633b0b7d485ffd651d0f2e7b487b4eede5c4a744f52a7afc6ed2650f6f0ab870d1a2e5e4445814a5e869dbc6c0f63ca9b3db8c73e9715227cb5c9a32e73a1d53175075f2e9349c4e2a37e42b342e4459e257cf45517a7eabe1f10b7b7c0467561f9d86848fd105bacdd0a4666852311d2b0c4c94335e68534b0885467a7c7b547956aea8dbf0ee1457255d7e425c902beaf12557f47ea111d49b3cf34c8b42f381296ff07aca332fe5303e370441188661188671181d6ee6343c158dd3f0193f792a1a3f79fc8df3a4579fdc10044b78948cf31726a15f4283d46f1aa42045c998c01c6e06f618b9c0b384abde930f9570de8c4baf88f45adddace3bdf7ca7fb3657f29c17cee75c7a210b2f3b8f1be46a38773b463e942e95bcf48cd4f80a107754e7a251ca0b519f398dd782cec983d0f099cf874479a195f1c2d49f3cfe180fc608eaa56745477479bef25c744494df9a3bb1a7ac08c525bac52eaaf9b7b90ac33a07a9e7a0bec2054aa0ce94524a2975acd3c1116d561891ac501a8d642b8791f68173caa5dc27c586538f45cd925f5cc2c61725a5531aa421778950c2ebe57a83d46b1528b0407da31ce71bd76dddf6a9826caef9ced6715efbe66972a6e086e0d32cc74d0f1f3f9a653f15f64d1b3ad33472d8f8e4c4e5a2239e7c688ba25c79d9e2188d006dd4a747279d7346ead5996bf5e82161ca833b9d7647648b7e91eb3497fe01bac3cb185e3a5ba6b4b23de3aaa86fce47af974b453f219c6b2eb3b8a245d1ebc5831d6916b52edd8566d1cf7ad3ae4044aea4742d8aac5f27c3e59c99624d97533adf2b6575b9a9b2cc4a20a4d8c40529a56716bb3f139047240a0d4ad1fc876c691f8ebca15f20ee4ae69b0d786ff5f9d555d5d9a595d0ba91ab9b664953951b7dcb6060c053da74e64566625c3ae577337f36b6092f9b8aae74fa5b732c10e19c0f5ce9d37b3b955cefbe4083cf9d0e0b212f7df3db6a2d66b10ade6edae9c413e2bf4e67ee43b6b2ef26c7fc24fbe28eb8d1253373741c52ca9b1094524a39e59c734a29e59472cacacc98c932e173cec9cc129b75d239e79c739ee046cf70b8d1e71137fa0e6e743927ddb2f188dc2c250f2fb248c1a6c352ea00010b23b6383966ac72cd4c8a5bd1c8a711f70d3e9cf98e48d1c8281a590ce8cbc428867d3c454004275d087153cf4546bca0e7c23461c41042b8dac1d06d40171849e9736b3c1719418317f1c58f1bf9d8dcd41c52f6de6b5333e53738e0bc61c10f58b1bbbbbbbbbbbbab00c2c1cb22a4bc742fd51d05869d00402878e9386c0c4cd418a106446cf1d26f5c2e6306276c704e4d2480744b840986b8f2d25557059e8dd963881144f1d26b743af2760c42cc88918a2c0419b0e8ae4d646b1a0d802615535074e182c90c5dca60d285ab9118a2bbdb5671f9270f2844ac6828d1cd804290f1d2519d8e4cbdb0e84c1e1fa20af0520a51e5a5b31037bcf4984e47a68418600a1c9c88220a2c7aac9060861ceea472915aec0a62480b184fc5547686c9affd1cabf4a62487aa01e286ef2220ac0802a85d46a08ba5247a98d2022c708892831bfc10bdc034030f7cd0c413483488e28a23be804183bb9847d5d80c608b9f137cfb4d3978f3030dbe9dc3e12f3d8461430f7ad083124c8c88a1c98906d55a4be448fc89519218893ddd6e59ebb6d65a5b535383c176bee248fb7c6c8048e4418128c21a60d6a45188c0f2d9b68be086ac64bd340b5322927967d4078b5080aad497edc176c676c676c6d664f3a1616bc4dcacb65d9ab5a45bd9eb8a5db24ad68b45aad11ac568edbda00c2292b1ac80190fad16948716cbb7cb206bef4da568b8a33e9faf7d64623a6e3e37ba0f596b0638e98b444fd20e02ed9a711a28477d3c281a281a349c86060da77194a71a927294a75034348c9832485a7b6f2ae50e823726226af51faa27db72d817b20cd68873bc6fb7569a2539d5101994cbb812578ca71a12e3333ef3f1cc6c282f76f1fa25579e6a080d47398d2f76515947390d9ff15443687cc669be7e7d2aeb34be060a92ab56d92f8576cdf8ccd73e5fffc8551f71436b64b9ec3473bd3deb7460be93c73fe34dd7f5b819949fbc0ed8cf360f6590c7353813141414d44292eb19ef886e83364fdd1b947d3333a846c04ff4424e9298e78af1d865f2bafa4365bcd008277d1784695002930f17cb346f8b691986695a86999edcd01a3d92446a21897dcc5b06a33e0d4e97f5ac4c8c635e07ec5b19af5d3248b6acb5d71a055923d960cac81e7ddbcfca787c29321f0f0cae98cfc81acd48731b4711aa5a53fe63880d8e15b0724ca56274cea9bcfaf0866bacb5d6da3518d4bab853c62fc53a6eb8f593627da6deeba73495a23ef4c90f140a2457181236a886d4ac7ea269e9edf5ed1a16adcbd64453d2b8303316df1eb72811d860f7c7015022d9d278d5365ea86944aa6fd79234a5505b7aff5043a24632bc1f9d4ec1839fe7213c4f91050bd03d6184efc2cdd951eda8414ad43f77a343cda2557cf02480377c050240b96a0de97b0b6e316b489c53b9352f422dcbb73704a82b46d7b48f070657e61a9286d4acec23563d1baf6700703988714a1d1432811c3644dd544ae96d5b134a29a59147f63b5db7323f11c956f659fbd9b86d4daef4b6345cd509d847cfbeb327a2226ee8b40866d1a18e4e9d688fe2db6757275d5dabd2a013ccd2a260b0bda98862e3c1c9b7144f3ce6d58bae5569d7a2682a78c0b60fed6741c5871b0f128875849c14cf3a8e4e445fbe7a0bb1fd4434853c8e261fe874f7668595c69f18a28dc9c636210dc0b7af9095d039180bcef78cdc724ee6cf32bb471ed973946d629bc455f13ba13f3acb1693e8a2b2d31f3f3601716995d860539fe844666012ebce060c2e75bb43fda252ddd2bed92be937b5c54e3a866a304ac99c7a527adc957db357f48476ea43fae81a9ddb41dbb4d35571aa22e643aa631e1dc33e55b4ce535dd53157e29a3c534a211bfde01c0c00e1561843d2162c84e93738a00f2522468efc44e9564a280914a3253d3eb463c84528b062245ab21c95467d8cedc97c54c5f654b1bdfb91e6e3c76e8fcd7d6c2fe663f45454451df5b53ded63f4a89f6c28712b905c4d67b1d0b295f9ac3f3fa787d4cb246201661561706e993d42a46d283267661ba702fd74af40b2a58a6e9d5d53153f550a996fae82e6f67be1d33e55bfa079f6a9dad99539bb7a665edcb8e442fcb613973d27611dd3318f03ac637a7bdd47ea1d6970ba36c57ae68373903cb75a88abe9d3869f73b219571c611db3c71268670fe6912433dfb2e1c3d32c2e6241d1cf39e79c4e3bce1e264c9c2ab4116d3584487a4aed7d9317876ac030ad6ab54621ee166a16e7ed45d1287a88cae212ad552c7e3d97bae4bc300aa13e8c42420dd670a9b7839ee3c64345f92d7243bf35173d1917fc26b9f654d5b98a2c9c3c577184f4d153d56fc7b37e9b5cf42e145ed04051c623918fa5a2f0f98d7211a82806441fbf24fd48b0dfc07c2c06e9378c8b1ef783df2c17bd986f8fab98c118bf655c7b2ae95cc5959e978e7aeb690fe5b78d6b4f5ece6d2871c32874245bd147ae9a18e21c22d93239ad484f8f60907a58ab3c0d6af0086645133048dd04d4bbfaf5fb4cb81cd8aceca91531d8e2c31c4f6f4cdd99909cbe3ae6492f2e31d460155790f8d89dd07dfda290d7bd66821bbf7393877c04c9d2d2120a4ab00eead453e0564c415c51a742a9fa851126aee217c6163cf530eba20cf747839dd7835b3db442cda24f8b98307a3af3d463528d4fd1d092252b472a789e72442356adf40c281534ba093f6ad2e98be78fde714e741b550437d43cb3cfdcb29a77ed6b370b6f8c3ffda66adc06dca8092ed8fd5fe3cdd27c736fb12bd39239dd68a7b36ddbb67998d23c2fd49c7a187fe62979eb25918ff9903525a7d3f6ae631d9189c2b8e11cb60e66cc4e63e08f5f4863f8c83e198b496cc44424749dc943d9999c314de34212429c8f270fefc3609e218075b4b3635e02188491e2dbdb4b883cb22f27eee8fb31afbe2bba07eb680f59df1e81ee04b6d7b82f9523571d99074edce1d6ad6cc7892db36cc339faea45a5203c4ee46102133ef00e7e1398f88175f08739dfde53cbdc7e66bf7893d5df4e31341fbf90841ceacc198e9fbe135f4a0efcfcf88675c498653580ecc6ee3552d7f62ab6d8c5833f14c008ae90c6b787fd99c0c41306f9e36702133fbc83bfdb8996be584715afce12e4568d2b493d1400eba641e9710ecb020c4aafc12cbb5980592a06a5a71afc893b4a78e932002faf742b7b45d1721446a29755d0b0e5e590e95505931d3e8c5682c2b8c44bb75805d25f31186ef046c5ac200cca1fedb225c4149a5e1e297d8c21be5887f42dca483ffbd3cb3e4ae1a4b85d3db6228928c88d6c4519e2ea030c1251c04b299914ce7d340bb2d52ee99bd72e229a2bc9a40cd75f5a97f418247482bbb9e609893f72f5ba5f04922ba945280d4a8f1a11377e3741dcedc5392e8c20a8598cc1c49f66c5339e7e304357e6b98a255cde47531ffaa4c14854bbbb018d1e7b809cba0bb29539b54e876818312ff3e859df38324b939476458f5d99778363f3370dd2fec06e07b71d89084ba594c47ce6e815051ba4396ec00629751f5d894882196905604e9dc81149998fc8960c9d08e7784c3533eeac2e3d231a51090dd21c393a9d9b326e0bf34310ccd12d231c9106e90c6ec848d4a94fa05b725e9fac061bdb847c04e39bdd1ac66357d53a9b65fe999d9917decdede64e3b1d2931d967ca5ccb92ccf7f9cd6d5113afdf744cf8e103e77b34ab88f52dc8e64c6e166a4edd84cd4fbe39f785479e73188f07c6afc773fdca158d19bf38950a7dbddd655ce67b01c6a3b38b7e617c934feb27cd4f9e2a88f699675f11d3a77de785dc9764fee6daa6ca7c7e66428ca7ca3e764d12dc1f9f8f0689b8955df701d8c7d1adeb0f847edea871b64e23662d8a9a866ea3caa8f48cf7843d0b19a2110c000000d314002028100a06c54281402822d2644d3f14000c7ea44478509a4ab32c876114a40c328618620c20004044606686660402877307ed8b8334560ccea41610ce8160d270b2b2cbd330485183a400072eba1382b1e4760861205b0baa36aa81fd256c69620dc6e364bd52f1eeb92050d0efbd5204d6be66306bb36a36c86e16a7d0c937240bbcc9a703efedfed5f08899dedafc41f3330ada51af9210b5587f5d4e00481ba81954daf3910d40b604ad11a2bba808179845f821afc464b3de626a25705be2b8030949c67172f1959d035303dfa0e1636f3b3176f6ebe2061f64ae05eb59f5f8bc0824a049acb41fc35f1e68d5d275a0f8a3cf4077eecf412861b62fe7a0c460b1038ccae309f398aa8dee0e771adfcfd16e3a9d051ee4020a16bc3f3017a67989c97f30b035e672298acacf9ae9c7de042e61420de782ece6633f162bcfca9ab88c96bec6b966a4a56b2cbd7f4361c4f496406249d9389bb5fc95ceaf171014b9b90974dc808938ee5523fa18f842b8d271af78f240eb4370092a92e025b0dfa4960c0e11994ab53bcd8ae4d211970f72953540df4f904391f057fe9f3ed13a3e945d3f0ed85082ede7346f316230fe54f607c5edbf19c32215dc697397c130e3fd82b5030a7b50c3473d19b84ae5b6553048b281b7cfe980e8f9510f85e7de36e60233d9fe386797aecd0510fede4654be41e948d1e3e15049171fcee857733fb29500b5548d61bb132bb841c09186db0f3e5c416aa33811b13398615e4488b50a4710971d84c5903d30c08f9f55edb1b082f629ff7405fab1ad9a75049844c59eb36ae6c2d55a11ca8be5611bf56c5641a44a807ed5b148c36c9aa871e907ad0b3a4f8ab4e868b069857ca01b178e59cfcde6c5373cd13453d0f0fc8a9aea05b361fbc0e790f4906fd6857550c21bf1b6a060da0f24657577d13e3c8ca25251a515dc54d07cabde3b60408efda2f50dcdb704e55ac8d722d34460c41849cb3f763f333f49e4e6f1d7c0884e4e45e77663ec270f3c7b6904c2698e49d120ea277cfbb5aa8872cb81dc9048f55dfa0d3ae59ba86390ecf546a2da1f8c397f79867cb672f7ffa8cd9c234909854638c825a6a201a028d62049058fb3c8cbfbc3b52350d0bf388b5256013eb6067cfdc7416bcc503cf0bf0ef23d9d86a331f0c5c93e8f45e26cc272cf550f738bce274506e37a257905cb89513844074c543dcdef91431a48402155a8410370960305e9c943370eca6c9384789f0ed80ae5496a12a4e91a3bf98ff451f118c5be947530d4da0348af8e4b7c5e11a8f59ee738d0fa1f61180e86735deb84facc77a1b69c83f8f9900ea80b97af83860ad1dfb186c09d42fa10abaf1723d6c44e11186488c5a4b783a4776b8805aad91745686782be1e2344b7690b0c772156ba07a57de3de86a486f2c4dddd46160e28d24027c0ea99e01c85f047bc0c8cb5cfc8bacaf9494daf1fc4363ce33c3d437f2239d76767a0f072bcaa5468134b5ea6594208856cabe09367b62b290eb7f58943357028d400e806ba3b3a1a879f5b52f940a8dee0e23f1f7ae68305e18c10f0263f6dbeae6fa2a9be78151dfafaaf32967560715aee362cdcb7c56eb1386a4df4a06f0af2419abea55b71277008c5c937f40b591061b254569fd2f635b4eecc865e184804084fa51ad36e1f0bcbae722f849d08060031ba8d57b1fe7f0b93dc38e066e8ca166a92939a21f1733be8554f9430c77ee82a42c90d94b0ec11ff7501341e589f279c66d9c00d709900c62e1a1617cb1960ee43b7bc6a2cac59afa94800548ede08f7bf1422a258c9d569fe5f8ac47d8dbf0ef527625d1304d5f42f8269f4204dd002286ce30c162d298a69f0ec024334b54130d1373c2e790febce4b28a2cc2c4c5d2dcc5973c5596c6c0394de3576e9f91ee8fc8db331b2e8a26e5e5447b766dac7b1083f89d773039e4fdfb6d778715523f04c574dc86e75abfb967b8c21356af50e92db74e11fdf01ccfe718feaad885fdf47bf6056a65924e5c6d52c446de0240242ff358bfabfed0e00fa71153fbc7ed497001ead78ea33145ae4c19e35fe288582238b33215c94a16627cb96c11e6a09b598e8091df2f39096cfd400ddf4dfb17d42403184437b69de20edceecdc9ad421bfe870200888141a4639b85d4092961c1dc694e530db8ca9e24077ff26c51a1a6901b7d7d848737fae61c3d4283a5891fe5e60689ac1a70ef0001ac6d130bc423ce62ab59b43c301e7742edb3cebcabb86909296a444b7d94c7dc0a52ac56f674dcb79fe581e97c22fffc27f787ab24d7e33fe2d31b8218b83aaf7ff5d190158fb3d8c54c69c08062a0cce0390383a72fc69e0bdb20891d6a183492d530bec184a91ca5ce31cedc3ef60f2def1318d6c03a20d04614eb006bca7e5217cc19e144ab964278b52f89e514670f45342095e3ed3c78c93e9602c10b71187d08cc7c6f14c24bce2f52054bfa3ceafcfe302054598ed84e4f8d29c30840120ae161a2209c80e056d0dc562314c8666550b468976f6c87a613363b6cb23d049cea435614afa9d815b5009d6bd47898a308549c08591680158197f5ddedc391d0bde11a8fc317a5bc8e6fbfd0646d0d5f25afb5d115a4d409eb5549179fbaf8d5bf7b87b6e2a8616f004abec32b0aa7537710a71e1f97866b375fac7e2f58cfc18e8d58f139140e9207a9306a0c0befa1a82e4ae2b458e74feabbad289323fee22822418652e2a3eeb0aca3aa18c2226b44154ac780050c4faaaea5e94926a6eba412e718ddc1297ac4230b676f749f545b2bc2a6bf0488ab5d2c8328b16f5dbc5c812712eafa08057653d31d72023b169f850e6dd1d0efa29cb0c404d2e3ea1ffada35b288216d4237a8a965233334aa19989cde89df6d61d80d0b64877273534aed08b286f2579879ed3631bc2759da65f402b1517fbe9a413511830f67645d406bf34a7b348b0a681043550e3e4f8c38925faabe62773630df374780ce3c3316942463b688e5f6898f18f52e02c0bb455bf1f6bbcf063811adb896c7e45f26f7cea92e8a767397450c773c4380048b889d223dbc278a09602b16826b9bff52dbd7a26116e8c66daa56b608c99fefa6cc79218ff14de8abfd244973702444f7597e8804b7324ca624d4a656c629d837a37b3bacf8108def439e3153a10ae03d18124781451bf554d87b86d7e100762d368409a7e770ed03eb44f74aa9a945b2f0b05ce8e9bdedad79d5ac1dd3576657b4ff3834d2861c60930ccb75d29dfa7b8061cf6d06b3a3e5c617ecec2a999fcdcf8f9d516393e19073267d224e214d06610735e63d6eeb4a49fe0e333a0b771c1bd87fe9ab98fb29d0b4a8e9487e04616693608e5e292afc8d46044459e4e993c8fb45d4e950714bcdc9054fdf4c4567e1771628aff91d9e2c8a17384c64c6be29e4a3c2c4dfc0590f03b9365d03fb900b39f847f782251c50b56f028c941f121539f26eb85eb60f47c203b9c8d05a3e86a2c35ec02ebc3d72a7e5c2e941a7bacdd5813d12e43752c711a8b13d33ca5d6167e548008a43148698146e8465ec19731db9d218b967293d78e13a4a0cba475e6d143464f48ed9c1888ba968b0bcf14d7a1bed7e360b65d055fc095b3aa68e81da4974e54f42905d113e69e33d3ed2c35c3f121628a9043b47ac036c5933a517ab294b195fae568818c18933c8cf50c3175acc08c7b0d587e6adca90e2f094901d8ab0095b008213b816df0b99c38a8a758930c4bd15ab18d1b9517f1fdab6da0db5c690e26f76bcc0814197c822909f80917d9fa23d5b1e10c64e34dd4ac21359efc2f13df89e6004a54705a0538f8311ae0ef0aca1c9ff51d934053c1651916cc38db41dd46f6ff2ffde8570654560ce9041c0c97406c126e30b3b8ccdaa715d400e0656a44932b348fa97257878287e600b1aa1633c210a52ef91ef44f769e7d16577cbdb5117be782b45de7586d99cf4118a72fb92b9703849c1a8203b7607906ea1900e597dc7dd08f069073c1217da952f1785089aeb826d7239e31ca0cf33cafc36922149709710df6f159c59b67c7399b3242e3926ce2ba023093f50b90a8038af07aec7f8c6fb777df804e6a6f4f1d89024dd27c4e30c2392f230068190739ae3d1b97db90ba1ec178aa8c70044afaec518e531dfd0ee21456b24ebfb047e24fed10a1dcfb40ab1aa54f8060655a3cd41f030da2f6c28b0640b881692bf9f5a9970f0a14f2a4d5e40ac75fcf93f30681f49b508ae0aa3d94aefac90725144cd7ea5edeade5f4cdb7ae0506335bc79a8f53ecf569e17aac0b108539cae5d79e772f8b8d485af1c4d993b1b8e94a167cd7188f2a0ea54678159a89e4d3c9f86ae27bbacc89899eeef309554a214ff37e2d663fe79a5ea98745401ff3c5a1e8563fb6158c2eb008da8a7bc7668346e8e4fdf4911e9c82153ab972078faf7d70dd93494c8003747b88b4ed4db4cd5b66aa5c07ef475a9722297d8580955fdb101465dbee5ea93e6ef801fa5034cb548756f3ece33621cf79c8b681e3dd18691a0102de7fef6e75c516fdfd2f7825cd093cb45066c995c1c9a47b832f0d8141ff2c3849c3455a3aebd6d0e828d9b8100d942c67d07e6ca6765cddbc63bf404f81b2e2fa7da39586aa2315e864664e6ee2a1abda62a99128b6c18ea5f4a9ad007e6a2cca632f62beac96596c99c72abdf2e4b1a340580fda6459848b0bc3849e77fab9c03a2a872b5d8a72a364d0dfdc4dadb1697add77994444fb7ae4b1cb40bd16622d141d5e089112001d1389177c1f96ef8afd2e047f8fae29e44c8a6d012628546c71eccd004729d4250b51b032c81176df1f94099c645e711fea77d0af9b62222bcd1c7b3c4b0c8ea9d35156ce2e369e542b2b8e0c74fac0f891a7804f1dd01ac0f1f1d2e98a8580cf01c6d0cc72d67230c3c7f2a80bf5f3583eedfacd06dc28606bb16842aa2ff90b183dee4c76d69fdc98f48b550b35f65f3d3da1936d6d3392a7b0e515845d9ef065104ab468adfae0e83c8f38a0ae257fac6fac93b87f46e243038d1966fac3df052af4f738c427982976f73105b6225c079d3d25e667ffa29fa90e5e2928472f11f7490133f531da345f9312c07754b143b0a43b721770f8a2b3033cb90ee67477414260116df7df8b4fe150710b463a91887d1faa2ef5a5277ba035181823e3a32caec45abc2b89cf70246517ada31e24cb4204b0a6f7344eb655845f8fcd4608f735fe1b29d36a7c15eca5f05976e14af5840825c93fb888d3f7d48f5d19ec02a92bb47ba7505f9ee4cbee65970ad406768928de229104115cfcffa3e43a0b1163a357a6286f06e5efa88b7266c8724651845ff0c13571a28554f79a88f6c45caaca74b8ddb13570387f4c8e73a46c66bf8a9881ed1cc9cda2fd98ca0a1e2a268e14a4fce4d2df87d2204962ed23f9e820cf8344ad6a9c1d9c4054ba537b02e6c369693870472fdec3548ada467b7a01983a4bd76a28379c0db54301a4316c6fdfbb9f645af1e97d3d6faca4507341c874bae13affb7581b20850ef9981172c5b268ad2fdf017069e947805cd43a44eebb15c172ab66ede934f280a3bc389cf1bcc2d3195f7e1e01e9e4a345a8f5089cf4e44d76e0bfb82011e8504c881be19d87ee4b23771eaaa8ce35c9b5a10d90be1dab7a93b1f06612681af984e172b70e4f133a2e5bf0bef1bfe6847acd2d864258de21a0d2140752aad4ac120738f31f8d75182b319131f87b2edcfe305c95c9e39540db8f26f24cada85a21029054c777d19e62c4703dc2e70f30a341a6a19a5eb22ef2827e2344d542146bfe3c2782b66d056fd7e5d1311318bbd99881d86afca32bfe49c59e30b255b9f53cafae7e67299f1f8f0c7253080e694462868a46be3c4690bad11ede78f840210249ec29e604519c2a0710d98a0d3c96eccc1adde30a5f2e668227b0b30e72136735c71db9da18918d885b4160eada49869c510dd6968b5621e06ade3eda12724e4fbcc3ce1f5c72f9ee051b1be545cef1355696cef9c44ad0b0e3438834c9ec2ebb568a479cc9bb2ae0ed80837d054c6ac04be3c9985bbf366a366421a53c907a3744cc9a9b2ff6476b7146d1990498dd14b8dc4449619022f3623a349ca356224b156cfeec06dbe59a08620f44200a57943a971c740b68464c4856c58aed27ff6ffcb93f24455e7fb27016290aab036c547ec09022aa0cc1057a60b1872fc912af5d1e3459f78b1a04f6c202084a0fdbe13c67cb32ccfaae11db8e16d57c78a3ab3438004e4367efc9edb20358a2360339be5f43f14410846c6857cad9377d51d0bbc35870c878ef7b333d1a859543466634015feb31080a7e3f45049c2c2674462bf675fdd21c20df12a022d5346d75936f32feb06936a566a0ebc6c8aacb81d6a202ba78fa9d136c3a7434ad7485624ce4541973c5e8f232ba7d783a2e5482ff9bdb98ecafd930e8df0a0fd608492b8775646cf9c94c1ec5b80844f9798bf2bd629410fa67a88f200f82cc448a9264e0fe33a3bd7e60d9c4e1e47c5498c0102bd14056d055011021a4b606ec36b124ec9c4481bcd4166cb1ecca3b3e06a610ebf44c2c9c6708b0130864eff8d5ba0f83ec36a502318438624ff3982ca5f6185608e5fb811a66def4bd532ccbe0f92c370d8d876225c4379e3669cfade531d01dcb95d25be59b26f72a7de710b25cbaaebdb6c13b51b000bf480fa58bfb83cdfdbcca06e61bdace5d9f08022fa83e03dc26fcf6dd2f701e3ec10edbb22e4dc9e5501a6af5dfbc8d620531467f40f766c0ea9034971f95ffcef391a1e3a997ddccaafda1da96f440ec1511fc3802e565bab8959c9127367e16261904491837595ecc6f0d8d5f98ca8c2d2d350652f3fb193bcc7816240bb2b2b21123e6b5400c062df3cbe4bd2ebdbbf82cf40115986ff5caa0bed3c42e2a6a04ba96ffe9808554afa1c1989a154ef464f39b99a3f9611a4db0b8ec07f6b50f8a127ec4887d82402931cdc4f41be946dd277b960adf73b8f6b3b27d7e265069709f5ce8607e73d7f64f8b2e8733ebd6d56ca36bd649cca96b6ae1a5c247602da871a6509e0e201edb7e4050d36cb77969e695801129f28ab0cd3dcd5803e8d4469d46d1d298ccc41cffba4b1430817403107fe13bf7f690e575f75bf39a062f87af7d146ad8d8198d58b6c0f461ea30bfd23c018ddd4226f82bb4b2aa43c025f3a4afd157baf7f0297314dfa641a94fb3f289fb47b555d7f78168199d9528e7b9046e4e42dd4128c4aa3c81b3c16d4f2f033e12a2c15b0522369a992a84e1397b6aab12ab1cad4e039a748d739ce2a884d6eb65673370f030832753d7f69df5cc568bf940f01e3fd6a9aad0a9de5bc641d55249ec624fcd01dcbcc1fc81fcdc81749fd2e8f11aef22ac25e87d0cfeba10e977f8ba3b2d52fccb19262c3487573b79bdd92d90d12e08be2f38938eff2e7840d763f279dcd8fb1bae8ba442473476c86f8e843af5b8fb1ddf550ae32900028ddfc4dec54d14c28193f0f21e150cd50a2949c1fd406f1af8ee3967e4ecd5f71be094126b06d7ff785ceb7f757b74157dca0d6d69d8e91b30032a5d02cfb2d806f4bddc53b0c5dba8ec8427662d6c452eebf40fc3326c703a37120b8c4a36c9a8d0ad2e5e89fda06006658ca3b4d59c4e079f0014cbb09fdef1f5c253345be9e91a98813697045a83206acca9bb92a2549dbfca3d413819113299243abf92c0bb8193c84aa5850463bcdd262639a252e1a84e8f539a205be1a2f84143d70efd98888940b032b4b913cd27bdc90847b7f8221481df5a8c6742ebf660dae7a713a4216bc6af3e6f907a473de904826a029fd042ccaacd672dadde13633b71fe262517852b53906796862adf8c79d4ad82ceb095d206ad9cce7b68363d447fd669ec596f2aba543b60287d4f4b9e8570c039d04cc597b407021e982614be9a4a34903c9faa51e08b44218f8137a66ea6a79fccc47598c2b29946dc58c6b7f4bdf308483306c2c69f85a8769a1ab72d4e531df6564331fe33e2a167c93e81836a9474a4a426c484a82e7383638b791d9da9e834e79b670b68ed8b51bbfd19443976666aad89bf089244a53feec7a4f3979734f99c464a0f573e1c46c16e064b8aa52b116202407c699cc789032d076938d5f6d0d683a0eee68b916247757e971f4f7bda393d9ea28384a18421ea1570b567a505751d67511de1d37847ccd09fe4b7f7933a490888b7f128c9b22caf5766e9b4f241c243c53da0bb2f01c42b4e75b69f796f5f3ede6ce63fdf3b4b0482983db52c880e62f14f4af58a4c25f5cd028d5a9dc79a099f81fa0c4c6c24102c38e3462fb328b6a2d9449840abe64073d9cd813c23e760b1366f56c455ab8967f81948a0d49f688664f100a78b1fc680302b6d2d95e7011cc869c27ab88d7236a4e13e8cc6f2274122555ab5f193338bcd7f3a35c36662d9d93b906acbda0de3e0ece800a4bbe003c0a83d16b2a9a5228717aa3e875c9e295311c512f19635b7d6ba4c5ab5b43142001571f2cbb5e86d6ee030dccceda2d236738e22d5b8c340f78fe3993cfde37f7c36f0629580b077b3ec6fdae0cc05259471c82c2e5d9f0d02c98811232cb411f534f82b6a0184206098e7cf876c25e10cf6832be1d3af86dee7f065e81b45448734d81236d0ebd48b2c3c2fd206aaa547a1e2c0b9c9fb815ee173e5c1d038024de3343294797dde67793a8a12a915f2d103a866f9c268fc26fbb57e5414e99482bea1049737455e8c48d7b9faca52e47026e35dcdb44fd7002daede1fbcd324a4c15f9303d7d719d61bfc69c5c7b6c510d76d875e81cf9d4cd5c1d6a743fccb12b9f8c3d9d007e7b6b3bd1c519ec429b9384b630eaf20e9e05ef0b8e8a4b46e3cbbe948c19ccebcb8bb2124c993787c4aeb6c88254ef17301a9343a54ea7dd0369863032ae7380c307b58ad7cdd509b3a58d326c1bf625de1023cc701c1e5787d7a9de617d39157ff4f9b4ac2ce9588b1ddf4e559eac5110b873ab175b4cd2b01ab1667ba4345421a3efc53670ac262ca4f8fec96a70761efbee9b5dff95cd6737dbb1bf5c48af19f43d1f99ac6a44608b273a727455b51d3e112273bf921239f1a160bccf47e770d43bc81cf1ce20229a0dbe633b78406d48426b4995c0b89cda1a29aba7bcc01eeefea8508ac76894804ce493197dcc02ef4c5b35ca864b840461f004b015c845c0f5fd9c724590c16c8cf786602f6249c63887aee6b2615541959abbb1791889003f19d6105768578a9aa1d3c2dd09921ae9b16582c863b6500fc0e33f6775d9782c5490a1792d91a7286d07300c62c0f0b9f974d63b3c42d092ed29e064e51423e62c0d69ec113dc4092adf8afb0323ae56bc4fdeb4747f6fbc2c0664e92211d0d3e4dadd9fed80340a08dd94bd821fb881e91d213b8bb56413230548899e0b96bab993e4c4f095b9fe894c89dbf12fa43894634e6f74e0aa7967de992bcb6c35bfddf76866835324ba0edd9e3e9c8750d9355dbcd8583f34448e0be337e2bf0714a5d494e80952824266c23efec1c50a91c6993056c133c775badae7bc5d5d7d5b516b72254b53c9f7981faf164009fdd5d57f67ac13bc4611eec86f5fc8572879c21d0419d0a3d1d048d45fcdcd0eb9177ee0b1ba0eb977991c29e0811b1f5851826b9505eab6216b5c3c7eac4af4757e52b616cf58d3bf1cab1b1a89acd9449d8dbfc10cc6f409a32790e26beb293011e6440589751d0e2398d91ab4c5eda3102cf5d078748d6587f674aabbafa45e4ab6ebf79c92d21f89065d8796378e34e4c1267bd24f4235961c6849abde56b9f66eb4be931638f4982f1817eaa021a10a17adffa6baeb639fc562f0b0da967c155c63f7e66fd2f4cc2bf6f319b38e9d25ee8f21a8867246089786b028b04f57b195bb059331c11c56195c1c18bb181f4ff0c093f22c5aa0d422ddd79c0453058e78d61219fb18313b36daa277faf02d74b092b18bc381edf380fcc21dd0eb9526bd1f3232aeb6cd33187a88dc3ea1eaac4ad5e271877a5e257dce727427edfa6637abce8c064123a04ca7e6a59c2b9b0c5625bc27c6671da20e6ec7975b8bfc2e1e01f88489d2f40fdfdfbba688945ba380c147e89eedbad0b88d8310b005e1b9058a17e11e7f67bfc8f1980115e11c44c082aa535597509612f7927dc7319b91a20dac92a06d01f5a31bdda9c2150c5c2ed01fd1779985a76e2002933d829ae0abb541b06b431e13689d4adc6c4bd8c93e020d41cce78ccc43267c6d07dd1f499bdca8bcfbb50d0f1a53c62f794fcdf7d22ce6ec5935a7e0438bab54e82635d524c256ab22e909ad8d6c152a1fd076099d0c68c7de5488f9043ae341d3844eaa88edcf7d3c9829b7ca060364b1acb12649c41a0cd7cee4c04bf271baaab1d049f9e0c87de92393722382370340e2c038c634fbbf6c07304be9db30e632c6be3830490ccb41c97dbedea17dbffe03a555827bdb17eb57da6226bad6e390b52b6216d69ea68821cbde4230437dcdfc5ff94dbd172cded0bc5340fccb68fea6c9f8ddb1b935b86dca712d299cfb7007811531a0fa7bb3db377ba5e138d25502c26f0d968a3a0ceaf3c1e02927e0a2075a670b9cfed13a05378c6cc051cb045a33bbb3b9af437534b984f96db550da3eb8d66375a3451faa80ca1dd0590346d12b2ee924847a9511600bbcb81dd01556171c7ae4d3d7641a3aabd56b5f80ea8c5f31c6027e49efa00ee29183d55a25413df243c18e3563e8e27e05e8f8ab1dd7fbddc81b784a777c18b362d8d4ad8a7f555c1652e8216f6ad00a33b9f0b8380ce50d964da43b6468ddad9534617fbcb7790f3b0b47a744200324f472ff222e65ea77419bd5a4261f22a625bac2a283e57e50c6a8c38fdf4312ed64d7145ebae0ce059d87b0d95bb216cb6356c0eb9441f5d4eadfeccc29acf2c1b773307e2df84d3da6b2ef0f34b8b265adf6326b30a9ace8943252b5ccbc44d81bee23d65c28c5901e1d9f290b9c0cd30b49d2a6706016d17a101189eff6288ddf18270f3bd0cec28d3934bbd0308b5769bd0ad044bd5685d523ef521f0655b1e057945758df0cd36edc0a665a543976d0619e71ca8c91fb80d1f3beee0808840b9c67de075dc6deb414a560b89e93815e6eb79b358b45dc8ed473bc5d4dcb6acb07db926afb34bcc9c50b9a986c488584f39ee7937e51414401746e03d2753003882f2a6d703fe6070cdf2d8e5389dee68be769b95202bd15336513a772b7bb84038d79c163e6d4963b6ad22bbce3637871a5b770cb3c3d0e14401fa9c69d15303cc122c3456a48f17aa365728ac08e9358066947df6ee621f9a460b797774aa2e360ef8b0ae237a00fdc6d9bac140ede54ae7d9e2ef1440a1567d86c8bd5cc5fe88d9b93bd600f8fff669e76dab4a4982e5830fb92c5d2c0a844ead3bb2e14173da9f798e8ddb06309289fca1ebb4b367864343518efd960b1ab0303c4890c8fff5315ebedb4e3242b96c44b5d995afc1bd0c50efa4c35f4ffb9c2a1e382af112540462324aa0dbff24ed3b6f2a12eeb4f34af54031bb78e8499a86c861dd05ceec07e022a20461e53d8d0b36a9d3b52940243dd0dfa74a8d1416f08e72806e88db59bfed915d9219a2ca19b9c7386aeb61120b8e5da0ea022b91d8d39b303fcb1c9a13a4fc5ef02b5cc0e0a93fdbe293540b5dc08ae53e8878572cc62787fd227aa12b7d54cd0177a4cbb344a594e0c75e4bf95c22e1616e0f68b39a48fecc3aeba3b7f6fceb48cc996d8ac67d7777e4ace38356f42248f3d0b4c1b241f590d1823c1e103db0c0db628b6f632a010c2bd3a7b9490e3078ace3819d9eff61f261318e82e5cd4ae6af691fd1e3b69f630f6c2c672db83848900352c5985075da0fa14f28ef462834ec59eb12a4aec8d3c745dcaca07efd88a93f6fdd035b91c9bc6b55f6101eca0b852bedfb8ad0d755296014c3d5655575a01590a37a05c6040534d5dc4c1b1553bf882b349497cffa9b7313831f725b1347f1057f1875a1833ee04196586829a582a58d68fd264eb81e34e468fbcfa68743b65019c721a47a41d62d778fb7f5b32fd11bf70d3f545371fb487ee1628503d11798ffbe11a35994a3ec9f0d2317241d24e9e721da66a9d48980f164e8e5eed3e82fc2db2654f5ef866a1f2045c3130a3082d38a1d15ce7b8eb6012206940f480eb6a6104ed7c011dea6e2f9a791b951517a232f4db2b773784b292bb85835e32361eca92ffa710965b55dc00b509a164263228ce5c49eba4bb4887a7966aa8f4adb2aac25dc207ca0ac5deabd67094fdd19c9555fdaeb32d7a51747335b6e1d4dd80b37706b541fc0c0dc6e55afc26b4ecaa22f3b3524ab8d1be211b387ff74a05769dde1b588c1bd51a791dc0a678f8c055c983c2f26380bb0b59bfd32258fcd43d0150d92c74edbf26852947ef4347984b5a8e608b3fb908beb1a680c690de02a8d37c4a7018410ff4f77eadc793c53a7f6e3d8b54a64b4357a3441d92bb045c72ea24d8183123177b178a36778f5c04d07ed74ea087cffbda23fd97325ad316ac8ef1f4a3eabaf78166e0ef4d54a10c51a8da0f17c43f01b60cc22ac0dd8233b0b4c0c3902d389e42045370d16a8f5ac6c76417aa40465f4a0f60d7d7ff9361fd42a2c6c6785625942ba7286ca0c2b8a9654c971d34712f9aa08e81750b63c611b9efc8961de53308a153559a834247c41fc782791cf2a859352a92338e920f836fc0a5eefe64734513277c5f19cf92ae53a15f7cb78ac79912afc56418828be9c33b36956057dec091b759f1aad77d873452f5886afbea7a2030818e04f81802a4aac1d41ada6e40e619c2a69bf8ced869099d185970bf99a2136b7a3716342488f96237d4f07825b0bc291576a810ef408cc90845ca1662af045c5a65f9f4ec001b869d5fffdd8a4a1889729b276fee7fe546208b9f45db8dc654b4097b5ed5100ade55efdd9ee3a2de24f33810202aae033ffea58cb54471154c83f703777491d6562ea9b8e983964bee8afcd3f6c023f494246a9f02b84f78b960c23215a5228cd28d5c5488998e4f1ed214fe9f371ecae6ddc8e019d1644d55c16a5c4005876f3e172660158f6af327b34a2c1f4a8852d7cb9e0a1850e5d732048ce83c1965d8fe4d5d4edcdcaccadf5a4eb1c64b621f6564fa37d90fda4447f7d149b3fae1e463b37a34b70f3ed9af4e14f7717a4790ff73be8a601221b2cb1e9821fa08dad81512a0a6c13fbe64c917025aed98fa978774785ccced4efd24edd58108b23b74b064c18c9a554e02494b1f4805bf00a1a55dbc028db1b376ae20b49acaf2bef9c0de17194211a2f5a538709011a0d77dac2aeef1ecb20e6e5060423675fc9765b596218b1a198ea1c5fb7064439344cab816172e18e35d9a96879b911b31e8823dea53858c79f094aca942f4d0c2f859e9dc966722f12d436d3c2c15fe4172d9b8c9288f70802ce92064163dc4e450e31ecd7871360e5c4248a8e22392f2b465ea2a1ddcea53cbccceb3ce2610450c3b4b9b0a8f890d50ded49d2613a334409a0752deed6bfbd70a70e335d783615b4c81f5f06a57082829513ccc12b86d2998361fe2bb17815571cb80f0eebe8828ac859c59d62fb4709cfc40bf4c4eaa99389513126f33a302bc1c73d758bb24543b33cdb301ace674c4439bd048136c1c46238918b90978e07326392145780cbf988e0df81d7d433583ffe89720dd3da5da344ea7f97149b383017c67b3e703c929e2c6c8b8a05c13a9360e097fe5df2dba29bceee1c1e1b5c84e8281013787f283c906f7eabbeef010b9e3d12f8019239d371bc4eeb8f4dcade6c14bc8cf89da048dd6dd9adb4d101ff4d5acd04683ef5a2c55ba65bb8e35f7eb0d097d48cdb6106d8c4a249de52ef6a210a6224cc546cf92aa32fa5f142bd18a885703e0d5ff6266d917a7c3856ef9e7f08e99960e9277c7ea395cfb1ee8699d0329b29850a362672c16000010beb926f186261c85f2bb718a1f262be2784cec9bae2e4fdc3c8e21a5933bd778271f21856d969d015b0e2667db3e3b309fa13a5b6cbaa5b93b7351db8d3d98a36d79a4dd87f7d84091544257e7cb129cd49c46e71eb54ba5db02e72f2b7c7a7748ca96cfc849e12b6ad8f6d0755b7fd107a9e7319036adc303e32372ae139a8dd930363b46a40c49a7dc0d08a0afafde5a597ba120ce99b11395e492717c26db9a7419dfdb69be36372706e0b6da0f4e87a50212872fc115a1991881fd2c6063a47ffc934c0373fefdf193ee8a4fa2179998278c9607c23ccd3bcec4ef3f4a179accb05e2cd0d39ccb001f11201494898e60cc1fc54dd8ddceca5133e0c97a2961b091a9d6b4cd405854e66e0d1bfc9d721a65040d30ec96aeaf7aca4e69db87ee1f10d49bb1259c6c801f87aec86881afc7af89c375f4ae791cb13405138953c35677e5e6bb7350373ccf22ed135ef7007c90a9928a3fa8b0f8d3612911da2d7bdea030c9ee1872f0481ec5bf23114f2b51c8992bfa9d99772b8f630494c51cb6bf330fb1aee54c3a9c14942c4667c531306d2efbe81ca5403dec224095dc4fc32ad437bf884852866eb946770e36576cc1979ddcb344dfa2e3ecd4308de486ddc5492140afdea6fcc9f2b2a58c64c3c78a68d03c5eaf57b4c1f2326f94f97f383451ce757a92a129ec0f18af3f476015da437a3a3b1950890cc4632da73ff5ca4742f19a4b004851dadae5d589cad902e29040809fcbf4686779397d09863bee98c50ec38229699c96232a9e780959c2ce8333f7ca0d03a8741afb755d402ac36ec345752edf38a228a793e0a46ef35be3d8c22fe2f284eb6d330a53bd1d36979586f46110f0710619f68d1f175a0d4ac16476e0b8f209df13ac9a347528d2e99ed247d78f72b5e6d52287a5c3923ac757f47dc3a855e5460c013e0d7ef8dbea19a77c16f4a6f8b1b60b2ebd71bae51494b973795d98a3656baf31bf75f3bc54706dc77f911cc611f738f79ae6989aefb35de57ff4b6ce750c004eb5e98555015a06b984447520099b8b0e9b7515af7466a5d171e578d278c8667cf2b319aa8658259c5935e40057569ddd9a47126423666bb906afaf09cfd3368b83661597b1e556c189f2e70ccaaec8cd20201999a93a5409dbbda78e9f2d8016a9b8d8e9d7c0509720257a920e93473a845aa419f7c7db2b29c5029afa5daf859604d06ab5ef891afdb94f46929d444542e00303ae18e31aa7add91292d35c4b0ff5227aa968d0080a028d738eee14e6fa1420bf6caa50788d0abaeef7ae06fb126703bcdf4d0b00ef49b7264a6db50ead75f296a6b254c1efecf9c89ded3727204593255e58706c7e34bb45deb3dd8a958886eba189e8288b53e6d19cd61251eb18cb7500ba1562a3778f2ddfe44afa9e029582a5d5ca5154b89a8d07358c0902366d0b5cd8990a019b9e41c70a62dee4ad91f8f20188b51277879a2188694e2e79fc1fc2ec84a6ceb1ad8f1116c272a3de85da59ee5385200f399239dfc3f82bd48d48c62ec6029e42d4e0cbecff58f431fee94555e2320ed15cdd10863499b7eef98627d96788c24449c7785e4b0455ad98dc74299ecd1e60d052a8c5a32cbf206e7f47cbff5625afc7f818c15e8615bf3c5815ccf729eefab2b2df456f6483eaee77dcc47f952f478ec8952f857133c22ca1bd8621e4ae76db3595d516ae1c20b3e9f5f9a78d5f860e391289ce9f66ce12b5d3194995d0ca5c1ea415b61fee5aeb1f2a0978061ede139317f4faecbcb04c5e03d790b2b53505d9f13d95fee470211bf3196723e5d36eef62a6cca4ca5ef125f601d6f948c24da7c3b59e5093a75b639969119c5dc422cf77f0731571d1970898d7f1727287da8ab15400ad304b48afb568ef9752c79e210827e8d09a49f0b9a842676edd641b42e4704c310a557d96f9a2a6f9e662ac19f7e03945c5b012624fc8de6d77cc0bf99c80c694b34a2ee34a73d95a7d24ff6a4530270caa0ec591cf19d0831d519ee64c59f1d20435a375f6e90d0669802a9fa23b2aea443e07410b8c17f42f7d86473534560136126cbf9f0a28cdb0d1ab8476f75202c5f4506e4d610fb91e575de9dd2d08c518d5568d191ed69deb9bd626bbae48dd17d13f893aa1199b604744760bbd7d6b0c8340361fbbde4779ee6c137242c85a3876988fbbd59a6e4551e54c3275e7b5bcbd48e05d349a897efdeafe64869cdc00c03cd62f84f1d105b50c5aa6ab46973295a84b63eed7191db210586db42c152c507d76f77a11ff6428e0fbfa6df8b176b29a375aa8a77e444250c8d5991610f5708348a7128690b05b3930e4afcac1a24d8fda38e288fb62a014ccec760be7c70de6693302c79bda1de11cecbbf164dd3f9e942b75700c8187fa19530611366a91b8ce5d8c59bb29c39f86a9a81fbd7506e2b0cce5a92ade1b6091614471564d8c64ac26089aca6655dca6d46a31498cb8718ba39950c98c274833445078762c674e93063a6363500a1b53fd6d684ddb32013daed806cdece488401bb3d4739eb016ab01957df00177a8fbb56fb0326dcb97cc06f50e8e87855e3bef91d70610098f365279a622e1488beaa933074f0265711de0e07b1d1098486ff54eeb002883f5a90e041c66f9aa05f203444d5bc2e5b71b440ae09aa27a116335c2abe08f3279e7dda2069624c4e8f9eb06d0c83ccc88a2dcf824a311ee39853359d28213072f8851c05e37ca054e04095e8846e33c53ebdcd8e427aee44a6a00c9bf6c040d63986ab508096034e40d49d1bc5168b5a65be1751739fa821024ea2f85abf65993274f2a99e09a5e67b90f6b2b3b971c062751195e276ba7a103d82e3020a8b3253ff76218b9b44f5ce632875ab4e53c29aad59fa367fc57e9f17b066b30c1a11dc80b8f98f31d03b2fe0b5d7e3ee4935968a95609768bef3efe8168066968a9d8747a8862f4570250123029a99aea0ba70452c4f3058cb584d06adfe4581a23afe4b7aee285779aaff00b8cf57e83c95d90bfcbeddd15b782631bf7f2f00e169797f93f3ef9847e7b6dde3db8a97417fcadd8c0fbd014cfb129b1761f3a360b2e4effbd71b36e9b5562ff2f7e0f8e1ad2e07fd832d5b72a80fc3a12cfc87a7531fb2bc7cb876da43f97b0fa52075085dfb0d4e05d9a1f3d15d3075ea44305f2c875af41c5e437108131a3fd444629aa161e133ba96d134542f9d28605457961ee14128091729b3ff451636c15617e0bad229d183d16cf02714163a35ce4ab67026c08324957a55b2d059a3d3f1e45288423d9c28c37a60ba7b9640928f13d4bbc7fee141ffdb155360485b1a0c8123d6ea7615584e965f72d094e5926e4dd55680b2e8bcb1057be0a0ade75fb8349a15400f0631320f4097891299ca2d240fc738af4c4a94ca08db5576ba6e7a847c0fdae254ef5b1db7db1c576e70dce333264e1a33591797ac60825c6df09c7df6e6a1b84c25d095836fd65f57fa7eb6b3876c22bcee26f80f782d781480409714649b753c3f7294007ce42e4b23de74f416eb93ae8a8eebb30d83d2e994ca3f1b911db7f10b55a51054017f6715ff7d5609fddb23a4c4cd88836174d26e0c5b60e4f2d30d78bc2e299a3276aaa203cae32c5fbe66c77ac7d91e68e6f8c8ed81361e2aa82efc36cf4fbd7f8e2eb818456ea08859430b2e0e6032daab7b5c02581e1051572f51665483491aa804d2602e97ee5b67e069702f788574227050be8425245833eb4b606520698309b8b527dc83f118f42289d48358b8e2060829fd856d0071a2f626ef0562719bdb3e7f2ccc59e41a558c4688d686ace305814ac02102ad3de562c59a316e1fb4d07137d5feb4f16a57a0f1137680e9a9961904e32b75c02bf88dc98f1de5e38d96a8ef13ad0e258ebe702e4eb897f28ea16d44c95711bd35d6f4018e7bf015b90e46f7e56f7d39490b9f7805523542724a8d6023091384aea8584659dd95e739a7e5aef15e1332be204a48dfc84977a73a805c757afdab29e3116157b98a76fa95cf1072cfe2bf31a4bb4cc7d05f19bf6afbc675612b6a66023c99f84a4c7508537d7c7752a4c87af6734e09bd05c7d96ec068b9b0b171cd89a2ab4cc474341725773c80156bc2c65171f4c4e7e502242411bfb9c98402ecd179bebd41f43182909e392ae09e36973fa74e3fd5e2df46d85eb550f2f35b6a80dc165f326b04b9dd99d33b1fecc0c09cc2db70445b3dd8b069bcc3c80370a1eda2b801211d6cf35626d56fc0c1faa6b1a665c02d2e2d1ec1ac6ce70cd8737c0d96b0ca8b0da27b4d861dfbc259c7486cb6c3afae3560a924f7a4a3d53c63cc32c6a0e94727b37af39cb51e2a13f864921415c350572f1c16da9a27580401375b0937f13138d7a8ce945d0b241d70cf9746af755ad69d0ce5bf84ec7a8383d207a86ace5cf235d9acbd79cf66dcc147228dedb1aa9eaa8b11aea98b495520742220276cd3e295cd7f3fe5ef9d0d98f3b614dfa5d2c0246574f8f32126f28ab78357bba5986ee8d1c721774f7abd5d718db24de7064c176893a10eaf31220a5e3046e02907839e4cf8949e237029271d8dcb6d0707738549a8b18bc31247c17c3297329cbdcaa6a99b953ba9c613cd15906f6c8d45ac02ef90844e0943b00231ef0fd6e4659fbc4180201aae3abcd5035843b4bf20115f424803be1bc5bdab439d2db101db8ed8fbf16aafc4041286e80b4f4c321c933f6c2d1fdb9de87173c1bc04caf789148ed31d1265681aea07175fb5fde75b6d87bbf4a543d2962418c75891b928f8ad67e10100c3cdc2d8aea014c5baea9a0242988173873376eb8fe2f4213f82f7c3f0a48329d69f7ff34cbc2944846bff15d8e7b64360b21f26c8be3b7c980faac29a63d4d68f1aa02bf570a547d6cfb61ea7d4c94242e3c97c1139785571175f9f85a6bd5ae654b4b9253fc9f6c61bfb21ae29800dd4771ae7456f785b1e29c422d3c0a9846ccbd7cfc69dcc0cbe946c276bd16cedad93e6b03a96e84a16a13f7b0a47ae2b445c81aa851f9f344e36e48d29cf86e282b288d78d94b8cbed22b834162ca7dda9700aab5f68641b967517b5b85dc3fe29d59254e57d01919268816b46273eb6cda14adccbcffd19ee3f8092ea4d54a868bd994bf06efa1dc9de762f1413cbbac2266865c67efe65cba1db0420fbf2104ceb3d5b18c474e038556a7bf1a5a6785fec6bc834a809e969aabb6273d0da7c1bc32faed286c4f20f026299ca66db9e0b0fc451434c8d7ad275a078a9643e6e9792efd2631d9249985fd42c3a675052dc97aa3392a3b074992df364951ed5319369155725c4dd23b0a8edf566cc0c104902d52d99b8afef08ce5188163327029b9dafcc3a3711d66e179b8198f57233594e775c582875ee14938d54697ccaf659619509f0684965e23b6d885ec42ec8cf2cbd6721a70d93d9115ad2a296b312be7b1157db6d1460a2de1a4516e0aecab8493a8d305a3d39a6beba53bf5e97e583d6106ef9a3fbc1f58710bd7f9284b31042479ff0328350b46501a9d3285bbe35d7f941634e897f2e20aac8e48def82fe7d786687a03e7e6334640b4bceba84301896410a0a3a91b593102848c479e4afea1143d3b424bda408d231b1b52afa90a37ccf7d55eba0afe121cc8b4b12dba8849a5bd86c1459cdf4a037400007928c7072c72cc55342d45da5c34a045da723d969caddfbd334f0e1fc78caab011b3eab6a4726f24ed53368881d18e824f9f775434c43a5f47f3388a621e3a3cad68413d0f41617245895c6e3c897835d9e83406b20cd6b88c6ad3a07399dae2dcd106c574d47663d299798de6d0466fa835792d2912619ff548040b477493229498382c438525821537502e24e39c59f188c0dc360199ba79c836f8312564d5f11b2d0b55437505ee21d05e94490cbcc744be596ccd036b64e540eadf9bd93ac610fc6f96be2a76bf648a193826b54ed8e1759031d2fdee871f2aef07800ceb9064b2bac5ba51cf77cb6d6adff3570d8968d7c2c9a8b2a997388ce15fa46ec24af38a222c46dccc3bef6ab1ce82d8bb94059c2db178c8209618411e0bf741934ff62b4a085b017e0a53d2ff608c2d282988a8f6f121b4be0b5ca8df4f48162d3872c09624ef87bca7857745aa11e3d8536e33011c35601420ab6364dccc728f821cee296ad02c273548f75c166ade2dd67b9b05f45afae306df65f511948e3b9632cc0239b0596267831c5345937f87480dd64a8fca2db58f7d1bcea9cf8d0cdf2093d93e60a73b9e930072024fd2222fb752e86665540bfcdfdaeaffc9ed1aec840bab64272e39da84f1a68d56793665506835b271a25704054dc039d0c062f95d7d594c76eeb514d2a03cf83aff106a7436fd9c8767f099d9463e7be2802832740df55eaffa0fddc504659ecf653706f6d44560551e2ff8b0ed0b695a914166d7bb62884ac36dfd1859ee417838227a5de0c421b65f7aa1619103f8ef2ead8f5a43563430abca9e485472394b2a6c020cda5324b110cc7e8b2c9e7400c55640225fdee676b9f3d4afc104260cd6a224f1dda87b5300900063e526effbfbd5f0410f2531ee8e370d124a3fd26d446c94cee7fe68e991484337c24b693d6dc53dad31ebbbf31449e1c8a2b200fa91620265feccf346b45afa849882fc0660eb36336b1503a160a23fe998e97de31b38473e33cdb86adf32e96fe064123d43fc71e79fedc4744345f17b3ace6be4e2c02f75eecf902fc00e6bb3ad496f6ed4e4a1bd15f30b2a6619f60a03e412a2ad2a12843a007263b54e636134eb6bd0a3fce6c63dbfb098a9923cd26002ad038c68a409cecd83c4675b7fe56e541eb13c78cd732036b150973b3ed3f5537deed16ae80400956973623ff6cf55d86f2dcb7623e3d8d5cf0aed9389bbbf23ba40c0b73573e7b9dc86b6ef9b3ba9057fab509024fce5038bc58a39d1fb31d3358a3dc1d10ef3de703e340ac944c951c0ad1f9164e4ef16220c819d00773491ccd0d15d9c06b8a548bf1c791c7dcb993be3714e2b5501feddc2d1187283ef15c6354a261430993efec00f8773c0c218d056529a0e4ded97d1fde67bba3989c173f222a1c36eb3c498c4e2e9a793d1f2f2d00cb9cac0b80e41bafa5e2674776fe69727f743c4adb51bceb5f38a90f6436057011f414c450133b8dc3b3ae394366baa64401234f095ba140f405e5ee60e82eba53803bf7d6a3d67831f78f8a484db448f4e2cf26c069162449fd2501618d5bc31839472ef2df7e20a50e2a9ff938cccd689b27a4d20174adf46b50782f1464693361e5d3064b7f86218cb893119f16e193df3393f603111194f192ac076eac93b0716f3d6b105773516ff185addef254e3b253b5895e8a237fc902bc0fa17c33d08a7120697f9a0a06110cc10cd9bd507b295086b9c2b7a64ae7eb38c9a017e585b8867d4ceb39692ad4e2597066e3bcf5e38519957bd40f0455de9b0fb62e17d331a3a84e953cff8c460199eea3120767e158b591e724059d87253c34367d14db62c23e3c9d36cc04f523c380d23bc0abed6b7d988408ca1f3b05785ae64a4e647b4300a4fa07cbe841d5ca2cf85d8a7ffe83ec8b9b3dc0d2fe91592a61ac6023f04354ec448a46f015e759b43c9b0b175a83a712311177a5c2c89f456c276e801e561302a0ea8728b06453474ef866454d61f86420635c39acdae6407b008682aef8f5790b6d215cef668ffbd57f6ddb6cd90d3b3e95fe3b87bdf625c33fcb083cb05e22345c041acb8a22ee4b0b348c612358f1bbeeba27396cfdf46b91216d50f2d3a2237114afb2b7b64f1009fc80ac024212d51bca19f13a904e21d825051b58b531dc8d7a4dd6320ed4264468bf0ef07ca4a661be1eed608602855f7fc310dae38eac520a8ed48a264f0bd07c3bccab556018406286cfe96f063a7eb807419a32eae40b14ecbdd3adc1145ea8c5ed42dee62ae19ee614dc6249ae599666b2b5b3facdfd9fd731ce1a553ba0ae5e875a1462e0be0819254fb8537b2e92a744b9c5393c99364ec37460ebf1655a2e362034e8c6d77f37d308c70357714c4ecd33b10c623c3f08394da2e5ea9f72a90eb72da45ce7914c187aabf521d84acb25a0cfe34e9e892350a83f716e0cb2c92d8ce76950cbcc191b38b2eff7134ff8269d7d63033c704b60eb20caba34f5b4436a198d0962a59bad2e1f3f2e196a075f9c4f725b050bff41932651509831f4f4a27af99220ffce536d871e1ce21a976f06d10d6010dbe7ecec831f5f1bd084f68176a16e47de12b52f98b7e7471681c6ca326fed8875f4aa451061594790a0f3cee6cccf9c00891940ea0f6cca93796df0b8c42a8c171b060938ba08ae74b6d1c119a3a300257beab164c7095ccac717a01265f4ede61918afe3a341121b8c5caa8fee6fb8921d21dab1148c4779b4990b108aa50638987cc28cfce69d8d700a0ecc34ffb85214ee156fb789b496d1f985c364c794f98dcd80db862cdca0ce8623ce3ca139b557f3c63bf244da6147688b1162926de50a0a49cb9459afc4399e62d88762d7751219d43e6f25b2b271cee857315d84e438d0bb8dd0d657f0c9b8888e016cefcfc87f12d3027c663d05fc9210e0d501c5e3517483438e64daa391c35937cd6fc139b32f74a72cc5028d563b4a8b668e517fcf9fb75a1a056dfdb93139f4451f9dcf0bc8d10c31943366c2c5c2d334b9f9adfffbff429dccef919467f8888d8a8cb6b4a28181ec24ade1b333fc701c0f7c38c74f095568f278bd999fbe17cc1e55117eacc35e689c9095b69e81118bc3c63cf7f43645de90afcb050cefcfd82ac0f3f61b11c1734a7f9cfdbeceb9d2cdf5116e02de0e85d282a9eab7692788672eb5b1364d8b2c5d67bf25599fc5b6fad95818bd7b96cc297926b3ebbbdcb1247288d704433032fa70bc78e33d0b50f66176555a0cc1c24220382bcea624e8b92bb79da9d772ee331723bd516ec1b3b5eaa5f058d863d2dc9cecb8b245cb2dc0266004f42d97c9a54d7f5b27f1f29deb36545a0996c43aff0fa4b5b103e1380883980a9bcfba56400757b6f1412b74a22275868e1a61316e9426848b1b350543e441a344f6270dbfafc34c97adb0b21832c61cf253eb4376d8408289d34669337f57acceac69134609dffa809bcd4f3c42aaa8e8994809e692722ac64e0752eef91781b5d8f1a2067f70b40c4bf5a13876b799d100b799ae842a9f66341532c5007b8de602a77199215bf6b8f1ade9898710883571e3b3e1c053feb75ad707e5205c81e1b7559ce36476fa0f49ba5ee22657b9d1e9c58a09c0c4b1bac4f5a0d6cc7c5a7277b5466e43441a01a1c8d670df60605b5798b8bd2233a8b743135b291488a1b9ee122c576fb5ea4d36a4e26db974ad14f0882c5aee7e23dd658e09038937e7b20f9d8a1b4ee8dc5400fda7747ce807350eff801e24827346fa5d08c19d109d6a2f51f48b01fa2e64fba65e4aaaebc52af60bf224d4d591ec3755c1ee301358e68d8c0bb086ae18445f916ad31c209e9f94710e94730bdcdbf3b8197b6f1f7153f4d8aec30dc1bfdd19f784ce767f6e8f5ddb41b9b920d8d058a6f20efc5a461d1f74529c57e29a7b4efe55206eefef230ba3cfe4b49dbcef72f4075496893ac97fa09a3570869f017ec653637d1fdeecf41e80a66cbcde8543c8d0e3a9ceb17ae01aafaa74f5e964f16028e178a98533d5e5c5ce0335fcfb21097a719fa38b6f3cfa8cd2ef7513007a3edd5bdb0c79d3e2166a1f0c43cf0ff7488064248cfe937d1b6e48507c1330ab04d2fdc88c55ed50788270abe3628d61d7f5e82d2b80bcf1387e337e88afd85f690410c13cfba9a3c2e11aa3a31d9f17a19d3e8623f76c49a77e41cafac1378c7ee02396659a9bb42e2348454865523bcc056b947cafc7bec6f303d7889411db8da175705fc489e25a928ede435515bbade1471c7a61c4cdef14e38655828a3f999011dbbcfd90140654f2de8df682769e140840b996dd8a4298ef2d6a098a6c08a406347a4643a04259f03d48e562fe95b8fa529d0cea7a8694675c9d132a5c0f93899f33026808b52119cd48437f818f04858c015f971dea93b0d2923a2f77c7cffe3803daab77fcec9da39d920f1b4e78214509a4a904247ea72afaa2c8374be975679bd1e094b895054db1f8f44bc306636c9edcc4a276ca009220920f675a434ac61dc157e100494570a86c240653fbabf8e1f06b59f56078cc36b8bb8994a1e35e9dd3f42a2eb70e302ff058f289810305497f7286d632e96710a9d2c0cbcbfdb3394885d6f64391bb817c0fcbdac085cb6f0d866712e89e20c57d909a4478760f6ddedca11180593ea096f76de9e7b1dae709eb857395a5b1b07c7f82a248095f03f96c9cb1397c41711b24f253f2408b965449f29fffdb311a419ac42500523b32771d1556b008cb4fe9af2052a2fcee2f16c4588c815dfc6e744af754bfcf21baa1425f18695fbeb59b10a6506e90c7ddd9719b3de0e1d179ff1cf036a26bbe4d24568c122a2d0983e4ecd2f0c65595ef2296a41905923a36d27f9a51409fd9a9f76117c0d33c0180da7c8c030a1c3b2da3570ff2aebe8c90c9d68318b6c141205f39393d4e42f3e07b1674750c833e1cb1e7a4a4ca53b5abb6e7eef1ba83a96a0c1b9ae97331eeda10c4db8b60086e0238fdf26aca3142f748ed3a55b04f2497a3f7a7e09a1f393ac15e746eefa917222dee820a99af6a66e29f8a5940a98ce5d7fbac856d8cd1f39685b241b3a35541422ffe1ac784794e595cb1440ac4e25a33d118dd7cdff4494e91b9e32b6acd83ae63067587d69632ef01d0a0c3df52a1947b8d222fec0ae514a81d79bec893b91f0a86e91faf9427b01399906815591eada5cc320efd7b085bf00420973d8469037a7139affa77ab5ee5921d03d0d23d8c93e83f385a81bb75e9f3829713e05b486f4e61bf8ae0341ddb259dc0dfe2057db65795857d9350f26d60ff6573317372bb9c9768cc14f6d3051b64394c63625d1b316499694a87576aa14c913e5337c3e63ac6f1de0cba459d0291b897555b5a0818f532239dcc8a2a572c85a814e89fdad71b484a517cefe06e1d3a5c591af3a0af96111b8923674ccb4fa1edfdcb95d89c0000d8d728da01f6a6b9efc4152926001b621221cd484ced33a56194b69343941a6d046a65d14029a5b68f69b32bd440d55193c66c1561392f67944c34841c640476d24afa12cab25ca781b184b8077e2ee17155ea1aa06c117d171051dc5b217a1677d90f09055cbbbb306d860f8a830c796f5a10cc7e65ce0f76f509d193e700eee1d96ff1856192394f9aad584fd90087b42bc14c2a63ba318b2d6cf48011f17ad844f2d66e17b307820f445f956c5067860b1a984de23a26664464aec6797640537cf1e67e36f9e9be845fb11f209a40428897971f73e93d2876935ea8054f2c27f530383c2fecbf96533f26a444b03d94cfca2c469be928ace6cc7446494c008e5392a7bece2722ee70c24fa79ffc3e129f5c07536e0cf50a8ea08cafeea52f1177f934417824d06d1a521284bab53beb8b2e5b38897e71f79beedddf461c931c28fcdce4065ddb80179d8629cbebc6af1fd8f11884a008eb3e9924366059f32030c620b882332fd690dcb5b9b8cdd36d53a5cfac8cea2f8e15475975cb43ccfdd53cbb0341b331421dd441d66654088ce4fbb97ee40bb0f5dd58880001fb70be859a25922acc43e7ef1466f3810cb49d92e34c92268a26d65fa388a7db545a909c449ae1bdc608c965f0284260cb556582c9f74f3fd8031df784333348fb5da25bcf0ed34ad76eae4cf5975aaf14339e081cc16d7f7b43243749b51b6041947bac6e86a892c8a80b589f7f23f4fdefcdcf46312d75236a012a562146566f6a499d0bb64bad2ce2194a8ab7406fe98fe71e13c43ad46a5ba7dd7bdce8b8a010eb4721c3b20b84100683f5c466da5f09e57613ea09a2704c22fde50d400be4640a2f7d95e0ca6e5661f1de8f1e800b0f8a39a13e56215d1900bfdf64ab6fb1e8d63c997422c33042c413a07fd0dbb1636e8f842a29c50aa9a611715a7b29ce3c0e29f0b08a172b815bfa6ed3211e8223bb89255d1c31dfbaf4d3456810353d5a31f1990820f937ac4b48ed1632f5e3b42c4070af000cb7aea152d260d8fd000ccbf809de59bfb563470cd8c8ee2257c6e4eb3cc3dd75ced314ab7c9d594792119f73df134d2ef1e420e4327ebf6f1b88699b274390303da7b2e5dfaad9600856fb7c0e9dae0ee79a5a337b8e81627518f570e3afe1cb3af1b125bc5383cc311b690c4a1aedbe9b47015575e664a70afa4e69cf8ca0fbb6671505c2a64bcef7457b8792295d51bd11ce66c1fb64527123c3ed48ef244605746831b748e4ba9d79844da38e33b092db35d191de6d4fde0890490739e6a6e9850dae2dedd7514e8a8e664780e2b80ce820f03f4e3a78339a406b6c818386f5d9b957fb084b600df719b199de4f0455da8f1a8bdd79739ba007a4714b12aef8fdfbe256d3c00e0d45d7a4b3d224d39170040fa7ba16f9e7197c8ff8067248fe33edc9c660e22c7d24ebe727b21031f4fad21cbd3e104051bae85013f8b9a77b70a906b0e9c6a230cdb9e23b34c3a430dff747d37c3d659f93c07fc5777eec49b44c66c5ad87cabf28ade173dd5ef3ee879a0505f04b85609be5bd1d59cf6e0a702234709d74e3b235300b6f0564160718c7cf4abf8536fad3b25d41004d60a22a644797bb0d22af8b0384746735b6196901071fddba3faa0188b6dd46742d94f850d6cdef2201b928f3979991e24e8e4bef5eae323b830c1d37ee5a69c6936a32e45df7af86432deefceb137928ff3d70b2fe2a495e46a4ca61603b533e14286a088bfbc23ecf73069badd2cebfc15bf026bc8b2882713d008d2590e7bf335c0a245fdd5d97f0255ddae8be431714ae3519a5d05161a546eda83b68f29afeda455eee73a5bd00bd581327e797a05f57ee1282d490a38a08410c28fa5cc0d9098ba8ce6099c414359c755c49196e9ff4407ced3cf1fd0b6c44958303ccf39f38992c44e57dee388f184ae121a8ede1842c2f0d0a29c94f29e898d7fecea205419bbd9d5f8802a2dbeef2a12a9c2888f405a71fd59d29f6ef66b9ea26055dcd953ddd59dc9d3624745d56a6ea3b5e22dce9514a1f9941458550612dd073c8e4e9f341cfac168ad2c81ba4c33e4764714ff23930700c024b15cb9e85253d457e373d4b7b7d200aedca37c6e90e9c05f4e2c541d167fb63fb72459b36809bd6f3a74bce6ee66a80773171aeed2649e0725ef790df568934c4ab6c344680374f92bc31a0494d532a397baa1ac6ef41b98f4ebc1e629a2cc9715126fcd19982faf2d035be287cc33ef250ce9f4cf4ab9928137a9f2ec745271984b5cad7a45c228840877fead42d96dfe8d0ea92bba713adf44ffae7389004c65a870d569d9c7b95a86a35e31db87c775ba4599f331782a10423a34f60838830bc7f595c224398faff2fc09d418679d841e6ff0354dadad70b5628f16aed15fd089cc5c060d3db13d907488e556dfa91c798525ce3f54b005979d2d501ca8506bcc7715de36dc37300963b6450efc0f6d059c49fdfcac181c47da7fea1a7f2c5132ae25f37987212d21bff164c1cafec6652159e1cd1bee1a43e0781f66b4b2cac0afe2e43f9993e23b85f3336e44af7764139c140849ead0ab678dc2047ea1a4e4836c0426a18a857a7197f38848651a76fd008be4acd303e242a8aafa7769d964dbc35abe57dfa88f6ded05505afd605c74d2dd76c5aa04a6bd8866b4294ac55dd2faca9f38e5f937ac699b995e42e0a1ffa05181fe41702e8b1127782f446561ab409bfa8ce8ce438380b0dd012088a063bbf453207c9fbedb1049a434b0f7feb642602d0dd641f4fbadd1ed81de6256f6479825b77a89fae95248ac6bca31c4d31a2f78561f19e7dc092d1743e8da4b859f0436e0b04103521e5cf572a3054d13ced24b7a4d257b510caae6ea240325ce8b2994c5f9150c2486fd26264edfdc146412285fdd48bdac975181a1bbb654a0d7381b734e0765e83f80ed1676855f8c4621b3c9ffb0f8a8516633ab1dc28565ab2596acf9930c39429c05cfe1263bd1e1c1603ceb54e626935e9daac6af4c555e700beab2e77a2d5966a730da88b534cc30dd4f35aec26d89ef2991a75f323133f3519f8d445dff80f04a8992dc4d6e075071cd2358d3f7ed5c4f7cf77cf567411ec0e025ff7d38c7e75ae747b9e3ceb7f7543d697340f49cfa3f1a49311637b9e267b16b9b3ab25df9346b3bc9f957f68e1c72d668ae17caea023eb39eaee279b261d87429e5b6cb15f94243c9b9e50965bee054653478446ceb1742418e56b6926a6241417976fec132d69c18409b13f10358c765b3e0e2c27a9e0dc3e2d4d24d24e689fdaca72601a09038ee9a2cd84e660d2cddc9a0f370096f28d9439e7487622067baf86a2583ee6c42e5889bc3e2c3b6d3758bae0bcbd9dcb85d2a6c499d6cdc06ec9f803e0c016bf8fcdccb20c8f0796b838d72122fef7c6777c2e59ac420df43ab2103f1da8e054d032b89416848cf14a7f9d978327dec49d99e003ea7a8955a317d06f53c59b99ba349963d93fdbe83c33ff5030b6d2df3def438ef1a5593cc5fe8b83c2d8b80f1a605c10ac801a87f363d5796be7536c0938c07d6f34b1d9983d5fac116306daef94c3bde83d9d027a04d60cb490d8efcd27f5652b95860af5a58f07b830ae970dedf0f674a493def4db9aa44597a71489148b4f2b5d63b75c3d2ff448b60b84902fb041d1cda03c91e2556e01338d8c32d8562ff926ec2d3a710c330386da68b50f7a1e7511f8c1b285492459f446168d734390524808ed149ec488495d84e537888ae657b771f43c1309c18724591bd6440ad4207cdd970b8e0e7d172de626593ec42b6d583c329c43e018d4388ec3fcf346c67e3c1b6cdc1888f209b2d5f778d9b89b242fda9f4abad24590b10f0fd20d1bfbf67996da8e899a900410a73efe08cf64b1c27b19a17b114a87a93c4fc56c084cd33e218469e319b0960415cd006fc4cd1c9acaabae10578fda6026aa29d699c469809fd65426eb578da4ab6597fb32114b7bf291b61bf80b094763b7707ea6c5864f55a9bbfd4846a239d3cae84aa1f6b2b14cadf8262b15e83920e28b7e77dd122a8f71bc71dabcbe83004a713174b48a3e242513acf47b140909d81a7f14c00f67b000a0602a7f1ef7aa6b82e9d71d15c4dc29cf0efaa6e4b79b2e9aea96f6f4471dbf9b1cb1d0933c691704e49816f5d1cf942ca37a5ca2bbf475ffb704e34aa8d3fec9e3de2a6fe289b2d9209cd0796d97063f44959e4b6c249493f63e30c8c8bafe69037e0f936b9873a900d08539d8ae21394363f1c99211350303c59329ff0667bda80b82ac43bddf7fb48c2e233d9fedd56d4cbb53c8c4a40115767ea5c3a873997cbc998a6f38b366aaa4c4d43d335dddec2435d4ac8974c65ecd1eccea1d78d27320c22b5592df1f616c26da48c6d5480bb827a157a667092e3cbfd2ae268b7576e5adcd54b812294555b17170138e555ffe2ffc1ba436015fa3dd9c83a620244da5275229fac5816d14ce1fa9e0ebb3b76fa517767c18422a7e602618968f0acc6bc25bf5d79fb314b79cf793e82106bbc04c6b9c6a9038700c968f1ae0d3504095ccd7e400a1419d84acaecbdbd26ef50c54b5b6e70f2c9c298184e6c7a8f4ff8a0ee8d1cc16e94cba37104b663ca544aebf132243b1937951242b6a55e3a022a4a635d2cb08b084da7d02b2975aab8da39148b94a90b3e12ed2cdf4989714c1aa3ae7f4c004b683133054be7d89d27316ad9f0112efb72d54a94024107242a5e85c90a2c0a8092427d76cee6bcfe86abadc14db5bbe2e83b5cfc0f3b602deb1750964eafacb7975463912eeb705212221b14dc427f2cb2c0118e6eba24088b62e39db1f65b12ef37fb76d08b2503c0048b2280885e493be4450fc4c799205c685e2c8a25c19912584eda520c8b073800f1662346c4736ac05c76536ffeb590fe14cc0ed0ae51c861f50b784d746dd2f9289892702cbd9505333d3b2542360d51a0b38be0d767af3406b5df8f7c8b9b0192472d915ca7bff78764010fa417ec1e6cdd9836eabfc443524ec927675983ff754416b3117832b945c5fb47dbc58457d4432314c352aff0e4d09d86de57f31dcdca1f1942a60aa836307cb32e39952d1663d80970d2556cdccb4ca0c2018862a9ca7faec2d172458ebe56f3bb8911a642c81cffbb793399273a39ffdcf2f07af69967a4d85340171b6f9fcf9d449716ac140c54d85d4baaf5d8c04760011360bee69391bb8d3823edf6c117e287327a017a36c98bb0ba8de9db40b863a980733e3695fb80d480444a0adf9a6aff7b96490fcb143fb24b585b2130c53ea207d7b1d7d4de6897afca6522a1993c6ceb25f7ec2edf4b32b28555d009f7d338b043e1d834de95de0ac37ae56b1aa58e3cf0973e88eb90014a7de78774f7ea1eaefef926a929f970af466addc84c5f2df96d8c3726084da17346a964d37311f90c7eee647fa895451c168b184119289023ddd7d77d4588310470a50f89ed5aecbe3b78a6f87483cfe9474b4fc116e4083bcd2c622cc6b9810fbe0768e5c42e037fd780c977efffec952270e26956d10d7e1189a1e6e938fa6b2d4e45a7181ce79c43a73de5d7b285c3a225b8adb2ea5d4a564f248670d6e995d4f7ea59a47fdb433b35d066107311f25fdb73c2cc5f45acd571ba5e5c68c2c8b13a06abcc9193f55f6b84c05bf218443a6d76c2f20e5a7e321d34f457ae26306a269f5386f0d96d97afbaf1e459ae88f69a2a957fa316c625599676f9e000d262fe8073699c6121812ec87a412c0e82eb71a5e0ee4e0a3c488b65ff0de8522a79e2239b998f90a76e4aace5fa2d81528517a46fc513f5691c86b806f2796f5ca49487559bf278384fc907c55e6614229f25095a02a48f0da36c8c064ca73eda97623ee897297a79282e2b0fab6d03195a704c5217e8e6b3496824948d42b3ad694930458b6fcfeef15917b3d9d9fdeb94ae6c4b44213ff139c723c0e55b780d2bc7a72d77362d817fa1f242a9c981a825cf8025bd8c721996f1891d7ae375d85b79850c7adc7e880038e9e6dfb825179bbe6c64f93ce6c8d69e20047e0b6b8404465af6c11b2517a5a53b0b0300dfa9cbafd84587f00a2fc9b5c6fc38cadf1aad30015b52acbb1106c8e25a2055eb99893a34916871fc1a38781490ea89894ce2c467f9b98ebda2ed6119e85b94ecc67d647e3a669862c01a38431b151e206a1cb7cb3e9becf2dc4c8f536e534a9e6231b0cbe842760cbcdfda7a36dcc14a312cf467326e459aec3771f2dac4e7ae33b3d08b3a2581d1e68148173339b457bc9ad554b88690bd531ff301e568750d23c75b26588f80540ff472cb14d5d0552aaf1e90f06d72ad90413a49f5e0140a0298aca81071d08e12d94619ecc4d66bc93f2cb0b5fa1d36644413ecedf147c0d9b048f2034cb195584afaf005f83731d367f9326ab2a1b3184ff64283d655255eb76a60341773e669af4e541540e36bb102a72b84256257f47261480c31bb9425a4f0edecea83d4c5c1c4ba8559436f1874aaa9f72a432cb11b4faae1413e8a9f3fa54f7e11cdf9ebccc70ee6237823a8a426003d2c61a2394130b30074a6840316c6b524025250a90ece2daabeb59f23d0357409c0351d4c1d14053470d8c4373504f26831d9828ec05aa78557be07e4fdcf65dceb66e4785426f26971fab9b47d274e6aa7cf934e8f1ae70dc5b2a45c1c0f56ef5fb02004bbbf2790962c04f8c0ad84ea2e7d5c06ce9283ebd5b8c2071f2cc276586d21831b2dd81662a033ac2c52662d8fc1ba15b3682c2260e6e7fc7bbc823349abd919c587044f728a99b5e72f2670143dd8829a949417fc127581bb3e3719913bf2fa64c416dc01147e8fde8919e0d2cc7032aa02e8459301816a703f929a183a86840d81ba4f20f093ab742084337dd62345be923fe86f505a1aec06b35ebc23c989a139b7c28e7071550c0073704e9cb2d4cf9bd3f9862eb7ccf9986d94b582cb07c2bfe97ddf6de7bcb2da59429a5580848082908d305e7fabbe0b8e060a4d6ca16d169a89f842ccb32d7f638dcc43de7d0917d08806dfb120998148404a1010cd09520ce441388e52ed75b3be4f081ec730fc43ef7fd1cf720b04608d07bcfa57c8d105408c17df7d6be9053d72fa359966599f720ce7b503f10eebb07027a691007eebb9f00f71d3801d07be00e41bc17727215150fac1122e5ed772b5f2304154278dfbd0af8923d9f545ec869e424ff15954675a3b0f9b4ebe1b70c2b041540eca7bc10dd7bef42d84ff997ec8178df3d9094b7dfdd4b06e2e07df713f0c009a4806dc11c568da2c286ecba3eec104da71c74f8f8c47d3a4493f7fe394453f772430d1540b8077d8d0702a9e9408e6666016c62d6c1255a9a1918b56aac7504610f42222b5594365346541cb364c7e6686ec39873f2e45e21d952363ec7b8fbaa552a6ed5942a958a529af3537b6a85014586db387979111794eb5fb9a707073f753dddd33dddd33d291be7365bce18fdf6bc4c351de5fa10871141a34182ce021a5ea47bda279ab8f7edfdfba75f4c933d7522a2f631d7f118d8178493bca7fbfcd43ed1d4fdcf89fbb6efc09a1a061448a082be905307eee03e1f377c3940e149d8cba6dfc1343d530406027fd1e3c449fe3e25e8e1be436abea7a77bba87fa889247417a5c5e7ae225aca787fe809a8838a11038841be1032d449d2b2343fa30eec41ca794621cc5300ad62c0a4a2d058140206f0e615a6f5d0dda6f9e57abb5a31189d4d5a0b17c2f40585ef4229617720a7d2f40422f7a115823fa90a8e547d8b7fce845df0b109717bd8b087cc17e84895ed40205a6224a5911a9580a02814054d4f22aa04ff938177df29442a948d4427744968f4fa150037da10dedf0dad309d86288e56acd22290ba52c214a290ba594524a290b4b88364bb350ca12a294b2504a29a594b2b084683755f13f43db89a91867ca4b0ec364326fa68e91993379e62ace546aa6383553a994e6b1d9e7d4628c71e620c176f84c45139fc299f30da162b6a6c4615c5332a7fc99e324af82637ca67242ad0a395fab826958ce2cac0ec76461c399d2565e9a2f53a9d476849bb972edff6e592b73fd59419ef329ed5aa713369c3ad7bfe9fba96259b63a823d615951f7120c54091d425754459350143542bb9b7e4ebb12584a049beafb4753d71d9c2f0cf43c14c734111545c10eb4bb1e850de7cb97b03d5f45bc34e7eb355f18c6b26252ad1d4d3094c198b076b4a3013642323c39accde6cf7c327f7ce708253ba9296e774dd8271307c7fe93268e9d993858f663a35d1db1d61a514911638c5d096ccae8bac3dcefdbbdbb8e48504a7f4077301486a574788ce4344e2f6915c6dd8d611886f5b6a5acfc8dd445c04fd9d78a035b234ca372563427acf78897e623d13a061da209840186f1ef9e5039d01f0d1d503e2a2f61374e438642a16a9d471ca61fcbe84c92b383b99604ff300f8939be6c992f07c7c4308cff0c32d48631c04c0449a397a48c08364e2a0329a56c661e31d75aa3a9566b47a3ff1d39e8c0345ea3c94f32359c051748a189d3109b144f9ce83fc1a62011c65faecbd115768a2b83ff36e704e9c0fae476e4f03834212fe1ba123c465786554dd54dafdceb0b6cd82a19e734b2b520455f9406b1c15132a44695044583d4eadeddcd0218451819e7d75134e15084f711400dcc31945f230802835b0409847029be649c1a8e658ea120925046865f459c86ec9df22b485f9a71cc112775bd8137e7e4c9580a96d2c367c7495ca30bdbdfdcc347c749ddddd4d54c639472b97e32d5112859ea4986ca6e5ed91097abd56ab55adef25634f9a905ac6979d110de04147e10ba0f49f4a1bbbca7ba5c4fba9f52fa3b6237fded9b7acb5bdef216a5f249f5bb1ae4b3cf4dd9b02307d8e7561b4d428cbec604424e2edff22eef2f337aa6f9d8e456f08c578debaec7f6aefaa3af46883190b0e234723d69a9f135c01a976f89809f6afc0e17d9781b608d8d17bd90d3e6f2b9cdf7bd007979977f01dde6457b977f791b36fe06e8281be08bf62fa0e3e468200e7eaaf1355c408fa27b795f7f6a506fd560b140accaaa2c1787c286d585b92ce6e325edbd47e583a877c59d7829c4c2c2b7c6274f21951a2ebff281a05e15ee55befa714eaaf1f9a9baa209738556523017c7612e0e7371984ba5460d97cc86b7e815d368bc85060a59893e3eb57c7c4af9c2ed032ed0a20a27bbf29debab8b3df7a4ace5e393e8e3d31762208390b050a4c8e572fd88442daeeee5add78f2b9a44505a246a117d7ef25634d5da72b55c2d97cbf52312b5b85ca3541512f2979d960ccb78c961b83dcc80006e31193b4c6464b288a2032d8ae8208b21779b732a59a244c90a5437945941aabb5d046c18093ea7fad915ec0e6fafdf20272b909a02fc9cb08f35687243191e1a3ce1914192ebefa308e3d605f671d07f9b2adc1ca41b1b9264ee8e97e64b1919194a672bdbc2362f0c9701a11946b3bbaba5c0baf777570308091bd69b5a2b9d324e176d15a52b56932337eeee4f9b996364766d3e53dd677c66ceecf00ef4424ed80c9d0141ef376e01ae7bdfbdec9b76ad0596bb1aaa111b4d2b7943ee619e1d0fd26d158fad1106082cfbfa61b3c98708e31f0226f96bbf7d21e092bf0fd13419c67fe6062e6cbc21f75caf9462c1bd87dc80dda86e1a8e645f33c1314a700c2a8eb959694fd89a84e508233f87991bdca74aa5c230bb034a599f1d1794e659d2e35c5f7874b799ce56819eb02aa6f11aaab78a69bad6a92a5fc9b45a8769c0ebdf3c4c93124ddabf462e1d1758f9a18c839eb0f5aa2aa004ebc0a199601a09708cbff7f084c53e6c5557430d3018ca8ddbbd8169b07e1d8ee92657b0ce0c332000013972e0d0699d160a62add6b28ee58ec1c11b38c6afb061ebb44eac55c7b15eb99cefdd0fbfdc313468a3090786f12fc2688c275cbf8163fc99380dda7bd5c9b269c4616e564e3a8293c4fa805e1c1461a9152836c6b1adba08ccd35ce9acaa8e012ccce772fdc60da54ed5b942d380705dfb628bebcfd86fdd5d2b5833c40903b3ebb5e44d684735552b5693233b5367329938fe4cddfb55a815d374373746ae4f234ec4de504be2a539e7c430d54d6827051a19d24b9a0b87bb957566e6dab5ce0fc627c583858b070b174f16446eb869a136bbfbe1dd390073819a60956ac56a7264e74687098e12956ad336191912e97f34da69d08755dc3ed4a7d5c44b18ddbcf7dae5e47860c630feaf1a529e3facd70375b656cf5a10b873773ca361d3b46c3b824333e75690c3cc95eb280a765463a4c40bbfc02549bb4b0970fd73292b76b302839927cf1c387af8e46c42e80ff14a0ab2ff10a58c327ad2936a9d5326078e5187644f5929a564585177a594b246d3065cbd4312cb3b333bcc497356da4b7bd9e02819b2bafe5a946ddb36f6f1f1f1f1f1993eae5aad1d8dfe79ba7872e7cf9ec149323224d26864ede65d095e6c98668897e4cfec3b82404b29ed7874f6cdefa64ef229771461378d46ed15a7cff4c13a6e9bfdf5ed9785376e3f75e91a8eae8dd0858b813ea1943420b00a601d140481ff9c18136e834840bfc337aaa9304a29d651fae3f39a3ecc7ad189838f1bf8093c46117cbc3434587b6d475cdf885cdf88c03c4a29a5d67ada4b7b65952388739529c4f84b38c1deec3939483333b30fda4cddfde4836998668edc258559f1e38f3f7a66cd1ef92c1f5814de0f37b36c7903876cd75c1c8f94524a19b13a310cc32686615bfdadbbb30cac19e2541ffbc2ec36e5af724cca88f7a319616629e526ada8c6af2c8ad16f04fbeb6e9581ddc1e50ae78debcab8c39c4630227228a5340c1bce555d1dc1a1f467ad15c372747eb66de3edb7cd7ddbb66ddb389b456018ff39c67475770367cfeb8004782c6ebf3f0058005c92cffa1825cbbe13073ae00c0ca712b7b5e012b6e96c2b379c3a7d3d82b2dfe1395eda947849fb7f8edbb4ec6609c7ecf0f838e927fbd9da08ff7eed320f154b6eecefaebda3743661e3cdcbd9b66ddbb66ddbb66de3ed3b17a641fb1b3227edc317e86f2a87f1d586e4634a29a514443f6ac3574b636ae1fa4f345806ff8d092e313bc1264a8960923f4d21b9dea7fe90805efb50f5047acd4fdcf702647beeb9ed859cb6ed9bacc97ae9df9e7bd007eac0977e0ef4d76ded3570fa6ce0746da5f935fbf8e1646118866116c749db916df56d2aaa52824d13a799aa70a88a36b1e1b6a9bcc45c28818cebbf2d691d376eea3ee4b6249b928e4176e01c8361fca70f6afa8073a2a68fc5f112a5aa6de52520fafd3755341df112f6d973cb53d534f7135545d3a6a22a55acd56eaa0a6edf17c9ff3084cdad1918da4db5a9b20c9b42aa5b2cead7afccfcbd8d51c872554e154f09c648c1b0563007534a2965d98217a27b2f3bc46be2fd782e2f8ad7e39171fd675c799ecf3ab039c0651e2e98dc269e9394bdf1eb27280e5582435f0dcb8f7ee5ab697911b73ae2a40ea74b82ad7c45ac7c28b4f252aeac7c7f7325aeac7cf3e362890c9779b81872e9bdb9fedec9ee08053b9593fc9db0402d5093d1c7a2af36c172499cc4b9e2cf0fd41a59323caec77b98b90a0fe5f1a04da05584f1dfdedffb8269b40f1f0a23255823dc205c7fcf89d77292d76408f65df871e1e7fa7b2a9e67bdeeb3f7c2d00d41ac1b7a31b029cf812b1f881561401e2a82e1ccd56660312f85dc0ac40253402cd003b13cd63f0904862419198f35734310cbb344b0a0553479a89a8156d7573c269fd7038ef141c3f8bb2785268c9270fd319447848e5fb39c04850d412c10cb4bed34a0feb4e2b5aebf37e831f1584ebab944ac478463b680025ee6d9a2c5a32709f7d222cae55edc6b8b9d2d7490acbcd744febccc134591bbad7c5e118759013d540d12f45a5ecf8e93cb3c3b372f5ce6d959723d5634792894f48e20f9def1881e118ee1ae87b261d8d063794f3cd40b154d1ec8425d1e2d9ef0689162e2263e396972438ff5bafe1e1337f589777004239e93eb5fbda1af4fb1721289f57a5c1e8b1aa145e8108aa2367367f2c418e3e7316971463c271ea7baeedd2d3b72a8950db728d79fe524df985c9f436c7c1ab95734714ab8d78b0ccbbdae7fffcb7bac975c12277146fca6279a3854e47ab6284ef221dc2a9ab656edb13e23e756db0febfa4b7a2c8f65c4861eebfed01c8fe5b162fcb9fd422ac503f083941c29a5a3bce43a3c6ec4df8b38ce1257398bc562917cf8a8d5dad1e85fe5cd041c2534d9a676c35ef988263fd9308b6431b0a6690085132d9c86e062e073c29e695e9826fa144f28214377d6753bcf06f4911c1ba2f8d14f4cd087146ce828d7f152d828ec23188e48f62bf8d2df6075140eecbf018ef2b137f87054f7b098a67bbaa75e2fe224f914e4d13fe3e7282779ca1df0129faffc1c24520b6ee82a044c1999991992a0ecddf18361fc7d380a5379e9c64bd1518e9ad3484a8e8a1251c8cccc4451a7ca61fa5715a7e628d159529720b5a20b8e4b8e4b8f0b192e4a5c5ad7df25890bcbc5898b8e0bcff58fb205a705a705a7c5650bce6c2945c728e356642b626fdcad05072794c449dedd38a11c2799c0bef4f77de1416f832d49ae4a6dc101c01600d801000f78c6f5077fbe2daeffb7e3c216758769e6b6e4fa8d275cff1b2ea6e977b9e2fabbe84cc1a6996218ffbe9ec475174c265a7038e6880d432f2a850d43382e4cc125efc65dc0f19c7021c9f5a2b8d1c334d9146c4cc134daa73c71fd99663671fd7798a65f8bc2f5104e2809d34c23212ab834916092cf542a0a2e382e385868e539c1a55014211c2f8ad0cb9b420bce13f5432bf9fea128244ee815b6c8ec862d38d7bf7aa30838d7c6142f1b381ce32e2d382e381978c3733846fefc6a5fa9d244c86344414b718c1bd18ed8e2fa872a555c207aa638c6b39d4e0b1bbae0b8a0e32e2cf1520760924d02e8878dda014387a57dd4888d26a1134d5387e5258a02834b54053a3a53279a342798a1c39e67add6022df097a232150ed85b51d1e40c33df3510d44b515e7226cd773a02792b35824d1a4de2fa6bd84fc5c006e356e98d3f722620e7bb71292a8e46d67e17b85112413d1b4db6ea0ec41082629a0635166b422872f9e72a9ab49d49844b9a190ce35fb52b683d11466b7949733949130297b432b49e9d9e689a3fa009c3c39e355bad5957344d9d0893559797a68e93a6ced47133d884bd7685eb8f6d677052461e18d75d0d370ca960fde83dc3d666d7c95c1cb39d61fb371bea8499594e6ecbcccc7212b9ecb5629108935846a7507aa6383694c8cccccd5521664688cdcc52cae6aa60fba394cce38b2ca564301c41ebf24605db2f274bd6747a6423336334fa6067cad85fff77c83ac1e6907ee818ff5875725c67e84cd93948396dd296e83c40c709dece1194523abfdb79a69465b419b28c18a319136c8e9943c8eeee0c94d183e66e2ec6e84ba089a36df69ced10f0dbdddf35403d51b0de1c254882d2646364d292388c3f0e04e6136a5a8a2920b139d5f7f06b4e172918488bbafd3b1ae0266cc5c36373fb8e7afaa8361e9e2e5aba8d307e85259860730ab9e7e6d03afaf663d249dd54eea0082bdca653c64c099fa88c316c4ed5092ac022e52eabb2851ceb99d1b2568c4884253dd0b1dd659e253b4b7472c0f2819c36c6d823acca97527e1d4929254b29658cfc02849eb0f78b04036b8438693eb0b5628c858f1889ad327af7c96b6d2cae68e272c18857e8e0c6972d82132471848929a460822d10e1469e22ceb831bb31c6184158d4e0faad3646267e5660051244e82209629ce210864871e32320c6183d2b340cab2a5836a77ed215abebd77b9e217f88bc2047070d149c5ee063473998977970c01a028555b9cc3385110cc0c10e4f0cb2e0b9220a2fa39473ce09f66c4c5219a594ddddb1bbbbdba5c71f6c5162386e884dd69da9f3cffa9344ebc4bed10459c713e20ca82786f61856da3e23e5781c2c3b1b48c05ac43e6b128580f6f36767c3052ef61a86fdc84948c0e6d3ce06123805ad63c00932722563c3ed84e12a8236c1250d22e69c7352248aac7081841344e830238d2b72b004183bb04113216c5c1849024ad331a305529009e38a2ef3e8ec6411e728babbd338a38c2c973fc68e3164399f3da5d8424ce3ec258a558dfb1b2cecec32d870e373608859eee4e17e9649a11eb28f93d687fa55264dee4e8c878f5468f1b9c14fd604fbddf83394586efc1d8270d34a8b013937926e8c314aeef83984f05674e3781ba390e5dcdda383ee2ec47bb6733333f7199188ed2e43fe774b4967ed22360ea4f48fbfc530bbdd83ad7aa95b66e64918c65e746abb85c821dc9d0c19bb9959d29f5fec98f913ccdd1d3b7273fcc9cccc1c475903944729a59c517616e41326f63660464a19fbc2bfc034cc3fdd839fdb839b5c156186b0694784995f8b58233f1a59cbad38798614c4a90e3477cdfdf9663cdc986c89c99f2ff2e90fecb66467e3baa7fbf92d2cbb7d7fbda47738282f8e03c33eb2649bafb506662d5ed890bb12f3a28826ec45114ce63b8e97d80b1b9f3b93dc29c1e66929c19077fcc64d7cda1143f6d909d96727649f1d1d22ccfc5aad1d8dfe49241f57b5221aad33587146574557bd54493024cd1b0cb93a2ef32861725d4e9a59cafa7727bf7d624f4fabc5ba33333a231d1de4a703c7e068591c387e4047b619f218b5fb75609a8ed8735f11dc77dddc73c73d8671dcf747b96da3dcf665cfd59bc5dfa18212942d3be73f6747dbcfb7f1242fb99ef4cffc8ee236add2befe0ddbe1973b4fcd29b250a2cd273d8ea7596c73ce3993541cc902144871c3bfd8115bf512b3e79f94636c9275cc9dd631c1f6e9185a09293b7fd3a16273590636ae38464e30641f2bb3975ddd26c2c8475d399360fd534e32e224896118c52a56b18a61d8c4c048a3aa2362c398ba3e577e4c45933cc98faa17195357be94f3c3989a619d291c9671cec920c7fa847d100b2812cbbf7d615ff8ca2b70d7196189907147dc85eaf6c9868d71746258fecd0cffc8345e234c12eccb04a210f365022e84fc9f014711cc41ca441820272127076fd09068f72266048370db23ab634801d334d83ce018ff78d9daf88b068763e61433a2e05a71fdfb762bb0a1bf5ed1247f228ccb9f97fcf154ebe08269fa5b080cb3d33a22d8ad8ec1df354d468600040000005e5e6e38512b2b146cd6143f39371cbde44fcf68e32fec89f56f5484a1ef2312a959ce62b1a20d27ab59af566a630458272f28d23d7a8c9e69da6f9aa66952823299cfe040ba13b6df5dda0b6ce8ae1d13d73df7424ede06be00d91ef420b006f4db0be97797fd7cec8830bd63bbcec776446c28c37da38f934244c521a02bac4d377fb1c48e0db258b9fdfeb107df1a60d895fb127fc706595cee7aacdc2f96b8fec47f1c8abb9cd455b09d0aec363373bd59c77c770b863d8466d0b0fea10c02c01927f557ede97cea58df38a34c9cd13c83b2318e30a6b8508d93dae6b6bbbbbbbb8c35d658638c353fc42155f854d193739363a4b915d629c68f18af2ec0587227f8ca6992c30475437ed9dcfe9ade78e3411010146c16d0e018faa1609967063e37f41714bf54bc62915ac5ea86fe629e2a5411158b307bb7b53d98497e6357030c2bbf878cf2e34b903966b6c4c04630f49a87c2713f5eaadd1136e41767293dc6487d61b1ef8cb0b4c6283e3782e17caf1ce8d70d87407d3804ea461ea0eb2f8ee9df583673e1104f19287f47fcb9213be68393f8e917448e93d88a26d75f95c70a26b7bfc64d7dead710a80fe320357dfb621ffd84dc19f6cd8da0dbcb1ec5491d4d22e8ee0e126d407f39a92b123614f2622f6c0cdc3e375be4294c1b3925a54bb6196b10bf4523163f973bbaa21f759bd8472510d7eb9d31c618638c3162d9ad178b31c618c1c931f24770bd59064982ebdf355e6412309573d26d900d483030317e140c7bb995939fcb1d5dd1cdbe91ec90d896cb72b3af76489808dbef5fe8ae5c952fe56e19273f7b378d939f77370e74378e935f77b76e0371f2dbeee671f2d3f824bfec6e299cfceadd5438f961775be1e447ef16da5838f9c9bbb570f28b77138db89791a8460d10fdfa147bf985f4ca8f1836658d9797cb4e6cd2147298ee80e5ea0e9bbf3363580f3297df4b1e923227acff0d17fb9e73ce884d6787c1dca347ac1b944ee2a9b3f9cfcb1c65f6cd09b0d8c7df26f68f7df5dd3dfbc21b2e7733cf7cf06d9007d983ccc55ecaeb01211793f57beeda07df08f62063038b578fa007845c7fac73007d211e445f1e62f813047ef635e30103af6ce752f6e5a736c61152dfb89bdd134d8eaa292a33447fa39ef72cdeb3b43c4b88498b28fe8c3fe774e1052c22d1bbb4b4bc28cbbe79e0e432102ef37ce1ba9b00bee301fa20481c9370b480dfb7f22e2c2cefbdd0d9d09ee742f783e53d76d2fc160270cd34b7453f127d4b8dd18b6a7c7d5f68697996df0ac0f10efffe5db871a3869df3b539e7fc5c461d8f01703e1a594be98fe8534a772e7dd1873255849e510781f893f68856565c7ee5298f97428fb276bcd4d9d048f8f92c1fdf50f7c3fbf9dcb5b088ba27acab68e253b5f46dbc94d2f1f0db12dab8610fdc1d7dcbe8c3f9359e87f922a67979faf208a66179fa1b0bcbd7f8c9f22f5fdf94ce012c2f123d0b0bcb8b7e87bfcc098efe07ef8e2ecb8fbe6fa6e9165161bdabbdc80a1bca9408890da5cd65f94d4624850d0f96dcf8a3f7ee47fcd177c7c33e773d7898a259030c5d44200f2e2f7afa9ee841dd0f17110bcb7bf783e55bbec6c737763ff4153dcb0782be221018ba3ce8b2fcec7af020fa20fab6bc0bfdb05f978a4030140df1520bc883e85b9e3ea8e5bbee87a8e5005c330d0f1e401f447f22296cd82f1e9d8628890dfb2555d2889778e8cf9e7ed7d9503f7baefbd1a0c7e66d82d8492d607d99cfb70bc170eb8d5b59ba5b3fe4eeecaa8d9f2b1f5f50ca17d6ee0bb9207ab6b4797594eea13f6d38a2e07c71cc448361e41f71e583c07044c45222aefc8c0353f26d7cd288c3c80d943732e524e9a81efa8e928ebab23aa9a7ca6729e5366ddcb61a18da1baecc9d5996f52073a9cfc8c1265e6ca01f63fdacbfb0c34ee3d63476788500fdfa7917ac3dbc2bc11fbcdb42b06e1cd8dccdf367cb6f4333441cd171b8f4959bb4ec492e736778e732abfd25f8838137383aca5df96b9e819ec4573b2f777c27478997e6bbcf687377f80e97adb9c4f49edd0e3ecccccc24e077f8f752030cfbd76b94d3fb047029fe54f9b09a9806fbe1e882be573f57de2b87e995b482fb108497a27f5c8f1e9c343f823bccefb6893636da639356d00c10fd0531bd2e0d1b76ab67f7dcf9edb2b29b48ca852184c9753393f1d2d436508be4a4b9b2b4478e6ec50a7e8df3b7759c84cdccab634ebadd8a30f3bb55c1d8ad791b27678a6e7cee7e886e2739e22420e48dab2858f961af2e47848d31c6188bb0a2cb3c5facb60f67b852862b63ae84e1ca1b57f62ab4512e019761b214fe3ac90486993fbbc90c5ec810d33a305430ec56834d468b05369cb9b332e099e78b22777e0e31e423234d2b3fbf3a0d2a1fe248f93034134d2b55e54729a3d972d2fc29d8f99e627941777337e7b8ce9ec5c638a6cc820739df5dbe4b904689011144957ee5b3ec0fa281e87f6127c91df1e56f61b97e3ffd1c4c537f18e2fad3ed297d18a6d19e7e0cd3644f7fc64b3fb4101b2d58512e7dcb2a72e9e390a16fc34b7d834bbde8b9f425a5200bbafea0ebffc2dd22b77d2fd9f3e5a1be64a00d345c7f2076dc0abefca0e1fad370fd855ceeb09de9842250c46ed3fcb04a241387c3e8b0a1ad4fb0a16d191ac95c216a997b333333a86dcdceccced84bd9b2654b2931f98e613e78496b3965b79ad04f871d34d03e6478c9f5e3416adaa68768520636e49fabf96bdf292f6d7c7df092bb7f7c83f052f7da07f112d7691833f7d77d0dc549f1f30cfb9e357b777777f74c6a52939a942eb31f27c59731b021fbfcd438297ef6f9e0a4e84346bb82705214ab811ddc4633829bb36bc5187c911f7f56ee296c8c23dc562d2f8d62119938c4a33ce1f726ee3ca7934a867d328212e5fa87243aa4c8f5224e1ad20dce167501d31cc13a9a63e8293f324d635f1ce230fe6e13f6305346bc24bd3429b8ad86b0b1641947e09202eb33e7721773ee05bab9f803c52ae188e8ae86f8855552ac6e9adcba4e72f1b3d64be1e2a722e594c2c6d7e40a97d2ad7473b29348386cc48f85858b5ff835b08b442d9aa0971f94022cdc4a0b1712712cdd8865341a85565446a3143b1a8dbc11a81b8db84dcb2a361280b6a3ed68606cb1db9d76c718a3945b115ba32aaeb022764e2a69955c95a1901df9d85a2b47716cd818bd6bb415e9dfb622b6fee65cd5b62236ac97eb8e31c6de8a74778c31c61863c7de8a74778c31c61863c7ee8e31c61863ecd8dd1d638c31c6d8b1bb638c31c6183b76778c31c618677cd9b11be4905fb0c2e6124df2c11a2a422452be0487a02fc410f3e5632053908af87c9aa08d0439c26048583ec1a012a399e8228a0cb6eec13c5edca860e4241218838e99435ef0a4b6cb5ef00cb1c2e6d244fd98c5186bd68a9ed68a5187d8ddd607540de25d2b6646f5acca9e188661e105aefc389b40279d603603afe598b6c910a39ca8a44db74531956a06020008001315000020100a06042281483822d664c57714000e7c8a48784e194ce45110c3280c19648821c8100306c888c080cc600400334e42b9370e3489faad6892c27c50a267266458c2ba0afb09585d427711d1d1b5585e52ea97cbb1090590862b0f18ca016ebbc27a05a54ea2a9febad55c5c8885259415bd56381658dbf82d0321f639892e4e056a214007b9780830ff504e09d5100e1795a01cd510f822088e78c2ebdfe344ff5dca0b636ce1cef81b06c0dbafb052acdd5a4899232384148a1631a1c73e47f66e2565a5633ee239f09603116bcabe50937d155a5aee641b9c65075a5a561952d85cb825f32ce4ea05e1f077b80162553a96fbdfd8fab936053b87e6a1a5dd92ccdb0a7a3e47642c8efffb89616293ebd5975d0120070e3573317d0d118b8d0b82afd8dd25510bdb08e80d0bbf4691232bb5b47514568c03f9b9e852a679b9e534cd9d956acb975e4422a59cc271ab1f8e5b119a0ad67253fc6f9fab8af979d5878ed51b5bd559404bcd8978b5fc6b7a392896df6d079c041d5128e1e4b9708d5d41309617be48cf8894f14010a1b03905339a631795c11bb92264b32ff09038b82eb2917ee827da91944839b57850ae91aa0c995f3dbd003850e8df72e648fb145b2052e5922fb0482c06b67ca2a81d9b84d4ebbcbd23e5f268dfaff9ded4238d9a4cf1ee2cc19afa326a762c68d6c3db8c836964d772854624a89d9de61ae38e07772acb11aaf0e09b59f78dc3254b5318da63849cf0fd120e92f88e2cb2a7a6f0e015154e835d9c8d15d69a2a0348199b76a69fca0a4adaf0efbf96a373e6a32e5f23b6303ff390c3148332c21dcf3ed65b4fda47d28240aca16a476e60954c5df66c22a39671f0e920bb08e5bfaa9dc9af2cb1f3621a061d7a7b4d7824aa671affa4d45f6b5ca8332e4810bef93e2940bcd6a2be77545c123d08078fd19e3c77e8fda7af1f6e6186316dad35212f56f404fcd6cd794970e36464956fb8a5f046c293de3ce17abcf79e6e2fb89d4d9c7ebe02f84f6507adeebb7835c04e0e806da1cdd96c2f1e05469ed171cb7a6a5554363c6330a8bcf96febf942584be7121a6d6cc49db893da11bfcc6974ece53fd5492b4178105d5bdaca706fbf17cf847fb95134bf68a2b50d665c9d3e70d7f52af1cfab3ada57a9d4910a44ce0f58cef082258eb00bb69737156439b8a3349bdf8e0ee88d51b888ed5684e01ede37a006b5e5560af6fbb50555c3e5d23638646e605407d481bcf3ab94d3d0d0051c028758a610561fd4f662cfdd287a8a9a37589fab7883c8c491da9e64a1cc215ec0d0b2a6786ae8661f8a9a19939ece284a3a629712a79d7c5f79c0f59abb82d05d801df6cbf71414646b2ac0dcf31ad2a80bf2c0472b318fdd2b3d4e0df35303c41914df1d4ca3cbf8dd720687c9549e8c97249349246a27b89c08e8c100d6c8513beb287fc4b20bb66080142b609b5b7c24c4fa15f30ccf56a37ccc1fdcbf711f1dcebdc96181bbbd684be7cb0da2c8c81c8cba924b53a8c79db1132234cfa8b362f84766dedc50d31f66efabc36884660dba8a1d9c75c2ba3fcd1b008d66a7dd5b34e32f905ddc654141162890aa717b64be15e3ce7207fe5cd01c1a9a7d16afb723ded582c6f46da705ffcd7316f1b292c83a82c54a7f85174fbfa7415effad6f02d356e53c2067a8af0ac95b1d2fc48f52cedc461ff9961c8e983c37b0b9f49fe50f581c0a6db64a219f908f348bec1d86a7d268f6c9920968a3517cc391b3797f92cda4c91945254f52386ca007fdab45453ebd1bfdd1c0997f748002a7b3128f1f02473fe5c33549b6a21263cd39056a84d8b4406c53b999b6552cc70767648b4202ee21011f130a490dc982ce9ffc4efddb7423fb7fb677f5cf863af33a84ff70df7f28de787097a93a7c81f06259295fdf6db5ac1a27e8b34ccc53c6bb67002dad2554a0897f5ea2f371a4ab653b0da9174ca6fc0340131a436255a267590559fa0de1d2aa12a0ca1f5c3f46c5ae25432d80d76a7b5b3e5d0678785b79ec29bb2bec8f1ddbbc52fbc55edb744aef0de8c79e7e9c4a742663cea51bf41f733b60cc04c1cf69f790720bfafd5c26d0ec646603daf9b00fc72acc0cc7981086edb07acb34cd97f24b803e67270a66ae1cb96a6323d6e7f1b625bd79b4fc764884264c7a9d500adb5bfe61fb13e7b01727d32d0968953c4e56b09b980f62787a10184591dfe008983ab849c1a45155f26841afb498877400a0d7e22e07529f7d5132247d8390251ba661be8e5ffb0a2e4036f660abaa56883d7548124f523a957fc08c96c7348f82b0d910bcaf56d70d6435202df4ed4bed13c1c598d9d8d0d353fdcd672d007da06250097a46baac851214588340cf17df027d9cf3094054b4326d285e1005f2686f12648028e30fe20f8108414d31499b69425714fac27c7d9b0c7962683d2eda915c68fbc2835963d268a61f1fedf2c858436303146a1eb912e3e8ff7ababd3975c8d294df80163dee7789c2dcc6e7770797f44e6c0a64b72ce9be6ea67a78e006980fb028e3a0784b32df48b107c4cd6f8f66deb7aaf17004f63f31b711ccd14344b4303019b34004ea246646bc4048d33fe80e74119854b60c79b04e2513a6b4916c008c15011b773e3fae08ed452e06c8d2616afb41596d2ac2c4f15c9432ceac436e2eaf85daf43e605c2263f09d3630158a714aebec24ae5fd09f7336a0c1d569d51f6dfc3443395a8747d8ff1e4349efd86d943c155f342a74f7d8d5a6e8a0b9be07655a206f8d00f61eb928b077775d2b10cd0bf13be14af6772d6ee0ea91daef4e89affc45cc00e40d06ad127e2ea992509e73476bc1183ec0ef2eb0eb2b5bdfd2bfa00f30f20f092316b9e2b32bec4c635ec91a881fd46683dd092b8946081e2ba061154d41901c0d6b1bb7f4a9cd09c632b74f9261eb1368b7b937a304275f8967b085ac1e6d1926243602ab8651968f2ab07a6894999875094797d5da6c7b0706b2f98fbf5376c2fcc54f2552a4fd298625658df5724472278cde14872733e0a13e03c01c1a0600200d50e6fae6f6665a38265da2edfe7b7203aa94babc9fcb00216702a1e8609943b04075f4a55127a832e7e2b87ba857bb42b62e2ca491d41c7b0f6ee01b9f4b416dc7c0452804d45aa65b3650b84f81877bed08e839f22da9bead5bfef0a0f2981c2c654d255b11e50c235f430cc663ef63bc6039b8fb3d694db7efac2336aaf49398d9c086a0c9406b48bbf5670deeb6a2b9a34dad8dfbd3f9889dc1cee7e16a5790443f693e0e31e5f2281294f480cd8736eca5379e27822638a26d8c427cf10f88f847c2c77e106a6ac8077b635f8a87f885220fecd26f8338e0234794dfb8dcce15dbf4485906eeeedf78ce87ba4f9603e5c1a2bca8ebd985c2824af461810402d7bd52ee7862e8e927b668acdc262aff9afdd6f43ede4dfe6398968e05b36ea02b6ea29eeb827200c8fa0065f1e8a0140aa2a09eef88d1042e720d04539a0899c7f501eba36f0de5d8b23be4227707d4740269de6a057c7bd402f72ca0859e163cb88016f6ef646480c60286dd0aba8a093644ac87ad582894f1c3701728df66dee380ccffbf27799cdc062f80c0ab8ad5376829ad5142c236a5957e4961b7b2d6318d37f58f69e23e767f094d645a63dfc3aa4ed197b4860381a0a97e5e0fb71aaa8c40cacc232712e22d49141b3f45744ff1c7daeadcfd30bbfaa495ff50fd04808684c93ab3412c9e135d8b41d0d54d47db677f759c50648be385da2f780361331280952a70a338aae03b8710f039c928500dbf6b0c8b711a5189d303e8105b70dfba6981d42095aae15ee1f46c7c8db901e437e9f44dfdd2ef5ffefc20cd625d689eddfd75248fb3922135b654101fe3c8cfcd0c09633140e94482a4a725ad39cd26311a1e696d06cccd24520f8225eefc77b543de83820b697c5597f4d608114eb3cb88cb08e88684c610fafbb24798f1b1104e261a311773c5c7058660c80fbeb68c14b2d81eb65be812e0121fb7294839290d247d26d6afa03cc8db060118cf22af05f13c47a179fc85881f92d70ce6144e476411f2cf06994665e727ac285e737c98b8c1ebd6613493f4d329f71f90d4d41f1acae47c63cb0d3784037c065d4caf6f901ca7576ce0922643b21c1f8dd61a29ff65abd5b46e56875f9675b17e4d7c05fce848b71af1e2857518f168a6d5436d2fad0b0e9ee7488fcb52ebc3492572d254494359b842fdcae9873629429fb7392d7c0448c087bff758a7b258396ed02800d9352e390b496825f1eb7e493217738a5cae61bcb58c6b171f487aef811639be1011cf28ee4a1a94d47382cf2e3a41a75f30094bdb3506c38e52a8349c86b9e7b1a085a0fae79e6cfde37e52ec2a7d655c844d5788c8cb8c3bb98cef21809caf84e8fb70c1492321b4fd8f82436067b19813ea7b63c8fbd0d7ce5b18cd06dced160713f189dfc2bca58dca6c3647149dac93d93199ffd70c9b9e7767096ad5f5c8ef15240a6ba2059508529e31e8448e35341856c1dd31f042c6c8f0ff8aacf95b2f7df302f591f9a81f64153c6c824a002e9b2b0de59fb810213e33195b5ad97e92af3cbd2548d9eab4ee5a68a6056bc9a945c8e23c3306fc2863bc0afdb6529c2f7d46681f7947c953c5d6f0e7da5b548d5a96a27a66cb164516edf387dc81ead7773c9c4389a04f3870dbd081b66983e4fa570fdb4c8a62501925473ce358f0195b2ef6c8a120b62bab87cc286537018fb1d116c776a58cdb37a1d33ef011ec30a25a22ca47d09d588da706ea311db7a208bfab06e89e398abb7200eff78a428293080da05bdc7fafd7a42b0bcaad56b6b90ba48ed2477d7aa2d3393c0d684dcb63c8f72be70cb748c125cefa89cd33ba6f57b89357d755d4185ce41aa575e3525d0cfea471f80778be4fd2483be18d36b55c5f6d045d18504889b916a15e826a4fac843529290ae0c16c996424e2c36fe4cbb47a80c3b47a320df4b06721f2fa2d67bf82d1134ff99fd0c369cff0613afbd697bf7f181acde01e048cedec2711fa72bf067cbd54be2a91330c130917db0f2845fd4df96dec0899c03ced84fd46665ac3810f905ab0bd5e2e8398fd268c8a7ab1106d55728e1b892545f21bfa37cdb054b5d36fdcfda696cc626a5de72736d73c0becf3d62d19391c72f53305838623e8a00eae9258e3460254f24311e1768ee1807ff6cc47d22ad644a088e152a0e30c9823cecb7c0d26f2314943391d2372a11661498f17299d92cab5dba427b1abfba9208200fbe4b4fa8dad9f2eb217aea37ce8c54df0699fd40a9c189cdf86ed65bb537b2ec73769f3cf00c18369fb32dd552118a1aa74e8367e43d6a878c0a2021d84b6a5378ea7e3a07794b037ad48dfe1fce574c418547e272376ebae2253fd22b7309ed99f074d00fe1f511830463282d3ae5608fd2a348ed57c9c0c726798dbe2a6c1b23b1a52aca1b73541edc9395725962c6ba5aa06496fff8cc3d06134acd87102630d9b571a58d6ab4bc5952848ad224cd6ee2dd883a425e5960a241a504613b91a7fe3f1baa8eaa01f5642cecee9563fccbee49a6635289f35f0f302670b1de6217e0bf7a187570b7e2b5e671eab6337f3bbfd53ab16c1fc5f5053de6b351367dde41b2fef4064db2c46b21e04cb042d62087e4dbd392df4555c11d5f6b61bb6793c20a76f4b548c217d24ed910acb6dd7ae8032224b9e4f7152a2f7d481844ea3e3bab0a4dac925b7028df7b1b21199ca4b728efc7905b8c795148dbc4c8a9ccb36af67e0af7daa089ec7202385e9fb84e76cb75691e3198d216409cd2fd47aa197d7730b6de358f7e680345aadf43f3cde28ef7733ca2193d590683691b29bfdc1bbfe916de498b9adb4d28d8347c36fb7dea4be37bda074e3fc6237d0ec442094e303bf6ed4e36af02f0f10523ac945a1421468625ceed6717a0e0cc2930b0c53f77fcae8e45cd120449507500dd375cc6d962f2b4441ab0ad2eb1fc603089998f9e14eb7f3fa512d946db86a80e488052d99c4b837774e836d3d47c14c5c83bb793aaea7448234e97033b2b8fa34067fa293bb3e4a6f76b5573207458e373118dcc26e6304b4eb300e6c6ee9d1ae50df022609e79d0ea450e2fed220ba9d1da9c18c0b83cfaf8fcb743a355222a2fe3413db2ff00b643a9c414b1e545019094eb4a72fc67e595fc2125c481fdeaaf207060de28534574fbe14ffb8435729f69fca53b9c7fef4509c17ca4c0c7117659268c2bc2d745f3d58c52e282441dc7ec5fef433e866e1947756245870566376b825b427ff7aacdc8b4a7346292d486aadebec401b9d263b10213c1ef6fc15495b79e173260036a73b3a448aeac205b869312ec16c85057d813138329cf4582b45c5203408a1210aa3e638556bcd581efd17924d30098cd2e6f179f72f3c5791b40f085e6495c121bae5d2e7758b14f7626d42c087a102c0e8b2bd1698c92b0570c976ccf86bdefe4368c2ebcb11db03b50fc546d16e070750b002844d74110a1a6b640a83c7919a5581e953f9906869c008f001f8021576db42090a2537a82bdcf25b43139fd43f632e881e276ead35a6159955cf98417998db3bc0e59add9098481cdb1f651b5869814fb5f8263db8663e950f5c6e969da000b5e9c05e90a051acdc6d8b5699adaddbd753eaa9eb26aabc95ffcb6d8a0cd4e744e196cc0e18144184751356b8973fcb1a20936b886f7db26e304aaaca724671e305d5388f89cc7190782bf212be57f6fc60eb44c9760f64c77a49c00ba6a99e1526fc5ac99521ee463ddd65c7e0037b80beff63221f0db03eca80675c0e0f7bf36710497284c5dd39fda0f9b799a894c951a49cfcf27afd0051806a1835cd15ddbca5f497d730aeb368d8607cda577203cb70366f803ca2ef663ccd0b82992558ab2f707ea23633228d15cd509e5ec0aec12159c7f2149ac925d6b32343e251ffe1606d04f2ac2812c33a44c6bc22865e71bed39e6deaa5dfb0ab39dc80e3f40cb590128ed3b48df2056adffc093fb96627da46bfc70a9fa3fe74b2e721da2f2f62a614f217bb0c918be957eb3a22ca7bc6776668df1c3040f522224c78c19bed681737bb9b95e40e5fd4a3077dfd54017c744a23c79e44894c2a1f49dbf0113df40e02e0901bea2c6334e6d05819f2f4ec167fa3e3537773310311dca746ddcda237c3cd6acdf129e2e96e4e1466de31ea2a96b0a6d63ac706d7f29fa0aabbe426c27bf6baeb80e09b8d4f4a58ecedd1ed59a09b2f60341c2afe639fbda1d7941c6ed030d9a711cf17b0b8e67b25a59128af2433c4ad4c1261f520997276f9c9c9120269141616887299268a4e64619f2f7bf8a929c769ee7c3458cf2d3b4829c7b05afda19a65c1e80eea3311b56d2acafea70d8809774270c2ca23ec42a181de2571cd2146ce64c014b6f7f946f48f9e54c721c1ef83a10890474f68cdb85227bacc86a8da06dcfe84a1e6bba9a6b030036055b7332b51b3f39ba212edfe101ca1f882d87f9caa2ee20379ea3af50d5b976880293159f2ac0362194fb5898d32766d264edc570d6b78b9615d3ff621148ae8ce2b1d36562962e808b411f583243a388393a63cdd5a6ad211199610e4213dbc79a492904e9772c566123ff112f21563cf288c1b369d9d90b15f0ef0c3ba1c1b6a09e1158dda215a4a1c8a435ce6de15a050551355791ec98bee66825b8de05694b9810013fd433ebbe6671a0187c1aca6a73cb892224818a217c08c1b85809c618ae529ebeb6021e37a7f4880e32de22bc07d2d87f70e6aeee3673b4788dd1559caf51f125d7b5c797e8f166cccb9aa0a4af2c5d0a335ccf64077d103423068c3a5510f8fd139eed0de945ccec948167df64af6aec6382a239bca11f77a2b091f2e298ca8a854b8c10152ee071c55bdb4fbc1729bbbfbfb64fe0d6862902760d5acf1cb3caa1e6c286c51e43d043d9c6da2104d8bf198fff2d3fe4a3f44a62fdd5deb0f29514fcf1ac87a023a74d8cf3595c2d1a4a0c4c46ed12411c032c2be5ee3a71b4959e0ea18a3c31bd56b73ca5326e0fcd6376c86b1ae5c4af540ba5e3db23cab445fc0f09ab054646a216cc868fd8e79f5a33b7e24722865ce20b544bd0fae8c8cc278811186cd35312474df72d85e96d9fe58b7ae009e997357303df02606100863ab953d820bce8ad6b5a6e8c1380dbd0146aea4c46d70677ffe704da98a39e94fc6dc8cf3a4df009ac65ba6a20ec78106bba4b4b0dca71244a2411989e006dd7520738615b2ff516bf934cf3e67e2268874db376a48fbe811e9e9d9ea9042224d619583c42c958f98c78a20841206f6edc6d4cc466920624d65a9a4a8d69a0914738064aeca2404990a5b352b8d9fa89102dadc981bd35624ae15ce5185edd06927cd8398b73104df610aeaa3e39d0e846c217072534f1af304527a273b1e4ec3480e21f9720b0c96b793b363a935c0b21461d3bb44ecbae5c92ed537105d184813632792232501b335f48120681d15545ac288668fc8194b8018f5b6c5422036f1cd8d203c58f5c67d62233e86f5069377e516dd07c951373e192d6068fbc3ea56072859c1862862f0b8a32b8ef0d35bf01ee30e6ca4899d4bfa4fe3d9abe4005179c856901020b83fd98ac7b2f071049a24fb63799536e6cb5170401ad5d2a820b1a17176a31468823c012771461dd908861346faa13dddd351cfa238db52a15a5a1be775aec5d4a9a5640671ff6d97e907122b9031db7cea861b77faa021d73110474a292999a51f63e7646b8b0736256bdd2652403cb480397ddb3ea59d46a3c90fd3df39ee01c0241a22931db2281ecde0d8d5c2545b35c7f9e5e447174273bda0abba7e4897f1c23fd789aaf18bf249e45818244f8e076ddd6ef3eea73dde507c3083fc949fe7be1b2b384d44ef670ec5d2cf943d25ec9d71375408d81b502b2e490ed934d0a1d2e199bb462151d1443293a634aad1764bf5cdc606a267f8017325733e247c48cae46a0f6b6a36e8ee16dd0f5b9e7a58dabfccb1ccc756514c2be36b36326810fa0d6c57a5b22c8808f4208520225e6226bbeaa8a8b30ebecd747616c41422557f056f72f037ca9f3b9e614cd8e07853e257df1f0736045b7416d4a5619c999ee908dd21a54bc9bab0be5500592ca430d532204e2fbc8d40147f6462273c602f86b262ead5ee89786c5cd6d24f8b870f8dea72580c6362a9f29893ed8c5999582a569369895537fedd0e12aaa80e4ea853916a8206727b82ea63843f2d63f6af0038a2670e02a4caefdc374a43c3419a1406fb8d6ed78641842eea63533b11c4e343ccf3560ee91ebf2ea270d9442b36f710949f22409c2a3d680d909de54b98235a67cda026a498ff1269f0399d13fb8ca4e70b685e1d0db1df0203a1045ea5bf8557baeb5b1bc92aabb93b54f72b4c71a032ad8e0916888bd50baca49d08ca8b3cb234e1f9d0668773c73e8d3be3f058257ab2ff0ee73ec4e6d19f58b183d7dbbdabc8478af5ad8060a7f6d72720266b51a5b3b51575d33e97e5812d536ad99096e11a28c1ab2e828ae55307373623ad2631ba8d1b116e9288940a568b48498b3a3f93977d1f45ed5ebcbfe180f4b87870c9b9de29ac8e8a1f40ebfd115f5f73a4aff71301e70dca527b47d5c6eb48e737db106cd7f533ec82ebc9dad7e67ea93c1b7dfee2e28c4769ce9bf11643fdd3e68895909309b2f529d14a353bd63253200d1e7bfe0dabc02b192ccea09aa0edf76a17232711cda4286cea744d0b4dfc6dee8aac5614dc5778df0e839e92d10e14ef475afc3b6df9a2cfad33d00d2b163859cbf6e0b6d1211bf7bf9495d12dae444ba8111c5e6d2f03162ef6adcac1019a17212a60b6e4bf62ecaf06fb2ebe9443b172ffe014f9ede7b65915c653a0a65930975eace145f02281a680fb1deb225c33f68bcfa263117ad63a85b22aca799e3543c56cac32a43377d9d7802ee60c914404db7b0ccdb08354c70c303e569322f5d84e982363f9a6f3f83e2d6d9e2ef68442fde08022e5a25f2bc80786063559a0bc547b1681474a12fd7e413b214ae628d6ec8fe3e89a8137656357b8fe1052763e973c961a9cb80805c59616314019162049ff6132c079588bc50a3d75e9358c32c819625d1338198d1eb4e0f78e311d54f000318793c6037d89ac324d66d931789130ccff50f29536157e79701f655517c1270354a179192c2666e6cc8871d7c4902896fcc58fa614b57160f0a10d8c17b0cb7a36ecee894742ad99b3684c3181a3b4d23a6ee0a01ec8a9998143de5d62379e9489a713a4544233ef1c978cc54f1ffaaa44fe70eae8dd710b23bc93639a8253ebd9ca48b1c958be458f905827ef61708c45878a55a55f146e3f6af3e82e2125e2c6bf6620b9ee3a6c6109f90c6082badce461006e81601c97b02946718dd4df74725f0cd3956dcd4ffa339dd6db74b367404148c5eaf57e52d796ad2f6319bd6f85aecb36ddb5306cf373c62ce9d40b499e3fd2c59ab01b7d6362970a797c6621caa2493802fe8a5ec2cfad9e14e21d3bccb193ec7b3de7c64a34f4265a831210e4cdd068759c6184ae4820d5a3d39206dfbc861b68cdc5c40fee4cd0d7d7448c7510c48fbc45f4f14d1febdaea1ef6112159ab5cc8cb48c10846f4f48851e0082a43d85a09b1a33b86c9f90891cd0cbb27a983d3aaf917e391dd62b5aaf2a34e8ca18e538752e57de7ac6dc04b63905cf49d83dadaf9e5e7691549d5d71d3e0cc27989b78b90c82366c3e41edc2d4a8acfe551308fd03c745e4fed82c717772cbf4ad814af0128c6c5c7475728d7b49614e430ca032862304cc796d8853964944249bca7735f2db271036d2ec51305a87f2c50142fb0ff2f4606214f090e99d3e1296d9c1f215656466945a63e3541587089a0c884c66b8386556bc3f6f6aed5145d4e372f4d21278b163ad9c268a9c8f6018b948d996687cd47d1b77e288c828cc6dbf57430ad02fd20149ef33b237b24fe6af83f7d23c0b0dd571f9a84c70f006b76b963b6097def00b91830bb9c6f1970b0b73cde30970cbe55ec3ee5b7b2638562084d8107a08c7b160c3c206b236a8847fc9e18ea174cb6c943c637f615f3dada236bcda052e019e23f4c872fc521c544699212b42226a27e401dae4130e967c7be13d00c2abbc099b25d78b12a0d0a068a0ae52ed2b6f87dc1d30709cf9b76e1a14a4a1452d51be31748339057a18da44a25eaf08439eea34c7c585de7191ce3ea1b005f559769e85d25c56121c8544d956968d9eda18b9fc6c042fe3560412f14fa63ea5949372fffc94124cc10e0f1652b2f36ccba7cb94c64c563d4192a31c70d11bfc19365274f92bb085613ff48d8418628af7a7e91a441928a6cf4c790614ded5466ba52cfab680da542847f156f14e94ff1d5c764f693e22b965afb6a0b175d4619c2d73453d7164012b4d7debb8617353ecd057cd7baa0a9cd4d3123cd6a0d6bfa9b67e5accfb02a6e062d69b8f04656e5e2a2ba81889d7a7f1592c3e33e8c9a8679544262c7836ca6c05af9c6ea1107925ca71e616192249e052fc4df0cec7e36f07ad0204ed525a177cf3e7cd73f8f8820318e61e7015fe9ba68fa0e7f0f508cb0cbf40662ff684a4c1eb80ea65fc27447240429508f89695bbcc80859ee7ca027276ca92f9cba82f927d4392ed922875b58a09e75046d1c1fd3c53000d1f974785506f5ddf6e30c302ddf67e26035140b3782dbb21be946764310379814a110e10b7845bcd75abc4b15d3363c2024d14dcf7b964fcca63515c95e4ba9b78642bc632ee5f771a597bb580807b496be348ddd617d6750b78886ba9e4d0617f64903802e0bea11f6c2786e05c06d6ddc4f07cc9d4bbf808331a505f08a05d94efe05514a4b325b4cf0a0d9462831553e31a6077af0f730a9157cb026cf1bd0fe002a00431c92f470712f1fe789cc961905a9eb33187d6eaa4f31ad3e19e976142a700318d36d6771324ac04e70944c2d02ad4a117728b4d73bbc26fa0bb4da9a751821585b70568c4e0f6c977fdfbce98b8f11dc343e1a0c42090638279c98851b0e6fbdf3684c9cc0b86a0a58e1a55633511023d8d35c0b2b2377944e38fae15a8e3546d63f5900a2ca4db6b8976b1fc5a0cb1e8a3a247bfa4a27725e9f24f6db637590c18819693f624492c4df0fcadee005a78ad05b80fe8150fcb4c8abd60b1759ddaae7da2463ee1b79cd88d7cc6877da54d46c8e2215f8cc34c471098d575dfe8218b03aa790ea1253ef45d18fdba3897b6dad30124601617b4994bf583af7f19f7a058816661f8756c0866f8e6e9b92de8d99a214cbbc486d3dc78f20ab34f085f4964e429015a7a4ca3cf01e30c5b150bd8d425a80e5384915f58cb7b2e0a286cc759a3e6649ddfd7630237f22aefb1f8978bb567f2408238caafcc64166f1f7f5e2c384655969c0916046c221d5ec1d204285baa341cf1dc29c461494df880a902810ad03aab7824062487146ccdfdd9647dc5b42b1f6797bf61f14eb2b77ffc33a1a5cb3860ac432ab20f544a4fb90ba33af525b73746bc9ceab992b0b7519489652bbd43d1cc5637b2a82db750769e50421f7559a8fa38d8e72924b80ba5aafd60eee296d96890080358ab64f8f85fa51c210228acaab930f76071f1be5dabf7f902ce8a2a94c8ce5734b698a4822af3069dbd4ab9b2ab8423b432f5a933a4bb318822e4d89016d1e116bf8a62b00660b972ca6906cdebd6f475764eb4f7f624b3f0a6a26284624f2f7231b49693101836fccf476f894450cfda4e8e6b243e77676d5e3abe504ecb0e9ce940d88591f35d2f9d866a4e476e3440500130968931c22dd2ecbe499133db4a00ac3e315a87df285b1c8b9a64b3369a62a0078e5b8bace02fd00384005b306821cbffa59262901b40ee97d75fb24772ad690f68cbe0f0b69e471fb1a9a016f41354fcfa5ed3d782260c5b242b37ee96aa9f6cc7f38986ada8513a10030d3475a2a84cfe16a6042c5f898d5cac33d89f438006fa738955156bb7ff99de19d2699bc489865d32d59221022028bd766b8ded9d1a60d4fbec5e3a06bb036794c296eef0d659f52e8c3eecb093295a6472b1b2a49f56b61602c39e9083fd5ab02c0deff58eb3377b2f4a9eb893654a72e2b72bb23bfa768e8e882c380a32aa2ce906b617403c7c8c35287d3581f6f68e81ed432116f4c63281b786a4ce567e012d87dfd6a85926f6f15e86a98e012a9d0b7d56b1d4fcae3a7b1905480140a100287496493611203c6ec1e2e74700256e86b9cf79ece0127318f5afa398e4d4495b0c90afd325233cf22382f1e7eb6673fe1a578a5bc468401c7aeab9313b0344ac890453dfdbfd2b14e76c2b6136d58d63e60bd78a1ad579fc350c893d79c1a0e293946021cc0a0d0ae7346dde2afb7c05dbc12cf8befcef9c3510a41b6a7d125cdafa5214a1d9983b9aa19c890c31366b8889e89da73bcb5f1a0d977107166c5c39b470321c88a0bebac488ef95e9ca1c3f3191d59fbb022670ad9df061f4ec887e3d46fab851a0c104fc6431da9f1c23bde06839b7738b09e6d30ad8e5b4bf54cce45bf9cdc0852846e42a4bb94d57b85706803712542d1fdd8881041128908a31829887de25d9f180b71a171fb9e982e08c32d4f6e5c68e01e34cd8e21b7057552efc3f333118ea080cad7e0879c2b31f1480fb23ba2e44f75e853bed2d3d0170d2acd237d3e92c613f8c723fd8ffa22fc78672b47fcb509c983b92b0f35d9d452cf8b74c402830c30eaaa89b51dd7b4b2c79c2f7ce5901d03579fb59113998c3e39aa5b2df33b9aca4d472f60110d0d1bb89e503a544e3b19152fe642eec7047e8a57b860cfbd0ed633b07cc261c95d5bf8a8e54eecfe408ef00a83cf874d0c706a9ea620992cdcb334f1a16b8ae8f8426fe363b2354db5b996f4d8d99fea5ab7fd734568c329ee6443afc5ada014b0ae86af1a5718b2e3f33291e7d1cfda557df8ac870abdb021b874f82cc67ba36f85c6b305ddbc06fb1992580d2b77729f4952fddcd7d73bc4c9707a0e2275da22f42da8037516d4902be45a6be20020e20f4b9d586daccf1b5aa2d4e9dbf1c5208b608b34ba5bb0416d2ed11fa5457bcde55f57663e280e41ae31c0a4f8e63cbd2c5602b6bf0edc04c386515703b0fd74be28d8b0bd0f67431201cf888142a392cb2c460b44b8610455cf645fc0cfe36be9ba7681edd9737d86a601331b20d869466134634c0745b9ede38d3473b52c19762a41f932ca2d1f6496112e2637fe716056193803fd88f7a8928fcca57b2e5f6ed7478fafe76e2bf4b171374ad2bd17c24d20a290620d2c73254ac08798275f8a2991af88bbc6cb2a8c87bff47fc67d75f0b560c798064302d4ba310d440775ce5e962c2478f19698a71b3bcfe2ecd99b894e539832362260ed46c089bcd2056093bd35c42e4c84c10ce04555778adbacdf5ba5f9d67d967c4d8a8e3b2cd31eb18e94cbe082e6da240b971711d3f336dacfa300ff6ce48a1d436a4e0d5547c9d323bbd625a085f9183838944e6b505eb847100e622d12e89f7895f1a090a5f152e3c3eaf64d3ada56300a10daca55aef708f07285f6222a6a1a42887fd17a205311994e78015751de112b337472c269b051bb4879a7cc74a755d23e7614a1529d969225ca2ff92901bc034d75907f28706f61431970d04cd3a9bd964d85c33ab6cb1b7e6c7f36ef6c9ae23ec415c1a8d9d3f74494c4e0a9ece70cc8b36f5d90a505013a6d6145c61148072b44b57c13311f37279ab00d92861fe3da4635744d3c88631a11fc595bb3fc319723bc7026f800d28d4b36adf73ef09858e60b33ec32da635b3cf9e0c6ff86ce0e8d605aa64c628c139fa6846e97fc16a47026cdab023f70a8cd08f6a35ae32f38376873f3d3c157e7fee99c62d136b9b8ae044025eab2edadd23b03a89617db3616402ae6d4b5c1d28cfe85cf44b1ab2de31240aeb7b2c68160b902d80aafb51b6af42e4d866f7c64f25418defc4420d3400954d511b4686457e09f6fa263d619cf500884c5ae167ae542260ba4dff3a11b810c56c0c5eff795675ad620a447e4f91bcaec90ed70d8f4f84c04fabd942d1ee5afd3d80cd073980bd2becc45e21a8faa847a6341d99fe13204ed2765b8a3d03a61574f530d069ea3607270c101799b701634d5ec098c052de838326c74af43602c02aa63353a18b0a9ebffa8dc48c94615400466f242ef11f62165f0b6f8ee7ec9e7434846017c60c2f17de42e0220a2d4f85458e340722f240cc82d53166c5000e384e5a6b25700b75a5ee5e56a30eb47f114f8efd373af78f2b2403f2acf8087b33477adb32b9062c38b2435fd84865300e5650fef1f06b404920c9bc91c434ecf0c408fb65272ddd323b91b9ceefa60c1461827e3ff87b1d0551dadb6a5255b7396ea2a5a458b6a50135962a4eb5136f5ce473fb4027e028062bcb7ce36e52a6cfca2e0abc20decb4f82f2fc9446f5136fa80cd6fdfca828234ef347500da04f6ff2b19f315e01e9e8bd55ee1f44d31a01a24da9b64ff8f05dd833f687a5238851a438cd34c1d34a330d0deb204236c6b0f708d8a1c47ff3270918bc8bde559e3ba26202445c02410f1cac67d0248cd2d370230c13292ba46d2f1f6856ccb24f40a08d7951e9b5e0a45dd6f0dff07bce57d6070e6d37ce19b1e452b3a2661afbfe2fcd8140b72b669511c69abf2db3a9c8cf2d22cd0657e7618391323bc0f0028743dba7f67b38b6aca1c610c7d3fa1f3c7b02be48b65fb836ddf99f00657b69b1bde18122f073fe83d19bd4f9c5dd8b282507094270019145934254dc4e05f7c886463a231a075c4158b9fe248c5d4ac755800e5771f29a8227c471eeb1c2b94d690726e1d86dd9d3c2d4503ada23beb5f80eeb9411c953ad8c400d510e7beeace974698a4680a12b64d193ab0a689f4bca39fd4f8ca196a7289ea09ef05a090b5afcda1fa41b2a9ae1a5730d8e00563429eaed2fc94d8ae03f414ae52a229889457097f35659bd16c8c6403153680418205c68b688e6540afd1673eab01de47980b3bf879d6469142a30501a5a2761af19009964d9e46e3522d0447f22e4bcf9b875137d46883ac7b4ea1034146be2f4309be31db2926ec008f00c148f5466c230c692b10c8f84270ce1d48ffdb982b92ad7f47a9c261282e079bb665c1a5352715318cd3eae27e77b1cfe7e50f25145917e0c337901c40809b27a61adbc60bb4781d5417affdbd524458f1ae624360930e2d150b5f634b5b9e70aa7eeea84fb608c023cb6f7e584637e013118a324a11e060df4115763f6d1c49e123ead84209fa5144cbbac9dba17043fb45b4d8529a23ec6e5e6c8e3ed65557ae8779a623a449fefc3f5552441283879d88a3799814ba2a071d485293fd65411d74ef067874e81de6ea75c1f5dcdf1a8a25453dac63a011e77dc1fdc4c8aed5f0b33a5a51b25b65330d6fd9db6bb4a0520b40d862987e77fb5354b7fbe21f42d705431ebcf995ce318ed4452cc339a3bba5a12224f988b180dc0be7a43b148a11a71094e2de09797b693122cf0d1c83ddb953bca0a9a0c75b975268c4c6ff949a86aebb525e2e3adc0a03456ad79d9fe0d9be53d1b8be9ff69b2703b1e538e08dccdd96171950180cfb8a21b75419583e3c804733c4ecbbcb237c87db542f93559df1a7e5bb8a842193948887db25a846590f4659854b464f641712e26e214fd0e313fb813610376fc885e3d7c0f86bebe1bc80f101b9f2189496df7eab553db576a1bcf865d4890c6294e1bccbc7602652b25b9aa8da9ec398b9203601c7e18be86586042792d919ae3a7744231b6efedc23e396a27dcb48cffd4b877120967f4ed82e30a5a9dea5b545bd7d03bed8ff306ee7b9daccfbd04862275504d18cef5768f1829c679331282399e4326e93449ee6835678dd0349ad2491c7667136d85da5df68f381e4b0c2ac5366cc549ed461c68c453a85e680c6ede34ff85a3a1a9bc49d3c63f365b6908dc25dfba63dad591a7c013536d30e12e8b106d93119e8b3a9b29b56b963eec533a2a859de26c438608eb8c58d00f509a6b3f2aef1f18fdf7d4298ab3682837179e1e6d58a0262977264faf249beaff0ec1ea6d0de6f1cceee46c556ef367b370abb58a86697be1ae883c6d7512900b749401479150bef2123ed1602bc53176b32843aad9d76ccbd304580541318e33b20d615eb6234358e9f63c5e195c3d5decc1c4378d51a470dd6e458b4b9c8e9a458202c628015342205c78c55b7474f9eda5a3d5c7a0bf276c7a15937f515932a9b6fa0473de2b1a164b21ddc8d3a456c494c6ec1674151449eba583a5529ca81a90cc8d1660584e6680bb3b2c1226c4233510c790cc0127d40dd2c20f6360aa03ff52552694b3417e2d92a277a0e2281d74e945deab890c07fd98f3b7ce24bcc996a6ac0d9e8febe4d3879f4bf53fb1130b9f024400384a39725622acfe84f7b49c4580d8af75ff48fa4dddbc060e3bfe6691c311c1513cf9738153fdf1a3d977252c0806547130f96e79ebe8cde90943058b78bf3cf18927d33f8f992508e78e81d3a632c08e86899a152ae47d8d1b7a3a5452b2aa41fb7eeff1b152bf5a19b1f209983c5afbe398eff60f3a7c9670bc14624309a4f905703120fc4c53d49741127764bcd901d5ed57c86e676e474a88b8898408d9f580dd1049a7fb4fca257ebd5f8862d080754ab0906930e11723636f32e00718f65ce14fba49dec0cbf65c397d857bb34ead442c1b6e2e58b9a6136c6bccc44358843b5f539fca17faced355e67a367db4962631abec902c220788e3fc0880eb25825c79f2fd807f8474e536687519d9104d7ed74e387e35805bcead4275d888e1fe19f737bd024d8dcfec888faed762cfd19083d053dfc75b3164a9a7d344c4de586ebf4a2b2bac2a42a9ebe8a5aa441c6e7eeeae3bb3de1ae81a271e79dc36440a1fe5f1fcc2f284107959d0a058e68a28c68f5e51b14543288bb4154aa6019498d101acdae40a0535ce85dfe0ef2607f6524423673135cd00b34582ea8b1b0ea81c56f3bfb71f6c375c6d5bfcae1fff7ce989efa375b91d0cd80a75d01b0648ef5935d770ba0f6cf18b7922261e67c814df6a56015b7cc4acf52618f0debe1860a5c91c0d56310093f51334d4084c71115865e6fcd4fa6cf39840369123033ee7e53390478ba324f06f9dcb43d540d6c45b0a7981d84a418a2705dfe7523d9b4f93c72a12d0c30c02748962d381c7d07c8920e58f1774c53cdcccad61b663305ede2292e298197107243bc2c992ae656dd73d89c4457a5c644bc311f0fc58417cd84e2e60c98512d716805ad800424cc35bd000e6978b1ed018141b7e24d423ee24bba9aa9e0516c8722a0e22f111bed1d1bf5d37d16fe9bdb4c9ae3b7f2a8029a600bbc0e043fcda811e2d0454d28fdb4c84cb3911c6f60925a1a16296896a1f10818ac07d4341ade5718dd43838e275e92c44c584f17a4a934389eb348139e1dab026aa16f1b339ac1de50561bde2bc66972e2ace3e568d3f90ad2f65a74217750aa93ddf6b891b1ee7fd71a9211a2c2900dad7fda4712a935809baa7058455fc8177fab5d169c91e02618ce323cad815e450e122ab1de5e62c7872cf4d31c0b810a632108a14614049d06ff89c6bf1bcff6ffb6d980c05d53a16eb1d6e5d3afe8e82d395396a3c2a1cf27afb1fdf2deab93d3ac18ca6267ee204bc395911cd015cf4ca9bbbbceee04995b02177f4373838e9e0f3f497103a9d0cf5a5f9c9dd7e6661584ed8e9fed0c7bf560d736bf77dced50046d8f0a0d35e1d8dba91b350fbbf8d19ab824fe3f74cceea123d4bb7d077d0140192ff47ae6ed46484fb3e9577c681bf7320f6aae294ea8a5ecc45fd63c0bc940f00e37f5d2a2d8779e902c6791ba0a64ab17521f27f18fa3770bb93ce2aa494de471439b1b6b708cc952e469b06dea064a97de074956bfa172b5d58f1eb63c1477adea3cd4ef0a690939db5c2d5e0fd89339f8d06e904c6fe7a7e7cb35f37d1266584a18b221e8242a531d0aeea53c624690fd0da49828a016ab08883e7bd36b45874b6fde211423453aaedeaed60d5c3da49014e63d8332827199632b80caddf22ea9a082b1455218fe9dc1dedfd85d8e5d16de287aac9891e3bff78164d325e8aebcb4abdd10199d3b5ea0770982663278fce9de8b33f0fede9344779ff9ea5e3284242b77b1078abf77d8276dd6108ee887e521e152aebe936554588fe18e7b8bf24fab8495ac8a9f9d756a16dd27f7c30ef5f1bc6353aa1159819b9c80fa2f74d97590032ec70f8558696a06ed269562d54b220de86ac74c371c45cf991c5f1bf4b2cf5d3f7a10b1d8087c373da087edd2b4ff470a9000a04c9d5845fb598ecc7c7225e13cef031326bc2b00f488cd07677a48d31e5d7a23c2892d0f3f97c264cb1b839f712ade772292b25609bd5aa9ceb069265f31024c2707c16a503eed498ef77958686a10f4303372df9ddf6b6ce11d623c868ed744c52aeb70f74cd94a369e782826bf3660b3915ed2e7fa857f88594ac32f8e065007cc10d8897167a8a48baefe22dbd4980cfbe537165d20c2a9f73ae00b6b681e85354db51665933b45a0541b370dd8abf05f55b8113b53c5b3488c74e968f051cdeea551d145c4b58165a6fbb70ccaa1dad10f49e1354e7063055b30af650449527385bd665373082c26a9508c606f0ccbc8c7ca58af886815cf45546a1941f42131dc5b1af416a1670d517a79eb7e0d5c69dad960b11dab8e192b3b8bd17be988b4a680886a885c681157f5a509904feb95d6df9b053e40c879eb155f914ea8786a030bf613c3412e0d2b00e1e5f0ac68c948289c18a1181f93f8744237b5112a394b0ee8c536072880ba43808a87232b1f872af3016c6f3e5805336423bb9dc37cfdd00fb2a2e32895a00fa34d19846e57629e93d0c7622a029075be95d6839e1243cb9fcb40eb054a59d052ef092eaf40791638e24a4fd032612f921591f0dd22b8c9146a7185010ced658307006e0da5563980572dc7ab9b1ab5dc41d7bf47863a28efaea0122a34bf74a41ca068b4cb01d31635a03b061a12a6ad68c9e6758bd87bbfc00954308f287ae0f2eb251ed92dbda4ec493c5f50a5d1ab8fcad98542d0f7e9f50a8dae3b4d2d900af4405cd93ae3ba83329a4e4ae5f6bfbd8b5ec54bcccd2c7c2bf62511fc3c6aed7489b5d6d8d843406ce133c5c88cad20a3c65aeb450f6562410031f1af57db08504d81953649cc90ae859401d0a0b44443c79c2a3236ae01648ead052323afbf39102efbf0056d42a01c3054795e13ec4cb6ddaf09b19392353251b50cbc6f9fca6696541ba1fcec9ea8c68a8221328e8f2d8b282b7fbcbdc50a8cbfaf517e4785921d17005eb2b84e4c887734133894af3266773930bc7f9154f3b1e6967f273bd7511edb82e572c06834d9967b71808b0cd88657c57c392a3b6e03be4e3a37d65cd8591fac40d0a31f6aeb4079f643744f6d692678d6a4d64bb62292e284490fac07c3fa919806961b8a34f5cae03cc6e0a6e836d65176c3eba1f86f1c94f4eb5fc1e17c39302f8cf7e07f40a47947c03692e621617d7a93b61031f44234a020d378707b94b2cebec36dee621ab71b0bb74500c65ea63cb2c6f106995204d0b552ff8bcea1fbe8ffe1464b39822ebcdd74623e748e098f94069dfe67cd987ab8ed805d5cbd0cc9ca43596ccdefb8e4e970db4f434bc8a6e0653d6303cdc26c808748b4199101044b7de846c447648b8461bd6c1e154a7d139b5bff3b255190d8f4e2befb72cb39230e3bf29262a6c14ac1569a76ccdef0dcedef3c27a93ffba0132dd40afde38078494ba885b8db468d57125956115d597ec1da6005511a2fd9a368aa1046f21df190e5ee13699bb44e5418fc50c0d3083feae7b961676d73aa01e5a1509d40013106a8402b5920a00ea8e6ba23890fafea8d988c2c6b1a82003f926f674f75060091b37400dd24f051c43c59648f401a798d6608cf255da7874f6c6bd5630f80f04421752f2d450993e4b91b0cf94aead6234ad0dbd6d7894682913da9b5326721ec941c7f7a5bde1e5b9eea0b14ce2ec7c812a4b54588a13480b86fc19d540b1e020c2bdbe9421fcefda92c616e2e39fb2d2e3cd32f5f7da248e078e7dd198d549365585ab69f547877c4afd3c0a658bc158428cc73b412677033244600033b566041c9c87ffabc75934de84e03e8a1d77e01e937c29be4bfe4dde19e91ba418d40314a78bb2b02352a2727c6b7c103fddf65e6ef34e5dfd1ba086751cf107c99f445703e8ea253e7f33c44ad63827a85c13222b268cd2b80607d11ba5372cd99f58ebec862abde6b6c67747cc7c278a69c098b08d77e26fcd0992c07dd684031d0dcf45358f5b6599f86a6bd2d3efd59cc20831239467b1bebc8ff6337e27a2b64f70827bfe41e57c1732dca8601cac0ba609d8faede5ff6de5f45d459261084137b6c0a28f3210e6742fc7d2966af1a0d770d4d5b96b0f68ae5839770039873d0e1799780d82d29ab82fbfa3c34d0dfd3c5203960bf919256d65c54317e880d204b4085d04a14cac71e2a8c3f357a56d3f4c542985101f84134abfaf0a55ff83aff3bf5921afca1c4e9f8a93d9509d0a3da1fa1a03fd666036ac21efe825684667f6998a2ff606c322711fba13cb94259c1fb364dab5e9cd6c3221ccced68935f44749f7c9508e0d200478691d52531c3aaf1e793506715a875caa006407e3e5f7b0e2ae3830a04edae021ac8ca15bfd02f869c945ee04ea66bf5402953ceebd6d7b0243473487aa2890217fc8745fd24f3cfb0c292ec575b120748479b73c6bd410c7b734533432611fb186de95c772e18b3d0a5dcc75d8cbd991be10e8af633e9b6b7cff73902ca3e981f584f57ab58e0a7ae5df544c7999c61e665d601b87469518d24881e5f9b0ff237a6f536c2543004c49ca8ac8554730a2d679d2479f5cdce0f23a321623179ff0810d42278f935b2f7367423f07ffe18dd9477cac2d923d8d86ac1c5149b703c4da92a19b5acd8368d6e2957f5d47e07fd53fdc109eaea1ae2f59b9e47a39ddb187049adc6dc0888c65653db48ea7351ca6d08d92f2e3438816cfd711254277540c5b95dc763c25083a9daaa84bb989c3e1686deafacac05c90d811cb223edefb993d33b5e0ae5ce1c7b27570a7ef5f45fd65b80808cfa40f8f77f6b1512bcbf1344e7534c0cd84325e234d52ca9c523071e15440bdcda62b5f5da2044122df6c404f923a7cb7cadfc1549d6ddc0f75465f5816f4cf6651515ec833c65045921b42074412101997476ba69171a7a34c6241ca5d8a485ced9b6d55c0883112e1890598e5e8e03fa7bb5b8f4405b8d016ca227ba2da507b5ee14ff3885249d1c8e834133087602b86f0eb889b27dfdc400a9d8264ee7064b08379017b9576fe70a47ce7bae61d62f5c64bb1a6ef8f5a7c1ed0ea695e951237fcafe75c8521600d73d31637f0c8a930c9922ff0ce05e9d6b07078f48c8f3c855564572b0b42b467dae31263b5dd5e9bf3cd481b9f6e54a692ed4051440f1f3a8dc84a53e7978a2c0e09679bc62500a56f39b9e4fe98c9f21a225af6b1d32d12c97b6606a1c98bb5096499604ca60ff8d32f4d471ead35f2c3bc402b6a8fb8e35c2499ac086f48007d2b9b40b11b3611e0e82ce1b88eea3c7bb2232cb54251bf36e54ef5393abd4e101deafaf578e1ed971eaa126cd865dd0d368666c66d2dc1d550d95d280b203d27ccb3ced5489d3de36864d6314ee6e9ea06a8a585ade24f6d12cd1bbb2c359051e9cfaa9a06e6a6328484299647ddc1ba27c7fc4dce0739bbd217f043a725736641f49d25a1732be45d56feb3358792f012a4d17afe28ab6df2369bbf124fa5150f3d0907953b9854c633c067acf1034af73bceb9f3c3e014174e28ecf106cc3164d4a256f1eff0ee24a42cb5202d84d725a79f2259e152250498ce0ec5f348625ba2d7053f10eb95f2a4f516ff9a36d90be73f907cebf554d8e09ba1a35e7610fb6949e8cb3fd94156718cbe9fa6376183f1a478a78237814a2d8c1cf14024565b8efbe4fc632765a9de1fc792f3f223ae46005c731e098893bcc90897fa010a902d411fbf252f9ead93903964de82569f5764a6953b95cf2e0c1ac306e94ea26bcd2e4701b05a68dd6018952b71294ff8cf9e964aad1feacca58bcb343f20aa9837055d58bb8bbebf3f375bf0db57f53b0ea4e4b4804777ccfa4c00bc601a54b3e474c6d036c91274955e6db407ce8addd01a30283c7d2e04502b5dfee0daf9146270985bca3e7534606de2855b93319a4c26003a1fb2abaa1a3394a37033d52d815618831474f4260c62ce6930b699e8d0b76968093a4943810418cd962516ccef3c4cb3d9cb5d7752ccacdf1a42a6dc33a64a5d6b86534e6be627e93f7a3a689713913bea03acdef32e1d86b0c136df973a5e08ebb181817b64958c942e9e43eb17dd305944bb22d47d547b56f475b6ae5dde310b75ce19c4c8b9946dca5182ba9e3ddf4c4b894be4228a4a9db68726eee9d1b09e4fb4db57089768235f831af6ad3fd140d688a0338ff9644f5df29f7660238d828400d9cf7bafbf56afdab8a103d2d9122d22f417838d12dc80501c6ce5bd15b4ae3e5f7ddf0edbd752e95fda6bc70e831348df9644f9a2cc3575fb68e81180d6424c93ae8aeb5549b9e6ec9fa9c07fb8789c70b49be157fa8a0242d7f5ba1c37ff9b6bb46f1eb6f31771dd1e37813f03b75d245b55c9456ecbc18e4e4212187ffe692ca23248bf4616f5f2e5af49a7f601cbd8e12626232fa6858661e507085eb817d159d26a1e8e1a05d68e2873501ba081c7d666956d7debf6952ccd9525f5d4dac4d163f0297b346c311c4e63f9ba88dd4d232ba5c888b8c4e6513557b7c068b43697f3310f2509b9f85f70c3d7ab5889f9b5358c1083f9d604742435d6ceec2b927701cfa8103bf7975e813e32f8480e18e732f6eba260642c02a1e9ef206b77d8455582f7b8235001527e9fbf0d65f27a60339bf01bdb3fe9e165586106af9a289e84681c9b103e88003f0e682a5769d590401e7b014408dea9c4259029d84183e85d485f3a4dacf939e0e9e7f4b21f5c19175fe0fec846b4961a75f781a83611bfe5c051212bae167ecc81e939ca2946dc76346415be0b56aaaac6348f0e636b3445c031e6e4dd04c09c7881691d3bd53dc0eb02441f04af9f0a1570df5a1da81db31df9cc91274c055f192d6e2a789d52ed32a73143bb84a8da4c87e567cecf5a9cf921457526cae48dc28b96fc88790b77ddb85b5044d21a6df8b3ae33529245c33a2b8cfc508241fb448ea2f8c5bdb59c45067c42873559990d4ebfedf13f639f3db38bf37f853410862339c3e4b38f5e5458020e5598637e55b2e78a01dc97d26d9b70d0e140dfd4598a7ddb5dcda1325c674f228621b6e2ca9f8602f0720038f829dfea6e237d0cd8f23e0bf4b43b8109899887262cb4d2b6eeaf8982ca1558da2801d7fc402fde3581b9e593300fe64b8fae3472741ed2ecb405a059590ec6961fbfe6a48ad547ce8da6b8955d29999b49878918076291b49a1fb26f1523ddf61aa6d411a956c07bf168c09f23f1b38a737485ca8f120dbc3fb7f4162cb6795d0d9d82bf7f271ccfcfb3239cbb882513432c3e4eb3354e1685a030e7023e62a936afa704e1fe553a4b637a2c064e3a1204235f821bc6178cd1c6aa4ffe733cb59e69f737e4708eb983ed81c7a9cc150767a2605c92fedbce7661b55c55df7d5fd9e7d4b206922916b5456d61bbf1d93ae1179d485c1d6467e2ec20ed141e631a0fe8038702d08865814838314ca24adc8198fc6892a45b8a54021865e9cc0b718a51188b58332c76654f98add7358ca432678d8ad42b48df0c62997090915f1c6474e5e02c90828068fa43cce96cb4fac08a81ee12ca9593f1aac27c75279fc68c14c81f5683911ee33c7c7d48fec6b49a34a2b4098135954afa27cbf28d2f9dccf837c8314fdedb1d823763288752b5c59fe1669fdd6782b9eb1038541dd17932c1519c91fa4be9c94a2135a9c40234ca5fe1875e4707d814c6f3b0e0cb3c8539c1adbe390785aec115959275b8e5f2ef18007a844cb1feb075922427e95648475dc22f2a2a1bff8cb79096cfb5ae81602ebf8a1fe4a3709e284050a727db602eb875adbc41d6be3a9ea0791e29fa460bc7a96761b9030b6a95bb8af998e4859d6895b7e246ff440cf1b86ec9cd79267a5471f88231bf1f10a8c4e9050b402cc67e2bd612800d5a18b01614571a732b11094c14f8babfbfbc92ca4e9af3cc1311166daeb3064018e60029991dc6fadd7acc0f25ac5e5c4d710b03ce6066f8857afa21255c8924613baeab123c12a4348c968bfcbfae7391b145f57f2a519cfce05379a4e025484514336d359b721423ff6317347db9a30940490da816c1412b2be8151e324922518329954a9956503c2541c221d649a368ba11e1342ad54abd966a2425a7b0bf65427858e816b293b795e08ed92fae84067d09e115007d6ab7a20d5e33edeeb455f60df9ca8df1c5478030eec31e8448567fd9c440102bff19f9ffe8e73c576e22947fc68ad95748ffc8668b10169f091d24dd3d24b24f1bda08ffcdb81519ee7fdadb666e08fb97d96d9bb1057471a75904ab21cc4daa17ffce191c3a8e667f7c6415d409f75567bdd93f077db8c55e8f37cef1b3df95746a0b1fed3daf547758b6e2879eac0db094f8a9479de4e5ca768e0905e1710b84d348054ef9efe45187a862d84f68cdb1d1eb77c7331bbbdbd0c20b0e4f9d65341b9c9c36db28f6f823e0f7addf07087fc8657551b74c2073bc5e34c826e06731c98c901792ca280fbe4380463c7a3c73ee4af03daafa9a022d7c35526dba3615016b85e636e9d16cb929b58e574d74d016c172f089a3e7cdc6dd366d45c747549b5fa6c7bd92bb56f0890479c77f696dc2eb8e945938b3de5e9fbe76c6314e35b27ae91d689ad6058654bef204930bcdbae60c3f0d65d977d17dea8763b37e25ca9c7560cf47c34aedb6de24ed4ea56cb29ea62acede6b00e83d4f74c65cd29474f7ed30180993ccfca15aefdc66b43eaab114c5a1f7725a0e3eff778e556f36ff7cd4af2a0edfba1fb7db6b9031879daa3f0fbf01ea75c3bd2dffa35c262526beb95613cbc0a3489ca60bc79f3461341b7633978023b6f7b177e11dde1ecb5b62c0f626d00aa02bf76eca5685f337878193f0ff89e35c490189b9c677a311510090dcdf4ab78b2e9a770f17cf4dccbc4a41d795b1b146c66f6610e2437fb5cc642320020fc2d7ed7231b18007df730f70534687c0c804b5d75f87d82c1f00b8b26d7544376e2008820ff23466dbfa1fbef31e2efa8ed079d1caabf89fadc677954e3632f3505e6523b32c4b3b610d3cc5c8190550e43e302e4ad556736dd97cf7a55d015fe2822f2a90e57524da6d75925e75f0e654c54304862b268322cec588426bf6801ab878907043790d0a5435c620e255860c3a8b88130f87c5a3b5724eb83d50af902350466da5fac8f1a5e334d44f12481423bd281b36055f588786bc2af8bfdbf1293e84d16f1cddec897e7847c1d65bdf537b6c8516fcfe876ad1eea534e5c897e2a744054f4f975b63077efc9ac52fbf9a4c432f501a444c15e70b3d60d33308dc5e1407f3809138042175ea0dec764af7bc02899874b0dbc41aae268d769a46cf356098ca0c8a562421bd74a24bfd32fa890a068c58a8144572f5ade85290311ec96d7a4da1a088039102cfa8eab5ab603288461c1050176b1bf46f62f5148ab6f305ba8ed9f6775208a717d7702f91f7421c0f0ec08f9626891882f45b78e95e4356720d9aa5018e324a0148a4d09a28c033514af8941da9905e6d0ce07bca2839593a2069de70f1a1f0324d3e75653f3ae426801a5a003a7e3384b6ac6018028a1f5a3e6b78ebcbb1c0c82542b87b25d3bb61d84e6522e5779cc8c5b9dbbf5201507c5447c7dc1023c0c1aa0a43acc30ded5382f2e0d6366bdbe666b22990926c7c2385e85c0c76c65d0c81c73eb58fa51743eee878972f01a79b688dcbc2bb7a8953f3d37d35f41d76ff0cd310e055b9adf2e13f3d9f1dc2dc5c50f44299aca3d4a55385476b449e260902aea2486da9ea9be33e9296873e86b80de512d92baa31d31c852059a24632c6ab9323c4dde9a98a950e533ada75259a693ba76f8b5674d7fe9c036cc8a011f4ba958b453ba3060c374721a1c0c43791346005c21c5a1558792eae23cb49ddf40da5dcd7bcdfa641099ddabddd6da7e8eda5f778805258fd291eb55ef1bd1f890d1026e4160e1462e7b24b9e22a57527b6b0d677095348c9117592cb0fa76a8cc6b9a5835937755e36f3a5e49b728f65890aa1c02bc1c2255890195cb58022ed251f16fe05b26647e0faba85d2402969f66351ead90d00e7ca3cbde6ce843dc1c5256dd1287c505128ed6f76401ce47156317ebde108476e3887e5dab835997fe547e251825625188d1605549ed81311610aef2fbef5b40061b031508fb7da702fdfaff3263e5dfb2e98df7b0b5f02d98d7572134800573a0cfcea0f9d009242abd99f077fc1aac60801f60dfe59c564c8bb214b89f2abe0a196bb63c1461c15c1608a9cd8250997537e1b35f5e3b899ac5bd2b360195f57d136571a89cc2cc64f61c7434fc780cdeb2dc72f94857b0892300e2a42bd67f4119f5c8c5b8f2d5e8fcac5b64015b3ea71d32f20c28d824541410077d8585c43a414bffeadceb19c749c0f8bcfbe2ad9fe48fb634fe7ac3c021a32d3d6d664421863db0103a36a02dbeb98bf7f6f940bb9429ff45acecb853d4cfb9a3992052e72f81fa6fbfcf56d14ca1df7c4ce9ba6e4207fba3bf58f261623c109ed949146c1cfad4418d1ea2420a624ee59301c75b4a6bca78dddf3a65480e7e7a396305da80a7a615c0551c499cfebb07b81385a48f0b6599f801772f03154577e4c3e76b755bd75fd65abc83392d275b7c6c0e9aee2ddfd1326123d9c20116f359cca47e87a744aff545f00bed676b688e4f9d5f5f9e5e3b0b56dd2d68c324536104271d7626f3b798a450c9d24f5fbf67ca16ebe966199ee5db3f2a95c1d2d9542890b99d42be21097f205a1514dd4cd0a04e3e421367c40075fe2566d28c977da0b83d2bb94f9cd7ac3a8b416fc0b0a807ff17776a389d12ab3f3edf3e0600779712dabf5d028542f3d66445279c03e3295114446acd1188a89688501393155f9e6219f0af35cf30a713ab52a6cd1b425030a41143dd8378e318045bb58cd5348cc0014a930000dcc38c7e64d34f52d3945cb72abb68114be9d3c7f2f2e233b7eb7f61fea4fd13c86192ba242c58e4128b8cd15b0975fc11b63f483a6af3d7685d9120d835631784ba4c3f625936339dc45ee3358e97c6c3c4d0a389d44313fa18f88eef7cf9d218ec944b9d856c34bc68d5d3dc2b54fe59c7ff7bcb440fb91f70276ae38c26703cb3ddad5dd53ec7a0a6fbeeac3728d44368a6dae0cd753e38870d3db137a4967c4a36e3c795ba57bed15e7dae40c5273af9d0fabb4971a76b62f349fcb23f74c38431b6bce511087dae87b0dd11da8156f525d3abce9e507982f6c217daf7da0ef8965881ab410f95e2e549ff873cdfba77a090db6cd267182c32e634266bfef02c35c46b6f58858d0c76ddc5521b12390d55c2367006445488a151793f02fd7205a3cc21b69ef071c92e72bf7083ad9a48edd05a281e4a8c658d066bc0e7d5b053c31db99a58ccb700b66a14a650a986a321106ec1bab4eaa2e35db10618fb385d6b3aa24f60ae21dfc96a2a13c4ae9063accce95e4b47e47f040923de0504b06af9b9050eda3293273a9b88428052cd26cdb1c9a2b9202238bd9547c76a53fdb66c1b3948568f14a2b9c4b928f46c66ea0d3d8c1c2b6f028b90fc0293489e52181bc15123f5bdf8161c40b022b2423b53b874f8112c9d4003ea4c77bb643a2c9b4d818106e2f07715611109178d74fd1719aef39a23953b78b497b1a3c4658add6b95a93b600d38959f81a3ce9416a1b14a97bf1d19cdbc04db0e5141debead6419a8eb019c9145c77c842a3ef8cde5c532e0c495a277e85e2506edc684da23dc2ad2eb4a366057963066b2a0bd9a1a0e1b8793d7cc740a090662fb39e586b06fb768eaa334f1cbe932c6f822b741d8edd29abe47d8837642d8ef93a78a0cac6891cf4dc8ad9b52fda5b669c95df6b9b9313773176a8b16147e30527dcc0ee13e9435abb6a7ecbb2aabc71c26e66ee59037f3162a7ea16791e04ccf773eeefdfc389af59313d14b2cf49ee771ef6507ebfd7c9cef4d4e339b332994ac7d1f6d352d4cdf812b025f2f856b9b0060c6cb41c5c3f0b87c29fdcfd0e76464eb0607a892fd4d5bb86eef14baab47ef568bc300410ccd288ff172e6129942b9923dfd121249fc69d91e593b6816b891e0c7ff7aee6601d824c69d9f202d90e8e3eaa814cf6501b05dd8bf0497a7dc9510ffce0d5bc46a511b384fa1dc8289cd600082f2104e3d0e1f84c10625bc74c33e2f2a82aac1caf905bd82ee59696be897c9a63234b40c313cc2b988bcb78de36f010a0e96936598f9c58e7efe6d3f0558b8c0acf7de1a7e78447c14967d00d30bf64371be404e5ff58259afb79cc3284655a763e878936a2687df3dec4cdcc9e30efc2db5e9f96ba3b74dbf5bc7b91efbfeb0c21e3c3fd633420fec1b9f6274bef5749e6cf7d4ccea042f4f078a94e5e8db394c96ca313bfc7f1e505178e1dbcd8e51ec23faf6793b1830b355f7f3ff181e284f240bfa0e3a7bdb7bcbef12cd7153ab8166a198a7a0ce17005fa61805c531d5e7c1866dc68a0681275cf8c08be173c50167f8a3b80c027f5b8d4d3abcc1dd2972bbf9cc7b613cd935f4f1c30c45926e1fe0540eafa6ca28ca201838e58a221a0a074f36cf417a62f7491bd7ca49c4895ad0b538732b57170bd8faa00505c05ce615597801a2bc74e66633549678a7126610921cb3c5a4823ba3ee7e3b180d6a58a7812567fdf248f084a3fc342d43146c978fb8efc38960a7889b3711572474d5db5ff1ec4b9e0aad083aa2025d787094de973cd5207bc36f5f1c7550074d36e49d48e9aa1aa8bf6d43c8a238ba08855a61ed09699809eb2e28a4379c62a43d3e041be4e4f1740e4dc00c554a6b0dd82ee26505b3818406d9ab55f9eb482e43c7258871213185215aef6a7c2cead5f2c8a060521a344690c46a08ec5a529c5b07473f262c32fba9478f636982db75639d764d43654b47b9dc2de7814ccc711fdc2652cef018d160f3c09e27534c009137b01c068317347467ceac6e5c3b0b57acdb15649a358626425cea6eb7b0b05b37156acaa79c90794fc6fe86b40c961e911216a02bd2f593ed633487a839e1def2b10cf39a35d224aa4a5538224701dc968a88b85fb22c1e18c805631aef090e148ebee13ce8c1995dcd8773e9f371703d2538c1da05bcb19a861a95f5c70bb8768fc713bab630660f5601ca7102714a8e1f26cf8b734ab53b201a891127268d3895835c7aa2605dbf389385f0808188a918db6d16a6717a7ae70db9b1b85c8364f508c5b6315506a1239f45378bbcb8abf75a3dc449da5ec485d39cbc7a66ec2b50cbf2645c9f132dc8dfd2303001f118252899aee39ec46bc578f38696fc53b3c607aa2c23cd0abfb806cd70031a5292105bffd53d6fb8a6524ee89fae3cc2e13111cdea86975d8b5792909445d86f880c1367b15f1ac666036c2eccfcc99567d8eff5e2104c1e828a695ab55a5d29f6fffacc0d9ee04814831952d9eff5279d4e35272a4c10d571dee79f94a3254bcb2f75439898ed870b4adaae98f0eeda50b8072884600cb08b9f24c5aeacc16ff36c887315c8f2f6b5528def1bf7d78fbfa76cd08545bcb3939a6452f471d9b306b69d6ecbffa23c688b10bf820ff4f316e8733e0c69938ef4faacd115934f8c53848016a515e4ea0c00baaa7beb801ef54c4e62bedf3261044f7828e9869dda208bacdbccd3241c238d081d2384502afdc9057ce91dcfb3788281a583064b21e00e57a0464139d0b815cb5e38a1f55bad97484e45c50f5bf2e1492c1ed8c1346c27c12df9a9255163a2a742bc3a867f9a9ed3f6576062ead37035e53f77a7b1c92f1b7744c55458693fb6e3f1aabb3777842dae7849380d5618c57653a77a9fd192b695e23ca2182bf86585bef840556ab2e701676b9e212cebec0de2845f66dd42052f3ced3b23ede8a21bbcaebbe4c7a79c1a2ec7f03e8ba6fbd16eaf4850736a7e39e2a93a000202090df44cd47d541da6f85caeec4c8e648d0a46be6ca25a63377e3b1fa8867f95216914b53f5994fd965f405f3fea39835302bc6dad11f86f09d1adc8b9f5430a699fb20e32e8641d81ddaeee7610f03163639c7c7b665574c567948d565539150626f9e945adbad77e57f117d95c9736b49db005e029b0d141742d52878af51c74605685d0144b8f77b13d5e55301763016dbd965dee2bc3dc749870420b9159a2b488e93f0d6d99f79be02ecaaa4e1f92e2b932dc00428112ca2d2d41200fce0108ed339cfbaeeaf85cfcd4d62c7d90a03f7be859549a4efaf015f54114e1482cd8267f94ea6fd0080bb41702ea7ed15260409099750395728621ac9e8e130f628e127dd81178943e02bdb581358c3b1c0d77325657cb51083138d93c006944f8ff1f896c7a1f8c67d05d61df416bdfb0ec7514b4c6e1a7e407560b8f0cfb28804d717122a81a690ba1647bf2774a29a5140505f904000537a5cfa53188e1675a7ae3c6521938949403edefc6649ff274ad05c4951101fc42579669ad203796620afa4dabbf93f2864879c194f74373a82ec772ac5a2c2c0e6bb12c33ce1d73379e25c9c6f031d9eef8d8a7c072bcf0b14fc176541df8d9bb54ddd332ec5dd4b2a646a562454d0d0b16a64d7b8c6f66315cfe096bb13da8672921d916b5b3972635d4b294ceb4716baa1a264ed7543ca9610776e06a984aa5523c52ba1a16349aee258d66da7a504fdbb312a6d20973ba66e24cf4976929a4dc8b5c5a4a7863435deb432dd3e91ac96a99aac6ad7523539769aa5c366bb834158e1bcb29b01d14ada27cd5f0e71d72759e29dd8a9ae6d45487bb31d9a3a8ad261502123853c214868f9469a90b37d687bad6727265294f2f2295f1f3f0673f426d015b6c8b6475adf5c39519fd7ef6ad205786a3e5fbaa5ca6b580b448a3e0d902826dfa3b288be2406fdc99ec47158d4145752d15e5b1a8680f5db52c7b1a0ccdd5385d33b277dd68c0a067d078a2672cd949794968fcdcb293f27ef6292fd38032ad97691c55d39a691b6129cf26b5316d29508ea53f292ffdd9a7bd7df6e98fb8fa234cc5c46533a7557285ba738c2c69fd7683a155f17715df18ecd1ddc3e361ac7852ed5981dd2cf3fec54ffb3c71518565c2983b18d366ee78316d29cfdca5bc94178b994081e2848c8c6953e5c8b1ec634c9bb9cbe1dc4173ba9f3dbacbb41d73f7732e065487e6c8b41d06685ef6e6eede5caeaa2e258af42aecc503996b1da1424a964008340d8450da7beb168ab000040e86861d88b9718efffa8690d6b394818ed3fc0dcf113d1019e2f177fcb9347483463244830e431f102ae20598a15345c8e4ec463710293955565d43071d08d9d04368044227f9af4f08045c68850fa4ba054cbe9f10444ed4bfbe9f0dce1874609583fc7e32fc80f87e407bef9d7138fb6e881f0e9f5f0b793d574b929ce691ee21ca3b38fbbf3e222c0b67f9af8f480af211119e8f48097cccc3c47c445ef011b91d9de01c8db40c4e15212ea880852138084ff45fdf101cb9e85cf9d737440379890f4e62dbe7c30d7c3ed4e097fffa7c5042c995256eda4148fef5f980fbb07f7d41497fa63def7a00dcfb1ba37d39e31c790aebcf3e52e8a5c0f31990dbbf612ab905e3e0350b515e989dcc2375bce76a59114be386ed90329cf75fa1a59ffd49f481271e730812200cc0d165a13113c06cc53294597b157ee8947b08e87ced55f829bfff04ad5ddef5b377e5ecfbfa9c739e7fd62a2e42c6cfb79f6df9ea11dc5f147011f784ebf55dff85ed227eb97bce7914412afa2d629c2c03d52fc6c1ddec3576c6ed51f97cc578fd1186c2eb8f08e1fc28e06108fea380db3f7a53e7112247e900e01ee5b54a7a944aa2fc686e3faa397f277f1d23e78f301472fe8877d67b4404f29f80f84718ac84539c4179b198b3de9b8f248903140a5596a2288aa2b9478c220aca79363d1145511455a2e8b5d65a6bad354fe95c85afaca0284661d96707a0d67f42866115446cb6a0e44a4e16d60ab5005772aea8a4a85227ca08b39728723c897ceb8cb992f3b28cd83ee7d6df77dc380a705f508ed841bdf7073fe618c65889d639cb505effc791c5d2f9e67b6fa681efe873be31f9d2a0bc17e79c8ff87b59bb86f2d79fb824d551f7dc9c3ab19c64aa88124771dc27f2ca448f22151b59c47de2b0fcc514701671f97553b937101682c25ac6ee896e492e09976f3f1cfe2863bca9a75d528e276f18c9bb7d978fe4e78c3b2df9f909879d7e421a03aed70b755bc1283e1cb06b6f8673076557608f0dfa11f5baab547b5a2def5fde85f6501ed656654385eb485db8b63f2e4d0aee8aec5daad9e3b2c89e45355793fd9937b327747b351298940449d04f48908b93e2b1f7a6b3280f411fed655a1ae4c6521cd6b5c79ae2d25bab6ba90b57664346cb49173e49776d4a439bb6ab5bd3b0f5cb3122a096a12dca36f5d85e070e81c0140a7ef62d698d8a6d59205edbb66ddbfa68db244849da368911db028dd8a01f915107f6de94b66c075e1a154ecb52ab96f5dc9aeae7ca744db54359a5cc35c553cd903ab2ae688f6d59205edbb66ddbfa68db244849da368911db028dd8a01f91510776986a655756d74c9daecd34154f0d2e4dd5820aa76be62db5ea1a0954fddc5a8a876aa76b291e2fd354bd1c2e4dc583a9c2a970abf35cffdad3b58e84f6d8f4b7a63b550b2910f3a66ba90d3db3060ee62de5691a02752de5408a477a4bf174ade5848725bd4c6b0d91ea84486f005317804dab901b13e4ce0c91b42ce8a7652850cbd0966d59205edbb66ddbfa68db244849da368911db028dd8a01f91916ed7cbdecb31dffe56ef47d55b9e005535e9da6aa76579c5bba1eccf9e5c7d2dbb025b36e847d4f67a3e5ab6076cd9a01f51bbaebe1ebb027b6cd08fa8b7fa7aec0aecb1413fa2deeaebb12bb0c706fd887ac37f5f52e82aa4e40a18751d5cab89336130713f7b9c4916d5f3bd1e95a262f8d7a36e5c1a2bc774a8dcbd49f9ab0a9d4006fdebc92097b600f27a92bd372a7feff0babc8bbfde6f6ec3aded9d83dd9463b906bf3919e2d6f86dc55ffff2d7f3ddbd49f1d7739e3dbc3728fefe209d40fc20746b3c57e33faeecfa0de4d6784f888f7ffdee71699cddbfbdde1bd3f3a69544891bf5d77b5d5bf9eb63b3d3095de93a9ca338eefd49b5274d73300ce672ac2c6d3da9a9d2ade82ecd8e8cef08d5c4992f7460373275660d48c221199465be2c7b57716a98d2a96aa878b44a54215597cfd223aacef0c15e031e069a23b3c83936f3310cd5e55809543a5dd39fc7a2c656260a8a69eb71b57acbb4f5b8784acaefacceb49759643fc6f628f268d9ad853443462b7865ba1e2fc8dae3ca803e0e37d6feec533ffcec4f9850efe79c6ec71b91f2ccdd4b3d5daa2ac7895bca959595d1a5b37a5cae1a3cf7e352e96e69e9ea5d070d81526525b400764573a80edda13c1b501b7b97af4aa92ede8dd169994afb634fd84e2be8931d161461ba4461186aeece5eeed55fa60d25fa542c61a488d2e60bdd08a52104924d7924ebe25d9a1535cd993568581faa603b2d9fb981149a23bb2e4766e1c2b9a3d2adf0326d7bdd88eae7ce7bdfd255d5b461af6a35a5aa9e95a6742a9e1ccbaa1652c31411f757a403fbd0b461e24c9d59c38d656feed41296f2728cdc00caeb54909fbdaa051ebdf6d01caa23e2446980f5bec3f9527d52ed7979d48b645125ffa52935e5b931b99446ca8154e782bfd302f2b33f556aab7763b23fc1c7cfad1e3796fdea55d44545792ef4c695c1fc14189ac3a53c9408c3aff394aea8e34b4aa2bbba0ea76a963073f7d2cb52abe92f73475b23ac6705c6f249b56705368a22df2814696ed54ea5eba20c22dea715bdc430144ebff4e54cf7299f547b5a5afc8a3a63c5c3bceabd173b30ef1c5c5a8fc18df15bcad3b25ceb445c594e0d738c0bb9b41413bfdd56399e83a9e6cfa5c95e554d9fbb227baf9a365c16d9a7aaf952cd14d55c85b8a609e4cab23fc1588199bb4b933dcb0aa80f1408ddf14f14c7bdc91ebd7171543c78e606331834edef0c151cb1c533d9979f0331108eb7a3c538d8863ba303b623d2e0e35d39fc307aba4ed789607cd037f06f3f37d306b80f40206b8e74b68e6d16428a1c8b85d03ff820fb0f6288d059bad6cb8eeb1fc0b8e38054ccd3b25993991062f4127a8bd8fe9c73b88efb75dcb90ed161e8b98e1b6104d3a667246c9a76e143f066bb1b4620a1df7b3333a1347d8e15c33b0ccc61deae49c7e91adeed70e78cb78299b20413b20900c00008c0cfcfbb2bcb58c7ad75dcc5e5f033ee8600f419cd6c858ad4ea8112254a82c881b978d2fb7495c4abc4afd2dd472ae89c6740f1f848a3fd984ff98c7912085e6e799a489122d7b3881a102c8008470a08c64041b83957da4a3e735154c295f81ec493988445eeb1d2d1d111028e107074140c06718238c1a078cadac3ec5385d59269289faf691b51bbc6a6e5b26a6c608431cd4209b3745b585b5c3a71d6818023041c697d127d7681cf01473b058a3cedd3d661cdb14f8e01384291a2076c429b50eb10f480f101843bc51645208c314e8090af50e2dc479df369dbf75f8d6346467f9d15671d73ffa972de14ffc674b4cc842ccb22e470ded83ff16fcd6c06429609e0148363a6cdb43c072b87df0a98408002263f49336041670518e410c492140ce9c83210424308f4bf3e1fda19ef65786230c629eecde52744d92976796489db6c66638322f183e92fba96ef55f00853759ec5d2372e1e554a5759e928cb8ac5c35ab16411a082326d87012bca9769236e6ddf6fe7e845d47a6fc671a3d61387c1d27eef8dcaba6a7c792abedbb952aff3f4b852e5c1c138eea5eb4a9888dd2b0acb197079827b7e96dee6af332d23754c9659b9a90cb3d6da8ff76a16d65a6b7d3b0b62ff7abcafd6baf79cd867be4ddbf55705df510479e461ac8923ce9dbc31f81c47181af57d4a129cddc98967bcd6f7ca681df353fc1dadb5d6284e88b253bff75edd638af5c6d1c488224fba137b5e62cf40a284b9b7bf882d5b0566638c613b2637fbdc5b73557461dc39e6ff8ed65af79e9776a5a8b4d65a456b6dbbfeee68adb54a4f37d75a6bbed1ce846f166b756f0fb4472bbdf7f6eee4c4d7bb30a57051e4e1bb972be55fe75e4281a9ba111cd6392af7af2f974eec37cffdabcbe5adb5d67d6b0dd33b937b2f893e66da0ebeb70469a28b4b63ec744f7c634414bdc889ce84a3e89d09df7cef14bd93c0a6f370622f7a91e9a4f72d6562b4d67a466b2da3b5d6e5accf98b6ebafd65acf66646252a038218b99284102e605a6fa97cba5256dcd708ac6db7b9cb69c451847ad3d0c753974c0de81bdb75a52178b4bb913fb2bb29f4ea5aff4f54ab587858573dec4e6586769eab16b6fbd343e4a5fe92b7d2f5367d6a0daa974a03df4478a478a4722c9b2b2932a56e152abea47b52b8958f6b7b2ebfa5bf596de82da599d48b13d06ad5ad6d3325e0e08871b57866a21b52d27493e1037a64aa1482dcb36b56ccf453d7b2daacab7b2b2d2b4b2ab4ba9f6b4f05a70587bb4906cd3caae2c6dd9554a602a23bd39691a22fd80ed0f4d3db6edb537e6a7652a4dc227bf04ae6ebaa3d81ecbf6dadedbde3b8c1451ad21d01fa81009645bd5d55e1ad6bc9936d892fc11651628cbaeec6fed6da9f6bc5e3b1d2bcac36e6bd091cc9bd963ea7839dc58f637b397e2a549d216a5fbaac3b7cbb4148893213a446ad99fca068b0ab52ea5dae3e24202354a4cd71eebe337c4102929880e915a2d03b241d8bb73416aeab13d9676ed30b357963d1f2ddb03b66cd08fa85d57608f0dfa11f502bf6c31a21b714a11282828282eae51e87ab95e4519806189f02a468023cb57967f7923488c246d564a4a4a8a57755b655d595959516145bc5287d56ab582bd2019bb0d2c2c2c2c2f30699aa63024481060a1154a982861a208693c994cf4d7ebf53211038e5b88982c26133fb06d20eb18f55939f6f2f2f2720245f92361da4890208122c505366d1420d8048a91899129b21601ea11f172a3cc8ccc0cafc885d1c431339b99ed1d228d19cd8ce6c4a371aefef5115942a382460551eec88fcdc3e671aa58a162c5dea13b8956d4ac58712406568ecdccccccd4d418e18d29a0a1a1a161c182e849096a36b51ad97621d50b362d6c6cc87f7d47dadfe2a6458beea49fc1d1080b0396a31b9c1b13055c0456afbf26bfeabe313ff0ec1d584f803a200ec8c2c77f34c2f10007c708ce088dbdc3ab08f1c085071e24fd9d7e7d475ab08afffa8ed0d82c0c84039cff6501500e3ecb850bd3c66fcc8d2982e4f4af0fa874d7a227a82433201130a88502e4bcbe22e01ffff515fd2ebf3797f5a2e3e0e0e0bc7881e270e1c2858b9c9c1cd3969393a3a353b46ef28ee5150091b203618293d4b9552447c64d30c64c4d989a3035616aa2f5501032c450c4b7b8c5605004da403cb8372fda1c68b571c3c7a7498992bd39d3e63e4488bca0495211df434c9b27f13dc4b4799228f22dfa6c9ec4f710d3e6497cf32d326d2e261505b1833b18d43ab8833b182cb2f910d3e63e7b73a6cd7d6e34fd50e2e3e3e3c4071f748e8e16f95ee2e2d64a393a4674fed187c1f50b217f21d42f841f80200481eb2fe45fa8bfd016823e8263848b5ce4221739c7c1852c89bdc418b6c46489c912932526180f39a261044644bef9160a370fce4314722e1ae1228f1e4680e3e787082525cec5252efe0c192284899211910f59e2a292c8872c7151696f91ef1f2e2a897cc8121795442ef2bdc4c5ad64e4880bb95088b1900bb95068840832035c1cb2c4c51fcec5252efee0200288d2cfcf8f0c7a6fbdf5d65bb7e87d636bd50b5a5c5c4cae570ad3dfae76758602638c5518d3aa09ec8569d5e4058669d5048604d3aa0989125a0fad82406528612206133159914ceff1740a064f407b64316d1a88153c71c2b46d147a176d9669d3402852ac29626cc4c8dc9099f19999f9cc685434b994a858a164c50ad3b66bf466dadaa786056d88561baad9b478c14b931637492f452a5678e062eb21a6ad936a58b878b1f510d3d649349a693bd55ee49cc89dc791b7638b34d049362d7274b61e62da3ae9c50bd3b6fd0b9da3a337d3d649393a453a3f880f63eb17c1fd22a85f043f0041eb20085bffe0fe41fd83b61034914c538c5602c126c2087a0f316d5cf78961dab6087a336ded134304126ee8262df32346c90824f89050824f0926f89800444868c4aa8f77453848c6d40a3c773a0e67bdf7e69c8ba2a8fdc98c3192a8b29b2350ce942a65366bb9b8581dd76ddc9ad8f69e9ffb0c7a47800c2388ebe56bc8f078956bbcc33cdcc3eb0b8afb02730286848c44895809133c4cf078584cc44ac0d05eb1f5acd8b5f97887fb388a2ddeb53b2cb6a87fc21193dd23bf95930864302750f4bce88850a0f8d622c9801c1bbd4d0239f6007297633b9cd20b50a029458a1855d7127788e17192bee372cc27c362d991f8e7d63aae84b15e7f07efce1f3c7a2ec7403033abe1e2e171e566342e37d0a868b941c58a9a5edeebcd1e035ce0a86be5004460c182c6e2aa69db2b1bf467d362e5d7e20687470a8fed382deb4178a79fca2dc1f1a047a5ebb88ebb31431d891a162f7252b45a8ece696363da46df4267f651304d1c4fbee3441aa4882dc61938b11f4f3ac4f606a7e3300768dc1ace6118c4966b9eeb5317076be0c4bb1dde610df00c75747e9684a824ab1fca94b1190100500023180000180c0603491485391cc6a96614800f4c72505e583c180984a14820845118054110c4600c8420c420c30c530a39740500d234156b099006d7abfbeb0cea6225089375b11e35795157227e0d638dc45f271cd606d07dc9d00bc1b02bb527a560afa2a22dc1d2b8074aaa0a5a303ade617599dd52b0550ec05d27791ff21e7c0ed41f714df5cc8cc4e959ed8ad85247b544f53da6e64416aa746aa367a56a446af2a2af8a54ed0452fcf600357b90d712a3a3ff1b17aca2bdafcb4c1e44bfd2d77b09e590666e867785013525b06de7697dc0f380366a90b0b06ebc66ca02be6dac7bf8221933f7c0eacb845cf84945be8cd2090c0d21a62664b6eaa20f3e2b06e0c2786fbc5b38275b1889d47d7c3c02107525df8964959f8db37dbefa73603737fca86bcab8ee43800f7c1a5c779933566211c215ca24e8ef49cedc09c7208a4e2a209f7087df747b305575c09dde44f5422fa429dcdf35fa24728672581d80fd7dcf8cc2549606b636c60013b03137d475c204bab11e3ef6c228340b18a7e98f19b06365e0bd70384270a904e49bfa3830c69e8ea113a121a9da6051382afcca72ee2824530849ffc818610d16bc31e81e27c1f78b418ec9e3cf91b803dfc119bd3c91ef0e34489a616da431fb6c1dd1e25573f64c410c83cfbd4d846c6490c4556ae6a61f4df2556f2ce9ad11abfe8542484d89e41946c20bde4e039209ae4ce3cae3711eecdd3854eb49801d176b5707de0a9bc84f760b54f3863ae6046fdc3fb2f12e27050f3180e62cec3b66cc0e5a19f8540bb2db0b60264dbc5bc0578c738fdea69e5d7542af65179b9d65c2b2a114570e28fa12a03e9c3ccdfd2a1c4778609a7fc65475a05835cf2f67dc6677533c577130b24fc2cd77386926632086f5c48f40a0ff09492790441606838f3aba989255417d22345a26ed39c69fa1a4cc3d3fdf76ece88a54b4858da4a24d7d4ad66acd4b6c94302c127a3dea91da27a481bc6ddfeb67c45140fcbee66879a3c00d8e71f1f56be2a61f4dda3bb364f74a7844593161acceef37d1012f445009a25da636dc1f655dfa39b31aea0c3d858cdbebfde4ec7a4147ff1a6a360aeece1d10920dd4d83e95541c9df815a9a52185b4e13ff0b48a2845c3660f8e26617f423e2a6590a7ba132e8afe5ba7a321ee02b745a3c69e7fdb337722b43138e4216402533c307dc66146d8dd3311eab320e00e1128d901aeaa88263ce943546cb9032baadb391297a31e353d2e8394442b1b74676e6b65b71d7969520f8c1dca43ecfa117564ba3fb7b1d96d475b1e620ff42f80621533fec291f11216b4b80ccafdfc2c6882dcba0ab2ffabc3ccedf62b8b3ee9864235bbcfd032cecf8226c8adab78725b155f792d4e03cbc032107b050a5f6d0a8adb02a8bf8a99710b7dbb6f6d3c1a1e1d80c3bfc4525d5b17efc0caef3b32f428a262af3fce401b7419e96f54ea1d23ba955e0fe71fb7d4016bf75e40e6710cc6577e83c3f87d51b36d51f3657143247907efe6850db99ba9218cdd0590ae87aa0936d69b9ad1a0fc49fafb0bae2a6c4760e324d9f87379fbbca925b45ac437a1ab8cd7f930d402df89f1a7cf5ca33ba552882d952ffab300e80a012ccd09ac5ec0131ef4202eb6bc03abaa5b3932d7a31c313d3e834aa6160dbab7b735f2fbceac24b90fc40ee53156f9806a65beb3b6b4b3db8ea63cc41eea5d00c42b66bc0523e3121ebcb80cc2ddfc2e6886d83a8aba770bc30bc81f08046cf0e03094bbf95dd000b1f5350fd7d5f195c7e038a01c2883b1af40e0ab4f4371da00f457b1b2267b4f492ff49c9268133c2effdedcd2caef3a32f42c2262ac7fee883e50698a1c94d913cecf4e048abf8e416f19b99b111565d26e6f1afc5ba15574aabbcdef2493537229fb7632e7c860cf34c674a4b4f5f6bf36583d1ca6f8154d7ba33a214954c239babb9fcea7af17c8a9c97bf929bbbd5e54245702cb43f1054239d5a3ea73412e9a5c08c1fdb0664fbe99af8983fc6a17f4d4d3cfd711f06db6cbd25cad2453ef715b31b7a140c7dbd95efd5e2c05b59ce44bed136a8274534f90a273c5f0026a6d0f3bb3c7f46f1357211ede8ac48e4ad2f4336ff553d7b553d7f5634935793ba9b653405c5c9b950cdb98d452458b0366343d9ccdcc9d49ad30823ef9f4d93a067fc59699ca8a70285bb111de7c65fc5235367890b9d818ef8e8ed0d35351734f0dfdaa699751d5157a8c7b0b06345b44f38f39494cc3a5c0e0556b52b3ec3972a8d36ace6f98dbad0e587d875c92fe4b3a585339055d78205ba1315f3c3d26075da97db3d201b1fcb9bbdad4ddfdd0c19617f85eac326177acef9cd0f6c74a61421c395390a105779f3dd703c3ecc9df081a372b96cea3428b3c25476c29b01251a346c92c1331af43073aab77f3c677d756137bd80e3218232babe9dd1c4a9d86c7bc22a8219d9f6f0fba0649e1f37ad338ff9052ab46da0b7fe28f3b09fe8353b643c80c20c9d232aef8c5f337179be2ef2294546ed278e8bb84187f742193234767426c3994846b9402b3a282db2aa0b46ae1491a9f69799753e231c1fa48a36270e5e037b639b41f5d693567115759123d07ad014d4eb31a5e5c2fd3c1edb4f098f3ecee78dcec47b048134eb181c85c31ae98d833c1890cdac17615db8a9706d808e73ff25a0dbb9ac3b2c033916d03c427705c9bcd4491e2dc862a2735124d509592702f6922e5a50df604d832a1cf08b15ffa5e4e77d2cbe0c0dc134fcb4ee24dc5e47e4ee7eb1e82264a6d90c66570597adf4759bdfb10b23e332512f5fdc9ea87c713e9278e117ba909e9edab0941d4bebf9ca48dc9a0328d39e14a413943988a3be9b623c3f11bd1c48e41f4614f0cc62dce5978a29c5ddd067955d1656386c1f6d21bb35de5040229aa011bebccae3cd8d35ab24d88b15a40e0c0ac185979dc7095d1b823c414915db12b4fecdf5178febb355c0ca2e5c768a772833762346c457a28d1cb8b8d01038b06acabfdf8932657beaa5c51297e8429fd11bf05d085f1fcb246de9549973802bfd222a9391b1ce4cde55f41a68b0da97214ad34c940eaf9f47b4df51c1eb0fa7c5c38b985a24414ea9a30abccb20019467d01ba2a7c8aa55f9216953e9ded9c9c2db4c614c4cbce485403afaabd51f75f52f458f31b2b369b37fc1663005e86b3c4add2f2a412522f5c14b1c3a833b9b2b031c8bf34f04381b05aa687afe369e878a319cba2c970b13a34d0ee920769fcc9d15a7395182815ea49e8deb7e4348ebb974d6dcde0227c5a0f2d6d9869444e35db1e10fafea225aaa1cda0a427adf781f75d844564652aa7a7aaf640d236b82e522a6604fc976068b52d4a10fc4975b5e5001568f1f3d66e1fd64489268bea0964eeddc2dd75c467698c005bea1049091d898f8f8908c8b2c9e5449e96a5a51ad152e4d2cb67712dac678f9db1b284883d347a84363c758b970ec33bbf4a58080e6031891f4d4a28bac1bd178203409b72c78a754f65e2c9686e4449833eb745095bf838ddc1ce3f90aeb4e7e91c4621ff611aaadcdfb32f57829c964f79da67c7e12b88696e6be903da314226264b586802182f20e659c5503f4c97dade1ca8cc3b78167abb63fd8c9b841d7662a9f4b92d4184d2e94ae9246b8a0a91a9c850569319e03836f2cc1d1ce5d570097b63d474bfb4902f492af6367bbe626b11aa7c87be97aa145993132e690ffa31bdbfb30b54e5fd7d903bae82a4216d6bab6fcfa8f9badf274ded5e5ded5eb7b17992e005f5d67e45e32cef6e634f9ca92605993617a4767826fddec8fa07fa25f62e662052af1a9009f3f780797a75fb115ebfedde072c23f873a70d249fd5d9aab36bb002c2bc0ea1cabd78c546358ef585400f05c1297827699d8174d00e6d62014f6739591e38daf53a0c8bed1a97ab822045400ece77d65c8322eabf14edea4222034e9e8b50bbd8788dd6dd3e67ef88ffbb0596edb8d65a6b54ce901f7b15036465ccf254afa031f68ae1352cd46772107297a4048cbda2b0d1f91cec39a049391511414310e1b9e9f5ea62a9bfe3f805ecd03b77d38165076cc2c8a962861acf4db0e8fc7918d2b65cc339143f518c0996d24876148a51ca0ba3a7aa0673a9e98e4f20f70862917537420a138384de410b5762d6629376b08d323bded5c31f170da7548ebb61f642c2cb6225a280e610202a120703f29f6e1519801c9cd2f1e770548681b8a493c9544a41c802294c5ea26fc389ff987b91733e0dcb5530cfc5cbbccf7c12241efa1ff19c6d966e778c6882578e951a309c192c67ae2679861dbdc660a540394d2c95d99920a1cd200476ca760350e7efd41cf44e0e34a3100898eacb9dce3d2bf7683b0c689084b0e36906fa2cf67d05bcde54bd185e80ea2233f832ac1c4d619eda8804ca49b3370c4664fa2d9bbf164422c8822ef8574497a23ceb33ac7311ed42d7cd90c09f52ee7e7e30831448576557eb524a1f8cea461a006ac07306fd374cbb1bb699a4b32a15261722f92c81a045c1317ad3c30f3120065ad4058d1eeea808ce53dbc10da90a73340732981620ddff1d01a0fd987a3e3de01613c0efbd6efb667a41b17c67c654339d15ac3b3fb20b95a16723ff0d1e7a6159ebfda10c46d5398c0fb17ad1881b82f9e47de15629cf1c250a82bc1066a921c121fa9b7594c2fd89b52ec55c1554dc86e9ed2050382c7471240ff36e4949ff8d424484be3b9d2bb260608ee5281b69a49ee409dfa1393264df35c7dfd2635e6aaab55eb4d1b2b44a6d341d3aeb068b3c3accc97f55dd589c752b112dc7181d43da616592db510adc8e5e5a673b757d881da9d3f6da22fbe96b42ee68d5158fa1234e351610a82c4c87d896fa01f93dfa25aaa621b1d5c9d7015a0d3c436b1129dbb5b34236928babe0307c44ce762d1659bba117f95fc33ddaf205339a08073017b8a9ba53bb85049e9cf2ccea8843c50990b0f86d7ed3b9ac4bb9029242ad7061c5def746f784e4637f4f240f4a85b5fbf16ab0e183537df2a7906934b94693aaa16df513751afdf4a9059d9a6526158fcf6d4a2fd52f9cb2698004cebdf090e7826311d29104612ce83353a0d329f8c0a112afb8d7c090ab9b94cd6b0e0ab31f08ac3ba20f6cf9eae9f07b6947403d4110c37a122cbcdf7dc356c174af23f175c123877b7e4df7df3de5064a6ab3681e8561c62dfe13580d9fd902fd4d09742fe4b98ffbfe01b1acd80507a0a4e8068e724b271d0e2bd8f5d0735107c5e1e370d319f7d06933cc6f7c4eb1e720fde796a3e182ef1b5ecf96dd8646e7018a711608696ace03446420c2a220258e0826351b27945b82292b62d70ad284e5e0fada4ff4db02591b34216868a3e3323701d004824fd80c8372187d016d8bc8ccc334aaff0a848ad67bf7367ae647c379fd43a1b7bfe0543fe2956664d7741f90ba3cd9b7f17f128d630d2401e277388b13fb72f1a07ee6a519800aed8ba92983ad72d036013492fbea9be83d0a417dae04655dbce0f06a9d2032c3782314dd1d6611110c6fc4b9a36b74ec4f0fc372b979f6aebcb748001b4c5b1375d17a520fe78dc169f0d626bf5fa9426f401427140225b28f2ab846533cc78bc73985bbf9b87b034a724b2ab99167b3d9735ea232a4f9f794cde4f6737a4ffb961474e3c234fa1fa454d46cc552c9a0c89f54940388e39d50627a0902706f5a1450c5a13494a9e26f407da6ed91b85a3b8c2847b93b9b8b41fc75c9ea80b480042f9ce21800fa431ef1deea7d8156f5b612c923ad85e7ba3c695f982b43fc02a9a821f044deeaf16ce4962dc577e6c46c6a71876a68b0544a8c9063369d9adebb054e16eeea5efa50213a036526d84db6d465a16ea0609fdae392fcdc5db85a3c9bb051bc2be36e25bd0c411f59339120ee7905266a60a44df6a38514d5a605b52c91574f0e31f91d726a8c1ba35c0238218d01e5f0f09be930fb6725ad805840a5c438051f0fd095baaa30b759a5d22925a32432456b8df85b5b5b6547a8ba83a833746db40392597df068970da6791c54c20b865097279e976b4b036c0c96c83f58fba54c24b53eb3e64970cb52314afa216af7440ae0c4296b48fa4855da42a955563b45cd89348df99d653b5287bcd4ea90fa838b027bd15797b40e794acebc59cf047a99c0a9ac46eba58372afa4b0ae9a200b91ccd1e21265ae2a3302453c5610037f675e6b544ef8e872b7d8e46182edceeefe9bad1df40d8eddfbdd385c0a9c20e8cfd701d9d973da333c20d3dd0e4ac7cdb1116fd49f35a297f2a5301eb49d2778b180ec03cd400e1b27ab3c473715b83f1f5ad34c5457c8de3d1fe0f20f8c3e8e135c6ea1324185ecb437e7a83e4ffbdc12bc618ecc0fb1c9af00851ed36c09faa942b690ee77e75010db2a4383e7e242bc2728acd8f4cd437140755b9da3f43e9f360ee3b3b9acf6ac2251bfa4a83a2ace3ca8f7a3b54eace62249a2ccea550e3160a6cf5b8068f4f466187e85b7de122314ca84df8fff06042d925e94eeefff1c05ae1434a7794659ffd8c582edcb15e160d41a861f06ac09c6e22be19aeeb28f4b85a874a162809ea763cac00733b3ed5d7d8eb3c410ed1f4d48a7ba4a7cc6ad90641be222ad6143004ed2a50250621e1016443b224a2dbed04734402c1188503d1a980284a02ec61c4833b46f899dfaec8710cc7b8b81d3491b7de7333a024736de7015517867497324589d8021f4bbf418e51d76ba3ac6192752e4dad02ed7e5753d331a0d651971d4390ec29b9d999f38b1f62e2ab7aefb031be4b09d541fa0cabe6ff5ff145611aaddc2b8fe7d357225cf7f522abc8365a13d4785b0c26064a76b5e3a7efa65847111072217a8703f911e2031288d335b22a226b3a70f46f3ece023d6445c11e2951015eb8811c95f4a866fae248f9608d20b27fe736110a97957ba8ae114c28f6d1081db01dee85c6ce86a306875e5fc26bd2b08eb72c86ca321e291ac1da2b6290f6d50306bcec57b3d63e95f4ca84cd471df3758554321c49830622e0aa3ce96cd099b28975521e489e83de4f295dd3c74afb022e056e9e69a5a75e9d1f3339660c0604aa60083fa3164e901803370d3451534b7276492c9cbf28faf04062eb490f69deee5e6ea42f8e379e4646612f99e60c99fb4a59596a70f8465a57b531312a08cf51a192f617a997a7d02b1ebc9dae3385512951ff76221321bde3a18ffcc279984bf338ff5ce715a847ad5ff9dd5cc350884550115fcff37b3bf26810e726694a94fe8426dcb4ffe2fbc01870f9ead950234d6e1c812b39d1868cba351b6384879f604961b05377395e47e712d15e6d2aec8f5441097818e925051290ea7c13572c585aee3d2d2611c7e1dafcd614609cd56eb061ef260710433c13ea3df08a11cf0b57f957e6e0d61ca0d8259cd56f52154fa7f68600bcbecb521e1c51b06db88adce00f89d969975477e9bb96c6eeb4ca6ca32f3bd8c04c3350f987950b82058e0a7fb41d0f62a727f32f19f567e3a894a63370b67ffec550078bd868bd612b543fe87442dd76062f46c8b85bfc5f90c081dbbd9f13d782414b79d32495b08cc82a06e388bb45d54754d6172a13397a8c5b8681ab7f0ebfea654b0f2082dc13226c2085c714a01cece2a1d0ab6629b39a28043b9099c6efe4c5de7261e5d7ace527536fb942dd5729f1d11da6b20c6c5085157dc55804987f874b95912a056639ae563d36adfba69917aa4c7e42599513c885917f8a7400f4269b248297db3b58f9f2c3d5347d6da1d86a7e7701cf9ceb329afed40252332b37f697378da99c65f379b6a896c8fe006be59c5e6a3b598e21d67f6a711b69e92f7460ba9083ddc0140430ea38f1e99f397f31fe7dbb58add80d96c5d644b641d7e5812cd227adaf0489acd6bd86f15e6a800ca001963c75a236bb466999cb5bdde0e58063b602a23cec21307c26b27faf7015b28acdc73e779dd0d9674d52d7a6a4432cd117c88bae984f3a49772ee66d55c7b58d6ac7cda6e1f70a53f4c2220f142dd365404c08dc9c4916dd04d1053ade005e2f8167c81e2de9281a9a4aa0a14cce6fc88489ed0a647ec358a2978e3019a446389da8a8dacaafa512a19db1354fe04360388959b424a1c6ad345a853ba9e0e1d9d332523946da1e967472b18e5a6e656a7b71cb333a1f00ad6f79b7dfd1dc778e3ebf3025d9ddaaf9f20a7c85bd0ffac4fa037101a75be95e9d45f1ca03ad38edac4bf66aa4ba7f3c5f09e5f48ef9970ebb4bbd7529391daaaaa51d6b4bfb2edc1a04a3a91ab1c5b557bd76e6e940194aa83a8da079f71f2ff3f19e94b32c38746206e47da53f2070a3c76980a5bfff1bd0d5351ef70b9cafd5e15e39b290d80d2e305e9d908e53bad192967c4ffe01808c354a3ff3e14ceb5ac900375aa13f27c8bf6ff5101f83cfc099893fe40634eaa96fea85a7d55bf5392255e2c1c2639fa6f556b387b07f8a0c5292d6da63c20a34282664423e95bbadf1ba4ba8a99660097158b40c7b9a670391cd1c8bf399ec03873b620d7f92144ae4c7451d4fe9c032e897953dbacc9517add29e190e4211366c03e8243999ea19ab000c8a03997cd5f41a332a5b190141a89f6c9d91b282c8c1362652a953f0e5af4159d87a05a51a68091b9d4a3bb23dd22938f1b4da5dd4ad9ae2b2222b039de76bfdc33a16f10f2d2d6ea5e7f570da605f141a7603a7718b295398d5f0fd2e082e7a53d161c866a84211255e7aece5f3fa932b35c87678c9bcf1597dea0a6bee92658966c26c55adac2de01c361abb9f50b9675e74fe5732fa94d68ee067f9688f4fc864baa7875e125c4f3789805f8bb5904f7394e043e355a3a0c5fa35e9d9036063f48fa0720001a52c1651695f5932bd1155d7a18d75964ba0c67fe7c971a77147cbe70185eb4d6b5d63a6a86b27738834506fe39392edac4b765545a7aa7768be13a2bf9ac67f38551e1ab2d856be8d34451d159f568f288a3c273a8142f68aec531a37a515407342eba489c1a9c0632b142654a8ea2648589910f9c7e89a2980037cc0d36307d3a549f7dc9eee979304651cc757c1bb002d8df621d57b2a7db281bc919d4aa05c3b0c7337aa11f8812bd7f3bd85b75b8acf017d557d654106e515c8d751222478467b27280a8c9039ac64e556c1b084455c17a35b0009650b7e263e5269dcd6a42d9c695dd6fa7b10488ca5a2463a54ff774f617105537575de377d78f71e62bf06120aa3f0c58b2c9b2e1ec1ad2d3efd877a4e65979b1ff1c248d204fbe288b9527a6fccf42e1f9dd88f2b7f96e48c11f817af8916a912b5365900e39dbe271e57c027a67642d2928d540bcbb1a2e8b06123cf922a5c6eb41e3d9d734fcbe3244b1a09555c5fa56fd099a2a6f20bf6730fb470d7d50c528f9b723ef2f157a6782bfef83e4d31b33005762ac02d89abb98e45322bbc11ba9b54a4093b375cd2b20f9a40fcf92e298dc72cc4a0d28179ce904475130544725b41ce7829d5c6c7d473e99fe54876e89ae1ac343c77c3665ba17774d3e99f5eed8f4096e3729f6e48284da77e323145e0a018253448e27e39d56418ad0e439762b37f61d70e0e3a9a3e20eba32e90066026ec6543bd1c49ac29b28137bd2771a610dd3059dbda61779c67236938a2beca8bf830174fd0ad8f4bf24bbb0a92a6d481c861719da5cef18972d29649dec932bdee7ff22c9ff99afb40a48565c95e549915d6f27ff401e30f6953b3cc5aba58535a37dabc48b23520f50b628c175b4f33f65d1b6d24e49127dc7e9520f0177dfaa131c5d4d3548318927f97ae6e999f80003b453da43dc9e090ae36ddb33622c9dc60e6f616e037012f0e38d539795ccd9acaca73553a2693d6af5441a27c02462c898bbc621ed3709b6b02891453ed838b1dbe1f66e66d052488f2d52f7a07dc98e4cbc71329ef180227692ac69dd940deafd8c1101e6b335b58aa05d003e93a5a5971858b2161c155b61abacd795417ad0acd94a28cf9b6a9585fb00ae837a2b8e0a928a26c24b808f58a870c06d9ee511df64a9614b69dfeab5221ab1b0a0104da6ee2a2e4df877ba9f909d9b9f1cd30628e811411e6c101cf4e16f387dc843eb637e775e4304d8119c9c6c149e912470a627c0353441ca351337471c4663aae9e734433482a9828cfbb7370c76579ccf4f9aba8e3b922bba348c87b49bfebc009966d4abb9ad9c3b780d5064c3ddf448938b20c6478097489878a22daec523bec8568396d39e95b32632b72912cef93e4cb9e6023d7d3889127417adab682913d0e9b569d6e8ef0f933f0e67e2a5217ff19c5911646db1e75b2f497e8f9a171c8ede0dc7fe4e1aaedb558612150341eb323c3e1cdbd974a91ea2b67005f86b0668737cdc0af06e3ad9dace3051ca6390b6d641f676268f50b9a54b636faf45ae33bdcf78c909ae6c29572e7ddf64aaa72f843136ad7c9b294904317e223c84c2851b6f712d5df941b61e949cf6ad3c8e96a72f39db3c4b6ce971b5c4c8f68114cd028a40c21b06ca567f0f19c7e170e617fa74a83e2d2342dcf99424591f4ec29db961a7ed8511afc3c6d1bf5fa512745a460e0fb56a324cf597605a75b4fb3a37e01cf2e8b6f9d13ad32391d5b5c0b7c3a5d762359e8c929bdf862f9dceab57b6237e75efa8ad66d7308088453cb0c7d2442c579f4721787fb92a487dc2bf2a0f3d661a04c2251b70c11332e773f7fc7032e02bf806c7950bd35b6a9b011295dd571d2830ab5dd6681122499d1cf82f9424c1c453081b6e72905b6a0f9af9b4245dcdd21e4fcea6df1a8c079a2fdddf3642d39620466bac7841388659facef6fd999dbda70ea699e3dc6589cd140d4e337b13ae0f7f107a2e6aae92b779b6a0393f0a1f817c03dc9ac3c5ed958b6e97191660c9e8d75f3b4f98c5404b332211904745da4ba6d37b3b179f6f249d28a926d109c1288f0231ed8a3865746e08df682dc7f88dffe5e1917f0fa28dec46c320b709b1b5c650f83dfd456a023e8eca61ea7b84a481f700b87a46a9210dc6fc956f2928f7c24ea672a08e163ce984aea82939034f3a8cc71df29bded9f0a616331c2c692fcd22e605be0e0642b58547118025009567ace6a64be7193d2deb5d785cd6e49720065ccd69d31db32764cf8ec6b1fb8d6dc48bcdad3ea76593b0c4ee289c8b24d716d9fa3ffceb1bdc5295622a7ab32a655f311f00dba29d425ff2f7f7c9e88d32e3130ac0b63fa55b702cd1bf5f3a3dbb34f9a2fea39430cabcecbf23b3ddea8e636df9edbb39fabc4c1282d585fca9e7e5c59df38a7ad31dc8064633c5fcac603f32e90455c21586dfd509acb920c205051196c460456c94218c435fb3ed7a9832e223373ccedef1457d4c755292248cf428c820fa4ac2408b1d6f765722ec90fb2dbf4bc52d8055a541b1c88c6c9edac3e216c8b151894860ab2ca21e3dfec44facce276c5d4059fabdc26d2c712ec01965992a6fdccea82a7e7cf23f2ba5cafd9240dd55ae887711acaaf2568a27e409884551ff6c54be1f9b0a35b08b97ec726f34541759a9faf22ef0c411c498c213965cba835f6d5d80bbaf7a93802acffbff9549e841745963e325ee2b2d41f6335e1a7fef1bfa4e9a2bc19a975dde0d6df16afce0fb0a802d922f0648de255318ca365356882842bba622df6ff99ffd34add6de38ebfefa6f7c65abca3d01656464059b4812415c9c817ca26081c3426f50041e0bcc5b9416625d091a48331b89fb742b911f203f1f494c6374e48685654686604e82777010a0581843087992a823599a387aaf53c9309192de82661c4f3db4412f8ed8ce5c49d23a43a09a41a9cd54b645b1304b54fd1782430655af802a240bc7ac32ea73b7a1e6b7b27feb2face356ec45806bd7e6a9148254bfce5951c407867a7151fa20c8c1414e1c2e1f43df7543ecfdaf5d3139f573c436b7f50569ad065b43a470bcb2258f465bcebc3033075766c0e89a89e1b26f42f18daadc1f4cf26ba26a50e2650c70925cee23651c0ca010d77eb64bc0daae778688c426b7e1b530e204b8b37d987b2565dd5b2b26e53e4cbda28cf80acfdd096f3796e562044db5446c72a165494c1248b82efd9cf1fd8739bff0cb1ca95a7dfbf7868f46047fe0ce70198e878fbbdaca6f6ce07da5487bdfe0ad8786ebaef7ee270f072348bc79395ba634fcf80f495a89493b2c7ad3f45735705470ad1b9cfbc962dd65801d7fad1218993824d6459dcf201050342bd465fbcb993f259a4122aa694adb619aa33c41b0330b0f118ecd21b2790359699b231f25fdb6078ceda373247bbe1c4b7a3c765776e0bb279db436661604a8b6024876bc5c3c6f107913b716feb4cbab53e1ee0c4d92383c9efaa9d86bdf148706d56793c4e96e5bfbae80133a8a40ba6ece6d6886b809158a78a4e0373aa59026a5478a8069b4e5266a3fbd6621352345874266901bcc0a0ad9cbd11d76434f015bd8f370fea1ccd030466a839bc478c02cf8963ef7d5cddf92464aa4280ef8a7c34ec7e25846526a93184db47c33211a340f06d23e18b223761e9be4f17569f06c01e37a538074a9a29bed001e186988dec3e6f009458010cd02d3742c613cc123d51f33d470fca446922d193ca2697a1a27df579d39cc5271ced1f25f1845d45be3e805bea4507ea43bb3740231e5a9209684e6f62a939c6937cc605cce27147052fe51cd26d4fb0106809fa71db960ef758e578ad02a14b7f8f3833329c917f62eece478428e85405d4740c3373ddd761439de1c6bbba61b1e5cf73a2ff60acb06d8a515246e2af7548e044494fbfba4c94aa34094588b54e9c9051ad428ff38bc179dae521e94217ee99dd81952a30c75975a4fce7e637c5fe5e1961303a128deb4310f20848a603437ae3191775b838d4310dfc36717657abdb6760ec62d3a6e7ca70109b0aa46a8958d5efc1a27949a22491a895cc69f895b4954b7b46d2b4671bebbae4b5aa7ef20dd6dd9510b40c2b907264fb0fec1c9895c4af0f4b5ba124efde38e9bb983df88d370af3d9492034b9e199c9906123b59162744d5aca859c0a245bef4a79d06a67c086fca97431ab2292b08257e81381cdfa6f8e66ba8b4e4d9c0939b934d5c0a0688f0ac0c012a0abd235948b52023c6da21b45c245066e040e50c8a55b94a2cc40bd06783eb58a8d26101f6332b631e1fcb190ac3274694eea01399ab4a458fdc14e25fc05f2b9079d280de0e98c569a3168cdc6e46b85533d5f41ead8bf4ff7a93ba815f9ac3176510bc86426a4ad91d23b76348b64986776adf1d30674968271f76446b4aedae7258928b696a06c76622a38064bb26afe6d85131133044412444779763599a227d12fd12f960d169db73f38acfda615cfcb299dc06fcb605f20214d3fd335579f9b8b55c4a21120b889f6024e5a6e698128657ed7952765ee953ee587edabeb7e34c9f5ab51acb5fca9a9bfbd34b2c7a4978c42945fe42637a7b50d7acf27abb2088a5d05e97e80100f424c53d49fcea1d4b722b7bfc1460148706a305004a664fd4d789c3d02c8b5372dd72a19dbe9517d82fa8b69f907aac0c8df3f4fcf07fa012b68ddf95489f2487aede96c6f2cfc93624531528e08c62d879ab98fa0d5bc9f49be222ba8ec22d9ea222f21bc74bb71964e2ca064105f520b31fae9b2506adbb81fdbbf3d0da8e293a4d3b702d4ae8257b71d561cad70c470ad293e36f0ffe7e7d0dc221464629c66b14c3a4dce8709a3f5c9fd3b353c704c3a00cfd487095465b7db059c76fd7dadc80fe4c56fdb7d47bec23969e6d2a949e092ed65e4d63628de2be66f4039aa349fbd567e96f02c670777117ad6be9bfed67a050b81bf30d884e64e1d6a87b997283c4fc557caa5c718a8696f2d5f725d650f64b4b0afcf1f39a6abadd25908c64dc39cd2e0a13d8a8f3714666290a6ada789f6b9daf3b12426cc23a1bfd89c66c3e7e0833730e7d2837e9fbd8a1e4d76e971418b4906aca22532959a76e5fb988150a5f8d5a941266ba01950328fbe49285b8d1dc2212382343b7ed584fa6a61ea9072674e87183f33c57fec38c1bef52ad1129ecab04be10e836276092b5c63ee05a58bf7ce7408ffdafc59de43842050483f5a36840708edc07ba441152202ed37e936c74ae30cad15742a377e5860d2242527158af9e23e068fd8cf891e7e9a895e662a3d89354c6b3c4b0a99a9e508bcd765c5f878bedb815a73e7659a65789eb72cc3bf06c97a6b9b611792133033fc8fdb9e53d447496dbf873156ab837f3d0c84d1711bcfbe12611d415bf7a50d03d7dc40395c5d7ee540aaefbf273efbc29ab7c6fbe7f3fbaf24f00ff50e59996ad49b552e3be87673844eff1e763cc6ee9e163a357f16cf1ae13669bc43c3e3793eac4e7c67f83cfa569425bbecf87573adfe8caee55e86f90dd37ace99ab08348e08cac4842c24b6435483d57597e941d0d5ca1be510d73ba0c0d41779bca82b834dbce29bf8bf30af467aa07f9703a73b66ec2974d082a2a26e3d1d9500b421c3fcbc615198c6cfc5a25305f0707c578a4fdbdb0b6d599417c566cfe5f43d9cce35e6938f9c28a800a3b44632c83bbdd4ec638800ebc9ad0cc1c3dfb778398bb1efc461ce28717dcd0795e38e52645e0a330f29685ac7f6eb298cfa8bba264a309dbee4270ae332d50ba2040313fbd5fb3afc65d843ef0c6e575baba6a5cb627e0d8c9897f56a9b06d022430afba52b3c849db3a457a2ff40c1260a4d8a9d50ec03facce6621200d374f875b7f2eb8146056be8234c0720e1bdbcec0252bbde4e614aa2bac076e67944518f7c0da8286d5a0b8aa1e31d4ff0e8b80d4548a27d6f462ac19bd421e4cfd2855f9569df2ade0ac2905b545c9a7c336576e452c0540c65657d849ebfb4c4e3211701361c034e365d00d67558b5b2a9e4632a646dafd8f185a5fc394be01bceb9f1f95bfb111ca93982a13231bb627d8996e3475566239eefc7ec8a5bb7d938882f2cad046fc02c5289756c41221c1dd38d3db50ef54dd6257fbdbdabce1389a8ff2c25cbb2e2524d7b07f44229bc936920960661db0ff946bbba76aab0405133ca7362657aa87a244368ea6d7858d126cb0509a15206927a7a19ea10217c296df8c755e1f7694a4fdde16911b046c53f798fce332527acd130c712809a154dbc4cc839dd3720acd96b3c395f62caaecce93835780ab163aedf8bdbd0b4633abaeb6962d60230a3798b27c60925cc4637671afff70a572af2e5522cec0331eb2df079b9ed13ccaebae20a767da8a4268bd46b1eb6803bf745308660ced5b98bb10bd4891ffd410ef11d587f85069866a960e9c041611eb5feb72c2cadd85ac0938d8379826614d54360ca196c755f673dfab92308f590a320feb1b1c373c3afef4de5c92085e234a3535d8d5a3fc1e4698a32718b3aee58c0bed4e6bdd4e8b9f99edcbf063596cc46a1ddf08a2abdaada80419c26137e661adb167ad0fe1a332fe8cf480746fbd1d42aba4c6111a19f7694556131047b228ad7c87ecb342a2fa905a62aa0b2ddfde4066cdc196e970d8533b15ac06d4c762849583efb4d254601dd7bfffcf84c04af631097fa0ab3969d5462e52c868ac30c00edbb3835f0e7ae494f4a6f3d185ad0e856b30a034a880cf46e8d34a7fc06f27c652f58cf5dc49dcfadd29be369068a5f608b45418acf8ceb0f3aaa887922292c3ae08048907d4ea4063dac9bf4e4ab9ce8686e5c8f568ce5629d90d25ad635fa3405167bfee850c24f6680e8067f927024e021da08a1a47fbfe0927816ccb312dce635a20e7a22bbd944545e9c81d49773e6ad8cf51a123c85b55e4e9863640fb5c1002d1361bba187317f302288edd3860bffc2d9bd69b20824928a6494169efdac15b52682e69ac84a7bb35b473b4598f6f82a2e8db1ec171879148119078956e69b01b47981a2a6007dcb0493a06485ce3fa9a6a23f8e53c89e98147c3c5412aaa039d24f3de8432a333d010653d35bc0fbd13e39fafc62b5a061b36f69cb9262632b8079a995212135caaefb7ae4ac974d19b57ca6f82bee0618c4fcbc470f08cef1077ebaff7719e0fdc9c7cd76f3817a7a1ca8c4fe8d414cd0200481772f4771844aa35922f1a0e666b19f5930ed69d2db3019745d9321cd04e4742f8b8f830338b271a016bd2bf001b80b27a80ff1298c62c44864886d4d3d5ee02b233e5f841bf930692837d370de24651ff436408f1836eb74ac32a727c51a5e346b51ba5a27858bcbc41a825b95191d0e129ad1f837513febcbb3039e29b7ed2f0f924fdc2c5838b6e60962e8e59e227b06858ebc86eeb6f532ca5850725face13471294aaccde7350d39d4828b8c18795195e843ebea72daa64f55155de772a51262a4a330e1286a232633b3e7077de6626a41a5198300ec1420b3f003a4958389fc923e199f570cf8c3e475a7c23820d8fa13e3dbcd98035181a5fd34190dcf99521cdb7a830d62e5003f5f7ff1ec84db9ec8c332fdddd48e0a7585624df790609a529a6d87edad1df73e46b43b53de8533949b86769ae44ca507b29f9065903e08d0d1fe121904c19573c31aea2ba531e04b367a26db354ecc5fcb8b2b742d463f54f72a003b977bc1b2a32a2e89fda75f2ccf7544448df63ced020893b8e5bcd117c00047af436995a20562a520772a5eb1d80de334c97fdeaf45d187bc6d704b07de69149b7a20a6bfad3207988e4de34e6a4180ee9100f4d7fc0c4c2f03617c8e1de4fb84023370e5dea7848699caff76982f6e09756f442c8de726fb9a594324919a40982095d09189c3a3b62adeaa22db28419358d66423181369e4174c5f2b434ce98b766edd63914ce98cb88710b0ae49e05ecfe049650b1d807ae242b68d3590a674f87ae264f8de59ab1099b3f33a600ce13fde89520bf902afba32731419463d3c3a1ab94f4c21f9ef75d98923fb2a4ced170d4b1d3dbb8153336633308d38a199b31c9e508f88a86c650f9a8991dde83ae46df79a46b3a853939dc7f9fd37de9fd86faf74da064d1501a68680a8738394c552f4c551e5c7d1f5fd8f928853dc21d3486ce1f9a55c0c9b2a0962b25e9365838dcdbb81652d6d466189bbe94ab2e266b40299b6c3a5db3e7f5b5f438e712578d1368c698b8aa3e75d68efc943e9533fd1a9cac1d74255941b259cdf58f5ef49ff739a77bee233083e68ce6ad299b43353a63383b5ca434a669d74b5bd4ede7146243d62ab6d0789f024fef92b22d60caaa8029cb026a2e4f175da580c6d477d52d14c3274d9efc2b2f83f7a4f007f7deaf843f8ef0e0e40f9207ea306c386a95ad0052a61a60c6d4024899baa9904c1273bf42b2a7d27b9644dac290443a793e4a367ec43f7b60ea663075c3bf4058b9be0e237bdb757582b9e01304287b944057f050eb76818c10d9f5e78eab58762a06d2e7e741fa1cfa3872bf0b7d989e14a62cf75ee863e539077154fe04fe38f2c314a6fc49efbdf725f0c74a988a81f4dea73ce4414ad995cf9fe2b1f2f93d65775cac343b7ad0e0d5d90c8da9a1cb04c4faa7458f102d5da05d86ecf9290c71958f96b838ff1332818290b1653882b92af502f53d276b8e80f60cda73f4dad2731043418f78cfd168684f590a3df488251cd800673275ce14b2e96b21a8a76fa347148b94adcc74b9052c3d0af49e0534bd0a78fa151298aa5d965fcada780b2859289595ce46c66c6233d43abaa55bd3f668ba6fa863e8fa791b438f8fa231f46ddc67a8534a6f48d98efbfaf3b3c1ff06ff8a72950d1590ac9c1cd3973ee7f4de7b98b2214ef772f3a09b0b534e71549efe4ce9f3f328e507c21ac54df5a694e60ba239407f0659a34329a6b401b2c69ffe8d5c5d40c6d0f1db432f7cdb3b2574e9bdef9ef4f8f42bef837bd3af843e56fe9433cb5717ddc7911bf2f0bcf007e957de87a914fe38721f83384cd51bf22085a14a9893e37d9793b9cae56fd47922cd61a955805c17fd204b988ca2ab2377da7091dadf3159369ef66caa5d3ef552d6f2f405cc6f03fc3e0596de05343dcbe85bf4a3549e04aefc0b2b054a160b0a94ac3c4357b3e7b5e98f343374255994daf051a8df33a2972cfa34a2f087e8bff7c2ef937d99ca70506f7fe4b65c71e95656189831f2025286dab0071e42cf47d1d5910a48164a9f7e7e37a45cf429ff0a48162accc9297dfe1cd37f49e8f9f367ca431c2fb4e1111cd2e7e9498d42cd165c6753d1458ab23fa2be148ef715902c2fccd59b39973ebf87a6ffecae9f0d1098fb7efd70bcd7d183c61079b94863c399992d65b86fcf4819faa21eed7b9c8921bff7327c7f7af9e1889cf698adae061a6747f7a38ce1e4dc144ecadf7b202cb97978988a41f4def310bd17fa38e2ef4352d17bc88345d3186cc1ba315d89581eff07fe38fdf719fc7164fb1fdee7ef40eca56240a1bc478536e42112853594347bbf853c4ea1a4313794617e1ba7db04a6ea4bd6f7253055c39c9c95cfd19f237aef73543e67f439dfe7972cd1671d1f380255c0e912d1150a4ad60894ac1e2420d84743c8331ec8752165075a5b47769fee2ec2305c7d174e083d4e1a6d4af1d5e8e9cf29aefa9efe84514a3b4957303aa2df4d7d6ff4df733ff34b5f8d4ab0bb1fc104e4eec2e9e282d0e384cdd08523e6e81c8130ee813988de071096e82b38035d49c7d9a217897e8258e4fe2211ae9fe7c3e40042d3d05b1c0e2d847133865391436b3bb9241541685b479020361539f0b047b9a4526c0424b6b36c078037b4e131fe368e427991254ceec1e471f739a7ad4e1305a57121db50076b40d1b8487d50bd16b12f58c2ce629b47279d52dc415798be8cc91668d942838c002630a1094d90ac3a591dc8d5de0d7398eba1398cba66d5a7dabbe10df7d01c465db36aef76b71e9ac3a8abda6b6f0fcd61d556db43abb4f6f866849eefee524a3cc563eaa57d81aee3190941d7f952a52773bfbdf53a1e3ef0df07c202c202c2929ad6a40a1a1749682207dce2419e4de164c914acd3d023ee6981141ce4c30bc440fd0f7a44893347e851b494e64312aec7872db298a226b4d1a638a3a5e333c519328880ab76c8c090006d3d9ccf144e78ea145eec30a1528392e0b9603da0a14407e303eb0168065f0fec872862b0d2c4a7a5d5e445eb02462b42ec07ec349f3901947d9ce8e227c8c7336a01c109176d01e1891d782d20f480c70c6ecf2f74f6d9c35575cfd7c090d3962bd4ac03ae92405dec6c297b3a6c893dce56501755ec710aa1ceb24368cf9eea29223890c55840581404c2cade3304182bd33a832056b64ba8b1f28505a1b13c88942056c61e052713319f162b735c7cc1c3ca5d0d76e061e5cc458d953d257a00fbd610c24ce451b0004b28e287359370832e5aacac3d0a4e1acc5e2c3985114562ac79844f0f6b22d1c4c59a44d2e0614d1b04b958b30650d05873073b3be0616594f4220739d28b1ce4cc244028e169118204175ac0582c984c2841c2c7658a248ae0a187c582599305e16563cfd40b291e4f4316c82a8e48d2c392cec258a2e05ce206422ed6d4e2498c956f78149c4620f961e5143c0ada1fd462acfcde839d347c401dcec022488fd144c6ca383c0ab260ce8830c402592081623f0862491c383a0e6f17070e1c2a8092c5029f360cd79d1d881dc646be04d022488b0fc25c17002fe61357b0f6e75afbe375335bd2b8b670ec7ab63f0d471106c7d3d5d3184fdf6b41972af47dd277636fbda32f0240f6dc1b58e9eade154d69c5f846134db0bca06cb4b8a46ca05e6e9c5230d507b9cea783c1ce9614bb6030df7db8aec77b695f56096bc4fa582356893ded8ff5a99dabdbb1466a685f1e88430546ab30ebb601c0e3d12a2554f54da5f4a892caa3700987a3ed59e1d3b67351df97727b6e7f63bcce0a8e56f45caedc0a800072c80c4000df8d0d03f04500c89e28edabae73a17e65b5cfd40274ae285bd2b6c434dbbabc8fe2c2b40dce6417f6016c974f7d43b521b36f1039f605b58b01d87688b62e0bec1ac66c0ec406f003cc5af724000b5dec90a1c6f591c18ef48c32a2c483a32cb4548264480912275b2a41b2648f580912a02d952049b2c7ba1d89125b654b254878f674599d50052e191415c524c320f7745aeddd30d765ef13a9aca8ac3809c2281757be39e70a698a7c0609e562e9abb5964c53f090e9643a3111928f706239b15cd817c4826241d92a4453a05a502df70adce2d2e2c2440b1ffbc2a8944bca45854c6142633263d244a33ccff35233282b56d069e9e14207282b36a52be84819aa04ed3fbe046dfa6328dbf45f825e64377a6e10095bb2868513d224d8a6ffb2579839fd9616e811ef251acf171b10818a5d7a7870eb1683dae508df43682ac4e52abbc36389b8ea657dde5a2158d69436cdaafa946553981a74b374524a69bd34b4d65af954524b8305032569add4d2ea78534aadb5d4ab556618dc8c4169fd49c34a6fc6d0c0180c18e3668c9b3166bd19e39691bd05ab7578b51d08c35e088471b716c2d8700b61606e86723ee5ba16c2e8b61648980b34aeebe39796de1d2efafc24707ffb6e03bd01a18e99195aef0d3a8728566b17a061feedad365060a036ca015779594a2e66c301cc79dc76b197710ff8de4b45195fa45106138a84eeb6042a2308dbbd6544b1af0fac7befbd579495e18346193d2f96c103436342962a5226acb56a2983a19052cad0dda953a79452ea94d2eaee1eba53e92ea594a21ef47c3a47141152baa5c9b6943f3e72b6666548edbdf46c02f696cc3f4ea1a1598b32b4476f6d7721beb37d269930ba72a11111f34922092023d6d8e38cd170d8e30c72d7d9a3a489dc5d021942c4ce931d8e30997da1c61e270f19b23d4e2241302140a2e707426082060f8ab0d2d8234d135e7b94b0fcfb04562461051a6bb4c808c2d24ed8ee42904b6cd07476a52d11a51565c9ae8f318aae7c36db39fffd6eb20bb3ce9a190129b3630717f6a419ca3fd6f7d94c0d7de6e2c45ec3a10f0915a147981d3d8a1f8c141787f2833ee4b33dfacc6b4e73719e7650281faae29e93664f543881c8186273dcdbef867b578df5515fdfc6bbeaf3136830d6f872378189bd6d5fbfb5ef85a9b103a052043dfa8cb6125bad561058abc59a5f414c574e731a137eb0e95757e9f86240b36744a7cdf6a4abc942f56c4ac202eb298368ea9da18928424eec200a480882460e44d22564c290eddf827b4031a1055098b8715c6b7d35c430cdd31663ccb6bf49a68c18c21550624328418455cfd8b5aeec5a6bad59e7267a0c1fb6fb971aa0837000922240818c1614914614ccc8c94efa6e5c856a438b3dc220608f3974b8b0455d42132bc0a801184a8664300465d79fa14962d7306a1b488c2b767d95ef262808199d1ec01270b0fd4758ccdf6349c71e6dec5a732c608f3a9ea8b16b7dac6db0eba38498b0ebbf11a0d8f5c523940065d7177d3795a6d65a3130c41665a4b1e3f3e384d788704faeefbba9f5c9142e6c7fef8a2736b0817318e34e5557a7e0301640491062d7af157f41060076fd2dc80bf495415f18b1fd6db74497661aaa70d72ec707919c65b1fd7d56eb0cb5d6cf033028630856541104cf0c58350abbd6d7516bad4fec9910aa9a3a6dfc80d21a858d08b144b8b69f1f2a4fd05502032a048fed62063ee4319216839ac7c83d6a141012a250c410b219901740fcb085a8ed215aa82127c4f6a8bf536306b5f9bd170cadb22550131e2128e14b682f49054267589026574cd1240954a7891850f4dd12a849cd0951a0d0c512519cb0c79f81c2944a82a06dcaf2cf81b2e1f96b28ecb1b4832061c896404810323fc796404798655fe197dcfe255f57c22496e999bf68cc5c61198e5c59988cae76b888da1b87b6b11317f12cc4321737b0c6de82ecedfda58cae72eb734b0643125a53687f7943ec8d78888b02a6b6972fbac24d64ccfc2f76187b7e943d7f7418cb67cf09c3b21fb5f530756f6eb92a678ef6fcece32a287c355fae2cc4492de6b1c6cfaf3d75b0463dff6e6e04c7a74792199aa0c189f9c48c4265b2e7cfd1feb0e7cf7183b2e7cf111729226bfcbd0c267b4e293128528a8e3dca588e909d27ec2e08cb700cbff6fc0d8aab681b6dcfb73fdc210bb33d9589ab64350ab2661b42a7a48bf8e7ab26c41c6727841e27ec0959e3bea5eecbbdbdd0be200ae584acb1a008e4932d024a04160e6bb5b687a9ede5dec087f92664cd1541a5b2f9d8c9a480b7360d45704570c3d4dc379442fbfef637148114dadb6f4f43a16d4129b42b984374514ccde8f014cda451a56c1ae0e2c4322cdb93e6a0d2944cc399459692fefe1c1f7c4e234c2c444e0cd1e0aa19a6b08b3e021a640d8bf6d9f3b57d469aa1718871b1e90c0c0790cfc596596c6f610301a4b60628a3ed3f275090119c6c9f19270cc80868d84afd5d0a7919db9d2043b9927201db95dc973530c87d034acad457a1abd446e7f6dc7374facff671ceb68f338899e281533c4a4037fd94a43158bbb00f329deeb4dad117053d62cf45eebb99f3dddddd7dba534a479d09dce7bc41249e5a4f207b6e2c72e60cbd0a51119ace39a5acf9be9beeafa8083d3f08482b8ad8de7b6afe256dfbdcfbef2d672afa5ecce1638b9e6e5198e39380ef2fcbaf024064e083431943547184085eb044a00e47e058b7e83f702cc1fede7e379f8f9deabe0b75ccccc0408b39b8a75d0a244077fe1c3e36f7f445d1c31c2e52710b676ec4999992286efa2e521ba168de2274825ad6fa8f6badb55ea11e88f05ae484fe5d434a6d0f154563705ee9381d4360363b502e940e4c3683d164ad85559e0524bde9a44bcea1e86aeab81ef536138642718f3117fee0388c611d86c170f486c158dba6eac72b9d674e85f45dce96cb59a523ad642a533160bc323f1cceb9159006878d3339dcaf7c07fe58f9eeb17fa918f2ab3c8ffc2a3eb8cf7f431e2a4f0a7dacbc8acacbef06732b2ad9c68e1e34a4206846b3a930eb9e11e8a5f4e529a537688adaa02dd485b2dc00f1bf80dcdb004f9f024ddf02a6aa0b8b68e43740c9a294527a29a594522a03fe2efc919ffbee478735a5b452ca72293500bd94e53149c6dea6cb9625ccc9c17ffa1cee4d5d97c39477efe3c8f63e4e780b7970a6b01ec1d15fc22b60aaaa803acca914a4d9d18306fa1f38a29852ca02c47a3e9225cca87dd3e1dbbd8f431fa2bf3ef46f9bdfcd631c7e19567e7b1c6edbdfebf8ba8a578f4665b4226a7161419d482517f07e0b38c27feabe047e4f02bdb771d27407b8ab803939dcdfcfc13ffa540d71b66d5b0953cefd1dfdf65be803ff4805942cd1b6e9982d6c7f9fc7f657873cee8f421fa250e2e47cefe5e71e6f7fffe2cedbb8fc5dea9f10768ea48ca66cfaa3292e3cae51ce4c3f8ab19c02f1bb80dbb780dd7b6f02f39340d19fc0cfc64d2717cf0e1a4347b5116d44db74621774780cfd5df70d758f33dc03d99e07deb6e7421f231fa5c740a6dc7018ebf0732fc3f65df843e5b7e7c26dfb1ffa319eb129657580940f90a135dc2165283d615d5ad954462498bb768fb5be6198f250eb4ebf0e7d7015c4217dc6e0e937d0f425507f41740cf47164cdb6e9a780ae549ebe1c65c57f7a1ef84ffaf17bc8637b53e843e537c9ca223c595f0a47bfcacb2fa77b9cc3fdb63202256b037102b7feb8420e9e7d7f05d70a3c2bcc56101200ec62900bd047d6e0bfadeaf3b225cc0d4150809eef899c2d0f7a84b142b4943159c28c2ac036e5f0f779eede0307af1cd7c31cfe1e4fdb0307af4ddcf0e773a94cfb7c62fe4c5b3fb9bde6135a36b5acde25f7755ff7755fd5a576976cfad3de1f57d50b85ab60377697b80a073171951357e13bbb42a9595d2e5eeef3b19fec6770d5f6ce41a1ebbb0d6be8603d34205b5af02ecf628b73f7d9ce7ed6765a965d7a72ce420ecad21eb5ec087f9f777d92ff7928ba4f3bd14e4c43b2c67d6b195d85585faefa7cdf4fd0eea0bbb73ee81e7e4333d2ec1c9b3fa3dec2177c6f76cae66c4299527c65ea99405bd53f3ac7b44ee22adf22c7b2ec0a1de3e122c5d27350cb8ea0e7d7cdda7baf126d7548a0a4a10e8f8a36fd1e74a55f9ff771da887e65999bc6d8f4eb6784ceb5dafcc9408f6dc66df56a6bbdd7d3f184b8483fc76be5da07c3b6ab4b467bae10b2634e93d0d8439c1ce86ff4f6986b7a8a57af6111532d52ba7edd735ccc53e6877b441726f40b222474e9493f762f529892e1f4c364f2a1ab140f52294cc950fac122e5f9f5207de9e5278329cca730f3d09809f6f8d8fb03f35ccb52b2943ce50776cfb82f00947e7e0ea22b92699673bcd69e5ecbc5a9639a619e6c32994ae0f3bc8bc600a185b6756b6b92ccd18c44d143859021d8aa65ae9a45a8e37dd50d9bb6ec7898eeeef7873c117beb1c4d522af82e9edfe971d1f4855cdd97dcf6c50113ddbbbe9bdfb6cb6927d1e3bb9ee7e4b9ccaa93008697eda1e7cd2f06d24b1a33eddf9c635fba5801fa5580f4d2d269adb56e4334a280145e5c73715a12c0206e18c45d3f93908372aab8c8ffe4f99cfeb95ca1ebc33002d945485f434f88694657a4909a8644a22ca3f4e75dd4f5e3227d95ef2643e1a2a85f281dc54f6cb4e9ebd8123ae3a246a149184ad4ef4f2333cd1f18295c3584817d3d7ae62a994d3f0bf9ca24648202c54ba4f736e9e6e81ca331babaaffb8a91bef4b214ce1f0f7f8c58f0be5cc4efba44f858036ad777710b95e80f1e8db896896a297d37b883c0ca8f6010bd8afeeeefcf0f069ddfcb5fddd393002ba79b8f6544edef05198efeb506d476d3ccc5cf477ba58771dfc084fd48302419b9d672d500367d2fc757a619f6846cfad9a9e79a51156f88ac994ff2381da834b1678b147b4ea9c4349d58be1cb8b8502da8961697ec42292d616c03bb0c1da1eb8f0f1a72c8a6a30a44a8d0b355786534fce9cf1f2a450f7f6c986bec113b4fca4b81a36d7f6ef13bef7255aa9381916bfef367d5e3797ef642303059c3c209699e3da2be1e38bc2d6de3c543a25d06bdf80d3b033ddfdd1d4cd51b96067a3ea9be3ca2aba631a8a03d6d0a7fffbbd113078eef465b6fe24fca8e080984acdf0b5b38d20c8e298ca87d710f7b34816396d5607d6e3cbc3ef7055e232eca40dfebf39e6bc763a887ffd5409b6674650a4d421e437f34cd42d34ce6fe3bbe3285a621ff216eaa11d9d434ab811eefabf4a7a72c2ce0bb68cc29fcd045da8196f7e5e5705f3e1e03c1d0888bf4c350e7c06be59aee81e762a925a1bb00ec2c1ba54ccb96e86aab4df929c7559b8e10d5c6731a7222e2aa54adf8a78707a06baf0572f01ea1472dd343baa665b5d65c2527142ec25c74e981ac27fc8c681cdf4dae4919998bd4c9a646b40adecb45fa2a7c37da88f7130480287e37dec77c6fe3390001f86ebecf0318c07723fa5caba7e408b42d953889ed036ca9e4084f6c1f1dafe3bb11bddd4c3513cd34943bade23cd86bed66376bf3d6e59cb79cbbcd5e693deec39cf5b80f8fdee33e3c66d95883f5d9be1b1f895860e1bba92cf959a5fa6eeaaf36fb7d1679f383a17b0f471726f45320cfa038d153051e59e33d4dc1ce9fef7b61db5e68757ea8fb73fed87ff3b7f739f0e7470522f2b87de73f7f541c4f7115e541ecd43ae9eca8d078f083fdbe5c7593d85d73d5a8655b14851eb5acd68dfbfbde77c37df7d50b56173f1c681a0b033dbff4a64fbdf0b2eb26bdfd77d195c4ef0a51dbc525655255c266ee8bae50f885694ce9ff4563e8f73c0f8d51f1fcfafd9ef7f99e77bdeb779ee789fceb777ec8f33c917fcdef5ddd6f600da3efa6befe5c776026d5cc28a6922c3615b5ecbb81ce356a9be8d134dbd904a57befe96b008c4dbbed3fe5ca349331f4fd4d4fe4689a39f7b5bce0256b4a279f531297ac61e184745e41d0dedef270b2eed7ef0dedd4721536d15ca4a6d9679a9984864c524cb50f340999a0b8484d432629a69a69a683ae5f83f5d12fede322ad1a4c55fdf21aef53428f9987ae52329c7ea4fcf492450a33cf4cc940fa91f2b008ea496f7ad24b562904c2f270cc3da08986024d3367c173793c7bbefd77a5eacfd6aea103260edbc3e7d9738b7ad0ffaed7186b8d427d154d2cdef7d22bd7552fb30d4f88aba46b4f6f670b41817ae62cd06701258d3181b44ddfca8a68171729aeb22bfda2a6195d99be4e314999959e149aea2703e94fa16976841ea58cb6470dc58506bae8175d6999762d7b69590c96650a4d331b68fbe3bb5e353d83abeafb3f118fa1ab77790c7d273e4c5e4b7a8078a048b2e97fcf7e1e13940a9a865ca47f01a9327da101a9320999665286fe94e931d7eecb3fe5b9364b2dbc6c71cbb7343dc1540d7776c19372657ab9865c99423da331f44b9a874d43ef072d9332f4bf24f47dc99aaea7abd198f92dacb3277525c0fb8878130a8fb1a1cbd0bbd0e8aa54a331340352d5e3ba76097419ca361f91075dc00cd47ad4a79e6b9bba0cf1406f3f9a6653b4cc5554881eb54ccb5ca42eae26f4a8659b8ed67547d36cd4535cc21853ad4d5fcb5c659dcc5c350445d36aafa7b80ab7725484b80aabb854765486b82a55c3ef79222e823fe47778def5c1b06d1578a40c7d971de8b947d3ccb5299ee9dcd7a69f1530b70072c80c8000330530c00174b0a05ad1c0e0404058d3820b09005f010bb0d9d55ecc75d9fbfc4db34d3f75af69661262b2e99b865c85daf44f2e570df1558d098aab241014966cea9a726a89b1c7938e0724050a7b3ced98689bfeb5d5b5e32adadab4aa00d33e95886509c3835bebee61516e4cb5ab6cb8b82ca1472cdbf37109e6ce341b86d845287b3a199bd5b13eb2a6745b37879bc91a96bd9216084b843d624bfbd281c30e2665a814af158e20c2fa0df6a7850aeda59e526d44b39f612d4a84b14bb5dcf29232f4514ad0a5daa63fa28d6a1aa6814a3db286851b9232f47d5c5a48b2841957b8b1795bd8b9fc86d86efad58736d1b9443e68628fa31dd7a6af03910f58684648b09d4ddf82a4162ab4dbd8396c01d201580728490081041f4481049ac3163bc81e4c2de68c684b2a82e4ec51ff1231b034b75e9daf3da25c12c0b92d036d7f6e796d85915cb0276ec05e68b2e61434254b98f1ba84e86c29c5a63fb3a130e4ca2a913143b2667a7171e0c28c4d29ad6e82f9f2861b5ab7e10d938767484faca545648d9ea1243fb025af211a14293b3238c1d4803284ac2e568ad236bc54ab0b91eb4b9871d264add65677d771800a7bb65c4c01cecc9e52d63053021f2ed29981ec13cd9e9ca0c7390be27eceb68cbf9bed6ef94486f69fbf657cb14b15dada5313f4b7d5fb28b0f37191067a94b4a9835ccd50d18f5eca2f7325c89975ea2063e897c063e88fc2711ad9f445e128b9f8c27126b1e97b610ec739834d635c384e21367d1c4e17d870e654700453b474f12b1a7ad650fb4b2023409172c9c25f12e537731a524a29a5cc5f11b40452038ac78171d5f6dbd36cbfd5df5ed2ed6e39f6a6636f33c86dfb6d9bfba5ccf6df123d5fd2276084f1b2e666dac728972bf4cb6a341c31a59452ea23898bb6a6031963bf899614dbbe15ae2131b47d394ed97dafd56a356c37fb7714e7cb553a77ead4b6dd6ca8f5904e84ee1de1a0c13df788b91fb284c9e1a22dc0b608b0d28a6d63442963bffe0c34d4d081d9b252360e8f2011639448571c08438c226ee10c3397912c61f267eb909e977e60ce11fa3b3c4b3a0bf7737d61eed9a2c1fc1daeda41dfc6c5fb16dc9144d37b7738b8c345ee071ac8967b9477fbfb0dd8be9bed8b0090716e8f853d3b15f67cd9d324573634a6c6e74f1bba9a42e478e128c160619433192953810bb71d29737fb65cbcbab5922cd4cc85d9f77e86624ff07ebd2f3ffa132664dafc6131a73b8c8bb616e9eefbe76b3f0b006175df0d61de45fb38aee2c164db1f8115dab6b6ad8dabe685b9bc1f838cb1df64db2f5e75431c29639768ffd94263f6184bafc1451fbafa808ca91fe567c694b0045de5385d3e186b8d42bdcf16679031f3a74bd65c1dd0b1eb7340e8fad6ced96684a49b56155d2bae344ddf7f9c19ebcfa8f1daf571aa4cce7c8a0f8bd1175a02a9c1e358789452bab2a961119d67511d33355ddfa601ae92301fd8a62cc9c4be8b944507ed3f3ead2eb139548dd257df27434f9ae083115c2aa101850a0439a3820c2562f82056051076d0c11323dc931d2071efbdf73e91713a65f4609f7cb1f190c69320ea93218618ffc9f689b147e9040d599e41c38a8db70442430a3cc47f24472cc5f183c02442963031d0a37d4917de0e9332d4c1517dd56a8d58d946b3495c16c8c66c907562a7d3911d62898c7c5224e4a440f8aa7aeeaf93a7bbbbbb4bea945277973244f06f5199b64a2ada42ea7403b9d385907465518f9ba0b5f84f3333b383c6b84d0f9c59c3f3da6aad194aac2db9b8861952ecf9da0c1f686e8f2533929881831ba0b8e07098657b83ae1432284268044f4acd4099b1b3f5964066e43421bbb06b6a9a60916d5a6b6dd699dd160df3b6b6c3c07d91bb31e6425bc3f86a3d038daeb699d5a13294d9b5cdc02231c3d102b155160929da1e990568da2f9a55f086176e3859a8e777448f9ccc45b2edbf8b745f84e39af807c3dcfec1c0c9421be61ab30bb920ea31d01566738ed8dfe1599ded0142aa44432ad11852f49762fb7341fe5c105d91485c10890b227141433e4616f3475194ed1cedb4adb5d6feb0c7118c1445c6f8ffc328290a254529b5e408b6b970853d92a26c2fb9b6eb6c771629884a5290fc6cb829929f0765e51f1d16660db920b0d4f315c19a2fc31ff2a7fc19a6eaaca2fde7c0d0f3112063fca518b282e6d347cf66a0ab943f0d7495aa189420cd764ab3e7cb3f4202d5806495f4e7dc214b982c3921f4dc367455b7fba3e8f76ddcdef76f0273cb1be270f56dea566fbd3fe3a2947f2b1d234b98af095d1f63b0d6d6b575c2a8f45705c24b5c9031f36513bfc345659fae2cd6f6f3cd8c8b4fb36bad6f6159c258cba23ebdfa7c80dcb986997d4310d8307ff43f01dd453a0ecc817b1f4058dc77e00ab8cf1e8e987adc73af03101617ea90df0b431be6fb0471f61672610fdc771cf7ddd4817b1db8d741863a70218ac6d44bdd85fdf7274b982cebcbaae59744d777156409936507b34107b3b6be95528698031dcf28b4e731f3dd55be7766b22968779e9e173bfba4d2aba8c54a2aca18da14e4f6fc6e505ce895f47ac57c3d6d20a5bfa49bed5eaafc71c62e8654f460da3fd34df77ddf1c88b10d3ad8fc2c0fc697da21d6e522b53d1448571ebab22fdbe362123d5a1feb93dfdf4eabf33fb2a6be5d6522dbbeec0c568f995fc16d0a140a358a7962092d4e7982c80894829f10325ff462746704c19affa5e045a6a990036bb5e67b378ac0719151596c4ec0e6772c57542776309f3b016d4e14c12626549c78c19eaf8960cddf4a4a746900c19a7f730c569eccb7dd0f98c9fc4abf2ae6533783e3c17c9f628c6260046bfeac0125fec8bb67133eac246cce5545f5e0889e2f5b5286c2f0b26908844e1e1f920fc987e443f221f9907c483e241f920fc987e4ab7db5aff645e18bc267c4524a29a5d405172da59132167b0fd381363cc63e076a31c7bdf75e4bef0d5116c8454b690d1dccc25cb4166661d6daa00a849c3f235aca992ca594f281cc4902af010cb47f6bc78dd8741524482a70686dbb471c33578d37623fae1a31ad2589ab68105749a03596ec95b3461c525aa08040113886367d1c339ab137deb8e1a55793518f2be9788ce09ae17823e893697f51cea8abe36962e390d19897282f342903bbdfc41e6fc4268803eff146ec8237623486e298e1f842aeb8a78f63266b260e337044d91447189b72210e8c425d1c33d7ab675311888e07c7acf4125d5226073ddec031db747e8b8f9489dd88dd58e22a097446cfa67f23c855a74dff462d851c5fd99e1b4c709082637643e8c6d0ec0c1eecf1062de80c267bbc31e5866ce298b96a6c81e11872d5d8e28343c85534c8a638ec110794161f59e34f455a869225cc58809e2d67aeb5d65aabac95564a2ba514d7acba1c763c34e6bee670adb5e6e8d9f7472fc790c9712a2a5be62042c6dc1c3cdf127a7c69bdb45e72fe4587aebabfffe27ad9f155fefb2f435cf532047ce9c0179d971e1789b878bf2ddad2552f3a2ecafa363ef2f0c5e5e2fdd64b8e8b379cb9180ab97829a5600d1d2c1c0a679f0e74380b855670d56a5369dfbe55530fb43a34c655af14fb5ad7be37f6b66206278528b62f0f5d91823ce6fed5929282f6fd11dfcfdbb862c6be2826a420fc234b1afbfe06823e52e6beb498ecfb1cf8d272f17e0b15ba0a002665eeb700e997d60a2eee6762b2c69f0bc7aa831ef61dc3d9be33312913a3d0a8548d956645ed18d1000080009314000028140c080462e168389485c13c7714800a7f9e467c5a9b8ac3208761945206194308210411010000189999510a00f47ed792c26d6b419839715df8d19f6215a843eade5c69a02fe400785cd66005a78c4dcdbe0e85af23168717e19726d560d983e7bc56f800118805e06ceb807072d06035c3879e0f7857412461c3af0ff29693ef15bc59fa4a47e4f0124ae788a0df9181bcb516e4c4c82586ef54ee243380e982ce641eeada0760f45fdab1464ff3d8b7cace78f01604850d57b8aff1366b1669670d09166c126b87ca72b86da1a928527c9e37c7c042ea5dd276c7d7604bfd0275225653e927ad0f8606f413b5c99d4630ad453910d7761aa384cda40e3b0f83aec6273d59796f98e12dcebff03be00e806a1642873c86ebfa5fff5e7bada0de0a3ee190e7f48f35197f85569ab4f17248042be705b53969231610119bd2c11bd04fe578a03d8b2ad9bc51c920846bda1e779d4bcb3fb7534a2ee5e131b5ed06e83459ab3a010b3cf6c815962452915bbb31b72883c0948f53626597ba715596295f19f49a27fb99e5b410b194d354fb9e42865e86be9e7f5363ab1a4a1280342eef72a573892ba6e892d08d2cf5bd10661945160d016554df462f922b0a7b795616976058d34cf01e6316c60981ef787e49c7227010bb77cee4f2866ae5d913a541da88021685271dfe593cff3d85b31feb7bef258c2c1f96495480d2542d5efb22ff847f0012f55f2541292baf73562e079c249c9dc48f6edd320e007d7ba902ed7ed38fdc763caf1377d05734a5e3c3efbb1afe72c31b15a9cf68dabbc987bc12856dadd393e5690fa9bed1c5ddfc11ffb5b527bad4c15a48b54fb74b066a439c971686ca200e88aeb8530238f06ba360fe2e41d32c61d8ecce0e410038c638d2459c224b510e4e53b36588518c0accaeb60c8633660c4c327ba7aa367860a88601824abf74138c7b9420d4dc7aee61d37b4b994a959c1c3b2215b8739030c8f9e94a70d8b852df89223ea21f0e73d2111e53fa4f06d9936c9c2bba223f86e1eebfd08ad5824b294592e000f913e1b40f096e6a60b6446229d5f6f39accd67f5e40e155615c85b9ebea63466cf6fe0c55fff789be9054e9bae9fcf8661f36a519d26f44ac29aaebc0b512f9c87a06d048b6be70c0921d19f183c1085978e0bc8e8d36630d6e4905ecd88f4463afca1a13c96aee584d4dce37eb3dbac5fe93d7a1ea3ee15b902c2c51a0263051d16602ecd591e126f38752c48314ee6df7a988ddff73e847f98db7d2193516e12b771ea435f8e8c14b6d1bbe133ee39803504c906eaf601022242047c0ae5ea75e250bc75ab5cf342d3332cdd347002eb13c02ce2a9918d42d72bcb3140d1c4fcef60a10bad132a137b64b341e005fded82ff3c68b02902f85c70fff9b3e5b9d02ff310d88c22cd00a4ea481844499d0bbe6345d19431e9e6386af5bd4ed3570f5e6a6a4f54ddebf9ca9eba17c8014470914237302d702f6ed33644bc5fad0b0b37aa644d890bef748b9adb1baa3ffa274958d23053d5b37d30fdd3f66fc718166472534fdd6efdff33d8b7e9059c1295313026f0d46e3378cd7320289eabdf57dc0c58c5182db6b5e9bf7c268516f08836cc6424e2c05f71a81ba2e68d12f645ffb11b27b7a601ba1b447e306a55ddd1d5d39df49602de884f927953e76c423ba0756d8ee811017b2d181f7c07eb7e9769b9a02d07b778efabf71eccc3b8dec17875d0b0d87cc72004ed496230a61f23613a7b130914f01a40b6e64cab4efb4d4d6e042916ed29cbd44e6bd62b7f7b7fd52799de1fffd24d210eee65820687cb68285e1b92358b57366e81da3bac507586ae3d4746b17c94a5d4adfe952849249e8b42254910d0af5abab668e28133c2b6a37448b5d95f9d4a1090a7885b84a9bad6a53fcd08dae468b9c8ec54dd2b70ec34a1080082607350b1b5ee30eacf212fd2182951887b9136fd7999a59743e059714768eb63c15650adcbfd10130c3cf73513610d48606e8510ef3539684676e24d129e41d1ca42447a95c2be8deceaa59e2f38c8308c472fa20b383774ab83853dab8864bb3a676a5684fa14d2c80e52c26a5585df11b4d32b0b1fac955c1d01de6d45dfcc41b045b8b716182484d809944f3c040ae2c4d4da87e8075127483a77df6076dd1cb15d8fba25c0e9b471bf77fab627c1373b9352bf0750884731bc9795e2b09a4288c092111dc6a382a176ffc8378da373d58e76a09eb3fd9cba73deb98dece83b06cbde8aa1c09e66cafcacfb1e48ef47ab30019a593f651f8bc29067876638c03b65643b92fb18e5224e2a77c568e03c774b09782d40f4bb6c6ebdf2525bd76f8c0905301ca9dfa50d1936da6a326782a903d2abdc76161a9771789130472cc758cedf58ca7024e6d5cd8d8146b802c33ce63436e57115c499e0a64adfa698a120546059e3df861147a2013e51804e73587159b604f35daf4cb6e5e971b799efdcde3a742ae5ea0c458fc2c9ba7a036e6f6005689fc743547cc2b2e2bcced6b7ea7e35498986068d610df39612b228f7b7e901023006fe2e3f9fe7d75cd1d75c3b4d22316f57e2a7bdf77ba5f9486903a3aef515b33b2db10805f2e1436a1ac407a8b85c3b3756992b449a13e170e007dc93ad8e9212c9ad986f6765a0e1b9ef32b80ff208b98a31cd09fe403903f0010d2d06cb57680fa814c8b456667256e220113299dc203466b4b0230505a855edeee87040e8b22258aa3780ac3e010786a512adee0d990c6f06bf59a05110327be3054fb89013deec55cd1e90157e97ece3e2a2e88d5d7a8457ed3cccea16000c1c36454e5b2392c8d301db9444b3ea043d8c05b91d35aaab064491f335311dc0b06177ecf22c2a38b3961154709144de3430174cae51b0d713e3d8822fc5453d3533a586d2fdff6da03bcb35ca7a4257bf16b892f80084b7f5d3fda0d675f0190ea55a199b12e0e3d5bf19c94790aa7a3c19624b20a820897163524d639746e472ec7d99ab76b0b5938fa22e67104094e3ff30af3347dd87902fc1b3a6d6fc70e90969bea651c0e7dd1308edb3de6ce51e7e61673608a4359531b69255e66ebd66dd7ed37683e6a586dc98f9ad8079e57e4f3ac7dfcd20c9963a10dd02342c84e46f71389971a2fb596385a7cd15dbb081b02c7e96e1c9677fac128f7c3787f75fda7f13ce5dc21f7cc228f0c9f0e455b79fa0aa79843066417dcf89c05377bf9c043259157019c7066971a6d4c78193b8d32a012450b284d0307087b16b0471c1eb0c6ed900dbe2a35e43e8bc455a59e89f068ca9632ba8fb9911c5fb5ce9a787b0a5045332095abb1134277bf2064276bf3bfbfe2314ee4eb92b5896256bd28d460e0786bf64d5ed76bc0df12bd91ac994c217c3e0fabc098e4369eac636b3a80af439e4c419b7a7cd4691913c2036c4d416a2a6d5daa9b41fd373a18cb10e272ea594a43d070042faa4caca9b75f39171a64aa39a59cdb11e09a8f8785929ac0158492160ac9293d51195cea68cfce548e52b9c64334c4280bfac59d984d74468ac736a152ca66257881f327a50e114d8846dccadfaa82b49e6ab83bae2ad063e88ff9271237d9ac82337abfd24ef661b2c25581ae2b010f246b72400df2508ed338a49ce4e941582bce9d80bb1e7ede6f5e959be2cc1a60c58e603d60018be230c608c1e0bb9364bf972b7a39a3f512c345f786db2b03011533a0e588866c9af3e9d2c93c26bfef9f3ec9bc6f387f4434906205214801dc4e11e3ef6842efb850963a63c968036b617d9bee9e00d3254f1ba0c2211e4e63e2b01d4d9852cd24a468c6af90ccf08cbc063d2abcaf5534dca1d6b8de93d04d5666df889ad50c4a033ab0ba1a4b90f72b21e729061ca668131af754eb2803b27c6f9a1b7a1cf4661592e89307113228c5fc818fef9c53e61dd39b45dc8814c8a5b8242e62452c12df8e07dfc632688f57a6cb5f61172ffcfc3220cce5013167f508a75b86355f683a26ccb377c654adeb66a5d378d0c648c947239e22876f7321d2f436d24d6e56bc6faf31eeab49a355f1cd4c4bded12d480dfc1277d43c80fd2db4e102c6a946c74b31c6f37c1590044ce9b48424681e2d054811c165a55776610ff2f0fccf4b339f8378571350741d494fa5102ce524870b13a2482ebb2d10b03963f42fec4f84eab1b66f07a59ef0421760e4e1a0e9b34b58f0eee72411afbc5c993945bbcc0163ab4c96e9e24798b4c4f1e4e5e81d78c3ffc3c9ba125ed76573bbd74051587eefaa770c9d14aff5fe5883ef160d252605f80d1a94a43f5c0c4ad8b8e61a9b3b3e9340cfb33e79d38c281165ade6914efe46f9879a082f58e67549585c9513baaa1d8668674c6fe858186a3fe9fe3cf9c64eab1c889c505080026622d6ea1e4b26c1d43036bb3ea4d85ff81e4e72937fd65288833335aee8a6380d4dea2a10ee091fabde5052711a79de94012339362f26ff901afd491d7abdd542e178ab2e0b660d570bf90829207790eea213760964639bdb6e8764d8892b72a789497de139a7a4287d5a8e399cc20b1e16cb533218b7e5552e1bad59a963d8ff5dc00618db8963070d72d45174b0ab6b4372bb061bf6aa5b6ad7e1820059e512fee12545636464ad864dcd2e66ed9101e8f97304c81f16a8999025652158987064a00f21c21571d13c374fc9db52163c159f56c7f81df3a8a797400bfff7c647cfa2a77df75abf4d49a4018b69abeee1fe2831478002465b6daf03fa908794ecce55f92ba20603c44364df8c9242d6d11f0c99504bdfdf369dc01d884c1242d209607d5e0812d422914ef8fbaded303981e751a4bfdd41a3ad313a81194621ac5c8c391049647768c028e74269509fc518dc7ddb232b4780627a4e7bf323e4a8d8a6d2d4bba24e12f000dc3dfc9417da0e3477063c132f3427d921670268d0386d022e434329430a664d921c65e178606f29e59a5da0451c1afafe4cb0089e70cd223529a19cadbf6747a14c23cd79177e9d5d4a216ec96427ca89450c6bb11a9f97d0c39767793a87da13cc14e10f6a86313a43e71b16a644f02f3e907ca7d2516d32dac7ec13d03f87daa2051daa92b6d48d3e06f2575d9291b104ef5e8d799e9885a3f4e38b4d2bdafbf665709a9ae9c0bb68556e2a3241da2ae7cde0dcc382233c3b93a7f911eba262fcf87cbbcbfc8ce6be02da16ba5190527a2df4be24687aa4bbf91f7ef26df60b8f4c3f32eb14d54e3c082e277ea9a38dde6a9a6ca3a7b52e20873d4a11b77870a0337cb8d5c0ed74a2b05f5bcb9dbaa53bb8a2d1951e9440235bf65f67b576cf4a4ddda11883a327cd3d6a228b523780b17ad9b1e82d5c92b1d3854f945c5ec3e5513d8fc4eb031990eb7dd57c50256083fa160a64e5a8ae30ce3906b5c9d60be72ee7cc9dd453cd21052b268d74d62607467c1be1b1e4abf7bba60345ee3614efc059673e0ebc69e9d00b2c6937faeb87bdb21df12b37f89aeccfcaf491eb5b64d4e2847572082ace96fbda061242e2134bc4890ecfc23a80a7358bb2c80d4df4ab466e0e84a7f00d26efec59409b719842f25e71602f31ab14e62c413eaffd9d5afb5d17c5d5fd39425a9e787bd65a870d1af49af51b4c16f06130f876269afe973af75c8990433980710c6d61cb0d7879131e24a9f0c824ab02fef23b254f9c5e55518fcb9f53b74cc2d8ea76488a563a96c1e036ebfc3ecd3dff2bdf60efe564e1c12118e862e04a933bb4843962ff18f1caaa68ecb350b1f399f8316e0181f68b894d85b6f1a5c259104a64fe5fbe8e0cb9c212d3d20e1b9e0d57892cdae0218b88c393af83b66e2db3a689d59d3cc7bdd6eeb689272a63300ca56e19c63b75bef995961d0c6c6db0479cb25e06e02093a59329cb24180682c84a930ea8f4a6e37af91809c630b2ac72f4a033a58d7b6fb0a87eae1e2e722a5c36087c828ca5eb510cda820f35e3e409610738d773c5de338b059036549fbf25e7747814cd4ff7cd5d004c1c0854f5f2a11875b7c3d6acc8e288509dff5cbc8dfc61b886a742b6c8354c1217bda4075a9a299f5f764d3fc873d83795348d93f9ae3b28f92de725ecbcca8a2bb17af5ecb9bbc5c031edf0cbadca59e787f1af12a5f6e3a063ce305eaabeea43457a44131128b85174951003e14d981a8aa551e357ff305fe6c6a8e2e41813ed1b51763513a2048c5dbde0c0a9577c857edf9fe4cd0d8b360ef63db7391fad6913281c6d31d430a3dd9a17c26b03d0af0e83a114f3cc5aee28d9901269fdcf46444d1dfeb62d7a64a9b9c21b3bfdb8caf993a603f30ab18fbd155b1cda3265bd95b5785ae6d0d895305777551667713f2540c6aac9140c45e5892122ebfbfe0a37d4aa0132f659fa559032b09a20138ffa41bba44bc76a27744f6aa1098be13d01816afa37a7183392e1985fddb12b5045669b03b1540405aa6a053133f8da6b4a22b5be814b06d753124b902095876fc0a1f62a1ad599c8b132577e4214b536215bf2862ceb27bbb8a95806abaa4768d664db6737db386d5adeb53d5d2fdf18aedb6e990bb92bd38d7b566a7b3ebf217470e55f31777c4066687ff0f61bcffe5acf10afaae2e6d702306d96b5b8cb94cd76283d1acb889fb35d5e9707eae03591524148b6f3e26c204bb88bb88cad0dc581b495764168d838046fb586f97168885dd74b98561f303eda227ce3fccc60623ff6684d569b02901bce6063f9a3ac850bbe71d80331ba440b93b47eaa8b4543d43a3ecccfe6ba2d806093b7d8efbf56e1adc15e2ed39af65f356051badd27036531998864538ab9144df47752efedf99cb63f377a11ae76a2df79e41154e597f08fd990c38984c7c0417c8be3c8d641c5343e4658de7bf25dc35b5a0028185b094e5d2aea3e0e244c2edbf3cfc1185d0678c61a1d396a080594eb3d17d5e05b3ec3c5f4a2b6c2e3cdcce86944ce6a1ad225bdcbfee61c19bd3b353f825ec1c849e6c8badae93e2fe9e12f83948483707f90c1b9a7336f78f445a3bbe314779c483620b0579a45e28ba279b73553ae33f63f66272e0c4639326375eba00921559f9ba783854814fc2e93be2324341c056245295a83d78966d5e89efc14f823f1d5bbd57cea81cc6f95b0c85621ce7eba6249ada2a9fe8e216c2a6bb0b0b03010ccb53aaf8467befe48e2b12043841d224abc5b9885b61ed03fe9bbb5c2e99006e2abb2f308291a29ecb023b44e462868c90c2a381e40f85dd53c7213f3dc3c8c74a0c13eb03d7a200c037d60f1d03e75ee1a97dd487510eb1d38bd47fcb97ea80ba919191b3b34938de7cb38b440ef47b74f735c3c50153b97fdc872e2db9fad097c9fde49e60c6c006c43fbd7fe355d658ac84ea08ee4f09efda28ef470de9f704441d98d5407d12b82d96f53ed1d591c3ed6c64bb16a174e6ca3439a3cba57ac37058eda8d6efde15851cf0b4cd42fb14f4389dd09028280f0b1bb0f61eceb6c123769ea7d0fd4d26bc27e843331ca3a410c061c3f8ee315f129187fe68da947bd538f94342dcc8cacf84ca1bf161a816872d5a4daf5347553f8b6cb4f224178f922094c4262a9a3614b42ab164ad0525b72b219d8ba961bf5c0136e4739b1373d800185a475745eb0548864a4a2d0451255c25919040ae15855b875445f4e745e05bc8f436dc8369dae440ef0d5a161b3d6ee8983d532c822628522ef75bb7813dccca77714ab6fe500aae7a38dba6d55c359c027fb8841f4bef66d07204b13ddd38e76786440935e00d5a794fe6be1ead48e9727686f556cabc57d572f379885a63c5d820f605dcc308f049c4cd8d176c82c96c0509e60870a8b308ebeeb2f7d46607af017a58051c0b3cc2dbb4602a7031d399cc6ac84800b8576679a15281fcc259852adc73c25424eb5ecfeb05f014033258c4a3326b34971cd6f686ad0d917191439e2c2c7b479b01b8af12eb79ad33922d2b33990b524e689d84eb8a026255aab93b6a933731041e79cce89a93b7836335a4e213d2faec38a6bfc326f87f44b8f96e1555121842502977805f1ca92a142a64b43d9fef74f5c97aad88082313a433351255a90b5838486bde6cf029e5c5128613da4e0c5cc018d5e8c8d9e5893fa85bc364fb0149dd72ffc97abd8c35212a83e5442c8679596991e185aa536ad3a643b45b0079ed53e7b3599c2e7370e5de361623087e7de2a7734810b1d56b14d6a89a157e62ed82e373f62e340a2961754f9bea113c08ff8df14557443df340ae8c85e2c44c01c4cac31fc31cbc9a2608f01334148c0900d8ba59ebb8c065be09d56041e010e846b5507eb15446b7b4087baefdf79b493cb8dd3bdccd69de5690b49f949945b3b96a615682d582290c6581483667999c4b3bcccb1c9cfbfd95547130250b6a155a2f159b5b91784c611122898d503eff28595a8be7b6f4c7fb2fa528cf35652b2d0d7f4510295a0dafd069608804c286b67cb9a60422b9d03f112b5082a71b96c9e30d7f2b8de58dd8ad172efbd37ae2905520ebaa57e296dbbcd6815ab9d4c4e3eaf629e6bf8d8cec1b50769546285aa33cd8c3dadf0cf22ad07d9af156b9d84db277b2febcdbc150e57c5b5386f87dd69233e12d9eb0bb30c9bd761b0241de940272eaf90566dff2e064f3ed15852e76d150044bbcc0e1e302705004fbd200e91041f8fe7fa4aaebe868c7da6183a55645e291294573009c999cf29a9a5692fe7b84e43747ab364cbb269828f88618f3c3d9e6c9b588e9d9cf4391398ab10e40ddd8ed473a008c5c94145af8eec5b6b83b0821d8d43ce8bea532649878956e0b4b68bedf9cccf2f4f40f0e5e1e0aefff93779c2859d131cdbfca7b327dc5e56e0f713bc1e095b1820c734bc7ac2699f705e6eb4a524fba0dcd3c0a4b89c433cd28eb4a1187fab4c6faac151f6fcea569d777c516d34c3386e7a0d45f9179ca1690f0d568c359cbaa46337fbe06914d73944689b8286fca939f9b7a3e5e644a39cd9e9d4a19e8b3083bdb5b36844c3c7e10ea5f4364288ba99f57c41d4d6af9c7c265c078ea44c784f60a98116ad82b0c35e323ecce006c0f180912a8ed3243bc9a1dc48c9c823526e5134a17f1626a6593ef44ed198e3471eb6f1fee9127ced18bc4962f075432620a520aec25128bb2da98717e99a6bddf1debe66b91b9b9ac7785a14962ba04a897763a33a3ea10ad08e3be623de41f5c86d945232314f91a2d65f2ffd8c890f5396175b74b68f2bf9d7f191f93d33544c9f2f6309c962784b27d410dd47590b0299d5fb7e1fda5ce3847336e9d963678a54e7b52ed16ae4fd30fbf1008b1d52020cefa6594da76921680bbbb9768362681968225339ee78dc310d78cc9188750b7ca279597433bf7c7f0af19743b99d3133ab52214880f85fa589d5de7bb8a143c8ed800fc1aed37bd4d424bc2178eeb43e1bf10a119b5810d974b8bf43a45e1ec887445e6110b87d237a69a0e7f9e80668ec20e5a2edcdbecace30748a9cac4eb9ad433f571d8250fe6ade299748ac458929e3dacd686e56b8a5322ab7b672348623c092636201372f52409d7838d9c2560d038e136696b3336f5e869334cd612b4b5cb3b421a5f7cac52f651e298630b1d631b0e4a392d564c430474abdd4d36bb8f89122b162825a8800c93269d902edd69ac8de7fea31f047cac082617cf6c6a95adc15b5a8f9d398df215712591a6806990e3732752695e0ae23bdf3d620309e544b09c0023da378244a8fe056e3a951b29955d8e81c995791209a2bed8a386c9ab8593ed195d2d2bcba65a39f8d0a954f8198cd73e8fd7ddec2cdcfb5a779ae54cf8146067e1377bcc7ffd2ac1c0ede4839a4b262b0e981170ed63ed426341a5370b8a6552be07d8ebc2bd1cc2b26b1fb315cc246ebcf468f71e8a60d39306e8c4632677271a3c2b2b8475e0d8bf4a9ea832f4e54a09056f8b75a8e947f15210d456840fbd2f843fce42a2e8bcdbff362e2d04edc307e27ec156643a1a00e78f6b036430185343b12d939299ed2cb45ff92fb4672d97bbe5cf528a5ea189cee495288ec9368584907a6762a74333806a502b8dc621a7dd7ecc53b7a1da20b837b15212b5e234a0271853cfcbbb79a4948ab80bbe753612622aed5d81060b32e530cc3f106bc01b9a219eac10c868060cea48696b7575ee18a948f04f35fa3ca54fccbb1b057fb70dcf3ae078f662359ee0473ac3a645699807709f1eabba0b0da2e8a25987a28a2da1f561c0977ea5755a3ab28bd2e6a010bb929dc9602e74cca5cf3767fdcfaba2432b0ac5f0376169acc47b7d6ce0afce87967dc874b080ee24f9a1cf6760562a0616d901040460bdeebc9603c4dac15d6baec8ff1d63344e2a24d3501aa6007c6cbc9b368908c9ac7a234c27f2786eea6e8c72e1e52aa19b9297fc2002ca6b6699ff9e89f36edd2a84250d74da14600ed0af648268304429516a4d0e33b20493996867349218ab94c1afb1cecee162750e3b41cc0e6469de6a4213b6d602c5b7963449278825ad0cbd2e28569d13938badf8f692e817c9668519c3afb62da63ec7e2651a83a8a09aa48b4a4074ad2f0a58167a515f4b21d01e6e2b8f5263f980196a11d579140a12bb4230b3c531eb16322fd7fdee3ad9980fd924338308ff64c245a2c597ec6db2cdda0c515378455dc9bc8edcca87440f2df0894bed5a5fd78db29c3c360f8982caf96ef93c32841cd1823a412cb3a7f7a4c6f26940c7745894c5c486f6014ec3822200d8d8d80ff5ded4f0bb57494dcfcc2247e75100f5bee55cac2995dde0bfd88a4607fb8095b9f80579f7b9820811a4efcb6bf679066150aae7c572186b5e8d2166523b2b171432b55ca7eb3e7dcd4ffd521c3929739cadb0bce0046a13da42997b62337139d140f7c29f6011275c1ad47163bcd05b39627e4bb18333c523ebec9fec67969fc1c444582664bad624d8ea0b1027298aff253e4d7c4b659492060c255cef42d2fe36169f0d8b0594d051c5c82da367f4dc0280c2132779a676f8e1063d7e02c4152b96e69002f51d72d2944ee4d8c9d31d27c7d3fc69c13bfe617d3335e5f06a72ab2a0ac7876feebc7b494bbec6b9b55f205a0ae674165e638e410112335d7ed8c112f7d446ee6c1f6437a27adc6d810d66f4b236bfed994ff6f19a0a0ba1e01ef33ef8db224d095f436b1092deaf9d08b9abec18332acdc0fda4fc6071124ddf2f8b72809e7635b200454ddfc4829494eeb381974141fcd163e2f1f2de233ad39e30b6a059d7b438f0fe1e966304c555ccda85dd16de7f077e464f2b5b9c9538d6ae146ec44f6c8cff97fd677404d87d073c82b23803dbc994ff4f80cdd987f47abbbae64a1bc2ca30a0d927257fa9b28349833e1de664845507973a3206815453af799c02a418cefe88d0c1d857cd50ed010d4a3f7c4f1c1b7f69adf01f83e3fca196e8ed2c4cc376b3b3238b4c043a7059026865e64ca27cc9a9c5551f0c68b31b1aa8be7ed0ed6d1cefe999d72200706a1191c21d7a119a63ce15871c223d6b7eda09ac30e7b6f5594a7b1f02f7ea5940c2baa2101c10dfcd254529ac1f0dc15584348820df150545ec0e67bf94df4d8277d546cd7e536e0cec889bc5b2eec4c8d03d8d9659adcdea1b85db3c988fc015e570ba0a2615c8230a8c0e41bc51a67cad71fe085edb33e3e39f8b0405cab8f5143406128b7f58ce349a414fa0e4bb3ed9f7481759ca64c4eb1da9f1db98a20a1e3908d5e1474892dbd3a16ce2f099038e610063f8e2bc068b94429b3c7ef5da1a3cbbcb157bba3de0d31ebc12ece8950590108bb7775a9f1b3fc8607b29e43004c62574df235a577878683bdaaadea2d7c24e7bcb1a271394a218ef4f3901e34f9bfde3e91434d7e461966f1aa250698e108a724b9ec6ffa96bc616f5db373b6aaa68344ebe3d780507684f4733ad2e57dffdeadb5f9430348e6109b85b14988a1016f0e63d63fc6a4f92483237a6f2c4e068124ab3f9aba22021f4e44c06f8b39565de17188ef943e7a5c129588c853f2144fc5b6cc8b1d922e9b730b4762504e6bdbc546c9ea50591b83fe7911771eba0c7a46486fc378558d7e6ef0b9cbf3840405014b9efd4a172722bcc4c00edc816a7bf4ce083b398b8f7243acdc54a5144193aa70ea9eeccdd2171cad4b33c1e9e0593721236debd4cc2a82d8858a2954d20b46811d70a6343bfa534cdc9e600af83da14c74e93dd06d34d8e58bf2f79ac784d286ecc01d2971c52e43daa26a413efd46ed186158320022fc10a1d9353ff404360e9d94c263e21ca272ca280f918d8e0b4b30bf5dd8fcfbf3b64bd4903b0fe4caeda4f742ff758af5b0bb59149f12c285a48529705b16c8cd3aefde8b9bd8d6d60d49ce64c000ce5c2ed066d90227a58533130b6f582b1f287cf6a75d07221c8054e50078ddef891c9418e0b4257febaf6156ceb1f1192cb4189aa1204e1014c53f5ef1e1d570bb40623b3689298ec723d0d6d72e4600a81f7a90e9e0ce15e1c4a26565b34d3c466037a6d0d7a3c872e531e457f0798db422f3bde5361cf449300f0d60e1af4f5030eee1d462d241c7081397b42943e93347477756e076a9b2924e2040641906241c8ac43e0a383610c597adb90aa76e1ea7b31ad493a00189982623d562f6494c30c189be20b43f3c699968868f94f290453d84c02a48b787946ee3a030bb95f8e899a3aa6e0f4d52480abebc899da458e63c89f606a2deb10e7a5981460c14e712aa9c94adf79f15a262ceb6f3c5979aa623e921345984604dbdf92509bd06bb224d09ddcadeeb75c40aabbb8f9f94f3eeac09b9e75ea86df10ca66990bf1c41c63d215b54433126bfda5a1259a117c1481368d560ed15a9c219b115ab79cc48c9f5d059684c5c87a0eca53c04d7b550388ff6f03fdb06602ddda9969e770269217ee68fabaffbcad5437a591a3dd916595b9870f6985576c31368c2894e16b75392369c70fc227963cd5e44ed2ce67ee3bc0d01b27dd2afc53e89b18c5be05e224f4729091a4237662d5a6e902a409e7e9fdbe38bfdb6df688e27f58e5ffeed63495971d0f7f9b27e4dedcc49c0e90660563da0f63e44bdafe936c83e95e1d21ff9947b59630409529711bd374cfeb537ff32d92e42bba856d3b31881007f1b0b4438200420e4303c2391d698d9de7cdd3acfe9a5499914a5044d392617932069c52d6894eacf984011862529e39e5433bb53aba8b31925543c729f3be62538fc2d1a28c6d011db098d683ba10306486cf811805159749c88836c4d1ca25c3e040e21421435c248ef04cd6a7bfed55691e660b9d29efccceaca718cd435ac5cf7f4d9d3f6e7598ebb42768ae19a7a3fec4d8a4d216a39a4d1dc25478954e8fd1c0765dc33d9660f076919ebbdc1584b0e7cf40313733a46057c5261e6a221accfcb6ce4396741193b5bb9a634f996b6a2fca84c96d666176c84fa36bf4149b06735410e645d7e7d38e7d47add5ac11e1db7ed30bf98a18ea0ec59582636f9aceede0569abd71b7264bcb7bd4ff12d3130e323d4aa5b5cc25d9779f68596087a4e05da542017be9e1a5d48d6db447a2399166f2094f875d8072f24ee266889ba3a4d9721cc875c58638a2402cf6cf5902ecb71a79928d133f03d63964a42b921504a871c2474e140c5455602347038cd9265180cbcc59dd6d104cd23dd430c8d5d92cb10482e8d858a5aff0ea932f8090c166264f5fe04c604766cbc383e367eb6e6f5776162c6787c25cca3dd287636161ba4c4bc616e9a238c4385a54b0f95b726a383581289458a4737aa04b05643cd35066c13ed7e5804020ff6e4af3d4bf015b95216a0d401eb7bbbb95affd8b181f1e08dc71ca1e3e78713e7258d06884c03358036e3599dcd28b13e8470fef4485967155abbfaf99c00d1ad5b22237fe01fcfcddd5442300d026e541744d592fe92df7ce2c86418c64d5816f188ca623c785ce2b22787154b4ed76c2cf67860a8279291250deadbba5a70c027ca4a8912ea20db38035150950cff6bb631166170f9f02ff40d14a06996a193ce2ee068e9e23da7c29eb3e0523d10ed4e5b79e10e7b1d0e62a018117a1c495e8e7a918cb2ca4d3a4b05d60dbadc247001555292811c487e2d9df8930ce510d88de88f9622875ada9dacc66f758fda64bae9c43ab1ab85963e7e49559c97af6494becfb3a27d922043cd6745711d7b1ef335f23d6670e482149156fa6b51ac67c909c100b08c48b8b706bef606c68413b04353fb28ad2bc84d72dc49975a2b01ebdb41b998d5d0e270e86139a1580f872e4119a93653428c5150312992cf8edc1e1e4ba697a2dd60135c4bcaa7fd15aa6c90023f01242cba19e0f024d5bb20182befbaca88f1d989d8134209d9dc81151a5e0c177f553d49354992289cc4333740af97079008fcb0abe1501759566dfa63786c985c89373c65246481dbf0598b31fff062ec50e2b25e182c49de298192e35efe54fe37f1a7090d6f070d2f84c1294b8862c52cffc7f6a6cb1bd8d46af587e000527d3b487ab405d022badc463fbfdba09f1f078492fc72475bb6cfb51df6d8da523b7692403bb32cf14e65e18d7c51d3cebb652e531fdc267d4ee2ae6edc291fdd6aab852da538d2da652565c6d102287f591d08d59331057f813f6d03fc6f7856fd5025571b0f1b295623e399cffc1153adca4a6086d1e930058bcff59a9af8b1df333a75b342a8b5712caa0e052c568a6af94ff4a936cec067b515c0ea7dd0f6c170fb584cb34eb40a7d9abd9d81a58669d3d65914a5c54ff7bb37b7278f6a8cd989efe5a84416cfa4f96e7002ceec89321e1194d2b244a2e2c0c193305b4051e0e6bd903d8aeff83c8226edd2a86d952fee23e3397bf627bed009774a13236d95896a0d399e2814c10887bc54fbc1a55e46dd570743b1f9548681def11c2cf1ab1a0a66e9b03304f055c8bebea84c47758b0ddd1a4e9164f63ad9438a1bb409d270076a21e4353834836c2d35ff15a703b4ad06a13a65c863b5307aec05c128e51cec44c73e4da678ebe8f74259c3d1eb0bb6ec8511b0439a9d309bbc5f336061b9a4b110f713c595d9caf98fedb9456c3afee8aac66efbbabb8333035633f1070593c2ace8093b24dda84f53b46fd7b8b5a5e2a841a26f7aca85f8147ca6a7a9dcf6b74033dc18e7975ab15759edf483d74e85acb853eb49ffb0cdc020514c486b71ec2799feef989a7c32ea0ef85ad9d202b591bf381a4565e74be4ca732710660041db66621df01ed7e84558edea7bfc8eab695fa308d82bf66b95d7bafef17b6136658fa410798c6777084be8b716e1fb603f6b1772a07d803673cc86a8c44d902d09cd5fbf1fe04530286fa56e63f80ecff1152ee169d098fdae30e6c9bc39b69342323cace03c0c2836038d8cee379f26a3e69b8a29e8402807115c004650c4acec330d482231611c8a512a9f200138d32207da77f07fe3e71bbdaeb70fbdceb2f3d80cf16b8557b439e14b983d505601dd0d47d5013827d4aac4905e7ac1bccfb914fcae7037ce91f5f2dc13210490b430eff72061f75d92a9b77a2d3016b66c527b1379895e3c3b4bccbb8201569352e57f7858447fdd0d162fb4b0d3ac781ec81a3ced7b7be41d56d7bc1e4aba60c77762c6f3b286be40471d7df88174165dde2a166adbed22e13e8b515eab67e6b20594bc9e0a75c2d44567df13b312cde5c8a1b26626d3aac3dba8273460adf5a5952532a72145659196b0276969840e52d84d46f0dc64bce608fd76ba5fe2949c6c5a52220078a6e8b464e43c89181e342ba67fc918c4ded418084ab7ac225b008cd39ef21f09a9cba9766e528ccb067af8f99d2fcaeeba918204ddfa4258ab158ce38f56e131d305ba527faf949f3c7e691a36ae8f7f1f96156c301038c3f3bd37829f7c7cbe616a8e668ed5724a8b0e776dde33e59133af548adaceaed7c6fe4d6490d620ca764344242449694181ace8dc5eacbd03aa7d4a1942e9da4abd6857d6807b282a03f3b109bb7d28953f73b491a30b10ec4795d204f8a3d3e2c2ce34af3bea100a7e2962cb571a23aee1580d6a0d8d62e3579c0e365e1fd386487eef9e4eb8a83777060efd59c727745f62115607526ae924f12226458b06e4a6363cacf3a9886d7d4e23630a4cdf29e0d5ce533a1289d3200e2bbc07a4cf0f2d9ffb76beb399e3b0d460c38816d7f1f2cabf5f8c273535d227e3eebf7cab79ad173c8ba04b311a66cfc9e75b4a6df28a6bb1e7878fc2774f58ef42f0fbd1bc146bf49fade74f3db039e6380978ba2cd5c49b642e5d031c9b73f96355c758eac4ef92e00c487f2753c4365cbb2587450870111b9c4716dbc3436fa18b6be22810a58fbe7b13ff1d34d6f9488834ba46b9ca4d48a5e5a76dc15865cbe2dd2d22bacfb1dc9cb9be49e4db10bececb2cbc344a339b6e93997551dbc5d22d72c5c843333cd7038bba8a08815e028c9e7accc8f10547296d508b2cb7a7619d549358df06e50bc3c056176225ad6bf920ef3b41f1a2734b5636fd953db7ff5692bde1660e2eea18216ce2ecdd616b07cce0a133b5898a04e7a04ce69aa863d7f881919348177447d2782cc6376747648477df0c4bd60f5329ea76e8464a7817a5c292b2ae0f3e9ab0165896c41aabb1c46a88f28468074e4171dde6e289a9f28b57c6ae6074735196b42c121ff7e052e11e21cf264abf897d73025df7e431b70a33d4d4529b7b6a9ba71ff05567bec15a680a9b9864a1c6662d19104f7da84e0d677eb83d66260a64502b62ae8773264c196c97ac7aad32e48a0a8e5379887cf6ba42a0593b60d84889fc70eae010eaad42ea72603e26ae852e0b10ebb1d67f870345637a5486b871b28adc501899756907943384d8bba119c7fc78ddf88f4b6fc59af33d871e6fa76bd24403426bf85a94e6b4f8d8794581d6b6b80dfdae930acaa019b94b4c021b42ec26ab4dda6591553d96f4c2c4a66aac77f0f55b9eec0065391ba4e94c8214394658729a8ea138f5fbeee3f4dd8fbe682bdb40ecbf47d2f99af6073e0fabf882cfdc1355c345cd9e618462fe02ffdc986f2b6de66177ff5b4f17bc771c3eb53b8fa33172dd07a51af2f64a067d24030c5695db2bb77937639a94ee9b10dcbf22bf549e13127034f726e20d0dbb9cb710c4cf04ea40bfc8ce382cd88c02c3248a7179794c33c5c8913f41a0e56335ff62dfb9360cc63e01c6a4926704526db7191801be77b21ca49511678c2585af673c3400bc5e297060d20cd341d810df224da3d0d218c725c13688346fe6649fb6ff73986f8a94880e32dfed65d73b16a1b24ba4a55a104158be81cc14ed4662f3fe4956415a2b42c1fbf212e78b75141cf6356321f35aaf732434174cfc3ba3c6dd032036f3c3a6a09c367cc43621dedf581c34d5c302512c819417b7e6e141c493e9e00e0e95afc288309ee4ca16c01715cfc11537fa04cb32a7a183d0fb2843d017a259c5bfabb2b4dc40962d0dd6218cd009b7c327248824f54cfda4f42740209934d7c7261a0a5b3c9c0bc30fd0e894b209462daede4970be7f577d427a7d915d04b262d6583bbd6aed3c6cda20301d2d3d565742b725006f70d60283173b6284a657badc857d0c2bf4e3acd38758231f2cab7d194f3153e6a188272598e67fe6f35ec6e5c3cf4114da9219d7782ceb59ff7f7784ce7ca7d24dd1f129a2510ed702880a8bca251d21bcedda7906c539504f522ed3ba113032fdad8ba61607e466b4188c218031793c33285e73621f5d047902bf1e8438d15f1b0230d1ffae117fc42d16839f51c1ab600b2494b9375f77391a1d6e9335366f72423feada2f94ac41887eefbf9c4580411771c1b940dae86757fc7b4a81270306b7a8ba37e46d196ce1d1f8fd2290493c62771eb177e726863fd97ac003bc0c8a335c33d1f0730049d441efdaa4a66528ed00f856747f431bd0c79701e20a572149f989ec056c746040222aad3ff6032370f271ea40b71a5ca2a9a30175651342cbb1f2985ccf0f550a90fa99197f5412f1943e53aefd93277db9015d1ea95eeacd801b01ea219dff0653705cd50eea8da2bcf192a4e24620db3bc4e736e0215e0ca430da30dc51e03a7cac42d551b06c8666c00b5ac2efe5beb97095ad43fa711bf30d2b60e9ddfa9fccfec0d9150801006a3ff0bbc22b901f2e4a7b8386170f7877dc33ede61a70512d3a7791a1a7efb177353a469ece17b5b4563334d97710c749b7cf4a36537e2f91442766fa07ac38c8806aa1f4642427ee121a0c64240723ac126c11438a84f2f1986e175c8e16589a1d7c0ba28122eb19508d5c23e541bd54fcae83e7494ee057def8179cd37af131f02ce405fbf4aef4e660ef3b02b1e8a333e3b850466d4bc9c8e30b942c91119d9c0c6df0840f8c66cdb5d585f44fbeab9306d13bb9998d9ba13d6b5b0ea748c9ffcc0c4f0a928063f3fa854bbf52747d0e060c4c862628cd3b61a575462d7581f44111e6b811f25ca9609a7cd4095b14a923ea06ca81a212e7527558e30ac982ae600c49fbc3227a339e15a43644f4e12f071aee698997c1938c497fc2a29d10fe75356d44eff3d983b7dbeb2bf101ae4dc5d5b66a485376fce72e4beec7392b424feb96c2e2f15929f6d3b8591f3bb1536da32cb2764e231b512f417706adea62ae7300db29e5406a728bee78b93ab8bea287c906f3d0d2bae79dc46b79df4e79ef12818ed1c08cd895b43182f1972a0bd31b53991eb75dff5dc7d2dc687695eb7ca3a0e9e0956d440e6df7923d99a6c8573917d19756eefae132d910e04b416279e1e30bdd8e90a1c8d3ef7690677b3b35b07c730c1515a17a6f1a3f0f55a8e927460f5890ce277b2f5b0dee4c186fc7962e9f26ea3d5c3ea0e4e935aa642f52587cb562110e22b4933389a09d62ddd4ac812dbb02438b940f7c1e53edd961f856da30eeac72706dc9e9a6983c4daf50db5442761c2a30a46d65d27f19ccb4b87c034b3d4d772b868e5f0365a3563295696bff3fa31bab3b61f1cf25da95e5f4aa1eb5cc7509bccf1d0935c9eea86e33968fd50d7c278ba737668a7af6992c55b5fe109fac5ff4e0af876320a90481ab66f05d04ae4bd960b846cde9db1df088b1388468e12a505c1c94493f7dd147e8cd6a46bf7c8b928556be3b7e9dc00662ff4aa804ccee89bba6ff3621abc03b7f625a4e889d6e4307de4f69cbb5cb6a2d025a8e0b416001b3a64ddca23d9440b104e5635f25b8e486440f1c078d643b80dc92a786bb86e892e128f6ba25a3700b76e896ac8aa38c12dd8f4975e7b0d9bc1160f29d19091a3d67d535056537ca0adb0543a9b8462ab2c500a3f4e70456621ab1deb98b07db5c60634afb1014c7c3345d49c04a87d5ee5a491cd89b94a256294cdf05d44168ff285ac3601f6266930f912634688e2e7f4544ac8574caebfa71425b4869c1596ac61c97a2a5303124c62e3a90015458d8b836be2577ae5ef9f43a5336afee842c75c0528ad1ff3c7ffbda3ed0761f5244fd83d8b246165daab3e8ac884ab68daaae48a4e7f36ccd50796ef0226380792ea8e76f0ecd31bea46a19150a7cb1f057bfc0d0f28bb1c1da5adfd3d2e92e3b8ae90ce06ff80d8d8df75fd69af62974ec98feb6aeb685ee14105fd70abc8fa77d063b0aab6e3cf8110314a9033a31206daefa4a8b722d23fd464abc2bc8e2a04ea4ac5f1310fe4af1c27139eba37ca50d821dbd945f55494c9be90b45fd818262c221100a676b31a4de9844ebd316234021fa09b1000e434225e39808ecb91e62891f1049d59d95fa746cbf8ca38a4f38647eb08accca0d92aa40a7a56f6104cbec355bc8fe748bdccc623282cd69c1ac4a211e39f2bd91ec9fdc3f752f46d492e8df14fb291bb8cc791b2e8bde2cbf5eea3313d7b7e5d0d4de1d62096fbff817ee68cb18d18f7dae6fe70cfc5c8dca6d73505051b576534e244951e5e1f27f49d1b5d3808fbf24542b2e9ba138921595a8afdf01827824097f35a1c0352c8ed710f07b1cd12c89359e34de47a350d6de4d9117b719b9279a747a5bcec0a9596e07b1e5f414c5696c12b1432933aa0c1400ba021c74efa9aceda89043fc0346959d8dd4e7c2a91c0f351a15bf5cbe4671591e70cbf63d058af0f26efb5a7ca5d0d73aa85a9db4d52bba4ec5de997f7bd6a5450e6f211073a7e8a69e66b02fc614786a13f46e8940b058e961293ffcc124c419693ca0a24465bb943ced427f2b4a894ab36ce6993dced64de0c3034c2dd6c61162d7c4b0c86dc633d5d66069c3684a8f7cb04ac61dd2f3061700b044f6fbc90f82f1f920c7f392ee72835521ca2bc8c615bbb7e4e08f251f9cb65f0091eb975743affaf9c2544b1aebebef547e46b6587d79c254a2991fcdfab9edc8dbb590e1d2fcb59b45821aef73c12d7d6e5ec634c4592dde9c44f1682fa9d2adac8a04f63682c10287d2a5cddb6685e040acad6ebdf99e84e22f76f71bd1263772bf72b57e0a8c23df36029277be26c6ebc9379ca257f0f870f87c058a5affbfe8dada52633f2b2f6fb19cbbbfa223cb02963fa7abd57208597483129b5890c9604181e8f7f6280bfd6cc6d18a88564d8b503441e980247ce4d3e890d89a1e820087cc340f6b1f96a837f09cc9ccbe0fe5c08dfa442de04ce3c6ba6ba54c8b15a94007d0946626d59db1ce92b88e92e76ea20d5ce76b4efad1382c2476563c7b4e3a3bf17433c41dba0c8e73da8e88be47b4e02b75132b6f2973948fe8b4e046ed0d71defc0f517d82d3750befb9b4ab2ac6c70d8d78230f2d6126af9fdedbebc0a0718c24e04d6b3dc8ea0796c17300d16bd5839dfe7d4bd15c2d867e69b8a4dc3da7cea866cc91b19dfe7aecc6da340a9ef8043995590b1f93c45a08333bd9659562651087873502756dbe3d9ff588c4548ee42cbca5743ea5ea14f767a7817358786d87fc00398658ca4a40995f262ffdd4d9745a64d84722ef381e9d086e07717616fc38f83ba3e18d390a7518358c4b3abaafaa66b538fe356b53258b7968c34c9ce6bff14f3f7cd67584535255b355c5780d73b69d523863099b0bbb0088d302aeb33e897b7f2fb397d0902d6a089643bc2cf2569cbf377ed22c4110dbf41eadf2a2b0c03f2d74b9d8aed0c4aef1f265bac547d1f0f50d09e75f9229d295591cca69d17c178e30e907fa84575125ac7bd34a1887478936f64f8579422496bb0ebe633bd9db46f16a1bada8e54c6bdd3bdb23e539d21e6ff70e774065c6598e5555c9cb2ac53c41e5d2d5042a35a475c50cf2938808c8d6757d5e6ae74478ec512bb3516fe0d2cfc3be64b13a3bff5433c3535af9dc8daeba6e45666076eb116c4e86f7221026e9999fb00e7a97ec1ca616ccda37fb01d33262f2b9b4bc946a97ff34e36c78170356467e336c109f12b6bbd850e79e1ac5e0eb1fe5108216b970379a88cafe3d056cde8e0a58bbef87a78065f48e815599b052c0a6ff8beb627aec2ee9610837cc01b05f25a2dd25063153331bddfed05089075b3e6c7e962006f4331e620d8ee69a9433d725c8961742cc0c5276d8b04f9324875e9cc5d35aa81462a15ac44ad50d64009e79f5ea3a1acb63a87c737d3b1b2a8cdf5475ea43dc13c3e6087c2f34e43ef3156c38098646de5a4c7a15eb2c9667f74f8c0daef966c2d73ed8182ba27d2fb39d162002e243621e28aa337bdfc99ef2668670251b19b09f4c61901105f2c1c94db448f05ef299beba40712a97a7653a07da6336a31fd61d0146fe97cd24f99ede5af7092c239df5d3e08a599825090750ae5c55ef26648511b1cd75e73d20bdbd6b83eafa66061d33056e3ff034de0e4d626d48537f9033657b09d2458939eda834b1b775247de9f6c39f5cf80b59fed4809039a21cab2cb8b881a4be856cb809c75499ea42505bea3d9ffab46abae16180a288f5762f39b22d009fa041474698c512e9cd18d8397f32e01f7d2a31a128f30378d7c656603a27ca084b1655d5fb14770e3f19669c5aff0565e0009e5c01a2ccb643c19abc05a736a896db86835b5bef4b009106fa31073ebb197b23f042d4a6e705b00a750703cbad7a6f29c825a8fba69254341fe92746b5b62da95df6bb431aa7462608c0626d0b95821c2088ca2c8d007dfb8b67bef7f924a15f53e731648e1d32d612e815a900e1485ca219d4ed9b44e8acea00609f22333c4bbeac268c61eb54d0fdc5162a0ff35c931f005ea1e8d1a0560567cf71267338ac600c4819874e3bbc0747c552ada4f819adf7df2c25feb48dc4fedea3ed477037df9b92e056fc843eabb84f358c6bfadaefddc0e98e79f80c5d7c38994719d274554fd38507599d188d5a773d69334002fa2d29f874474c21c8b91c1435a9ae566b760359a84a5740de51a6add2a55de96736859024e593f8313da9eef1a79859da67aaae2ed041b5e7c2d53b8c532c0e71e003be470440da7854c852b47c064db53706398f65b9ca245e4d03b450f1b0a1af9a4d4d60010c80c883e8ad873366fb3302ed4a6e221dd1c5cbf4c1048536cbafb127bd1f6d6db55b3584266cdc605aecf7a20b4dba3fd15d43e257842c5b4de8f74cb2575fe239afd48c5ed6bc687c4f73913fc1bac2bc90654fbb527c2a59d628ae82ae31ccc4694709b3e90427a571be20c023fc3b8ff4bcd3d7f4f516fd75eddd0eafbdd673699376df203bd5ee10f25cc7747c59f9f0b401bf431a496933670466ace863f16f733f051eb79ea2fcc24d8348cef549a49e36344918be041d690bc61ea54eb4e532bb2dd85b0720ac05f9bb2f2d472610cfe57bc90a7c59a49482111a7d7dd3f600bb1630059b06aab385b5309d3f7753340bb84f0e0a8110ff7cea2e1054edf05913970acec97c25bc844bb88e7b3fca675adf429d4718b7385b1ecc1944ca3106251376727a8a9a1b831988cebf7639037006f2c784e5b9443e4b1ce46f04602aa0d497bf1315b01ad53011c147c91fa1fe8c9809082d5a13beab1621c7a82549b42fc43a7b857d3335610c6dcca5ef4ebb58a4c128e1925aa3763128be3b6846b09216762e589cca6bfe68c7b000d1dddcd8746ede309af5402b0ee39e1e39c099f3f31cbb5a4cc52d6764a0ae0cf02ab56f5af65d96b623ab5b444ceb7ba4d299e481a69ea2d8ce842c11c61e1fa122f5f5e0068266759a07a680190ad4615ba3f85466e02a3f76cd5d46b3418571c74ed6c5c950eb4f4f20330d802bc30185d9ef838a2cc94dbb3b655ff1864390cc36b9e951e0c4ee6877234f866500613061551c6faf725f46547a9c9e331e790a197638cc8599ab0d2751e9fa65b12f43e4cac843e4696bd12ec8adf06c76261624af5d0fcf6b2ee6ac44b2e8440ebe7530fd022a5e1458cbf29d90abefd3f2116435e2ff492592ba76d8fd19b9db010bf4e65a3c6fb0dfc8b556253305893ffbd74b388b1819a1a683a72ec8b76e1b7f95bfc6928a4fdb79731de5bdda06a1ad66fb1d6a574249ebd6135983fae348b05d434c0e136107fa28ee35772f65b9f90e7c5f224ba2db631a457f62b38aefe43a4b848d300def8a60d901a8db48eb0966e1386fbc56debd417fc0d61e8547dcc53a1b061f5e6379ac831e1299e56b77f855901247a3372f84644c61b132470771a42956fee1dda48391d77d1714c86aa8ea094c5dc15446891b349504e23c8c4a4cffabc2b261c57bb64813b2f3ee9520548de688af93e0b483b9199fad36bb112b7f55d4101ac33b9a633194258370b833866067a7bafde8f6001ced90e2a50e13cdd0a49eea3652e36133d37d294a5fda81a4df4172698bbc3204769c10677eff9635eec72b30c4e6e61a738e357a082d62ec8a21e39faa07d0c6e0566f8cf2019fd086bf787cdc3a03624475651ac5b8dd4753270bf8e213a1572ac4e3dc1bff3271f13f49499d3e0ec0a2d6c507b7aae5918127084c7db8df32e13d4a27f4528beee359975cd54e6a2efa36c8096eaef03de2d3833ed995943f27e00fb7ea1f1aa6ee23f3a4f338bf5540c2b1ef50edb875f171d2bb8289d78fb2911356e91df91c39b472e3530bb27be975d0c1f46eb01f02b3af7878ce8bff37cc76a3dd25a7bb0794f59a3db3872f17b2784494cfb510a668ce9664af02606da4d4b114f289c509642fd8ec2e66b74d74299b7529852f51bdf149371f9798f1618084cf0c38105dcf937b5b7600659a3fdc53564ea2789881a20fe8c300a94a734af58932ee506b0d119f128bfad93eb4a0c59d51989a575ca11a41885be50bd492e2a379aee73e0bd6fe959e618e8586f412cc0c413653f1cfbb6e5856173ba0251c865224fca1c2babb1f6ae03e63e25e2b7b8ee5a1872310c07cc827ba60ebff50032ea09cedeffdbcb0c0c3154d3c2db05b004e13bfb91e1638604c911dbc070bb0cf19a31cd4a871c319ef586eb8bf3d01882f3a0f7e7cc3642a058c6bcb9b07fa7ca957273960c7c577a4b450bc041c970c44e0b27c402057844304b9fc72451ac04359f0949c21b262af813ebe2a06e16e0db8547ce30ce5fcb7f79e374656fa6dfe38da2c209dbffc9ffe70f6573caacdb859dc35d335c2d2b62b9ab712c59d283142fa8cd3872d686a9001d8b0df46bc057e5f63a1d8167c73f813cbb17c924711587dc49116d808c91442f17097b43baba6e7b041a3a692329051c3707c1a09585117eedfee508a6a7cc213c5682dd7abf1d045d26d0094bfc655dd954360ee64fc5b4b64076b212ccc8d50179117d0bbc8e4f30a4269b52fa32f59c8069491a82e880527121ab5dcab08bfc303ec8751827246b67d5c0d548538d3f9d316d65f8a07286169abbd12e256569d37f9a1259d29108379577b18dd0563a02106c66689d2a93e21e8f4f5099ed771a24797a4f605a1e8b4e943029a5a2b67e829669e47f4a3a9c3da2f7b5ddfdddd87c3f6245d38a194aa67cb42695c0ee91c069993f273556d5afbc9ab4f1777fa8ca1c3be37fcf0103f758e12ede5b56f78ab399501413a81b4c3874aaad53c4f47f1c6f8f83613c7e8e517a409fef70a19bf77ddaded3c023631c7312ba1a22834eff2b0b1380b094eab6d0106fab3860c39ea2b692cd61652e41fc4cfb271fbe1bd192ceb4729650af6be84000b3580d00e990185eb6b160a1589d62d808bc9e812d240c0d1068e7e14b29416049dfa027d787907220e12892d06139dd70bdb9ee0131ef0636a04e0139ee9b3ff5540cd41c7aacd5e9a02240a814a10de991291f73b2b3cdb38d0dc068330beedf2c5794e0dce440ec1820228a1650e200f5c0ef2e46c11c1b28c143d068d85899bea10fb438cfafc91a668c3b3b1678b163244c67a36c4cbb343168c2b45ad603fb60b1494d9ec1a9f7471ed1d521e2bdafcf890dc29902cdf256e911d50caa60fceff4aed65031a1981d2ab3e5e05663d16e3820bcaab4439c2e58d0f48e5942e78b1ef8ad4d90eb9e15f9fd51b2d8c8d08f2382a0caf0e36c342785126534e23282fdc5dcb96c2e2863a67463ecc3d14b24926e0f048a524a960ff5e6281f75db5a75951638678e2a269f48753fef552e83106a95160b12be06f2600d16e486ab335aa4056157ae99cc04d1108515b8b4ba6a77d199b8f6f41859721c7d8348881ba322c2ad01c2e8127715914b97067272149c789d5f0bb2929f4a8ddd85160f73aa055e56bcd215840a7b49a0f3dd5d1fb83c0ef61c4c97a5b4492bfd61175becd58b4667da3a55e19a127d640f1ed3e07b3329249b64f9f18a4b1a5f3a7c2417503640131d7373687ad1f8360f6145fb8312c01415874c1f573d709316dc017f2f783b45ae5c84dbee75d5929d0476bede9de9ccef5d1aea9a69c8ac9d378d55ba8bc720f18bce0e642bdfcb144f2c0e3e6f8ebe0bbf45605b4ddb60cb7922c66060f679f8ca6e9eb75b7c2d9c1aae39ede45042080efd60d67953b8dc3f840a5430caab8dc2ed3730e0f11d0e44730cabb2e03c21e687a14e8b0a3f65c2d46651d9873d365957c95f4ea2d9d2ea3a757f171d0a06d043ef94e2711c426fdfa40c4dc8f410622ac20a59709e89454f43a62002f1de9962ad16b390a76e046db7b46342bdbabe5b5c6b602a9f313edc5cdbb597b9e7e626ebd085363db4958ef04bd6b0bc3d08bb5b2d6582cfa62ecb0477e44dead3d3b668e408702460469c983969c50333658c02036d9a9dd15d778068e2c52c401352f9216766b222df04b2c0a61b028d7404c0821f9f0eadf19d433f670a5f9ad8618c80092c3cb6a33c211f5ce3d1392907aa7af34a08506aaf1184f3836a90ba3e15410780ee192ad95a48d80e4392a023ab4015bc3198aa828469badf40368e8f95079c0e01a786ef5f097985c686925a9d20da8f4268e9a38affb9ad4366681d9aa28c6665f244708f4f8dcff2b4417c4fa17fb297f82436f0608c044661c488746dc4333ea3091db3f563d90557225c4240890293316ee78879e6c77ac075ac7ff88a3107803608c66070312e2a6df11ad6bc6c2155a99edbd55f0f1bb27ac73b942aba5c290b7f2ca27dd418e8f92805ed72d611ad6489fcf19855cf4f5cf168e7a23a8eb8e40739691a7b4d74c858a0db91caa5e4314df07e8e484162c14f5687e6c90f85cd6795f2598a327db1ad5d32424ca604cdcdb89e11a3884dc172d1253cf699604306ca57d8ed6adefe5683aa8d7bc8b464d283ff21bae40d2add910079386fe3e60b561e7f02f29bc5b410077cdc31ffd22325a5d6f1e005c8add5cf5ae2b8e630759df9a02104b2722b3364e16b2812a6a1c63beb2558b86247d568a2d7d538b389336cdf5b45a53ddbdcd270cdd6a0260d5be2737a2dcaa24702da929550a47cf68624c0609d34f70ce41bcde1b159f3c7eea29d3072fb4f151dc326aa7066720f17e6e954fadeb7802b9de34fd028a96021b64f86d657a5436485f3f2a3dadcaf6064efd70c91dfee66b8af15b10e8368fd281baba979510ade8f93f84ec866a538b26d84c8f5b649cd05fa7d09eeeddbf5414a83f20870a0e3ea41e46d6aaf9e6cfa3cf9e7cc03b199708e169b91f5021facd219233b3fa68caa0f047220bc3a26bc0c2542db2a3c16c76aa378d4ac8832311bc3f79c1f80a0fe64160c7b08acef0adbf3631288a39eeed611063b8fa64cb0da8cfed65ebf13d700e70d1f9df03dd26f50ad201538867c84557d7fde1326c2aeccd8f42c5f2fa01ffc066f4be6f13c377ae8c894bd1f9bf248cefd2d8076f25ea0322f7dc13a2589fb21beaa3a897ca2cf2b5d2edaa6ffecad1e6d424ed5f336478f6bd053b0dcbdd1f8fae8df6da48f407d99cd119cdf0a0ace0c42d12736e21cf0b1941ed834a98d86d9614bf6dee1ccd1f039f3c825dde5acfeba1a12d4a97d297335fa2187203ab79ed0f0ebde2d6a1cf27c0a45c5e67675c0d97f53000135229fd2a6428c2787879c8cf832a39a1eb7465f8e718322b3eccc5099d2d4667505d04cb754291a9a8310d9828ef4d0d9efac2de61433746220859ac8f2bc9346b694634004ec807a40be2454927d06e97e84ed70b8569ca3c6b2fc44e95354e5f739661cf39ce9b8a983c512233e1e54bf4c7724b0d2c38491a7f23e7452d6d7aed81b0de5ab974a2ae74806f859ddbef6d24cb5106c43accc03b4db037d2aed5908fd7c6bea50a1d8c60d263284714f258c635d2e19347a85a1b85fcc7e4b3f07e54d000cf7246b885c3b9f0068db82a9cf81b60578474cf066463a7de1ba8b19b8f604a200fac6608bb3e951e5668e219d67f833deb40467e18ef77e7ec71d285a43298739021ad318dceaafd38592826a25e9a0844d2d3b6f35e40f115875b28811ef819c0d457ef1c47ff249f05afc34ab3f519e82ecf17d8ca5007041e0fe87bf133149ec4e2a19a3850021edb257cdc3b95534a6d0f3466d517dffbc8c59a72b21baeba2e9041b1ac9fe9bb05d186fcb26f03d834f1c422cc13ac7aa7327de024646643d4e556640ca8df5406a15400f8aaf28926d8e3e152974d165b5dbade5fa25dd52cb5149f848bd95b4d28ef5d865691d5b177b4c5f911daeec8c359b3cff42c282d5bc14ec96a0d98cf7ae30e2d766b0977e4455e78987a135cafa50ed3fcee501f8d0bd20d02e9768d269a7966ff2a95c30bd738140885983a27b0d0e26d1cdda9b95c13a6a69e84a9699d28f85a6208fa5c74ea5ff635b62fd90afe4a8bba1361a54e641a3134188af0be73b65669758762922a8ad6a5f7a651dccb7de4b09d1920db2240d3a312f0517346aa700dbcfabb10b59bed9297c8ae6fc036f41d9079a0e8db4f73d910c8eb71a25488d755b6e069cb82a260bed7f0fb634a76ed647544c69d9bd85c143ca0a5cfebebde02e4d33d1a35b01159b895ee134b3f019053d9a8b89b4f24c7ce61204c778df83aad946886ac9b16fcc37eb4616b6a37c92c8a70a978b721bab81621e20a08e6772b1fdb5f76ecf3912e67c5d01a866f6201d4b700c4e89fd7aad63d56dfad0655024915d22288c7f55fcf6d11afbcfc74d50b5d35ac648db886d935185ac3f552c5a222db2d5b8c44fc549a3bdf16bd58a643f4ea6590f53a1744260056b5c7d3cce8dffbaa1f6c69f5eb6c3fd817b5356d9d2b24a6974d93c92811510297adb483f6950f8c7b208aa98143b5a94f8c903f27e7261126e8fcaba469c0bc341dfb7f4535272a02714f4215d56be2d2515acfaa705ca99318cdfc0cb7af3c5081a4d478dbc0467b4b6c4b89eda4662f643f90e9a30f185681b5cab363081918d2f85b303868cd0035fe2391c36f0fed615643c6ff1973c0a131f9a6a78b0787d0cb76fb2a1573d7cc8ab5a14e8ff2dc74fd61ed7f8510d363942368172ca551d62580b773daabaddac91362c840e6e84aaa239846a7abfebe46e2a10945c438df979c636f9a5b0ed6cf9a4284cbdd94a7dd558f730fa07082cc40c40987142898197c3d45187d5cdd463e346f7e7c70c833c4692dd0e9a16d1ed7277c8dd5d32524889c9db5aeb2b8494b7f070b06a1c30d0b238953673691f7a41602c3c49da52f3f941e74c063d9869908d068e6059a544a7080806132014b897a4290df9a7fd20bb8b352c6397ac18b161729cbda41cca2bfd66cbfa897edf3b3b15357bcc156e85614d702bd8d1bcd7787ccdad2ca5453cc0e8cc0b4c485211422ab754c5129e83f1ce8c54ed9da10518ff1237a039ac26215bfaad6a39b7824b8869f3544d3fc9134a76595b39b16e27a391ea0263e26caf34991fd1d1a19c7aea91f9f4d3b22b8b3b8df5843469f0d271453b0e0fabba5e65d0074876152b9c563a61ffa5d247c4089a9d573e58d407aff3301048f29b02a5638805403b94832d3cee2754c6315a38ffe8e9a282b0882453b84d274cb62ba182afbe3423640007369d36e5d45fc7648ed9f9ec935cbafbc813a7757eebef3b32c40f9012f308af88bf5ae6cff9952e3b2efd683b861cc9741233aecfe659e51adb73377742f80ff002be7152c2af49238480eadc92ffeeb505c50aae9c49b93f56aa808d808e2eaf10b812b8ec9e15c5b319ecb1e5904a760eda388402fbc9220a42b19969d685fc70cbc1118cda5ff8fdfe7267e71035affbe8fccd5c0782ee151c85851f2f58f07944c0a64c3205380eb4447e51d4da7d4bf2303b64d0f9d0e2e967053ca6d07a7a59f72d215ab0d92019d78e846f7ff34ccc73d8537058d83ddf7b0c4dbbd4a75b93739bc258016918dbc756fb2551212f12d33799760e7c6a2f02240c543415f68cd475bc11e957f28984a82ab07d2e2fcc6ce9b7007e2a8b8046d80d24517671fe9e144a64a5d18cac510378cdbfdba4997fec53aab0c6a79365f4d03ca7a18d23c7bca00d570a66298c6d2914a8a4a2c5dc031a55bbb48071084c57720dd478c36f491abf6eda297cac045dd8510e457ca922e8644fbdad929cb2b7b3d93c353af59df562658b628eda00ab42851bbcb5fac2a80dd1bc4633cafeb7517e4af96c7b4db9a09de190fe06999b981608ba20fd8826dbf16d22e97897fe1b5b88c5e0b1200c8cfebc0f45f588469e8f3ecc39e18968be355abea531c8dc2ddef56906cb22c872515c3f80e9bd307ce178ebf3826929bd501046e0138ef100e00173c6073d257c21e709ce041d0fef50ca31d3981ef971dfb25feb9ecd36a6cf85506d4ef45fb62825c8708b1498b49b5660bfb5f060be8711817b7eac58242f04844f7db9888297f4cfda23983441c2c57c38f7a5a4457f311fa0f7f240fc872159060711ca6326ebf8a64beec48a74d92447da9838570689959c212a184c7ef84139b10e00fd2bedf7010a6c797e14001d54f0a0c2d05ec9e5b7012004ad0c7a0443dc2b08387b6abda41a2c9565f616f961e74d81fa7c231596f7169c4601d5a53160401c775a24062732b34f8cc1fbc92a4540836daec76ec4e34e01fdac05c51337e27a01e86419f65e246d0a41686e870965417f3dd69f3183456cf2f74354b2a9d0fc1979bc83e0ce7d11b29c3a5e55b56082aaececbaf7270bc874d890278d96e57c009c918cc33280008fe1c1cdda9690f1b810b607036d304ca10c746c5bedf2731d0018e8c3a81aa057af747d73e12a8853b2a7a8d6067bac0c2127419edcca4d142b0540c89332bbdbd61af3f1ea198a373aa64224ae4a5c22ece7f4d37a54e470fe8d7ab168245504b3dd909a35a0b456b47ea7f1cfe3b99bf00bb1f34511c997abe9bd3286244fe69a9bd01ad734d07acfe82353e09b6ed5ac6c208bdafc003966f93168664225b06ea0e9c4c4d76eb4ba395210209455420fe40c5d631329b25ec8d11a3d7d237a32aa3e3b16afab6c6960ddf847ca0bac85e418d431002544afa422441ce08ba64b3efc4a5222746c5b40f8ef0ac41bf92f3465aa20df9f11c598247c8f1bde6e1430a2e5e28dc49dbeaad275a106d59855f5d4d56474e962046c418697f79c41a856eb63181714905b4bc38aaee78aa25776a8f598a54201f66aea02a02fa594b0df1359bea859dca4ec3c6e32cd9f0654894c6028baad9b4ca8a0d8a58920f7bec8ac267d9f10a6c8c59a2a33eaa9d349415e6152981c40e665064606adaa88c999d8f228dcab0c29d247304b8b88e5acd70edb07e2baaa25687424fd67b68270ff59eb75eddc68c9a15d242675cd8eafa7408bc9800934a00f24018a9e100f2fea844bd9601a81086aa8397b4b0db596891fae8cfc5a5904285acdcf0a3e7f32cf4d20a145f010fb4971e043e1e2021c7e29cce431bc9f35707390b49d41c8ceb06c7c10b2e61d552f26d4959bef7af0296cfa88f22a3106a0d05e4a531fc7fbb76531bfaecdfdefa035eac77704f575e505cda35e7b3bfbb9526a63ce01a01c21b9d090b27a9e0aea6aca0c07f334a152c82708dab98a6729e1a236fd24412bbfa2a227ca8a36be6e7a21443aa513426ba864508550de4c556ecb96512d5a8cecdd53fd64c1df0a7267699fa18bfa33442873652739cce98a0e0152cc10c0ead94fa10818832c0f8eca480b21be0a1b760b96f6c852a35e5173298540d7ccde21f27db0a5601b8d4b922eeb97f16d384affb184a7141c3e330f1ac2743eab1f15d7412e2161a154a88197aaee30e9c00388ba0b439f3dffa3a55b68665ecc1d24dcec3a9ee76fe5cfcb50dbf494afdab5cf7e304e013b37f470711704bae154ed4c254028be2abcfd832810ed9bd016f1ffacb0f63087f0872a8bce2d49b78fa1b16ced77c6721c8d2d64f9c07f80addc5daf7bf867471e9079161caae38ec0037a4151137a2ada173944aa77ef046124e2931c5acc28e3ab875e682d2f55bf30267c2e316bfb53d8af5f110a7052550c2a93dd781ee633dd15d92bf83fcd8e3b640d7b04e0e05c13fefb2b3024df06fa99e30e3a4de0750b7183bae00a033a4921f1bf08bfc68006b127364dfd9599103f5d487e42b336b53d71531c41e130e233a37a859c4a2b24f13c806ef031d098048052371c7cc4d2543f5df9831fdcf43f55ff2e6ae3fc31ab1e3d21caa159bd7418147f03e9f4acf34bdf2ec80e1171e7fff8d0c967d603ead937cd0d957810b10eaf395bf4465edb023f58db8403990d8811c8c38813c3cb1c03a40892908ed7d2e9c697b55c27ddd33c49d7d44ec66a7f65a1fd512d5b1a1b22dbfa92b19e6ab70b83f9bd7cdf59893d513066c9d4710f54b3abc7fe63adb8eca6d92fbd04c90b2fcdc7067e0919230241b42c81c2ec3de3521bf134725efce8b548841236e2798bf6b25cc6d40d1227949de0cfc20ec887e24c255865888b9c9daab4752b0642a26629b53bb7a9ea474eeac2581cb6e19c0036e826a9a81e1b39a7066848aed46ff1140f455d0ba27b6e92224fb196850edeea7edcdfd1101a55e4ef213f654e52238f95e722b28beed7808ad5e97035e313497124e328a31c902dcf6026a24ea6c59309c15a70369f22a9d43ea934e0ddc5ca31562d4393d89aca447c8e5dce3d7ef2861d3c9c047415a82205181d65701008034051b015a96534a1440d36ee3f187c341527623bd17bda2cf7e023de9256defbdb7dc52ca94640af306b306a5067f92d2bd689d70fdbdee0392bc173519708cfe117802e2e018f245a0b4e118f243a08c710cf91fd823c7900ffa800ee31852942253214a195c0906b1a1a812458b9d480e0a3535353535353535353535353535353535353535353535353535353535353535353535358e22d33e69cdacb6719df7017d21d1c9088594526aa1625a71c132b154582d5825560a8bc44261b96079c122b1505823d6094bc40ab15e3c2bc4fa5820d687e5b11e6479ac8ec5b1361618b23696c6b2ac1006cbb232168c1656c66aa98155830d1a4a10d93e69cdacb6719df7017d21d1c9088594526aa1626279d1c16c54b3e562c5a4d2a2445f3cb862435db0520a0965740286261b5f9d88421f2884a1225735d623e8e375305a5aacb231d665e3eddf5a6a28a984abdbdfdbaa061b522eec6a2d980d94abb590f8e48b9a0da4ab82848ff90694ab6d5ae7edd0284538d0145f5fc601c273e5f387ce774a2965de6ca8a494564a29a594524a29a5953e2d427fa394fe1c9906caa574738d81e3165186ebdae79885e72ab92c49faf4da79c15c2c4be813926b4d70a44ff69fb8e3b528172a762d8b913e315f1412d48ba5854a72ad6529e252744386265c372d06320c6921ba6917ae3e5917af6b3f467b8e82a61c7482a61cf3a3467ca2e8f537d77ecacc143efb7cf9c8185e975ef1c54a14bd6c50ae7ee920d73eeaa6756166eac56ae68aa81d944b64695d2074ac08b1f29c9aa04987c9458fa3ec9b9e53de10be0c34f5d307f223553f0381fc48cd7fb17218533fcb0b1a8731756872c07c17dfef8225f441bf86a6ee064be08316e5b259ceb54f5d8c2a3cf844144beb5a11e5eaa187bc2c3946ae6539726d0b0dc7b0ff99c1e7a275edb3a86668d2515319cb8c0f17ef221422a5230b59548eb25f431731475947895eec28d1abb3b9629df9a186cbafe262227a4d51c4232387c6c6042570993af33ff4b0cf856ea84d16866cfe478a82a11c47d9098646910a0c35e99315c97883a219d190559f4e4eb86fd04532a12622954866342a5dd0eb65edfd1a14b96c469bd08d28c751f66718bab1c16d9acacad8e4894d6b22aeb5c127b2f45c2b72f50bf7f645379ef79cecae018a8727eac5d1eeb543bd1814925ab3cc5a4ddb36337003681243001537809eaef3bccf078404e4c5a05e48765049503c0ce31876a74ff63f2f06f50a755e135fe8435e0c8a0700397d02c012fa64455e0c2a499fac07445a834fe3b18d28589fec16a278f864d489b6ed354dd33494121ea7abfd89878aa53c37ea485e0c8a09487a92178352d2279b922253b4efab8522042e8aa74f1685444ae95048bc18948b63d817e538cc0c4539a2718a4647d9ff91a2a10ffa59382347f633f4313f0b5d1c65bf53f289285749a5c58b989454544a3c120036b0162519e3cd917e6971ed8b60221e47e1107d54f08932501444712ea573e82386e06ea909724ac64dbffcb8f6779071e33032568eb2bfc9b891b1927163e37465ac867c3256d7be0b1a1736fd22cab8b9f62dca25e3a65f4419a30c2bbae953f72817d3d8debe98e9170fed16be506de3d5c2f617323d2c4dfa657bfb2f4437fd72baf639ee1027454c387084454ed773a21a52030c8b9b6b5fc4e33033655ffa6a33c2312c0a49bf389057bfa0ecc0fae59304c5d32fa3b78f52d22f2dc3801ffa64eda780224ac9b54f024554ecda4701c590cdb53f02c5d078ed9f8062c875ed772010d203453740cc1b42b940a01892d1422ed18c8b9418434d1ac6a6ec732da6c1d77ec8c66138f55ae55c2b92695db1ce7c4231d4bad6e68aa1996b53600e5323d4d32f22229fe5f962d7f67cb18f47f4ea24b16b45eef579c167fa95efef6af40f411c61e25239d284e5a2579d59c5607588b595d579af6966d0ba574c2d3ff44bf7f67bf48bf7f683e8977efb3e60a086b5a30efaa6674fc7fc9550c6890d442141bdfa64356d7b6d09d3db807281755589d05c0ba25c200a499fec9b40d4ab0d609f3d1c75c65175e6da17bdec736d37d1ebda376d9bf6a2977dd18e7d11ccfec98cfd1322f64549ec8b15936b453dd79ea8ae3d1972ad88e7dadfb417ab7e11a5ea0511aba15cd7a25c1a88725994cb75d2348ab0c2c7294ed19f2f6e36fc5b8b796b6d3675b3b995c63aaada5b9fb262b7d670ac3832af5bb7d6ad95d2dcfaddea35a6aadc0a074811f56d26b7d6d82ff5eb6ff53797b9e2f6c476e456a72ba63156de5c738823cc4095d2421fd95399051123a9ff916afb3334e598f527adc2277bfcd0a77ecee926804fad50b23e50e2fb4135a3c34645b71b9162889442e64af9039a2be5068461a44cc99f11be0b1f2141ebf2c6c4e7ff1cba7c289a4ffc2e4b0e35269fdca6f8d8d5938ad39463cbc15947cd2e64b2c1383239261dce75a110dbf773aa47dbae4f5f7a36bc2132dd085dfaa14b77684fed573034dda06f9fbe0d3fd077477dc691c909dd0a328e8ccca5e00fa1af8fe0f201b38a92c8a55a0525c8a9faa5af4aa65fb497afbd4ac5439fe85b9af3816289aaf8e013a58aa7ae68abaaea0cd3a897864ee4d8fcb76eef6f0cd076944a2533d32f5ceb89865181310e91560e4b16b9d4561ee8e36091915c6a1da6658988bd9858a16e7256a0ba99b9b9d918c706aedb017b3900baf2db6f8c58c951e954adc0e4f24bcf6b7d59ab3fed7047d7f9d25f863bfaa594f2bb0c2ab0813121a928eccec9931d65e40281b6a8b891e2ca67ee1729a2ae7c8d61982528c5d09595999929111a7eb0d5e246a43614168176e188806417172070db738bc82eed0a1f7d6e33719cedea7f3314d030d666f4c4add545c5155d6eb529e20b5744c0ad9cb6c5f0c018b3c9dfb6b777b3dbe83c994e2969b7996e5cce75b7adbb8f2882afd13253d539a680c9f7f5cb9cadbb44cef540e98a41a854aadba3742567fed29bcf9f65e10effbe7cb34b7f7e0d290d77f8fbdd317d5a223c35449672a203aa51a5521199192285036e213b9e9d94b552afa28716786107054988010eb270180461021135c81568109e2cac988234427293192448769085235849a49c958223640a84d417542288308d2084fee95bbe16c1cd3431439f06e981160489194a29a54192a0419600d244a440c56d595cff51a9bb8c8382252848b223256b2139ddfd441d405335cb42cb3156eece040e881c18881cfaeae854bf940ea029596bed97ca32641f81773f512d584ff669bb7ffdb2c39f933080935c9f724ea79c16fb78bafcdaafc039a7be2de4ecb7b053f2d9dfc02c07f736f47172949763fb2cf4f1ed3d8053d3d6a7df2c53dc94cd2eb37b0a8efbec6b60a67d16fa286912d8de863e366bc4d7cf631b65bfec9029f67aa0532e99b2aba655400b930174070b5c1ffde95b6b5df3f6ae39dcec496589e783f1e3e0d1658675e11e8d921df87074bbb8b8b87c3e2785e27fc5e3d2773b6acbc4e7a32b5f301e1c6dbb7bdad145d6307cfde2c7f4f35a06cef64b77b777ad5d6e766e2f47bbc931f869bd5cd6557a39db655a67b74ee3ba8deb3aceb3d13fb98fe418fc97ebee17c72df36467d3d962eb8b592667f55932c2503014178adb3bf038dd5d26407a378fd7daef2b95a4749931634c00f785e2ca1f4430024321b3ca23bf88aade0ebec38f2230147752397bb84e72ccbd314f8dda2b76774fe95977adcc19b59379f3f8c4ffddbdb58bf63277dca6791f6d88c98e83822b9426012ee3a0a0c8155dc619a2ba69b0a0ae5f3e30ef8e9fa91f1c25bfc7071e1caf1aa0c8e374c08f248c5042e7260936602549cdd0c5512e7079c1154b485cf1e4822bce68c115f975c41599e74a165c0f9c404706415ed0c40f50e044ae0660af300ce11192849c145391841494f4408a2df4a088078ae0d242121ffca0092c52f26b388c054c40c4084e112b2862488a033438830e9870c40a603085940356108418188ae042196e52f27f701804e4e08a3118a1043a70214949d5add1730c31404248ec328e10d555c2659c1314b9df729a43ae7c9c1aec5c19f6e80bb29ecb3b4351fe7cff70877cbf7ce97d0fbfd20ef9f3ee903f92322cf5a9b9f04581e362488df3d2f0498ef38a7cfdfd72013eae587770805f94dab30587b0efe34708ac9885a2bd99b5f681fc48d910c8f65cc82f9f2f3f8e5bc3cd8641ec03d1346b5f632096ed03d1c2cf51fc406c5872943b027c2e71e20d20dfdd5d06c798de11f1c9175beeaf78589addfdbaee17e795d3c3d23799a9131c779bd906ce0ccd0dc0651c1370e17ebf88fdfddea36f9defe18efafe1d863be6f7f790b7e7d339c39e487ce2776fb44aa5525dff6ed950e8b7ce9c4def41ddc15aebd750a49ff90b4b69e85e43cbcccc7d7ad1e79c4aba39ad9d5daa4667d1dcd2a5a400e70ec3eca138dfc10fcc3b4366678ec105a8e20a551456f45c8ec20a9e2bdadb56ec5c8ec28a255c71466105cef52e4761859113082ee3fca009688a8f5ec631a2baf20403c34c6b7d9e39be54a574864bd4af5c7b163810143ef91ce24a5688620533b8a51518181012be1df327c8ef5e0f9204f7c7e518537d96d1b267501c418e56a5ec6b2011335299e986b4b9347caee28ee0d61047f67c737c29fb627dd38dedd69003a04bc325ec7315d7e57a31fc355c942aa9ba16cc40389f7c791d358920c76fd9fd044e23428b5dffbcfccb4c03e58469885ebe8c318dd0cbef9169782fdf574ce37b097a496bcdedcfa4176ebfd584dcfecdaf5061e276d8d3d128b809f5085953b19015e9278610c29d80a3178127cf712150f41ce75d0814bd07869ea328e088d6cc6a1bd765dd079cd25fd65cff7ee2fabb90ebef575cffc9c47594ea0faedc28aebfc9be588fb8fea1ff802ada8b150bd7ff03b610b322d75feb3e60897bd10e713da78ee2137d4561b2d2f88a742d0f123ed2ed5cc2d4140534aa5b3ca1574ea4612a8b66561ad66caa60b16c00bb814abec0880d5436b8416122860412267298d8617141cf1123b1cbcf36b49b5df088cf92cf92cf92cf92cf92cf92cf92cf92cf92cf92cf12f92dbe1c3f776e6f1c17ac6eabdc6e908b16a1e969efa63bd3599c4cc3c534506e7fd7a3db2bb779506d286acfa0a6696cab740af6a00c32d235700635711974d3276902ae8b6232b3656666666666666666ee3a72dc141ff3305d01dd35fa248bf87a4e9ffef4fd7750f78f840489c8c75f6d6767b8293e7f1e7450408d3e3115dc0dd20666b62d306858c1eced0b8d6573c1ad74264fe5d30254fa529843244addfd64343a41119142295f09d4e2a3e299ba15cec5c6a2bdb09f8135a430668bd7d036c81b3a66bee1f4419982ffb8b466563bfd2c91a1b4719df7017d21d1c9088594523af196b02aa615172c2f1e0c61b4d460c30d277a391400022080930d314e1f9bbd7cb7f1c3ab08e674c966ac36b709b6dccd6a588c2c38c40f9451f4d20ea0f8e56ce8cbdd7083b7e4d3e933c3c931e8f3f4f762aa0e6064b2e72fb5bc16e414e79dbde1726ec3e5660db7e56a608571b92cbc9c052fa7fde5b61797e3582ed7b9b89cb772b90f88fb5a5c2e54ba9c28e57227231b32a36c102828a3cb91524a2dbecba9802e67fa5c6ec5bb9c0b8e85bbdc8b0743182df47235dcd0599053a8d3e9e321738cf9cc31b4ba98c8bfcc38cc9640f49877099549874cd197291ace7429fa267f794d3740d71f749708010dada3d8dd5d0c1cb78853b6910e42cb1c8943871e93044802d390a18781762c45ff7df7f679d2700c1ad4b7f6fb4a25233c4632cf390945e127f4422f147ea1e7780e17f31ccfb9f53da351f8e8cf9ee9999ee9999ef19169743ffafa0e05bf4c17f0a97efd36e230a3d063ffa20d450178214d8ab5a4ef4329956a174e9a26cd63bfd237cfadaf6bd281327a94e71487020a51029427bd0f12e949a110241f284f0a3d1c2828e00f274cb6eb537d8fc5dc69e4cdcd8dbc09a2a7a7a7a7a74707ce61b4ac64bfd29faee834b73e49c8273a8dc77aa66acecc95d3e0303a09f189cd436353df6fea7babbe1bf171da7cfaa406f7743950adb5566bad65c178821d7b84901670577eb5f2bf25941829cd153b9856fe278d502209dd95ef4804f95cf9cdd67e9f0541368295ff95842471adb5d666a10dd9089fbc34e4198a9f871d8a2fb2567ea4e0567e45ca2f79775e03ee9bbee99bd6cb7ffbf96e05bfcc207c9a71982d7498a332ab09400057f496676df77d5ca93473670ebeacfa8cc4210bdd4fc0346ae81ece99287cfe6eedf7954aff3daf3b7b72727272727272248da491349246d260c06a9f2d655fe90cab7db694d519f6b3a1f895be86e29384c078623d533567bcf52335df478799a9f99ee3309c9aef2e8779310d793b3048799238787823dc010052209162045c19bdd2d28537786aa1a5c2274ff3e4c2235f9163aa690407440fcbe9e0305d6b48a1f0dd1a9dbd0fdb738ad62d14627bad6ab55a6d0b1fcdecd7681b33944a30143e79efe64b386ee170f880bd19372fbb7ca8832440fdfa2a4c43860be018f55d3a6e038140cfdaeefbb85269fbaf550b837054122794fc49917c34ac59943c07704aabff750cac10f575e89796ab141c110371fc326c7f96efd24190922b198604c71176216086005c5a984169e5d75d9fbac51fb77f82d26563c16665450c5c51ab1fd1b307c4f79a06b21644aac207fab741bf475f5008fa1a6d43d05390057dfd62bf0bc5d0732150f8d586b34f64f8e4d7358ce8ed7f16f43c4af77bfb20b00536979b5cc62112bbd2038140ed2d486f08fcac7deaf550af7d4e04ca889e884f894227ecab7cff79cef3623edde7f3f93edff328d5e45cc68101ebba5cc66175e1725af7817ca9f785de8d0a7a0b7e40937d69b26197b25e151ff7e9bb0e04cafb7d1ff801ad36977ca2bde2e779749c8cf91ee47de6071cd16bc3ae4f5c57f089b6b375545ae917d073ddf7dc179a74e0fb7d0e7cbfd014fa1da18a123ed38defed7f21f7e97bfba1dffec70585c0cf7bf63e20f0c7fd803cbaeb71af819cfd4c5a6bc3da750785f7b49d651ce5b8063b8f52afd3b86ccb349b754b274861f8fe9b1e3884f79faef33e9ee77dd7bdd7759e3765e68c99fd8323c5e6047da0549b53d326b8cdb965df6d0268b9167467c8519ca00b97bd1ba0eb5bf8d0e013bfebef0e81d6a8aa6a0f63aa5ffd75d8f750082772f4fb0ba1854ee4a03a5c08fb9a7d0f3f213a34e5706b439b92a62cab73ceb9b29a4478ee9c73ce99553a9a33a0a6699afe39faddbf7df46fe1c7720b6dc743a3b8906e9c63e70cdd7f178a3cc4fe4ddbde7e0ddf6ef49596bb50ec3a50ecef7e82e2d603ff73a0f9ef6e2fd77dada0c8a3c7651edd6ddb281b8afc3df473b8a345fb79198a3f2ed74defe77b60f732ecd177beb6837bbe1c7b3970bf75dded40cffd323f20f7c9e3f740fbf3d6f00ddc713550b4218f1eb7ff07079c87b7c75dd30c6ff4f3b317c336dc11eec3f3e1f9f07ca2f868a17bc77c3ae712aebcf2e228b1732b03184789272e5fbe9c6ceecf8a3d430b54dc223633334f99190e658f92584f121892176c09394f8c459a9f43b9aad1a36e763c4a5c675dd148950fb9bdaa54fc01bc170b806a11badac7699871f8fe9a0d899f9499e99333f1b9b7bb74da730738ac9dd2c8b263f0e3184f5c710587d5c4154b2b25a621e54522631e8261b49047c844c8953206a33d7f38a3677ccbdbef766106b80c5f556160079f38838786b1ee34467b62da962ce80305fae45cc8c316ce709433126d860e34e636b5888f0f9af9e3033ae7a4a53967578186cf0ccc9e71f539e9e73e7de43eab18d2d0d6d9b9c4cc6990df9cccd6dfc7d55220bb33a759504a29a594725de89a789356299bd42c96310df9767377db7d231ea31148cb365abb963d8298ac7377e60884bc1ae268e292dece755276a1a391ed73d26cfa0b87e5b80cd4eecd6ebddcec32905e8e7619382f57bb0c74b0eff4b2fa016d9fec33a735b3aee1c0710697d5b46d034fdabf269f378e52db7d231e238eebb43a3d2b7db6f38088f1a71ea5d4edcb5a7344e00c2eaf86dedcc2c7c5b54fda2f6f87a28f2b434ea27ebaeb30b609e5c1c676a72d03a85f3811bfcbe85243e4305dc7794c83472d23db7da4136f871da3912884e2011133df5aa73ef92a00d421c64fbcee43227940c46c9fa59cfeb35badf541de0e16109fa3a0dff64f01a00e7db2618d2c3e495bf29c1f7a3fdeec17afe3d82be23f7c4e9903474169c2275f253335abd91f6459966535cb6aad21c8ac8d71d750b3318a842138ba699b5684412037e246dc7944b76ee0bb59336afbc06d3ed5efe71bf3669ab68486d22905b3bb695209d94cbf747195cf300d19bad41caf4f70b771983a7a107ea9ae258cc5edafa3bbfaa5f2f4e909fc52fb352ee1225c46098161b2ec08d9ca075fbf1cc69bc05ec5edd775d0fc9cebae16eb57791cc6ab3b4fbf78e64ebbba8461b28a85b744a9a465555ad07a4b3018a64b3752a5f8e467363acccccccccc3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a0cc08299999999b905ad76eb3e1f184e7ff97cf97cf97cf97cf97cf97cf97c99bccf271a9142182f9f2f9f2f9f2f9f2f9f2f9faf9311a9a412c298fef2f9f2f9f2f9f2f9f2f92ab530b90861bc7cbe7cbe7cbe7cbe565cbc08614c7ff97cf97cf97cbdf8f0e5f3e5737b81e1f497cfed15c278c1d0bc1d1ab08494a31f4172fba78b1ec9669679cb6c74a75389db5fa74d3627116d6a9ab7d4e6aa56984da2c59274b3ebbc6507dbb65657e4c8edf7c60fa8489fba050a35911c64bb2a073973fb47328c325150bc258a87ae6a396c355af18933464af1596ddbf44db7da488f9d131b735c2f98b754ed52a9542a55bf603cb156abd56a49573d739f68348af5b4aa6756638eeb051bc7711cc7d56ab55aad1cd66a9b56abd56add74ab8d541a8bc562b1711cc771b55aad56ad56abd56a8546a4d2c92873a44bbe603ce3388ee36ab55aad560e8bc160b09e56f54cafe8388ee338ae56abd56ae530879152447765696c6e64cb87711cc7715c8dabd56ab592392ef9824d1fc7711cc7d56ab55aad541e0cf9c03c9a54b9c44647ad4ea7ff52e9fb248db49137b2d5721cc77174f1b9d819df58caa1a7d37fa9f47dd65a9e2f567ad5170b67acce189db139633e632fba8f159f8d8b78eae668536af394da9cbc4b5d577cf23fcedee70a8d014db8cfce67c7e5324caec658dbb86c26ba880c93ab31d636b4663583ade418fbec7c765c182657e3a4936172c5ddedd2a2cb67a7bbf907734ec94ee4b20fa972ce2927656b3fd00c72d92d8c076194cddc83f0897f7a572673ce29fa8afd6bb45b251ce833d4a97fa698734e677a7df887099e43caa561bba6a44970386cc1dddddd65134873dea024dddddddd9dfa0a369540bad4b3ccdd33b085fa55b88016a62baba44a29f5f93ba7242e4a66783652ae8734c644891cd6a9c9bb8d2b91d9c4421ca3bf20fa698f145f7590f4a36dd0cc663970d8b86c946898dac4cd04beee466b3941727d964472aaea9d9d2449be66c2a44993af61245fb980e3165193334c0349c37c3ba524afe43423e5ce90c2fad4492a911975884b9367525a39910e9d41a8144d190541c9d08c00000000005316002020140c884402711c46324dcdd50e14000a6f9042644a4e9586225914a5380ec218830c4086100000010a3043435305026c01195919559961e84709ae71f207404989004de3f761cfe64843cec11aad3e2add46b09e13cc1b6177fae3c7d5fa8cea620fed500ffff8d7c974be2b6ad83c6746809aa7d70a3c6264ff140154ba663a44a6c7b5d5dfa3b870400a548f8533aa90260a5faab8639208f12754242f3eadc6fcf6547e7c11fb390e33617ecb6cb6999ec97745aeb920b890f85736623b4ae7a9181b8b59c6e879a7431d5057132076906d4b3036182cdd8ec505ab885f389f744d4b43f62f2147cff92ed5c05c053268f1196c4fc37fc48d765b31b0a2da2308b79270d369247c0d68cf97ff37ad36203ddb74a7791dec1a8eae15c4cccbd86f6a1b77f22da643936806e1f18febbbecafb1797a8da5fed9f8d8968b3ab5f25141ff22b9223c0a6106444931120e1ed7a3d5f3dc12bbf19592de97d1a1ff93facc217d16f0ef8dbad1f54a202b93c5273bc8df5cdf29013f64a737901fc3ab31475ba73ec09dd0151426b74a05e0e8551cc03cffbf2570ada71fee9f012c1259fd8385f5ff57221f4b3d4bfe724a28be0b3b248d04ae23c453221154490edf4581f46afecb8b35b05a5d522e2860b1857938f37a11e28fb36f07adb548a0998da104b4865dce8c719dc1b0cc241a2a1d41596202c9a65a3c191810dd979f9a0bd34f215500c9ee763a419735d62a010aafa96ea1ce49b54f976aa11b4f125eaa946bb60fc676181b9b0ebe4168605d60d4b4194b53fed1948802e14d50002514f7295e14331a3b36a552e01ccb128a90507f99aac4468500cecbaca1855dd9fa365391620ac22e221260d958227279969162cdd7f828cfb58f667a5e5141e76e6e44bd6b92affc224f38f4a36d3b5bd3d6c3745300e02e46d16aded3fb1ff08133b85676088d0f9844e46e5f409ab3c92dfa05df49684f6b5989c6c894c2a0814f07311db2489c6ea13507d3d9471fee964e512cb3c7e9bc827f62e3d2b86d16a12fe2786220d905016c306aa4940d328ade316cc05fc37e370a3d7c102b8232afb6d200bfbcc8478125b170f02484354f9af875097272abf2679d604bc161f6afa537a154d806b6e4821a111451132a8b9933b1ba0d29c1da8086618ff201d71479a7e30fb55cd15b00dea0baaf878f2ea98dd1a8a6f3d40cffb0704a50fa078b9105909f426b6e0a9a382a1799c22de112de3fb442c7320fa2ffc166b59632f3e813cda97d649d1c7750935bada07ab9d8cbdcf598529631b555af6029753cb353d80ba288c70be4166f93f2f9aa906603accd263b702c3e0873ad07f7d7a56a85486475ea11ebf24fcf7e904c9d3aa5e5c7045bc0fe99d0f2a8790c2e47a524212af8f00e7e73a8d3bd8c10f865537d521ac3be5bcc1183d2b1561e0b18ba7b84ba7725be669893d5196d0d108bac3e18ba2b0e5028e50d22c017c9e3087ac2186265a6f981efc2425fb41862275f71eaae00f258507ea9bf8827f86812fc74d9592816c2144e9d422cfc5942619127803c67523374c894a6216d048edab0cfe56e00bcafc2b91bcfe1f2a5cb6742c640951e2184e92ca03c6d2dd88ced9c7526a1d9a32a1cf437e585ac9f39e81231d3e31a2958db157eaadcd3477f7ad0ac24a32912bb689c1a10392ca5bef34d85811bb86f75e88e3a41814014b14953fa5f3986c0ef6a8ea4968e67f6bd861d9d8c1b729f0b3663c0e04daa2ba153800cb569da86424bb057c7a76739a153b868aac1989346ecf63aa0abacea75b6ecda71d63c4427b0e1413ed81538a2df69fb6e92cf96d399ba87240ea14fa34358ef66dbe2103c383ca26595a7f7e11d4a7458d2b416cbd6d06a2a2ac1a05f924ad1c8cbf88ce1034d939386c6e4707a8d94d465bc5b33394a0f34504e8c0c7439b6310371c31bf452032b23608f60840e89b84eebd49c82c1589de69f72ced1883f1337370da771826dca3111e39583d56b940e424470fa54cea4d32924c9a10b0aeb52976e27bc59f6c40b2952665eb225ce0c107b2d99fac2184e2da28c9662692e717b390ed08194350357af18ad6d78dfb6246ed8ae977b87c7ab6ebebe5a6f5bb7b72fa3ec6c8d9e0a7f68f361c4e8c9134896fd88bd5a1555ca4d9b11babaf85d3ca6c1134cd02ecb37ec21901e21af03a8734e84051228128b0e91acf25f11c98efe536b062a46cd80243ce18cc209ff6cfe0e2cf0cafb0e15a09153b78358783872b92d0db6d5d20da692a36d4fec52dca4339fda28c6913a3548a8d49fb0d4d4feff1092057109d821d72731116be3719261c6346ea7d86c80e720455f38a5e0acc2a37a5e3394a61b8bc8892bb5a4e09d83c828f8fe1970780064e5d228d2153d456013c17d889d106514427968fb18385761de9b4848baeee496691118d9e2306f820751955bc9587caab796b90d1f4e6721dbca446b845c916fb0bb8a28f90252a679e87bc0e08d06eba0784f38195667c2db8aeaf48e2a370f813a292248194e30d0dcfd018d2cc7ce0c5d179c5706c95cdda04d40dc5ba5391d7e0547cf8511c0165ce2498e1dd8941bd93d2588bfac322765d513a901c9873f8cc5007a12f915faacf20f399fc4d880163a748d9038e362abc338e9e88e2be2ab06606110dc5b0920ad719330eedfc4ae9420b77d4a00e8ba318d3731e104f2d99f6858f870852889a69a22336294554ce447873d98edf374e3fc3029912b690670c1ac006626dc03bb97d7a8955a3bda8792435eb603a067454bcd27e1ef306a6c9ef57a8c19299060fe556c919da83441005026d5abb8f4383846bb31b6eca406fa8c6d56260d3e7dd47c52bffbfeb389258426582b4050034186561a0164f09e26812d999a1d2b958b32bdd7e7e8ea522cee4985c48f16d9c94dca0129800a9df5166a46c19f09c89d64c6e01449a56bd99828ec866356af519fd09d1929685cb4968a13b0b11d02a0c742339c2583d221ca27a691a2d27a0602da4a090559835060f0b44e1cae2057d214a14e0d044193ad175f62aa63e1105ad03c52718a7109f75d600c6586b3d40a0824c91a51fe19484dcb069a8c1d9b37837041e19e127fed40112f543fa7355e6e7e184c28e1645593823aa916a08e014c4e893464d668d00fe2a0b92040e3917d325ed3bbabd7c2e9c81b1db47a2826cbc90b8375b6a6939a70cb822cfd519d541c2a236760ac721479071459085b4d5229ea5a5a0008947bc37182a30f85e5c746d72583057683d3b7d0f0c5bc2870b771005bfa56102284ca08198aa5bc407661c3d58926fc36103f2b26aff3153aa0d66bc387f95d8e39348335af97cd7c91e3134f846dcc6ed3ca3b494aed220351601da5538b195cc0dca379cddcc22ce8e8d66302bb48ea06e623190f8739d0ec82d056707cc5531d766210a80c3ffe797eb92314a62725ac5ffd8a2d8ae4572d80c5a409c8ddb71c886109e0514e3224e49560f0fd2cc7e4788ef6870a6f9942051c241823c784c4311ccaceb269627262bee08c4dfecbec329412009d609fa40ef046c2136d9da0cf6bd9138a32fcff0b9788f5a9d922b0402edc3fcd07373caefe86dfa1e40755e88d2f3664c346237e6bf0f1430e66ba020b8ee49f2ad9a42e1deec5d5964c23d85e297063ed96eb475a54a714a31b715d96e32be97af52fe524fb5b631ef4ebbcf64d090deba3712837184f1c29378ebb0ff18fee91a080b7a0c85842d1aeabfd370a75ec78ef617276c468e6556b980e489855fea488cb64fe9a1486ee9dc1aa69ba3593dca1f6fa28b885d08a8ec9fa5765ccc1b844a0d07d94df4e616c0c1adc3f9e93cac7c6e44887cd7f6216e76d988ec47e3b2af03cc4f62d49be9d68bd138de02c5c7bbe06fe6088f883474b744dc6b03fcf32f1639e882632eef553fc39f390dd7b2dd82355cd344be197c9185ec91f72266f7c851b5c424798a0689046ca3efc0c08924ab232c5280a1f04e52e03b0b4dd66a6981155422109eed0bfed05016d69f03d04b07e19c1a8cf75cee1e2905cc52f839e896bd1203889a81654809ba990e10bbba15c6288f9153297f9b7c90b1d97c7a697cad120b03466e4acdb3836487a5bc18e034a37be4226a0182837fa5e933b1fe3e8c6102dad59c54c0be2d992d1b015786505c4f3d75972951b195808a71780623b230a222723d48ef3d42c00a136108fa7309d0f08789205ec12dc6290cac28c8028635b69b347302b9758a0571c66b89903cb37f710f4461ef886f7aa7ad3d8a0fa730c48fd732cac5eb0c53fa383ea4d6383eacf312ef5fe2dbeaade3436a8fe1cc352efa5e2cf6820f5cfb1aa7a7d9b5f557f8e41a977cdf9371a48fdd7f4aa3d03df5fe2c8eb3653c9fa6ee44072ee8ef86b4d03c0c1c41a739343026ef690e1e638b4bc99c3206e140e88e5c4bc3634a1c2f7808da6fa49f9004ddfc237c51e28de4188dd5fb8f6af5f72a6bb021db7b3e26d65ba2bd0713b2bde56a6bb02487dd34e51956bbd6a231afffaf597dce85660c7d74c7c5b8d6e05767ccdc4b7d5e85690ab8fda37dd564fe0526588ef0062f72f9cfdeb2f99e9aec08eedacf8b698ee0a62f9547bb3db4ab4c46ffffa2567ba2bd0713b2bde56a6bb02a995964ab7956ea960e63b80d8fd0b67fffa4b66ba2bc8b4ab9525b8f9ed5f3f97992b2d04fd9eeab22fd56d2844aaf9ad9ab85af71f88a326be29490bee531bda707d2874fdb43c903b5d25ce04d8aff7190c3861c6e4d64f10ac284cd8bd7840438d873f8ef9a71bd292eb6cc25118a932df2f531e21dd0bf3cbd8e6a42623528d9db16782082ea248c264f338429a25aa4d83f9d951d935b2f3d4b284ca1a6f2ec874cecf149ad1e44cd4092976f841292650206985130e962b8a9e8dde628be801855a3f0ec535490c692db3ae536eafc5fa9a05ce8b3ea255e729c5e67e5cc806b65292857f1d3caf014a5da0f9b86cd97180f77957a313f12d89b69ea6012b41939665d163dc971338ccb747ec9535dd27205364b723c6973d7f347792bb33f18effce7236a8376cc88ad3f99ecabb341f89ea77326336806ef4864ff48769425063a0262b05d9f6c90666f0351517a0803d9b5578913d0b4c81493963891202b38480a347fc3fd77efe9f01a087a4d5f12ef5655bcfe6dd3420fb73fa5085500c7752ce20ee00d841f01b386876bb8e60186fd07ad453b17cd785a9387900cc298c6b6f915168a5ae3c1349404da70c402eeac71e59ce1236edd5f7c2775c29dd01be3a4bc925229afd8729ff3ad09d72f131c804b61e96e176fdc5202154badd846d5ac28a529eed6478c43cf1eacfa217560fb3e261ee73dbbdae769ad28254d9dbbe971ee8d0741f06b8a7404c635fb6b9bbf4e8772d33bdd7cd69fc5fbc4052f0082eb07516b3777570cbe520fe2e2690c24001d97ef2ac8ac8916bd80e8d39ba131129be6d3f773990ff8b09bc3811c02e8a43fe55c952e4496ac301fc2d07cbb749c8f3c350d56175c63009ead850c12befda9b221497d4078df3225ff991c1cb555fe84b7ecc54d784ace619490237aa95ca36e9583362f44585bb3299aaa5f548ca076521b5dbd3147ce67fb340a5f16097edcf450428ba40cbcdbfabc35f7e02daffe844f558ddf19b83579023eac50ab2abef8e42a090a96fd7ba42b2b0a0c385b306433d960d577844a73faac0710f2966261d67a6871b37017d28a80e75e2e8e506756f6a08f182153bdaae5e720f9b259177aa4b7b2293449fdcba43a7ce1dfc811613eadd0a6c47d3e7c0af9c08a951a70bcc842fe224f36feac0eced5a9c7276a03f8b16b0c80be65e71b0b7097b308659972161e4af00575668b62ae9be5aa8f2a6f0cad2611e14497596e4a3c5f1f7ca4542a12e170daeeed9ab31cf3aad7aaf36435079efac384f9bcfe1a102a8f657fd078ed7d868ad17aa32d4228f007aa4509e199045314e3d882da4da7f568a82d4b17754152b5a7df48e7d99d8238f4e9d76a9ba3f8b10588a90a516537b4bd56490fe01006617b4e8f173be1604b5d7cb9e8847b9731daa91dfba1dc77af36679a9a2862e40b859be95103a9b10259c2ad14a45f1bf1feb5ba77192abbdf1d99ce21f6bb1b24d5287e9fea8f1b155caf0f7e2d2dba505fb3cc4273c183f2360a619938775349847b8fc165919495263398fb07935e2838c26af087512d3334c69530ce2c824998aba9f7099718d3e6750035f8514ea9c06092a0c3b59a64c66d69adfadbd32b6fc5ebfaebb71b93a4cf133c000b9fecb366d5d8e7b7fca4d191df483e6d90124d9818ab6d1162db745bed96e8ee8cfe6ee3387b147b6708a394b4500ac970904ec6df7954cdbb9e465db56874685358aab3ae36875d66ff2dd408e665c56379c51a14242aa770de6850ed09ad638c2dc24ea28d83917702339d2b83999e5cdeeded40f994235806c4415406af19752d424b0bfe3d426a3e4fb166ab81b37daa4ad78bc0dac0c77a40743a1370970513906bbb5092a82169c9df57c8b10fd3c91e5a2a15d1efc0d98f2c3fe16c98143eb864567924451ed511e0109cc85c10907e50101f48e05bc8c5b7099ba01c774dd5fdad8242c7c6a1ba476fafc096d9033bd33530a403811d72d982e90e4d7a0679e63b84b0bd491969aaa099c1ee0cd0feda7d3c63589370b9157bc7188dd215b7f382a09d2e49c2f2ab8606d726a9381fe0beebcb80e5bf00081b9e0e3b68d93d0b67beefff6d0d435e15c352e31690b53e1175e381a0553e73f2f28a70a3af50ea85df0bca49dc6b5dd22ad1558590435841a8a305ef12b0e68b1636eebbca677d243cd2bc09682a5007773086b2b72fbd24b314c3b7aa92ef7f00f3ad1980fee3c0c1c02f037f59f4d8e80117d97fc4cc9b8311d1b672f00e59be83fcd89238d0a1d0911d51a49d5aa650564e3c7302749288751724ca7c6109c27fd8f24663682938dd9121791b9303eafd015f955c60da402ed5b6dff9bde19e5f5a715e67aa23781d0a8e8ad0637b856bedcd6d0624e60bc750d87666ab61256298db201fca98bfbabf1887c29814b53d89dc6b74c08dae1f5734fc9167d3e6cecf9b6c1182ed0b176b8ed10f2cd2b5fd8788de4fcb5e8bac6ad60976e99b4629f972a18045c07002e8cb17a16d80152b781c0921f304ab842a2c64c50678052db7ca679d22f4e6690b3068db08fea16a1218895f817a6227c2a65dbf5f8e512e450208b101181ec1979c6e3d9a687f411815347885e4c48c8daf95b1368eb9b254d44b1059c9f1f11a80ee4b8cc65377aa0509350921adc1f35600486a02bc5489a184054f56841db09724bea215ffca7b3f3905b51f923f296c31d7840f077e3fa5a6eb9cb34eb57f3f051f14fe272e003a82d340419a88e0a6d905249c08b42ebe7d5a004eb325f9fa137c315e73b6ec7e4ea16710dd802fc11692d9df93d5e255fd827ec2705f86a5e729a9764b80eefb579f07304c05f8cc89f07e92d8161e67300ec106ace2b7454c905c901b94fdde9c49a248a811df89ccbb9dc6b6f5c0e41c875b184a25dc1e6ac5fac3b5d29c54904b66b379f355dfcd4a7ab0256800110c02534a0f1292f63e9ddfe8ba3190332c06117281034b606dc903f319ecb2144663b0e586a7b0004dad335adc797f9723c0db899d71ffeb57f0824fe1200eec1d91ce269784c89215dc8e2661cc0a329ef78d7700be3366302549fca2dee876e8c522d3192ca0103446668912cf99b2f8dd6aeff394cd3e4349b7c423d6dc6fe879736dec84e86dfc6ed0f3d27b6b0d5684fcfd866c09af81d4324c9b9bc4850095765ba8bc06b3b5170558185ad910281fd16a305f4ff8ef2a9f374b146e3cf8159aee2eb225640294fe126ae56928c00393132254193eb99a0a5a2c3ea714c285a4d9c062d1bb79047d28741d8fb9a59843675c5331377ce0aa656c97e433f54585d4797d42c219c2ce8dba03a91ad3a578f0f2494a7d5e37664b2e160bb562f1a014badfe37308dbd17068a4d28b720921fed3302c3b5b026462fcc1b1c2cb030bacf0a52710453d71f3745ed8f851eec765c2ec0f922242227b27c65390528f8cea3e9752b40cbf81a11f1ea7aadd77a60cd107de8e79d29b1f339ce347557508be52500d9096d0bd9741f8d960a3342ad29d4691f312c92a3cdcbcb74968def623c990001dc292e48bc88ed07624704ba524bd0ccb6281414d20782f205c259e020c2db317b53408a869b1b9070f993baa7173915f43d1152ed3cf1f2920e32f47ce809d3881dc3c0a9f2ca413d99898d8dbb44d47651c4580fa6b13e41b05e209363e09e9c63797850ca0f70ff04e1d4384a47f50bb7186750c9d99d1b475b8a2502067615ed2b31c1ba5431d9044352e15c4afc59cdb0a4e335e044889970425196aa142b76c4b5bed45be3881cbbe5ba2476dc362089ca4dfed172489724e69c4f13ca197f3b155c02158f15b02d828c30287f81d350fff730b0ab27e037395764645262b32864f4d3c9b39a402dad0ac432ddfb5c81776c4f9feac2be1d3026863f9aaf67ae1cd0ff829f18c304dab54c004226fb4bb67ce5870592271fef597def67ea353242eda886ba8a81feef5d27f2b53c739b24024b2e35711940c451f886aa44daa870d3c2d985d831cf22e34af8cc389f568492c960b11d9cc7c27cfe8d3168c83d36edb9e052e43867036cd71195b44eb604d169d1ab088c5e0bb76eef7343fe259817c7b6819df5404f6146af4c29e081cb0a47e2e56cd9e84cdc2195643764a97329028ddac4445670929ddb6790f66b62ea74778b5a6a288a6fcc53203c862efe733020eb35a0d1cfd2041a951aeb61640b9ca93605c9d470f9e754fd31e064ea818ccadf5e7bcf9d613966b0912af048ab3c59be5cc586ad04dcec168e18a1673b793edf06379e31fe405f26c0458ffed5a6b23301aa9250760ef18a1c169c51f495769569338abb50400a770cd3e23f05d6e3ae5078c405ffda59ca079d3a82683244aaaee0c043e7ea3971919640b50b3be3aee0ec1845d9492d05382c03c8be21a86a5b1fb8b1f0290c87c1188217ed920e70a531453df9a87bdbc1995fafb6d1b37ab6f6835116871dc1c0a397b419b53ca5d9f358211e529e0fbc99a5939b6a09ca0a0b364d0794cdc6039e9deb4d2f303d27b9b86cd33a02c1603b5bb678cb7a8f48bccb6547a47dcab25b543c65bd4724dee5b223d23e65d90dd17be6842d2444c5d1c1adedb8702d6ed1fc1ab8f1776906e16bee3a4ef0fa4a6dce067e656d4e037e6d2d27037fb5266703bfb236a701bfb6969381bf5a93b3815f599bd3805f5bcbc9c05fadf99c24083ebc9f3f787d3262fcc0e62113c0aed1dafe4f1d8c5bbab35d5dfa6586792e42c07f225e6dfcadfa0156e9a5aec8532be36d27837c60a9327e5ab38384b997bc49bdb2da4c24706afb73ea69abfa0ed4e6acb3d2992189f9493e6ba1baf2511257b914ed345637773b739808d4ea27f1be1752e85999b8158f2009fd61ef5a5b8fa803f30dd0c9dd050f23ec5481c58c126103d846cf86f254ea55365a92ccea1dae37e22ba10bb501d023eb119b0ff68319c47d1c1a5e0f40d3bd39b0db3b07f30118bd6a14c23d969bce7fd7b5a7d66bf4ebdf246fc0a25ff00216259220cdef5a9f594abe06d4b3a09cb28f8b7431a5e596fb4e76b34e398b02c651247d72599ba593c5b73da0371148a399bdaa45bb732fa81225747290136ac0bdf16ebbbea92f801d10d81f8a75a02494df4954dd044cf98cf8643509857fd4036931d60df9db0362009eeaaeffc340cf9010982286ef68624fe7af2810d3834561462ed3abfaae561fd2e941f0a0d23aeefc8ab91037890ebd31b1f9232fa3c9abf8774e14b2024f25cc42ff11c9821dd69142c0044172e8ddd2219a9411b1e44f11bbded6961f1d27fae4ee41b8128299a3415176a22872360502aaba97e84f98b6d079fb93772b688abee248ea5d008fd85dd7160428113d0d70600fb7e04b1b220a784f921862f90c53bdf632376b1d97afdf21701ab8c7874d5a037aeff774a347c186d90ffe04109ff855ead33fd16446e2a81dc0841563ad6e38dd7feb970a2ed8668162104dc531246df1a231b30d2033dbb44b15b6d2f080b3d06b44e86bfe0ec7ecb6fcb412578ad023cc7935e7cc3997eef1ba675de64aef9c1f7cd663a3626eaa40ed91ec925e3664fae5c81451fc16d46553c2401ef597d3df8de82525bfadd8a701b852433dd6e739ff50767d08c93d842c0fa13bf499fb9f9ea86787083b2cbcc280061b45e90987e1423b50a7cd425fde23fb46ac3dc3d455400877fe9ead3c442ec85dd453147f6f9a61d3c0e280cd30178f05ea118b2504babf0a9d5e0ef9a8ae35bbe20d4244d01935a0cd4af4adf4e5f33bfb5a54a5c27335eb2a764d67c8262b05c2a0feacec78fd058374f8405723aaae37418f602060a2e3c96b5e694bd6c5694c6478b18221bfd40fc6d6f3747b5c074ea370966bbf82e0faf23e44dfb0f67f72a38e1cf1df4fd4808f5d7815a823f8e794eeb89713f90655f0ee0391f89d85ae20d235ecafccaf37ee14dc41a5d88433d8264cfa79c0c379844e78a690919490314db61c61bf602d64d8d6dcd5593d9bdbf950f338dc425b4a370617e682c5e65c69c8a62a64b6e0a71e950b418f79371f1d3e6e9f08811db52036757f6ded44909c2b18d91676595127fc4a2504b00b30981fe52690127301c67e6180697b5dbb018c74ff320a62038d50de8f019c1fb0b80c2229e0538c6df69211341cf2f68ea2d1b50a2a696500ee6967161382c6015db75e92f64c4c1d1bb0a6eeba6937dd7a0b962ea78f282fa19bc2125e024d5320a9bc52c23fcef74a4fba2262438925275c7a0fc894071c136d0670d6fffbb58e39ec688c89ea784b12382272c4f686451c2faf70e09a689285b253c78117279c7b3d2186afe77c4b70deaa51b3b67860bf1a4fabcd2b040fcdd84580030b056a365f5656f6099f8f7b141db2e8584f28d034b33f7a8b8a90a1010c46f89d764f8bcd07fe6916fbddf424a7206e617d9e2f1d8434040e0810f6543de2d62c861be8143999aad396b98bdda82249943bc44f6ef2fb17d1d070035168b2167cd273aa93659e4fee66e5eb456f12d4727333347523c3c2030aed53993e90a5f01be837cd66bdccf145b4caeecb9d43f06c14cbdbbb6666cfc78c2edb81f745619e1141d79fd75d4e9d6f5d3b463815f9d537a3411fe0bd2a55b75ea64b68075d1687772889a129ba6e7317435eabaf515dce035037920a40beec0b0096b0833f70a319285f4a7db4735920d6f6bbff97510eea0d3f19582ac163484d6434ee8e750f9430f04ab4b728ab9f9b13b4f8df3658219409141f0401d130045d6c4d35528f0068d6cb592f81a3302683ab709e6e7954e35a59990b7cb66f07162d1cd08a3d9e58e0f00f2a0f88ae0ff7e137a4549535da60d293aaef99173e3e4aab16c5c60cf2d38494a48aa3e50250e7792ee13218e8649f92c61cb37047460ce42c8511e1a5601f3136f725546bee6795fa0a792aebe24aad0b508ea5307285e646e6d6b7a3c19cb73dfd0857195108fc0a920685b78af9c81e7b0a14c4d360740afa578274c956aeec89bb758d9fdfe8c0e1f98caa664dca689cf9de60a055b1ae36e8334f73203a36fcfe5104f7598da2c7de99e9f1716877886eb8bdafcc40f9fc0b411ae15693c0b5cf8f1f2639f43868e1946385622edf73db7016275c90feeb4a6e4dc1440cf5addfcde6411b3a6e3a0119533962837e6548bebb9aa1c74efee1b5182b6972d990dd6331c1fc2ba9da97a5607209919c4acde36b1a28e993e01555ee58eb8dc0de8666d1473c7cf6cdf2efad194bfc78bc762208164ff625563cca94653ab65fa839116059565618a0627a3ad2751c44f44973296543b4f8cc2418bfbcc7017ad67c02e5e657e6c3d3900a73841432cacf0a19ad29e40b166c1bf8ab733eb6940cda6605a40880be3d84000e4336d886162474f365a2df21418f6aea1c9fbb4f162a19b9fdf3edf2e0d9d3b56e55a68379a5dd2dd3fcfee993d1f78b571c80135c906f320cb1ab198a410d69611423f64efcf86aa01149d05c1e60e91543d2278a852e2345cfb60d0b66b3f91dc0ea8a21ab6a1ac631230db9bad26800e52254234326b03df695d9149380c5311364d1e57b3faa70c0698e240e2c3252725578774fa13aa58ae54a3bbef83e68a58e20977a022eb112c17a5fe7286059708effe21368cd82e324901487cc393f3d008509dcdabf22a41ac171867c06b603bb03fd190919d993845f6991af73e3a8b3106aaec29a055d0c4505d2c27eb91d25b51be82534da7ddc47e88f06fc8933a562a505ca318c72d55e4149f48c8f848280a9d4385518d69fb3c5d9fdccde64dea1ee350cd2f95499448e09adc490698fa839218b669783942f2684201a141e9839ff2c1711b24a1a5b2de6599981005cc8a98372ab12b588b19d8e8e8cfe0abf0bc65f56a19127b104dd64c76050bd37a43ed11cc82d2547af15c0c9c9036155f760e56992c741e64ffd70dc3c17c7784261d49091e8a85dcaf7df1d9008997edbb1093db845bf3f99b7d16afe3a76f09933b21d80c89db4c6938d18f923d4d40bef892e7680f5d1de31cd0be42f1887283646d9b469527513f56a02010ec3ba6a66149367819e73cb31448829cc8d074a2812083c249d9674a09e68ed337e8e8b5c6ea413c7a4b0286b20205f7548aa6324dc1ece92a7eeb1142a28ed491b505e567c94b537e1412f5a8f599eb2100d0f071cd13360269bf523099ef7cbfd66c03ee91c3149126b23b9ef35a5cb263175b0f59ab57ac7d822d543d3195d7ded9028eec0a0898a70f21086c7ff840945470a222f0d34719b96a43e2f90ce58c10f853048bb55e45756ab42223bdf0f8c04ee999bf37cc842bb841f57875a409e141efe9199f0e3780063c920812b8645ecb9c2a747de5e27e5efcb50ad4b08f5d636dac62d812989800ea2dc5591ba3ea5474e51f224b995435dc5c72f0942ee8690bee289c52835f1f37b96afe75e91b631e256e3147eb55a63c9b481dce04d0b65f55264f7e4356e94ce9444c3c6852211b43e2e87431490ca8c93fb6621357cd3f2536305268a98b0fc72a218f578e800d780316e09c72dca6f9ff5b0b8ffcff82b27abccdd671bd78afacc1d084dd3d22e10ebd24475dee47c4e5f0662ebf0a05846a380568db85c71956724a6fb6b32bd451215aaa99e6c3b85b5f191a759074e80eaad35a0f44de0056fde685008427bcd7bbf1aecc82d96445cd3dfc9e9880cf49f2bb3d74d6143c6bd0ad20f16e6b6cca0cbc586de7a0f515bff76e0b1801f1322db63bef45623b14fbe7989d785163e0204dda990803273b91bb79d71dfe7d28a4624888aef89d92b4e66ba74c1264b978cfedea91470704306389eedea42993cc17a33e15828bc1398b36a3017b8dcd5dc41c0721c6f018e68736ffe7cc231768879abf0af0422819fd131f407e229eabfc40d746a8c1f8e807cbf51ed112ae9d91be6387e2dcaace980c859eb034b503eadd15593f75061d96e4067d05a23e7a771c3b6421f4df3c23c40dd0b4f44ca2c83fae0f7a6c4f0946115e495f6496a2f100f5a80efc340ee745652ae21cb8e6a3698eff33dfc1e50585c646de4bfaf1dbc9f0f72116bac2fbc54c817fa972755d151d72dbb4ca3e09c999799504c22754a582b990c2a215382992313c58532de3a05df30c95c8d790e3bb40f4681dee7d4da11dfb9a1b2c15de08ec3bec41633ccbdfca4e96366af7b86c52f14d2f35e4312670b65ccf43a0ab965c777ce179fe882fab944750826067d3ac0301a3edcf24963e2b1a9b201a8d658529c91bdf851c0279dc6be62ebba9d490d1f7a332bfb24466cadf315471b9bcf5f2c25afa784da911ca8dc166382c4d691caaac67df401b1bf40e81b1cda03868a01578db045346da264bd75580a5f80a6541fd1958b6ed0e6938ca5a4d92c01ddb1b8b0df18a709b5a6a45eca3c348f228f880e16e63cac90d6c94002fc62d509093fdca8523e543240bbf0e5e9ba39f3ece72db8ca16f9329bd49886c518c485efb11689007100bbe040832ab16844953c0f860146ebc015fa50e2de4c35a2c52fd27229cf617cde79c563c96361ba966ab0d956de16c05763e6199fc9f0bf587ba690695a1a178c8108aca146267010263033b427e499ff3e9717d7f2c347f140fc74eaad9c4d975cedf6bd89f977ca06d86dffbf5de2ad9cef4d83b7e568eba76794cc2b7007b12fca3b7ee30c6b11122ff910c225f77262a1a4e20d90c265fe0a3dc5566846dae60cd931d419928f384b5848add7d039e174c6b3ee2b2f85f19718e121a7d556702fae9b0557aabfc4337c2a0a78e428cea813669213f4e771338225f1d0aa920f757ce5d073644ea331545e0034e80a8ac6053ba0f8121f393126131b3be189c7132d4b58f4f585dead605c866b54e47f051f5ab5263f4d1c4a9a3e9cfaa9062900329ed432d39c3f4b7ffe289918a4bfd27e5a42cdf270d2d0e5ec8e5509e38a076fd25eda8395e3dbfb4d633908ef003493c444535861c04931f4dc0cda9b93a39428a167cc7426c813e608d41f7ac21b0f09d2682a486ec639e7d2a37f2d0148b7da8f96567602406ad239f0c0c58bc4832b5a53438903940f1e80ee69acc9c98fcfc4119cfc981f2a08d2c7f511875c60bcddd11e8348050b49e0fa73dbced64dc4d069853af0b04b53eb93a2540d33509d6b37f3da800a756602ad7278d8c2eafd059c8fdeb5d8bae4b3e2c4590a05c5d766cc1bba5ac4d4293f50a2105ea344ae0dfefcc606fbbd64b57c4585376680009a637ecdc13d902889041cf6c6c58c0707c4eb6ba886eb23d58068ed8266622b0ba43e0fdff969582b0668ce4af471ff1bcaf5528470a73bdb1a50d892ded893faeca780b08654927a31e3f745170bda17f941e4846e9449c25144a4fbfdde460ca9f3065941e728b75cc695c7dfdafe01045e8d4868f0d63f0abf44d74d706e4f6308089ae4b321d2422212a18dd7818e907193b1aa31442a1f2c3b9b73ab8a84c79b94d1d3b7244d173b8c72aa31d6d50c3726ecc5310b12a42a7063600f3282d1838c9e3b2f89fee8b92d7528ff81fb70528f84e738d21480eaf8ff2f752e04dde2176df22512e5ef8d8d5efa1cf846f7eb6b7d2e016a0cd84e17782614eae4db1fc331681e6207854f65991f590473cdfe7bbc20046141af07ed438c7dfb5c506c89a4cd4bdb0d05c6bcdb16c353a8127f05e705dd530353d2ca776d781352b01a2e66693ee41e02c70b3f6545af86bc8b4a5f3218ca65e2ae1d6d1c4d37d12d0c791ac957a4a346aeca72429d39ac238582a41c520c79b78011854e5d4c681d2cef3c52fb7a29fa222553f9ffa96166ce0ab100881541791540210493a55f410b9b894ea2b500d6a384e046a8ba76843db48a1aff2e4b2b395a3d5c97526b433de4ffe6304b8104d84ada531a92d29411b1d83d8f7d07f22a32a4089acb9704045ae8723664a2f649acf26dfe52d0ecb9912b00615b7d7f83b313a6e5e0389759b57f63a88a66ea7e0dbdccb93c2ebef93062f5475c710ddd520d1ec375534696a266d425b2a483580f472461a1360c37e49a04e3b22bc7b8623eebff0412951b81103d236a62c6e8a57dfe1924c9eab934c5c7255a582f4baa293b92d2b14238a2cbf8ae7a42cf9ef8dc8b857a9d8a41a14d72eaf2ca5fd073824fc73136d6c79633bda08d957b2e1a73b196c41882ff1bd32c3c80a5b922571eb0555c680f898b729d79df1506178099daff04a0e21afb81eb3f62a912c33b83998da82dc6cfbf318a935db4325e1267e41f420e6f6fb2d7c37a6f6cdc62248f4549304d9a4de9da40dc0866225f95cc2b2e2188f9c559ab1c8e1307a12ea52f0fb3f202de141564c0e4384134c91510bf995ad0e7d6ed5d735de66c689c944d70c2caa5fc71832822529e2c6cf5c509f31093b7b68bdc0f0eb7483f786bddaf93a6e12331f3a782d4bf9b43ab9ed5063e62783063b59a02064d6446bb16db7866a8ff82e2fa8c142843bab3ce37f30aa5105cdf635ff551961d3d98370b487f3379a824be791d2354fb9a324d46a316d27102cceb966a4d30579e9bab91600e0a1709a13b2b93c3c0663d030820d0ee420d01d204ed221066a794ae82b6005162424ceff24483704a0e31146cca5c86340f10e4d7b2ed6219b8832b964ba4e61f2f20d90f068f0a3c8bb5c0eb390a0d46b2fe52439da116dd806e4228a7a23cc6204f263a3dc9931dc95b0af506250e70f44b4f970232c101af2c3a8a5a96575480dc9e2af49558e057a2904af23d281285f95a7c096b1341ca0edeb10ded2bae1c7e91716d44cbd1da31adce1983f71f9274b02990d93744487fb7753618f700b0a6227ba51d9b89632045caaae71ceb5c0f2b5d9979bfe9f9c70d0ceee6860cf14064bc60b05989e51a1ca9ac498d6dd7f614dc94805dd1dc0b09859271f9e1d14deb93e2f85fa05d1ff0789af7a8fdb669051437fd040a60f74183b0283735422d2813341112fc1e341758366a55cb821d62c63aaeaeab0fcc6af69ec72f9c49497941b4c754456d3545c70b071671d8efe80a05e74e583e7240206c2765349f1e3fbefd05fc78ee841b6fe96c99d763bd1d8be8bec6b79732e825fb4314bceff94a2368135fad6cafe7ecc5eb449a638bcd1959472ba2d3ac7a2134d59fbf41df8c390c0c5809188acf1e9a69ee6869e64fc34965d9aae215bb73ee806c616a64615567cd3448125d1a49869995d37e89d2b30aa83db42d22aac58e40125531ceefe2f0570cfc261d6794f7eaeabd4937ddce7610f1b87f10ffebda3a42e4144e2ccc0205926e23f17b0c9c1ce6ba00cc77e16d12762f62231d6f6977d788133c10c7d94261f5ee6a441600c1e9a9c2f8294b9e09f6c4ff938aef0bd4089eb780ebde6dac6b5ab1ea052d3774caa41244b17a8db5c4c112e6c81e5bfa237a427e7559cafa87f67b3dfb2029fc94f2ddeb6e0bb3fd4d3989f01c790771593b2df2b2bc51e780a1f91b4f4f1d335ec588eddecc0cfcf5fdecc600c13c8f9054f10f8b0e2e4de8aadb6c8154f076d0f0a3b73b8739e0d3e090539e5eba14e6e9afc6161d20f11b1b8f4202aac3d2a3bc69fbfeff99b0a649795e37064984e246fc333fd6a80dd84c0504d6a1a9770a25167c78a7c278f3c8845180bd2f8bb3e2ade6d72dbc30b4d7aabc580bfd0cf450404932c1ba26d535b16eed5a429885f9a758f6638cc7554394685e1aff538a6445d3ac17f9f9cc205d6bc3cf6029a56ee16d470253d9d17481ccaf3f9f4e55a11aaf5d62c15a07a72cfaef5be53592c8a05602334e6cf081b89a8318ead25076c3fc8a52b0cd9ad3abd579e73391570d6a5e93590ba9abf897b57e6e8023357ab24031b7cecaee9cc96656df2f7ae6999bf6a687417cf7844b0bdde1b301d71bb32ce6b942c04fc023db7cc7c826988979ecf25eab2f14640f218d0f96fa29dc7c71c8bcd4395b8283f1255270051a1968e4458ae04d0acd2789aa8d2002fdbde57f609f7aaa7087c401df80c58cde09a7ae8a615ca87c3bec10c96e1b950e0b44e4b56bac859146f00dfac3f4c81e12fae41014579e82a83feddc267f8d773accf00a8e09019d29de1f3cf0cd8a59ddadfb7fca97c37ddd7190ff27468d06e860aba1e11e6bde4131ae98f8304be9c4325119af9ffa69d8ff4e9bc2b476694a41eb2d4c98281025b6af59f8c2bf325a4b5c8f2080edccfcd1e6a2ad740ec7dc38816a2bc7d9978ea43462803f3092461f08eed08618f9fa051196e490b7ed20ec6d7b32dd4e92831368e22c54d988e6cd220c01a478f4714888e4590e1d43243ea3bc870c985331baabd189cbf1009b8cbebc371a64cc71d90cd323f6b6e342051a9eebb63ab49b589a6cae91217122efd128ad7dfbdc911c34ef583378190ca4c5e80e22f8e07e58d49bfacde71e1322069ef7b8b92f1740fa9c244f3721ea5063f81576484726ac0e69c5a17c80c3c0beb631727252b0ffa1d52d8836a2fc8be88146d3c277aab21a66664c5c0ca70a34df488746bf22d1dd27a27895f6bd41f4afd87d3a10e5989d5e8f79cda8b28a132a6cf68b47a1a34186856707327b3272decca0efe8e8cbf3489ed77389a37f568612d3349ca4c4b2b9bda480474a6ff9262fd499fe29785d5b94781a736cfcdbf4320ebb0ff16ca8adc9bee49450d0e9ab88f50da6ed5580bfbd5ae53e657fa510a69766090216372a6ebaa296860e9731b60da52416c27d4167e1e3504aa9879bb340fae2a55ea558e32a2e5cc8ece2ab320bb22a7e2d8587db50ccdf3e018da476c1dfe2a198a77f79e9c6bb2b15c48b6b97f220638e35952644a41cb1a9f07b41e61ee9ead523569a2c8e20a93149e3a7b9053fa362bbcaac07dccb39e77c0466f189c1ba9e327aa4d9e45101f8f2d21df8af90becdd36d84ea2656aaecec3e092018ff1637ca766ba93040f9ee1392cf3ecc3b9137215b5f4722bd03812434c4abb560ab49417f6e97d31ee022d2bf8810690322adc3a9b6e2cf936255fb38312ac09f577e7a5d9418413668132a9c1a5a403c8a1393282181da44f3f322230a65cefe8a6eea532c97e04f7f85fe3ce4509a604c6cc29378d0690630df6c8c9f3252f917a7f2897fe2da0f93cbbba92486c5d07d8bf904814cb6f69337c8f87654898caa396d71921e52e8762ee8155c26783bbfc5551f48f5f00e477ea30ea4b5833c1c1a3102e56c5a1e7732f5a8ca006e5a5917ab64899240dd884fb5c3f2b40f96c1f7ac0904dc8dc622622d18fc3c97f3f18920be150d55364976a52288b15431a20af10d57dc10181d1350920abd66d736a263c2d18b47cb363eb49de13203d3eea550ed0c34b307d43c1836e44c9cfb871c3aec673671e67c1c7c70ad54bf5042530f0fed6f9edde5bd31bce86cdc6b6b3a2556b5bca6726732ed7ef77d448ca8b1632ae5209d88c46c32174fd368b3ba991eca18a245486c0d7980ab590f80aebce76f1972746a4aa01f457059aceae19d50a8259b61f51ed0cac10709e3c45873941200aabb2020637cccf0722bc5242c8aa5e8ee7992b2e3be26a3e2fea60b34222855c76626a2eb00ce65a9f14dd62283fd462b405b2cdc4761c4c8c6581f6de9716208f5b05328505917ca06ec8e6dc8303bd9bea6d7867655c19f9a209e2b36fe9634f3466e26688cf5e891541f14d246b8e202e1237ddf411aeb7158fe436a1ad648b4d28d071debd9221d301560966d0cb245e8c02897c2b6723f96bda4e61a66cd0b200fac10718b15e8091c3d3cd4892c168c64c729ee8c01565f0734b70a1cc3cf876f46c7c2ba58c63324e72f3105fc86b35e625a1cb0b6ce5a36339684ace25a60ab6c754a81715c97fee6ee17e0971afa8c45eb816bbfc1d2f5fc9ae9e16353970bd1ef0f1c3dc90a5528066338a0f6965bf1cfc17bbf19c8310326f9b9d4365d283bb791f7d760dbeeae2a0fb5df461f30e4b5830383d489e54aacdeca13e7d40bafb82e280706a50af7a1b9a207ce911f6a39a0dd00dd96d943c2403d2e93e66c76077c416459766343d2bf413175afc9278d113bfecac86c2c2b2c5d43067dacd05e4b8a6527e0c356a09ed254c9e00b6564cd8951b7ff7e2960216b504d43f0c4503fc50459d85db13463fffd52997e13694c2e7d05e25098c390d870f7ce216d587bf2338da03f7f955541650ce08e2f420287926f19231a789182f53e3e8b15407fa2a40b1e54652baf3ef199a6b09203e5aa5041bc78a263f980c35c6815155617d7256e9ee68f69de02c7f3d4d896d0cb9ffa7f134a63430cfe2d6d57f79f4999f0885589a8271cb495208ca2f6844af4c68881b57a42b13007591e1f2b94b6f32c7afd2f50b2b32b444e8e64bf5f7652fa1e0ed3d6201fa99d36a488f38c40af301f8363144001b11a1f548a3ed02d47282a5e538c0c3bdad8f6c05eb464a8bcbcb789a033b01394f7147e03911ad0f3d66d00b449de9d92c060bc8305a3a19f3d48bc25a9f45e0e44cee4af912c79d9469139428bbd14b78f35c62a1905992631b9a20e0dc0a2b32f53b341d79252cab7e9b412a33bc8280f1420cfa2a28fe6fc3f98e5cf8f1e6569b188cbf74327f059649719d55c67d52739bd09a9df853c80828e001b12f40b4ced67d53029d25f1ab7d6be59b1b0f945b9e86b30bc5277d34b71a30d59003617da7e84199c005e2b5a550a66b4a9d141dbc3f5a351ce2377ef14fbf7f57bb071180be902c567cd1fc7472bfe5038e32c0f02db6547989992e1c9790210b29d9659ece97cf542c80cabfa437abd595255a8d22fa5628b37e93b028d80b1a61068e36478728b4b1903304a36828522ed850909694ebda21a79797acffb6f7acbdb6f7befa17ffad2937efad293fe493fd9a49fbef4a433d24f36e9a72f3d13fbfbdef36ea2ef3defa3f8d2866a94a81665a1089db990891596669e789bb4947d7594f16884649e97edd73f77afbff95efbf3ddfae7ee35fc41992fabd2f7e6fe8ebb9bfbefeeefbabfbbf7eeff62754efadedddf757f77efddfd5df777df1f31f1b6f1cf77dddfdd7b777fd7ff115bddc73f7b777fd7fdddf7471cdd1bff7cd7fdddf747084b7b777fd7ff119ed6e3bf5ff358998baa9a62c0b12d6fbed3736fc420cbd5abdfc2856194f885aabd8795f96fbed7fe7cb7feb97bfdcd77586df60dfe603496076e8ec4326fc093f11003c0beea8d40bdd05f4dfb00bdf5fe37c9fbf1f55bbaa43d62ac31e3e68174baf9bfb58a96bb2d6440bc9eeb22f88fdb7b99d2a27439a77d063d5d1c346153251a28850000736545b9fa676f747b9749d2049bd6e0677c534832737dd3bf565fe8b301b447a25fe0ff96c4f71d1f97138172c4d9be28001ff257104aed1dfa5cb4966f382d980323fc57ba62122d75a64500334a51e5ccae2faabd6ade7fbb73c08415285ad2262d705638a9ccd096cbe655e2c2501e37c5361fb79eb30008877c08d4f825d71ac74fafce8269c3b48f16a7df4e4e803bb946ff66ed8f41f6a56374dc1505db52a0cf86632e3ba119081001ac8ab8ce3cbcf911ad60919dcbf8239b821f6016feac7471a7996469cc497cda050784167e53e30f4041fb2f3459f02a6863a9bbea1fb25b4f43924931f9a9c3c9b3f08b20d4dfcba3a8b98e4ed0afee2ebcb71a9dc49f7152db81ae96367fe3b7e0de180382d3052faacdcb1763641e4950b0ae1c2a8282a4cab936f69e6a2c483c8e810d256cfb545fc205eb225ca23f4ba1f88aad5008a4d74c218612630ccd0c3be004b94b37e2d33028abce10b932deaec78a5b352c98b1d70839210285b546204b328a746090c7519418b8cbda8f545228e55e69f708de328101876af1e58b01fc2d37a3d42228478f6b901eb714d9b8745730dd40d6bcb7ec1b149e134f30b2c4f63d0c6b98dcfa24ad9bc9581f000ad697b2e57f197db83c5992078c8604a3faa4f47068e4731db68855f06e1dd6c857412b029c2a4e61d63dfd38865ff60a593290c634b78e0351f8204b6cad7fc93219f928c38b820679654a4c700982a4b254f8965090e2412e0f760181ff8791acb8e910b10c3aa593aae850d69e6af63eaecf39505d6322b06edc4efcc90ac87b153a1c9532ea209d3bd5c7d872c8bd1a1a877231bb3471dfbfe72ab7d0b7a51edfd73ecdfb82b5cfe8d7b39e77602f578da89af62a85475c10efe691505b35aeb20bc7f39909f1860cd455ecacf33cd534bc1569281c548fae827da2e4364b68d925e26dbb5bede38fe67ace68704849087ca6cd2e1d9fc7fbfaec6fceb210ecd0913052d6edb8998109e5528fda846e586b759eb1b2b0316fc18510b7ec3206f58420c035f4933362e4b490d3fb3070fa787f606418c9f72fb3d86c967f40423216ae17c93b6183318b22edfd4100512b4ef5a19e403bb6956e129122af8405cb2aa07236593280f001a203602e150e013374dd6060da4216ff6916de2319037c111545401c7431fb6dfe0536c561c2119643d881263b9053a76965b976d9237f7e54f37b43b12ebdd516404e48aafef4abf4c4498e5aad43488b315c3674e069466f5a3b42c5ea528de3610159b1d909b21288fdff01cc178601f10f4e76d6db48d75b489b25d6db24ae36c57ec509cb3dcbe2efa9517b4d2120521619ee78436cb3a370a281cb0fb5700cc940d3590adc175f742845d9381a63aba8fa7de60a284bf6a48ea238d98e3c69a34a8629aa6d1c61e1d80476ceb5df4ffa397cd1d9a9229babe1a10232fe42cf20c4805076de05098e3ccd62a5b252a36a91fd1b8c5e8a1854a6dbcf21cc8fac4951424731becb46e0bba7b3d99dd92c97bbe44bd1d86d5c0b63519c847926d1bbe4c9b13eabb3cbd40d662b19e88ea042c2d26dfabfa7b32acdead37f03c5d20793852af0f001932f12a46d65e3197cf4cabb441163f0294dea4cdc00e40889967cf125f857659f2db4c65a9c62ae72f334dd2fb40ce9211b9b25a104ab08322fc206812f90ff3dd00dd7bb1e86268be153fd508e0f6cd2e6948f91ed85ef1cfc6f37b1ebe4a0910dc7961430ff15f1aea03c2c01c1d1af2b3036127ddcbf3b156828938d98866b2f2ab0e49a4ae1424f757a052fe7e110391e98592df2639dde9a65191fc204d72a2968a600ce6f17c07732d8da3e220b737cb331fa928e9bfd7f0b44c6683895e3f8d9c99f8c64b9169ac64feceb13e89d91d6a13b2fff7eed03ba8ea43fa77b906d6d1f53dfecd46a16992cef560b4fe53c899adacfec4158df1488f6c0f4e32aff95c7682e5bbd79dc0468d6bc14d3575f4c6665ae5331d1388d4a9d4872f09251b32c1f204f543b176f262074767c2d7b0ccc18794d90b566b5bc0c4a87e30f6baf921c7b32cb299b61711e279fce0c99d4f95bf616c924b52c19a9cba183fdb061872d1a34bc03a0a49e0b6f6850ad6133ec53fcd39f93c086a4fc5389bab232c605993e6326c4a404988eb3dcf1d708a107c3ea5e619a2ade30d1c565a8c13cdd3f941dbb8d0f3c6b14826b82801d0fbe5222fc1151a473c306ac79d340508583f4511ff591f42c7eb3d79f04889b890978f23ea06cde90ce4960824e4a15290764cc8683d82cbc599015249402089b12de0623ad78816c5d512a08cb4d3130e6c016453e590258ce58a182b15764e5538ee7d2570785a2db2abaf7061ae44c656087f64d7634a93006b81865836bfb5e5d34027e878ed4ebaf5b893208c8a078084b0f24d5ee901896bd66114698871035928904547418074d5c1d9ab8559445f336bb361a12058592baf1841a2f3010ff80b528e46b6fe4c9207739e4a35255f962c39a5a035f9935f0d4a44cee1d880c17b1aa36648a23db2321820f38a985e069140165b4d22b527d7b729c9dfbb7b5b97cddfbc8163178abbbf5539229ffdbf21c820af1d96f1442240998fe6d4f384df7b0e825047d3a2dfcdb66ec87a684e258432309bfd18f50423545966d924449bac371d386cfe76037202082f6153a0cb67ac2bd4f04fabf99bb9955176a1e6bade866d24b4a66f23e65ced0620e9ccf5aae20a8e20d44197b33f143b68b00603807cf57eba867ac755c8f90bf30e2eb972de76f46fd2651434a8cf844ae7d176aaaa5216c9352280d7868d5389abf2870d64e2597633fc2d7dbb10096af88230ffcd8edb1deae88eeaf83d13d5d50ec92c8965bc012b835db054fc044b5ba50ad0309386d6a00f7ea37819ba2ef9d9b3eeece0e4f0e422f83514086cd6e4a9495a4686b7563c7a054b9026d86fb79d32525b7691647993b43f115c93209865819adc82872231cf642b40c10e35944f86917904ac087be508d4fb9a2ddffc49ac9d680d4519ba85c1ce1ede9951a6b30736026582d81ab3d4ca202c0357c6c06714bfc26990a5956c15f2f7cb43dda006e8d2256c9944dd812f40d86381b5e88c97c428c4f7b136e82bf0e4203c7291a0c43280668d0a3511a775d17d9975e5a17416d5e86e3b6c19304791a5f8569640be301d0052bef00985d11631a4cb61d1a0c82aceb81bd29f098e2769d24b2c292f4c41ef6395fce36ca6c1062efcea620ab35d244300de413d8b9f440a196eb67213672daa615bc5dc4e3417f26cfb27ac93ce95eb76de59a7103ab38bf84179362680cdaccad809afad0a5e4b70da395b63dce92902a37f5e1e36109410807cccf4519eedc9cadb619ec0a6f09925da12f31e7b4ba66fa55a7f897108c2d9bc3a56e6cbb7d6f04c34ae0528d64639dc53abb84c040aceab9e4c8038adaea92592090c24a0779fababe6e74357a341e0581fe5c410d7a74acf0faf575f43009f8c2b2cc5b726c0a0e7403319a43a41e96ee6614b3bd02b1a81c8fdb16bcdbf82e8c2124c903ddf85efb101bc7d61249c8de726fb9b79432c914a308b808d9084fbedd0697f8c4e4a3623c34799f1e239d608fe8b2a311311e969e3ec776787ab66112275843706564af01493f6711941441034c9464b71183472c3c7bd81ea3951d983cc7a29c79023cc7a24cbdcc38ab4da597f164a08ef899bbcf8cc1b69adc16470fa5771231f20e39c2a459bb749f469c0d75ebc9b5ad1d9e3c3b7fab05472ca060b9a59c724a39257f3616c5c93f89e2239f5c5943c6e99a5de4189425ed5a3cca38998001ec39d6048b009e634fc6bc6d650ea44c77459ab35e201c63e4ee0e3b3ea15f914b881186a41110dd86871b46a928d5e5861106f6a4e23efdfc82448e45a9223f8e415912a9322636fb12dde54bef725690228de53c2594b779819a8faef90bc67ce75eec4913bb75ecede0a86fb9657d2eef966ec83e24854e80e1528f1fb2df38673699779e8fe82eb75e8f1b778121cb6f9cbda21bcd0437e4281cb72e7dc8b2bef822648cc5bf7efef559f7592d16cbab57c4aa376058775e1bd2bc22ad3b1609d4b70edcd1b9b7e3fe8d6b5fa879ab75e3990b0c81bcebc673cd23c1c6f321d90a59ceeefa8c58e0f5115df39b8fe543f27e407078345047e79ef37395b32f6cb78ef319b57b2e3d1f9d7b6ebd4e47c9cddca8fdc6c3761b97ce2ccfdce6e31eed37aecfbf95652d975e518bf5f9bbcb33e7b72c17ab7610cbf9ab25b82c677ded383efa797a78ee72ef3aeb0be3b33c7a4537eefac21b5007f34fcb997f58eef221c9faacdb7cd75d1f3f8ba747cb3b6779c702b50efc389ce8592b762db0628a0d555048acd9f2047846e206506f4399f66e68e05209a41e4993e7248e387d18a13e3a8ee7248c90f9e815e55871f927508e981b738eb899f7acf095b3dc91f61567a74696ac0bb4711ee3c68191a95f4e72c45cd6e8f7246a7ab181ea39664314c79e6335a4f91ac4d4d0e53956c3d487f104cf311aa0deb25794e3c56d7fca4973bbce39efb66dd76faedbdc6d7af3ba9c5e29f95ef9d980371fb3cdcd4d585d3ed4d66e3d3bdd0543f6ca407c38e9db27b74dca9d6d86403c2b3de70fc84e0aaecf6d007d37fa15ddfb4ef8500002820f698521fd8ad147cb8defc9cf5e8220c74eb269ce88d8cd39a71036c78bdb3146aed6cdf9354ab7cdeb9781dba7659ba47146d9b1763fd91c34395d5ce65a49c94135fd529ae272c368bc6279367167bfa6963bfbc53e6157791d3bb9dcfbba4a47f58b3af7b5d4d750fda2b5ab3413cb3d90e51ccb762e4d0612d3e545e7b80a3614ff50f73c6fe940a426b5aa4d0fe4a99c57ce379f369df74def3e5795f7720b35d49406d6296e8b765b9c6aa6ebdbbd0db541a9e0bd919b55ddd62f7e14d3af3145114abf86daaa83f8ad3c1f92ddfd9684114bfcf0b55911ecabe3ab5fd4d34035376c2811fa45a78d8db33357596d863af38a36cfb60d6c42e2443620778deaec391846a5a7d6a75f9406a6dad3af2127ec580f77fe04fbea17d5409fe2c618a15e9387a4fc82cc29ea220cb1d1d437d06a5ffcb8843ad4922ab4a79ec625d1c3868a4fe5ecb8a45f39455c2690f9bd2f3259129768c9bca1987490e61106ea1cf52de2f0d46b5cc23fd43370f6abab70a6b0395fd8d08064ce26aef439a547692d96b7baeb759ab7b4abb9e6699ad6f234d734d734d734d7787450cb357ff9388ee63d1d34bf1c2e6e7b6babb55ae7ba16102056d7b53e0f0cebb7fc7e2c960fc9d6e75dceafc775d5566eabda13cb3e5d78dde5ececccfa7cfab5b9ebf37e6d5ea5900df8923536dfbc276e88e337afaef9f41d10b6a0f0254207f1e820976ffef2f9cd713aa87df39dcd5b5fce993b5d365f111bbf71b96c6e6c6c6cdce5721b97cbc686ca894aa9f5bc2aa5b5cb280f70a8fb44e897f4160cb73dbe06e200ea57b6c41dd24128a400a491b4293509bea6df7ec9ec3b6a7d363d9c22647e26351964bdba741e3fb6ba7120cf06ced7ab5f2f1da4fbbcaca6b58fb8664d360252fce9d4f32139a5dc204d0391e2176922741075cda96bcea3d57ecd2b17b641f102d89c7372b9534a297bdac04e31d957c47ac70c5ae7b74ea9b5ce5f471bade68c50948ad248cbdc304e353f13131313659a62629a8aaa02658138473f8d608c8a50316af3793730464141554d465923464149a10c0472628af3292c549a576d3e9dfbe667bdae5994518bb5cea28e53f65e303ae9d76cd2afd982ddda5b06ce90bb7c0884ada6c7a97e4dcf29e25267ea57b78e91ac4ceb893494cad973ce9694524a299d94524a29a55e13773a9df4c555f305cb530677f66bda245aa87a56f3429d0c24eee6d135af488b9d18cedaea156dda666df48a380752c479e52427ad6f1f0a2900f1b45c8f73e9db2637c9f278f073208ff4e8d54de8d7ac7cbd2209f28f0ee21f5bf52159ebbd38343431850f3507b253a4699aa67520bf5e361a8c5de616bd08c6296e78ab4581738cb8218ee82f7d0e811f0853cb950e860cc2b82c3607cbbd9db55e3b8885c350e798b99c4bebd537bb45bb5990b999556bb95aedb78161e5b68efb32ef329f9fd307a86f073f7bbc59ee8e2839e9771493668c4d5c27dab5f43caa3b3dce18bbe834478b3b3dae99917b4eaadb3e7b4e333b7f02ff4c49c5d46a29a5ac31da2031013c250efe99ee65b9d2a78d7ee5647165f8fa99a4e2b43e7e6eb9cb79fb5e9f0d29e40281c05ab76ddbb64dfe05c321bf79c87e420a1dd49eb90d3540b09efa5afaca67be561fdabc6e5b4df35b75201baf9e0ef2e9209a73c5edbcafe798b917e46a398ef3bc63b9eb2be2721bb720280243204097f5b940976f5f0b747df7b69c3d083091eb7e9dbbbed617d6ef40cefbc575a0cf73ad6f1931b8b2a5c7251a0b2ccf2c97c7090938d1812b9ca88015ec13d6a7976e23d31cea998214da7c7a4cc339be60a1269204869f0d6e51d449d668277447cbe4b4e28654aa5f72ea9d640d12fce753bf629ad79c7cb9e17c02e7d39cd241501d14eb5313220cddeed255255e51c7810f12ca721a284a4e9e633a60f946daf9d8d193620ce2d152128074527a3dd81b34626f8fbe7d61e61be52309c4b39d479f1cfa27718174df39871d08c4889d3f761ebd8bce6dd9048d62373b1c071a510fe7d6b951e6d349981dd881d917cecfbcf5c93ec26c8048a4d4f223cc06c83c120dc9a3213fa5b73e26aa9f8f0d34f27cbae7b9cc3cb7208f75cda98fe91ec863411fd533af9e71ae19d5aaf9a85addc03073db39cf967d3c1ba883ba75cb4330fd34e2dc8261fc30f3aef3ece3ef9ceab06e41e69fd0baf40d3c8a6bc090f3cc6d163f3eeda0f6f006080a6822cfce02c2c175a702219e645515142964104b5e32576c65b9cccccccccc2cc4e69999f9ea6829b6fde3a1ce913a671f0ff5f89a67aee91ebc74cdfba31e3bebac33f6ce2ae8e5b9c5e5b647ce628b76d96e69bbe54c7bb11ae8a3072fb5586e51d1b2bacdc373ec8a09be69788e1131e65fcf31229af4402a52e6390c010c48b45a56571af11c8b41f151ea39268582b7f11c3b4288e7e8ede098a8faa313b83233fc110bac0f91a6906287860f919c68b0537c88648229e8872a44418504020841f5a10a5054cf1506f378cdf3b3b70aec51fc4929978f0e60fe0939b684979f1ebd797c502e3f9d72f95085a49f7ec46bd6ac69b75e3e524df9efbfb7ddf547e3e947b97cf476b890183e5d7eb62905797a4497be23ba0491ec2bd1e591fa85c4979ef4bdfcbe6f24fb7d03a607e3dbd81e5d1631a3d6e5720c0ac9d71d99731e726eb47975ea5ae796f5f1b09c5ffbc26ef0a8f542bad6c7c3f2f8d7c37eebf3e5db1eb1dbdbc15230d875ed63797fb26b7d93bbf8d627d906dffafaedecc8549b19ab73ede330bec534f664792edfebdccb775ffbfd5af46d2b3e1b695e3d1c21a988eaecd17bd8661db147744deba179e5e921bf73f91d1826556971b9d6599f7522d6adcce2eddc82cfbc0ada0be9e74090f8d6a757d482e25ab7d3d3c15ee8ec182b0058d6590ad6c2b33ea0b7dcd7d6f320472158cfbb96bf79b73952f65d07e9bcf66ef3a3b886bd11d8c6c6ce31734d107c09eef48b1535319ed7759ed7b975cff33cf6f1c2b096e3ace57c736badf562db6addb66ddbb6cdd967d382bbbbb5eece34cd08ce5154398718cb2d216e2b9332932c65a679f675fca3b9fcbed695cb3120c63cf519562d736d32fb680d03cbcccc3fad8e7f5ade5febca75ebad2b97f3d6959b79abe52df738077fcbbb05c6b67a6872cbbcab4bcfa4acd92624befc84c4af554a97a07f058daa036accc0708894b2fa903c1ae2b58f64abc51f8ff4e8d2e5c763e8996d849a779ae6436d6b10a40e047fc257afda17563792120c72c46560b047b279cea544ea9e7310fc16e428846ffe918e947d07a98e94f9c8c06f4ee328848ffc3302db90609854a3c7a961b14c5d966a7188c6cccedad1908f47f2a3d71af993b2b5356bd6a8f97a2433af880ab90f64c2887c78a4a921a2a921b2e685d4706330bc5dd80d1e0511a2bd0a491fc1a246eae73ce3c0a3a8e667d44bf621a9c94f48670e8647433e6a43babb8f86b04715343692f3a54bf068c8162b0afa85c20d6cab88db2c8e01e1a4815b44f7512f24f358dffcaecc1f692fc4c6eb5842b28f1e24c2fe28848fdeb00bfb18618fc646b72d7606facd88fbcff9a747fd2a67391d9bc722ce5cb75f9c6f6eb76f724262dca6ec28252b8247f27974c88f1e41e71ff6f8f5db40a3ead6a777543f73eb1ebd1613573ab881f1bfb0462e7ee1941dd946f4b00149453cb38de89b0fc9a321ed1b09f28f640bcb95defe139f86942782475230d813e075b0d25b1e7c489736c03982007d137b1257e1d199c10c543af2439439921ba2e813e7a7cb9011bb2190070af343296b49dd302e85f9e943d8afacd14513206800e2a90a0623ca3c12c50f367538c10b5ab0c10a91d2911fa2e8486e88d8958e3491e6481840143dfb90308068489412a20ff931244a09da742d8243d88b1228d144660639806982888938490558accc30c3952e3d7041c444ec2150090e8311c5a50ef260490d96394708e4dc1f493aa78754fc0469a64dd7c00f646098391029a5cc5330f3707a94dfcca2e433b0a95aea210b1f4697d4812435f9ec030b508afa006759f2d4c311fcccc00fb0d55390ca89880fb81831412098bee739f603184d43d85968ad59b3a609d106cb91424a912b6030a2d8049bf1c20d4c9c040980131ea660482060ab6f827dc0c5089890052845ad00e32c4b88d8c3113c75668e51e9e191e237b5c056441b08632b220687b0b3f081196a8882881a985238e42918d68f7d7ed2db93c0075caeac2162674f022e3052c0e00645d6ac21621f6ad9445839a9c7a8554a9dd2ac635488fc4ebf6846bfbf58f629a503f94b662e7dcbbc66d2e58e0eed303873651e33e7991ebf9f67aed132fee12663d9d98773d01bfda2ce850c6bab885b5d0a714efd2585ac53efa94e1d07e770fea94edd7eb76b54e7beda35aadf0eea1ddef2e18da7ae535d96e1ccd5b9f4a8efe957e5d15c7e3f8f06726c0a9ae7d8942e7e9bfcc351d207cb53bab5d31b6aaafa3c5a41a90522b03f0a45608330d67ce62a247d06aa409d7e40aa520b4466b8c24b1fd9c7d343fa74e93394df4758cd3d67cea123e9c3ce2bcba83a3fc7a68c79da5e9dbf762fbeb5dbe6dcc7d13730dcdabbee8b1f3bdbf9d7af15753bd068db7cb46fee1dc53543cd71fda68c6102e1a0d46f50df91fa26a2203cbd9412b1cc91596ec072e6eafa35fbc538ee839a90b7fc74d7324dc3a1b9091dc4b1294e5e730b68dc85a55e0be2b9a783b42971881d2baf6965a4586e0d71390684970f6b1853a27902b1dcfa614a973e95ea9ba8c703d1594241e961b9f5c30de22b6f94b85d938f21300bcce9d04aefc14aca9750dfd5db277a409cb1c1872e5e5049010c57441cc305b674b8e1eb1b870f4b20743f04498e60ac07353fc19d7e4598e516d46def0460b9f574db3b9692580f4a2aeca0b4850640a4a9f244c49d9ccd996bf60b493ee73b56db3630dc9cf34d938e63a3b7435279ce3524f99be368fcdc77fb95c489b86b84f37b3e8261e632c6106a671e672eef8fa2bc77e7254cfa8b73c8f7794a836ce550a957296abebddb9102e5db7b682b871bbd55b0dcd672972465b08d4fa64861aa326576f24e7d7b8f537dbbcfb75be9c3770dfe042fcf4f67284cca52c673d2d80060b1e7e0d9d2e1faef38c59e02f76659d534d7b4aad57ac3cd1c90f914baf36a324c194672bf283395f30b8df38a33606ca866cd68985654cbb21f994d1a2719b943e9fce929a5a472467945ab96d19b654ca346a5674b4a595171ce29ebcead3b3b33f60c628c2ac4971d5ddd2da38c605a4a2ab36c47c6c5c9b44cfb684627edf9374ea1492912536e1d1c448cf1898bfbc592999963472e926a1a8e0cd7f449e9a4b3769563e6c426f46be3acdd6aa711c978ba2cd09a776e35afa8a33146dac9c85db6d5a95196dc366a2ecc3967ad382e7eda75909769952bf7cc769052525a5dda9cde73d2d8b5944f6494535a3da159d694528e59167bc61969118ee6349bb522f567d94e53704e2a664ef1348593d60e7eeaa1fcb6e94aa15f9c6fde5d4748e23e292588d44fbb593ba9f629cf312aaca8d842c593e798d5d2873746c51929e794d3e5ccbef0f44ca7e92485fa69424921139eba74994e5da6938c7e9ae1ee6eafd30dfbc9bf2833fa69c68c1933fa2968c6eca79e73ce2d6886536f29f323e833be09450acda9a7ae39dd7939cd907e515fa15f54ba0942916bcca832c3439c9e119fb28e86b7940e9c760de25e79da8187adc453eabcd1b0bdd098316346073366cc807aead714212ee7486650d7edd7d2531a4534c05eea20b902a7e1349c86d344e7224f8f9b4001ce319d7a05388873ea1e56a1cfc39bc3c6998534ae11ddc6b94f72fdbecfbf38e39381446dd960cb74b8ad5df476548f1b14eec9c9a99fbabb7495c6d25ba8d4fff861751841c99ca69353fc271eab45c369b03a769528a97eeaa0f68bf3ec33a2e141e2cff01f1d34420d987c6d35e91775767be964a6dbc3f5e917e5c0a53b097d4e7d464d7510074e7d52759075ea497938b1b06895ac359da6d384329f24c77314a7eb78d84f24549fa090e93ffa4547e817a50172bf389fb184445a75100da72ec54821f71b9f1389146a271c48fdfb26ccf3c9f931c26c3299a4503b713299583da5a17c72389fcf8121093e734d2a56e9d793ac413b98013a91f185f16578e6e9d03e03a51a1c6e741eeffa15c3c37eeaa7dec2e3d4db0b0e8eb770bce71b423d7b925576e9a709f2802bf48bfa8e87fdc481879ca68380eaa79ed2502fe3e3e7e0bb3a5f937bce17e3c3f982c49b2fec3eec279b2f886642972ece430a393875efbdf7de59e5c1953be5c6c03cb99ec717881babc1142bb11a28c5a4608a49a1749db22a60983c83597a96c1f39725cf4c824fecc231ba7c9251523e51f09565970ce3702b873b9c554530b14b97c9397c6c3e65557683bd547c4e10a8af887d3913c3c22a4eadb9809223a8b8c00a2b2e6421e22c0f811b2562b1723bc874bbb15c8220a414a593eec3df7ab5cefae27360d823bd1d697d4c2bd9d5a696735f1312276af9d43cea2b7539b5c39ff339399087730a76de81728a036b1572d4faea9ea4f222469e812d313d79aa32b5a56acc4cd3af14a59bd3f391f90443f02deb8bdf3450face37cf87940a71c0cdbb39b4d7a383ece0e79cf5f56f5e9107327f105a1fed83046f5d4e7550e7a37d64a094b2f58b3338f3edd17340eba39c925af8478247514ef54b72a49435a7679fdcd22ff9543bdc50464549a90e9aea20a64b2a0f48bc000a9076836cc72fea135a20ebf113ba6fa7078597383b29dc4ee3156c9454e412350250845162862430a62d3acbc571f7abc40d5b3f9d73006999d6d7881bfa6bdaad3eaf8c664060e840024b53ca45dc8bb333e79c5f92d89994d22262bfb2a21b75c39dcf767adce7553be60854b53a39d732d73c730d34d2bc3dd4409e1eb4d65aabd75aabcfda419f0c24ba817e684ae925e286fe94d2d8dd548cf90144c5208aa728949e63475c1a93b148a00a062cfbcc256e789f52dfb938940477ea86ad6f2900d81dfc31820690520613b0ecc3debd7267470217a9f7798e413125eb312968442938af95db1eaf0eb55f57cce55897291fd670feec02c58acb312e69249732f78acbb12e67fe635dc6fc8462ca4fefe92006a3772c65074527312ca462574065f3a393ea0083db1cc23d728f5cab180d98f817dfce8eb94a46bd6dae9a1d84cddcba8d5c8c9163711c0b0850e73bcef9c68363f7853fdeb638c76ccdeb36765dd7ba1cd73f63e4b8e99ced78e33a8eeb3cb6baaeeb3897cbe56a79e7ae96f37b2d707ad7b9f7853fbeeb3cacdc69757eb3522f739c4f298a91e438304cfa28d2b74f46ec721ed77cb8b9edc1814d372ebd26244e7403b2004414657a7777833c3eaa4faf5382362db0b51a55e79f6ea479cd6a5625adb5c64cc66de14ae77aa45550032b7844a987f56b8d19d8149d82b3851922752b0c7e655af411d7ac59b346e3e9d11414d23fc1d957be006182f005524f8ad45fbef0225188f5f4e84d06e15d48a46cf8e84527a09d4b25a5a0fbd08872ad28d1a476439dda9cd4eb5df2b48916980008904bd07dbce7d8132e7ce8403406cb3e19b39631ef7a8e69813d7b5bcc39e58c6951c38a35e1c211d92a93ed3cc7b66cf1dc736c8b980faf969813679c506a9db91cdbd225b605496c0b55cc89a5e9258c5195f95a69072c371050cb4cad404f411d20b7095a5a0049d1d2020849025159c518638c31b6f34f536da1caf2ad2bb77d3ec7a896f81895d4ef7c615b39c4aaee14d8dbca5779a015d0e7981254b2c69c1e7c48936838c190859fce94bfeaf49b1f9552ca10557088879b076f635729e0c1b38f648e32e460c31ec56f2296be73eafda91079f06fa051f4ad8344fea18e54adb7a7a3738e73f678f05b30043b2073e1c75fa6776abef3cdada5dbe663fae69d0ff50ecdfaf6752e3d1fd563d860e49fe89bdbda1e3d298b9dc57402bce556172b529fb9f6c38421ca4822c993b9fbbc4e48c10a8c120d2104b5f16266ae2e7998704207853b4323005581f2d46fd009f414870410bce6cd8e94f974100dd28e94f9c8407b0d48b2c1a0a763f346482a22e332cdfbab499f1985590f0de4f1d1ae79fcf6fe64777bbbeff4d821a63efb280e910fabb3c5c9bc7a4882353d9ac857b7dcb0d73227f2b1653d635bee71b63a273df7795ebfa4b7d65a9eeadb17313fddab41e65688343f3d1b02c94fb7d3ad4d8add7634e448bef59675231e1f9a53d7ac0fb5c6d27c682c8d73fe8d037554df7c8372fa69447debbc7ef1372e3655a41636c81b946437f36289e6050b4c005ecbc5d254a1a5c992c68cd49c68c424b9386974f8f07a12ae24543e2c61810d6640f382551668a0dca0290207aaa38b2b2670c109acc8a204920c1a181a185c30e7a4367831039717572a18e3c594961747b020cd11346690984b64cf5a6bad977d3ebaacb5bbbb6383d34acf704ee97a61ce2a8cc8e274458b5598581765cee4103b8343ec0c0a625cd820049625b822880a0d2eb400b3e265cc55ac0ba6d8191d803457129ad19bbdb003122d6048a93982c553bf3b2ea52bc0e0e20b0aa0c1028d1a22b278624c8c0b33128acb48520d534401f3430e5e802142cc016678a2e90452569a9cb0c255c455e4081947e80e318e4ca65b30dd2d9c8e6c81a40807060b4d11ae0a971934455ab1cd052f5c114a29a5368b8da2889bb1e299594269ce39a707926869e2294c0ab84c518599a717cc346d5cf000c6063aa4a0881998b4004393a930646e1839504a29a52e485264054988c4c089145895f142cb8059aa65a8b232501cb968623cc7b868c10c5cbc40b94c94164ea899724e502949fcea9473ce18172dfc9cf37ac1c1736c8bd8165f62542439a951c2862a4e68601aa2055fdc344c032c5c8874d122aa6909114ff111f0e90208a80b1ab54092450c5b4c39a7bc5cdcfb1cd3e208eadd3513f173fafc9dee23e339a6c593cf9e635accf0a103a5b159d735de3237f358b32ca605d3d5c2898fcf3533a7cfcdc2c7e7660164b384aa4b959832555452c89dcaa99ccaa97c1c841b36dcef8d91415255c529f5eb6271a50437aa2b853b072b4365c5928175032b0a8b0aabcab7b39a785fb088b092b06060794f785fbc301e19efccb77b5b3c295e10de154f098feadbbd27ef054f059e0cde0dde52774567a6fbc223e221f9f64e4c17eb98e89ee8be74525d0d1d0e9d942e88ce49182ce45252ea8c28752f28752ae89aa88982855c4d4d609aae683293a60b1516722db1849525624b3061b758186c0cb6068b835dc291e1bae0c2b046ecd21825382d5c141c18315337b047712a569c93fa76ee094704c639dac94e0c1786e7925c2c6ee85551515151511b155515551555155515555594149a55555155515551555156556ace8ca9aadad989fad0a9a8b6a8a1ea57d3e0861b150cd641212b6a4cb8859d15968fde3ec5741077105b6121d618d698186b0c13ac314fb0c678a9326360a1961225b30625382891a284a90b166af510c634325fe8613239a385855a4f4401e68a27ca504561a1561a2a5662ad3458a0c8242c745d20619031d4e002246158e81241041922ba20220c22acaeb0d00573c12871c168b960a2b860aaa25a0616722929dda01445898ad277135753531369ea244d0d43539a2758c8b5c4125f9608b3049925ce6c91c2422e322e3241b8c85c719151c24526bec042ac28565454012b2acac08aba811505e5dbe352075868a332f34524b2a550c4425c65a2fd8b081f0bcd2aaed1fde1acda49c035c0778daaaaaaaaaa2a4e892b828423c2c1ee180e565565b554e555528883f9933bb91367e260551cac8a835571b02a0e56e5e320b80dd7a97229c8c13818a70445b26c9614c08936792654c96aca2869357764a5aa541da9c8dc3056c9a85b6267d42ba3f17075757575757575757575757575757575757575757575757575757575757575757575afee156b383c79c2e48ac995121667b6b4386699cf59bfb894652c849a6b367e90f9fc2892e891105d881f4c2d36d493981826cf312b98c4ac68e10e11a9e411f322b9f11229a3b19874def17a3b12e768b98e7bd57f48a11cb041ae3a5f7d82a14e07c5932798de52ea15755db5f2e307c49732048197814080dee8687a28739ccb14d1f12149443a9ef38d40c75d366ee33a3a3a6e248948073472e336e074e9faf8e7e75f938eb7743c507e4d387e830326c97123363639396e6324c7c68de4388e1bb9d1712338370e0229a403ded46a736f5bad6379eede272306b773ea3a32b0f37e71977561ee268522d10ad9d29cb55feda14f8823086d2abdbdc73b4826d17123393a3936aee34970dcc80dcecd8deb7892186e0427060e8eeb24d971233176743c468eeb804976888ce4b84e8cd8154f7c0514d7f972be1a03e7b3f92875319d312b9e50d8cf09ee98624bbff8a5131793e5b63ced928b683e248948f3fa8d400b29d89ca6691a6864738ebda964cd370d4ca279d534af5ad5aa66e34f6079caa631fbd85e8317cc9d8e85635aba5faed3f572bd5ca7eb74bf5c2fb12bee98e83db3ca75ac2b458a18bf5613b70b13a6e9a3df1863cb9c2d73ce49b358182c344dab5b0e11db711cc7d98e6301abf33ccf63b5b21a5cddbdf7ba6c6c9a70ba9b9b9b1b9c18ac2072727272747666121c70c0010732785c3198d1f57845b1c77b7abc1d7186d701c7c2707077625578e9c2586eeb58373618e3e46aca7dcac285960d1abd2103952aba14e1441120b874b9626c98734a28c850e1804c1617d450149061eac83c81410d029e63565b7cce73ccca4b16a3d90efe2ce210a08726b02754c8a0d982b1c0e28a0c2f60c1114c68a03467f7944747bfa49f8e7e49234fa4ec957035b077480ae244302abc218e1b433c6edcb87159483e11032e4ec0a250c1845012132a29a650f0830f423441d4ee2c94e48219beb8c196232de0300351fb8b8522e0820ca02c49410321c030624804d675c51ee71c55019ab303c0877350eff9fb8300100270e33c78b87a867888c0c3d53da0b33afe4ed6688171f95bdeb97c931d37bda2db38ac682d5beea8a7c30586f35d6ee33870f48b030f7118e0658d97df4be7908397ce51013d1e662f3decbe030fef4fce81e3120c8180f0d281fa85e30657eeb88143cee8f946103f68e7f9222c2a758de91c80218d0775c01c3006189756e09ff6bb05c7a5e37cf1c9ca0d01081ba8780043ca951f1600e3c20928515a00c585c8e5ddcdf7c2b7db0075902cda5cd3e3363dd2ed790aff740975fabcad6d3be2cc52145e5c517131e3552638c11296175ca022c1f8e4c40d634fa2f9a35f404055925431e58930b01660c16aa4546902a6c309a8a0d8cc0aa0fca0c4c92a0b19780a8a16981a1d64003352c2e61ff3e40d0ca263fed190df1c6459a3a3fa65c28f344396604f7109473d0d1dd9024d0c655ca0e64a17492940410c885801a372f25482922ec6cc60430d5e0006039470e1c229061a707185a85dc629ed3af7a36294e434312a883f4ee997e5a1961d78d5bec81f48cf3ecac59b2aa183f6daa6ca8d1640a1833a567d0775140b252dc942c90e3848f990051544ed718a853a3243a0d122862f9e7041d41ea95828498629b0b8b2d464e5064c10b5c72e2cb481195ef044124b74d0520451bbece91e2e6ca4dd92d2fe18d4ba21c01acfcc273a893dc1823f818558821cbf0343b9aaa9a042d8f0060dc07338e35906691b171530e79cce7d975f33f2073306d7987e83c6cfcfe089f3eaa8a594c653b75c3ff39714fa213bd04e5a2b05c3182f1dc4e19fbb552dd381f373a84bc86eb01c67d788d9a7545de31c92a537653ed4d400d4b5ef4825ba79ea7aea1e2380fa85ddd92f5ac45787cb0024de60d72f23b1bb0bcb6dcd5481e677aa08833b60b96fa1f4a8940d9675392a19a21101000400041315002020140a074402a158341aa7bada7d14800b8b9c44704a950883510ee3300c32c618a40000041803882133425413071d3a0c97c4dcd7fb7e18a0db6be5de7aa9f947e4840a603a9a692c0c9b368d90a2dace210b6e6fdfdc555e2ff097daef8147a85407c2950458e7d9d1e1ef41b525e74ae535f3c21b0bc333d44acb64c4a14c02858674b87d02792b4fcfa4be89f832b8f72f6d2f040ed8aa4a0074572eb4175b802d7265c47bc1ab04197efefce85540a83841383b461d62c3fe12e21fd622f840d1c407be59c4ee5ba2c7c3fcfa9db6ab029ca4d35be4939b716149592c16318998fa87cf9bcc580cf915e656af559ce036d75958b0a92b74e82bd80568dfc56d247356efe0a031d244cbd45937b6ea08b5474b69a5d5adff66f7f9a70d8c2fe1c4a2b87c9729eabe177f8bb14f74f7f0241d42e44cad2e0876f3105172bb4a90d6695f784761fd9fc7303ab1dcdd42e476d20145efcd1a3b7ffd1662feda0bfa26e6317ae237c7545f34560619848f1d8892ef725da7422f59ce952e7f9068f144ed13cb9b384b890230ec0ec7a0e3454053b8e50cd5f17c2f333331b336506a99564473a34768ecd6ec2a5eefc4d99e8ec6e0632694f6dcec783f59b1b5ae81d24391bca203011454fdea6e0779d0f69294d625c9229b21d995fd540a4ead0b87b3b13b63303f15988e116e0d0545cd11ae1e5eea5f23452761d3fb8801c5ffc29f84f5cb7e03fed45e9614f026a5b12b9731915e441aaef692c5436dfe3876cb9d4f65bfa94189709ba8a08ea77edc5c8decba9dae1876c7bc836eada23684efea4a0646cd62af0217835d9369a1fc802edf0a3b091f6650920c0359e2374b6fbb75883530c0614e6ab99fbcfe435b429f00aac5ae7bca8837518fa09f81b6a5d3f3dd564df8ebdde42632e1d1212e51b09744a5f107deba6c27bcfb86aa889bed33fe0a2e05fd99c7ab5281f8233bf40528738f2ef4443afcc2354a237890fb61be0a1d6d1f986ae0bf6836418b1c6f6b91ab8ee0a2cc73032811226080193d552392c3f2e79184f1c93ae37eaef3a830c3ba2a10f52af1dbf8b5e77721715debb9b4960c316093e07f9d88c267559d24e8ebb4006bd4e9382a0852eeee2f88ba0894528d0f3366bc5971ffb3fd07091154394b975ee245b2ab5ea33470593698e04a05758836e2e5e916e68d77bfdceda47dda119e4606085454da3b453d86626354b61b4829b53f1a67ebf9f8dfb545a95faaf7dfaa01a3a8d6b36672324c1373ee0e8db65e01a67df43b3b48dcf17652b790df2c57e38c082d0ceb7d340eb6e2613f42acc1334e13c725111782c3a314033f82064d286f7f3f3115b2740a3df86b1f3b68062a7d66608d99b1bbc0ec864bd11774ded2a47ee95d763b30f0555240502ff3135d6e7b6351c470dc7dcd07fa8c7f62c403a9fc6ed80407b812622a367f90439ce90a09255607689032ddad2ad577b4d2c4eb52b6691c5feb040439413821c876304e7f129bd83eaea23482a3dfcd0b93b86d49da511ea52108e9ee3d92f7759cd5a6dd58fa553219cac59a770af244f1b8975474bd2f7c9165ce0fc191e1b81804ad447034e758b51b562003f5090613e11cb403b847eceaf9dceecb8cc1f4dbf2f518921313eb9dc560cb2812bf0d9712859739d4077d7fb00d694a550d686c4cdff15af174e22c3df3e5c93ddb6dd8cc5a318ff955835119447470f524daaa79a30a40ef75c17b1c7df0ee43eea8bd65e29254edfabef6fcc18a1375ce6a6cfccbeeced1433e60f11c8bc35e2fb902f77ea0a8fdb4c6ddf121fadd9d73ffd03a3de6dfd8319bc83293e3d2f27f1b1d1e448b27e21b8fd4f7f8d6dd3957650e9dbb9487c239cd30a3899b41e2f5a5218dded4a4bff949690430270dba19d2b93dcd6bf28620b3fc6848233725c99f111bf90977bbf052a1acdd17da89b70e79b2bfd46d4d8e2636a4c8e1f1bfa1b84ab944e6b5db9ebf4e7502574236caf0bab133eb3d81d10dcbba530adfce83bae2279aee46360819500a0f5278f8018f9b1745a34870f28c125de95587080f9c98335c91980ef25242c11326ba4a13e9af3a1fe0aa75b1502b8b8bebd9cbb91adfe9c97c78dce0c85a06efc312390c8a10d172aef87068da018b7c94704038b47e75f1cbd15d0af07a2848222ffca1c78e07ffe3e7d1c7359637e41c77ed9c6f5ca354c8d69a553ed7c48f5afc72f4748dedbc80aa92752f8fa2163f78a7a04744fc723e251740ff1718232c81213e59b16126c78292855474778caa109a0531454ad9c168e304bc01a32fbd3eb8a51b1276e64d4eac02507aa5a1b48415c13e6a9ca7e6d549e3df92a18660da37cdf4acfcda3a6ee2940883a1563cd7bf7e0d995bdc761283dc64bc9c2990a0f08851d5084f6da83fdca84caab76ba002203e4a34fc316b80ab8c4a49790acf76e11d6342ad15c952076616e7939df9b67ff4b61df35bd3ce532755130bd392803712f5bf48e118f27a3770b8eef66a6c7052ed4e4dde1a3553a2c00e0398f3015845da15eff85280042873ac41027a28c59000e71aa714bdb21ac42e5d10702452f321709e19cb89db5784dfc3c793305f516f2ce4a97d7b9899d2893948306560d2d9c51c785a6241edcfcba2aa325f5992941ed778e83721e1519302f4da90a338b66af70aca604e57914f3decc18d83d12d0c4efa818ef4cb993c674c11282769754b5ad9c5ffed933d2c3d692ba89e9f418f9cb359938b7dbfdc506b46a7f20861b2d67e6c35dbfae8ac3c729c008dfeee08421bf297b7dc48a08cfe7edb3b4cb5cd5000e1fbf31c0c1921093a7256fc1c4e31e47c201a274a48e008f5f58b2d207ca7d2eb6de86f88a8ba924326b92cf8acd8959c0e918a12d52ab181598abbd8e3ee1f454ef9dca5fc428e5e1749bf66d56a5e9ce297c6b18368869dad9a0b9466b877e6fff2c8b94907909c1c6ea55aa6366e160fe49091e8b068bb915e462e1ef5d78d5acce9af6d87dbc1981ebf949c7b1b0f71dd9db82d67cb1c680be64f5f373b25972bab039234541f6a22b592136a6b9d505b8b09c55a4d2856e54469552668ab7a82e2edafe4343ee8afc141bb0d2e34d7f0a1ff8d0fcd6f30d05863838610eb3321378cb9e5005c9156e3d269304d0da4ade1f41a4e8b06696990468da6d370fa351ce9bec6d3ace118eb29dfa1c9dfa879809a14c003aa6167fd92e4b8753eaf0d5a4fe4a1e8049b3a889b44aa21506f80e1eaca6bc6805c096105bc17e902d2ae0df113727bb27cb223db14394cd0950bb1fdc9905162082c9cf6ecac7f7cb5115ac3d0b9cda320bc4a81df1997cbf5fa7a943b7c81f0467fa744d8167f281d7a0c13bae56ea79b388956bfb81c246a2a9503c3202c4e1e9a1b1cfd3a55fc1b381b9cd058bb6faa28964418c84290ff52490d627cff8f9b5321a588f0975ef9b2ff97610fb3fb7b4795e361f6b762b2e66e1e138eb28adc3593a5b8c009d299811333f010edb49c78b2178b708f9abc3c586eb6d040a40a21692e2a7a414222a174b768760e9a448f31082878cfe67a40fa481f89420fca36513a4bb2ec4d06079486de066194ec05bb14f2ddb386055429b624f241319246f9cf5b6e204de873fafdf2b3416c5460a699d686ca079d974f2c7f34e757f72a39b9b9131b48e43abf585f668310d6c4e15e2b32561cfeaf08b125e77c82da615b1231a2dbd6cc5fd79c4b6015b697c6763c1ccf5bceca8a96cb56a74aa5d3d2e4b08736d12b8acd65ec9b009fa19668ac408c0207ab17a28a82aef6bbbb04dd14ed0b4d40b7e0b56b09846dcb7be8b9512fc590056006ee065a0d499e4e46b22ceda3fc551cc57ed681b22b635e461f6278bd7d0e23a1c4f24980613d9710284322f8706e0e23fff7bbe97bca568fc311b73ce36a8dbd012f80ac8d3337df039d9f7f5b639a334e8d1f54f782a736dfb851b992d0a5e98507efbc8e0714960a46d209af8fa20ac172458b28e5ce6fbb00ad2ac3293b839555aedb590040949d7954cb0b8d8357522f868f45d35dad1f24c9edb03fdd5b75412f591f7093b28b34175f63253d55026554b247492e705f415906cf2139e7f7a5dc7624cb7ad0549cf592621417d0752a94abec2593c1d7f0117b79884718bada07258234bd18eb834641317c99a5f48b70316808cf19f478ec64c272c826d5f5aa122964b472c870081a0504dbb4a0a78df4cc52167a0d8f06892e5eca75cae8fde5b691d2421c32b39482076e6e3520d52c38232a12d9a07fb8918bae869bedebc2c48acefd510c1ba249d8f4adf525b5fae71d808f1e43088058727f8fdf6373cf5851c49d478f554ac66a30d8dc7f24fdfa151968755e8b501fda7fe171c822468f047ce77f123daac0fda1c63b005aeb1eeda061f66356e1cb30a13820f34f91419f20a1b7e3bb6aab361065cef6d243404fb2e2a694825fb3bfc5237114f7069a815e6fbf0daeff4b2d98f429fae1496aac4fc3b19ee1987a05eccad4ba32e04ae5a659425ca4605d94295e7bfd458078fb050b64d5c915a797785fd55bf7eb96925a02431d37beaaead5db345253af9659aed7d8db2ba4670fb05ac61d5aff72d4b54cf596b3becba97bb9eb2eeb3a9651d732d4bb9c759677ddcbad7f19485de0b20671a40a3cdc3ae0f77e184b696a347d0dd3af81741a4b4383696a94b686a7d5701a1a484f239de66b7cda1a8ff19ec21d3abee64256016583cb124c8e1d43fd3f2816ecd5a28cd614ba76bb449ffb109ff9541ff5291f7f8fa3f98f2c79018bec3ec7891b52707cb46f79960f74b79dd30aadf4e9db1d2498ea6bd8890bfffd7bb1ee8e44b18e9e4f8af43948a21b2e17e03f95c222c8ec08afe81af4eb4ec74af0426d7ad4f307ec65d7fecdb0f96de880b1d6d53d33f8bf9d9fc114b9b84786f477e3c3f87517cec390fa65f410abecd2ff198f9db7cb4b5ad924e39b9e3f108f395e127c7682b974e13f88410aff8188f8ce37ec0e4997a854bedfd7a89ab7eeca0548d59843e872fed82b558fced4557f1cb0415ce3d7200e30f23ae420beb99f87b7515d2f17ac41efc9024ccc8c4b4fd9107cbfb1d4834359f933cf3817490c1a021d049360011666a021b0982ad6a9aeb6e647730d6b66750d818157eae097a0681c2034f8cb14fea74d1846fa5942c45901d9cecbf0a550ac749944c21c24f8ddafedee5f841ebe52a83a8af7130b8e0ed02abeb40aecf8cddda14e21ed1627cd00e71c5bff52050256b3f84965ae63c358e47a3b661faaf1bc49392471287009eb2ff2958a92d484b162b46986c6000943b266fa290868453e455b50a4970e5456b4c6be3d432e00bf76b60c9f9205ff09a6f5bceae198a24021968f72dcc1da4902ca259ceec266c92ba268dff110b7f820ca6aff363d79e4214ad7eeb62b886c693f59a4aebbb917bb7c49aa82395f2e1c1cb4d4144590659cf5b99d87bde4a208d3eed19e8a0bfea0b6df2be5b32d26cfe770bedaef83f5acba6328d1bd4256c4c46887213b92e33677426ece3e850d804fd98fb0efdf0a13284314e499f1cf66e90a0afd1b0802453558121dc0a2965ba518a4d23faa229d90273b46e2f0cf087d3a86512c37dca9f2638859667c777a9e2efdbce2ba631584d33e9273091ec6f32369713e6287ab170ade06548fe16bec94d356ae37a9a35d0e4105abd478ebbe4521ae424e315a6d2f42840f7b3ab2d615b80180bbf7364c21afcaa91719fc57c8f064f0a5e80f7d796c58ed31f4f247672a841c30d237d2881d4467084004db798a2f11e6ae8486a2a6882b41a3218e6a180dd1b8ddb690e30d7fc9080ba14a0b1fb3216fe5c6b34bae4870fa8cde6e01b425d90726f204df73286b5eab4c694ecf278fc86631b1e32e459baf0c57640d3a88214eb72de0b15cfa401a1a8fcd286242a1921437690d369baf2cc19acce34c3b5cef49aecce173bebd3c1e3548b20d82bf72dac415c7ac8808f1cdeff99fe3e04adae305af0bf50cd282d2ae0629141e225d3504c5cea9abc73e16e51d0c8953637c2ea4da5c5b928d2c9305de02f96986f65ded1950cc15ff1340f4cea9fe22bb50573b6fed49845591e5cee5b26545a15f42a50e664f0cdc39b1b2a0398de7bfaa25f3c50e6296d79219e0d1b56b03e9eeeea86136786590721c46491e90a30e70b6f71a02cd198a20b7eecc88c3437cdb7b377cc6ef5872fee12d197cd37d1265256e8a3785866e082bf7830c672723cc0403e17302d920c371513bd3f8828aa11911acc76c8e8725630b38984121050befd28017ba9e4d64a85da23003e08ddc7014b8bbfe1847898938f1c7286089ba2b1e62c886af9f740e7cebe52fee384db83a05114ea18efe218f91bcbb6d8270d30471e5264867b9a0a08847d6f956f078ab030833e753ff4c8cb70dba643c2bdc0bdc212a0f005461a686b4ce3314069607e2cb8cb0166ba80f34a103fa70a1a41ca9f43a0ca11f6c31eafa0345d48490c3dacb67ffec89097f0af7ce6dd4ea36446e53b928696bae165558540d453206832c45fe9523cd8d3e5c73582bdf31ea68f15c4553f058dc86c2078f593f1edf9ff93606748d36c7af31ad62ccd001dad3684168b75a35221c087192e43573832467b9156258a91467a9807a5c907c4bc75c6a50c6e90a42cd19e1c5f26c2de9fb9f905c96127f92be85ea95344670b71bb5825710120e1dc66fd69769268be36adc1ff3f6eeded9797446d36ed987c39922585cd4e8d0e3854864e5982b6ecca30d49f76c0e23c59484e22a25b5e525715ed0e44119a04a51d149bc1664f2961380a88894e7ef5d3c86fe7c1c2298748d2e8918622c0d49ee66c68d03d527088b215e800fb7be3adc000aacd3ebb81c328b347c641eeb2a2f68f05595ed8e090b82c6ea12a1c90ee14e50b25bc147429063c256595d048877c9a2e87550809f0c4dfcf1c8c968bb44ae87b0c9c24fa0d8eac02b69848157b60433188c584c526a38032cb2732ef3a6c37a359f364da8e1500962d2ff3e040a2eaf637af4fdf9bfbf3cd0ba4ade0a33c101716eb8c6add0a0a80168a733373229bba2ddfbae1fb2d917378c25a1490829d9bbe403b890c56b2786f6546de40c3567b7f436d1fdc395725ce157e0406a314445202c0bfe3b828a71e882241b949829792ee6b54ce841441b458f3308c516aeb1f4e09c61b3f49f043975b2f2ddfae226aa6af1609233623751c5e3bdfcaa23c8d1dccc6800bf025e13d413539c3330f371aefe0d708544b2f542b6bd46ffb7d9a7d5a01e89ac42f956815e8bd8dae58af00a4f4cc3de9f08f9ba0440dbb110658c4cad5a4efc5165df678187bb811444e073ec87a27508151e1bd3edd42e440112e5a240073117451851f8bd7fd13c4b1cb15f7606bb5f60eed8e1e233a4de1deb56fbf74c93ba4d058eda403fe8f73a4ab8dd102354a2bb8d3e1afecca40869176bbc58bd473526161e16de6bbf8b2972bfcd5c52a255445b17efe0450fe5354f1022d69361b4f96114389f44bd2d1672da8399e553baf03533256e120c60d19b0b034e3cf81d5af1a14ee66951260104471d1bf13cc08bd81a68644621b54663e48a7bdc4daa9dc30650eded56da4e80e188da2e98ed438b562f16dda2b2b2a220d20bd9823988247e437d470483b83eec2b57190c6cd71f7d8d05e44ab5a793550cf283b97ebd45dabf1a4d003ba7a599f87e6de3ce608ef057a6c161bcec3352ca0a21d41d67e1ee1771a16d95d06f62ec4e421ea78ce82ce7898b64b37907262e2306df81dc82d9a386ebaeee6d56c742fb88ee697a971ca6524083e8c380add80f2c4da07a07352ce21493df81bc0674bdb4bd4ed93a1f5bf014aaf5cf044105278a99820e791ec4e0e152d59e41e83790cf509aa240bfbe89964f787d45d25a62bfbd6ffa237f7a4a7c1a6fc523591e863bb45f013df3fc29c8fb1144ee3c54125fe4dc9a32b280c2d9c1530fbd7c113786ac0939263612a8c955ff5a18bab10f2d5c787f6487f6d5d91212b256f9e83371ac2f26b1e6084840e6edc173c24d63d1f9064278c1dd070317606317cf4d886eb291ce7795273827044f4512440e2c09d47772d4bfeb0533f3f23d3c7662417cee382ace8dc10965293599da6071492f4d7ab4f46ea8293251f0508ae687ef76f76898cf167b9f0fb8e43aa3f2bfed850ddad28e667b745d6626be16faa04fdef6334b6a55a20bfb511ac38044e17bf73197d5e1178bd8d44b794821c6a94daa6494e351600555005cac5071f6638f77f6f2b90a495eb8863592a112daa0760019cdd55feb59892d9309d6a78725b3af783a50b1120af38e7f22f74a144087522cae9d6885598674d669e16bcda4c2d4a582cc34d71aa752fe792d7c79d4da0c9d454ff636d373643edbdfa7806072a8d01718e46745fc7381f16cbd772bfa5d2c77799058f89950af1c6f8aafa2df8e8ac65dbb7fbe326198d2c9a461ea8cbeb0947d7f95fe6a3581e76834042613f90f5b744495045a8db2a32c088122dd16abf6c914066aafb4caaba86bc2611081942be52201baa9c305eb8228110ce92f9937806d4b70c23303d7f0a012fbb63ea0009170c10eb75d2d4fdde37a8d66144eaccf3c2831bfceec342d3248c100abf048738d5a3fa54270edc98e77d03b38e4c155fc7724c24cc3679161c182d6d64b39bca4704238351bb6a9878bf6a8782b3dd701705e91c42a5e643475c97b9f4b4ea3b626307e3421cba5b110d89ac63a499ca598b6dd835ac5748e92f09242ab531f510251ea8ee50d01be691837f86c727fc026855b53c7a70b6e17112016bb1a41d26ae7cc4bd5d4cffdeb1845f2297648c706c64b6163c7656065f8424ef8819300c3b18234a6aa4a1ddbc9ef82f95aeaf12d7691cabe2b60ddd53b180ff4c6b803e838ae09972c30d1691982a250293f3aac919b36621d849ea82ec61b9011fda2d68a1c4352115789437312235dd44d30f5facd70c4cee88817f303a01e1a82475868c1bb8f30c661c68c720753b43d8a85012618818010cd600df8927eb7e50c0c52220e4610fd497d0a1d83118f61362eb85d3781150144ce26ee6c714cbc651c1fc4666877ef7fe55e01c039d043daf3ecb1d38e57f812feb962168d7e5fd5f9461f9174d378d26e5a4960d5f556cb9757d3956f16561f95fa9406427237c35430b5d316412c8068bfe8eea312713b98b1af11ea282e31f09b8ead49bcf9c4d6bea314cd2ed1cd2775ce3fda85f877ffa1c747a613f368376941b81e41ac7c517f32fd69db0ec22b7a3f4e31a74a0848eb83ccedabc524d168ec13070b12920169d13c7decfdc9e5baf26702dd4efd7cfe05ef6bc932afe894709e651840305a958bf973ba774605759aab421c9afdbdde10faccc9df94b728beec96d13cc4b9e9da6b4246db74b3011e475fb5cfa27ed5cd36c7e54e33e888d6f8b390b01e584d076546b3f95287444d24e6e7cc3970dc669ec90eadbec7162258491d0e65b51e3a95fa96244a2313fd42206246855583366428bf608646618243dc2d900aa05f4983085990449b1b652c4149a8b265609ea456eee0e8d47710813bc199f42ac5b1c71215cef7082d99bc7db15c82ffcbb84ffefdc462671c27223eedff49e96c1e056a922c4d88f077809a88183aec6ead7b55648c8037ab122c6daac31a6b6be1a53e1795de6332f701ec60447ac20feab567a7f6ccd01a12f4a9d555c90fe5dfb8fcd6052efb5d4ac48775b2cb166d970144f0f58e83543ead16744a121f46b7ad06ba0aa250ad1db93334dd973156c8b38f6541b5dd935802885f175217b32abda6159d9570e9949ac2196a3746a8db941d42b7259537fbca2d53d3bc303552d6b7e4487b77338a689d8090f09b3ea7d03c7b362edc11bec61a2fa88888565eca8f85fd8104809331bccaf36e2265e3c046caaab775f296f6d24eb7f3c8d029254993b78338a894fc1da4aa11f4a6df6012b17c523aeb8dd77b296a7e38fa732c4c5c09c7b3832dd8e07c447e7644135ff96f33086d26023f651edcff3a43ab443d3c4068b54b6c5c1196ba1f312f4bf766af294106ccfaa2b8dfe43dfe72e9cf7afb03ed819d510058ac047eec2392512ddf2818b6416840d0833985a755c20df39230a8be864b853d09caaba51facaf88748d9e98f8ad4821f52d54323aad12d4f928ff03c655aa52f92c176bd43d570d7bbda23865c60282869d285c3661a7a283982ef5c50dc2a1dc83d370b7a2f1039e1c389807df65fc1c22c002615d2517f5d7b48088e7589e47ff99e131ad122af301a7faa92f1fb96e17cd7a0e2418cfc3e742ac1113b73dbb7569dfd32a41135229697076796d7ac623f5708b5bf39d2c7c30a1f55d8f376ba6217f4c5c8584f1b2328e835354b61194de687ce313411a8d1e54ddc0fab44a28ce7cb04383afa286dc6275c6cb934712a65888d6aa1b5c8df53a6412553eeec26620bd989b4e90c7413815e14eab44f8b71b55a18f76a4f8e4932e8139f216710c608ad90bc28fd371a1436f96231574dd89e8bf503c57b192103b31d95b90fa46dde432f240a159751a7322bb839fdb6648297ed99853eef43e9ff0525e1e3081a152051b9a01c45fcd3e2d3e397f6715f5fc561d8c7802c8145295bbb2087655dfa8959b296dbb4dd8b2fea9ff6cc8fcca1257188c91619231aaf99577798a20ca82eaec2d00b577012ee05c38ad1e2822a8763289231b25763c7dd081d55dcaa1339bdd6f3389be565af829855cad47b92f9dc8a566b12b350929ab9b14868cca09c29bc40e6a3f54a140673eb5216b49b43bcf7f330ecfdb085b748fa5018d81d2d938c8b33f7c0d20b47b04e0d6a745c9157e7a44e9602f47ad67cb858980bb2c197a4e2bb7763dd0e1069750a896233a0afca0626edb7143ff8ff087e2b17a2401f835ce8e41fc58285651c6283163b81e314e0451befdfc2fc8cb6cda71a3d54abf2f338db098da8f5d3309b85bf9d128234157108bb8c251e8f9c577119582d14dfe8ec48a07015db2432213761e990d95127c54ee98eaeaf78f3bbb4adc855ae83e4b675dd66bf296386db0b7c3718d3bca0eb6792a7d699bd4059e77826e7a41cde06068bb5d0f31cd775c0eda3748f0af14999485d8080088d495bcc36b253c067c0d8c86044df0124275d026112aa96b643aac6f435de57f067c5dcac1ddf7fbf76b8f574c2fa5cf66329352b57108eadf344fab386ec4ea008b9feba2510690275b757434605b89a38d8431479a41061bdcd5b355c3cc9e86269aa342ff1c4393525df809aedbde208982f4d8b812dde685362770ef2f445aa9261c5aafdef5e886594f2ba9f48fcbeb2143fe2a36524b9f97b8b1d6e24a9c7e38be77bad1872089a0bfffcd367b993d959b56885bd0047dac72252efab2f56445ad70b0086b2c7584948d109e6e8e5e1b1c0b2b98070426382fc33d9cff57644bf35937cc551173acb9c93a6d852319d42462465612c81755292406af6f237397bceb7f3de077157e03fd3194f5892327b67886845c2bb09312e163ce8d77e7a5c79b3e7af90564c36d110f2fa20755bd34652809bed254a1958501d67a046c132d87b491350156053934c45dc4b9e7641af6c5b2d026336148afc13411d2e2689a8482c3f446cc48127243605520906a445e5657c2bcb02abc4d8820de5e6155e8a5f0d12cb39de70c4462119982a053de2b5b19d643fca98dc3aae81c5164842595338a16d0fe7f40cc1d9814d873d690c997ab042683a2bc3e59f652f99c254a16e8bf291a3ba8af2b23fdb222d20b949b5af3a0820b304bef6b0cd64dc070b40a04e2ee6e8e9bd60e0fe7636303ef8d7826a575fa727b0eef660c8f49a45766170b82f63c72d69789dec4c00621f8402a193baec852699039a81d59ed609d69b48a6a24ef4be3703e1917478726a7f0be352f51af7892a11320ef5b875034b9feff6b460aec2d4291386720e522f1c0f40a9cf18f42156e7c8ca27a0263cb4d97f2dca0a82ddb828292b88d1b40288a004ba51c5ddf3313cb3f9c2d1236d0d98645d23ad610683b4f6923c214ef3da80c9e33546724eae6c0252358c756509c548e680608384a4beca7e50ecfeb05fc0590c3af1c048794c14bac173c8d4118f3a57a6d855c63edd53179c5efcd5b3491a0c6c2939a0883cbe3ddaa9cbca63733d2d6018f51ba565c692832fafac08f7b86ecb04d5cab43ac3fdf849d4be8e148744a83539e1e0f15333b2213d97b76fbd54ebd8e310937082df239dc3dd2944dc0488abd61f2c60f56595e79934b1410d5be0d070461a9dc6784144eeaf63ee7b38703b1f49db2dc6e29eb6864037150988f6fee0145e9c08d728fe0532deb478a6157be59a52e527a61f460e504ca0d7d56537631a94ee54342dfadc8354ce9dd9c4544a360c510bf4403ee9e47cc5bc927f1b802a08890a471fe007ecd9fe166c96b120390d46b48c42e5afff0853d0cafc3db7bbe890606db4f1f37dd379949bf1fd0e359864f5e74cc4fe0b17e052c23930edb45c61e5539f1c5d8d7bb6bb315a5586ebf4d1851953cb12d7bf98d9343f3d88ba778971579abacbdf04c040d81d1ce6cc290ff11980ebc6efa9d859bc4bc3e2a8c77114b95e11d158c250b4db4dc7b57f1cad7c0b9637c758dd697bbc6d66cdecf62d42c64a508f9c3173bd71ca57038dfc0ba12753a9d7615b16ae69134dadf5569f7b290e96c99913bcaeb4ec630303c1cc9e58fab77ee160fd6638ef8ad0e2b077bf4849511bb68bdd5f742b76a2ba3ec69260618a324e989efb561fcb9fcbf0ef14320f835699440825256a2dd09e1515d4322cf2ed071a39b0b13fc446dc7062c5fa4118e0d466a6687464619679754682589f18de60dbbf4b96a95a8cdca15a375213fe0906afbd06d049cd836c66e3f27f0bf3c540d13aae7599defc5962135487c5c0d8bf61d59a59d3eff8ec82bc7901da1b66e162041040a84dfb9c85adc47df9b8dfa27486ec88f60566f56a905eef4d4faab6def2d4ff6b4e3a3315114bb76edb8a0f9c9e040c8bb1e56412e3034c5b0922b74caec503dc26aa7fa262c087c6e4cbee672f4a086c931aac3f84e443947c8ca6a43db38a6c274c41dbc7b98197095493e79cb50b7f36f1d14af1d854aa6ad5ee5cb98b8d832514ac67857eeac2c7476a98cf29f1fd023536ee886758040b4272264d690607b513d999a7d7d206412b4c265f65c0c01eaa5967a553a3ad01b70cd349815258aafcd5c50797c8aa816d1cb4d40727d18bdbe83f4988f23d1f9ac08ef64bbb99500cc390018ba74c9db4f3c473aefb458e21c34e17d348822d0c1f39af10fcd1f49e35558ca7df0100a670e9fdacac6cafcf624111ce4abb9c80f2c48e350e474753dccd5521639b421b34c69b00d01a02d0d5dadf2b120db447b38750bf8ec1a50c6549c6500c04f79c2686ea100e8fb5adc2687912b4781c80eed3a177b7a8c55e11784a6e0a2c359fccd7060533a9f0d7ec705c07cb57a9c446c9ed42865435a7eeab32801ac79b903ae9187f3263441707fea2f113ddcf67a3be0a8ed0519348e7856a6bbe2a5b3dfc2b1d3419d006d1ed0ab6e00ab2106f7fd3e9a536150a9d77d41c08c86318a0345d8ef02d94d7894714830b595328ccd440a8f0de0626ff3d7bcceed9f49385e29460f1bcf44787f9d0c4849b5627878eb60f4f42859eb5e078248f62f636fab538b6410d6dfb40188acad1c82df1288cf389c532f5e0cbbcdfbbb1ecbf93a55859723b81c20f37523f63df24d808f45b09550d6f549c9ad3df1bc2fc949fea980844fb61d7e36da04de91a2c96282e28162fad6e0cfc5e3e9b84a3a810c9dc070a8f5d4e76dfd88811c2b0e540391af67697a9d27c78fe413d72475a0d80fa083a50a53694d5ac3fd16e2013455e6825dc7010f543b39e81835a40f72b48b93143d900515cce91504d8c7b1b5dca84ec07200525e3bfd712ad3b597a30c14fb78e8a1d6bfebeb29830279475ed6108a54b388479e261c6c6388981345a1e172de5cee069c0adeba74cc8c4bb6b33ab2b9147745bedf2e687bcc7db771851a0283b86bfdbdd1f5d99f6fb8e3e3e60bdcb214772721c529543a62b7073749e43f458daca3f8b2147798f0e292d794f07c86040ed0338abbd22a4007b3621e755c34c4cda1267cfa33d834a02b96e2aeb66f71779c0f2b401a88716d807b77a53112d21ab2b09d81cec5bf92a27c5602f6ee3247ed879635f1caf5c85f59d2931e306f7a3d4769dc743b88b7230ae276172b6f74d961c66d543bbba48a6dcfbfa4537e4753631712d40a57643749ba3f25d3ed73c9ec14cb8966eda707beee5a5711d06c688747da2af1b3297cdd611e3bfabcb115c16067aa460996d571161be73208b00cb75e83e05764e330a6b0db1569383e76b30813ff75c746c74a9dccb03b3ca100f60935b5af589b0af4c014e680debb102e538476c81f8c94a6ca0b8450f0a1c23da76abb327c18461f4a5abf0503d69d9d873b23eb49b4fb1b860c2a44de389760d53eb633de2c43772579cf82410f64491cadaddad7f38b114bcb2e5066c31bb6b72ab955a5c794854b314c1001ab34ea1c254adf2c7562250479e559ba9605dc8d8d5e2b22e1e6d926144347e8360e6ea252ea08630670c74a70674f919748287b08ca972f76f3b198397a68f6899f7372a95860ad391ff89b6c95dd1d008c83f1432acbe04d3cedea3ca0e8842e5192d5e8ba4a50b0490ed4df41d1e96a2e30bb4fb65f213f059a539a1245568a085be283f04cf0fc98038b4c1db74320b4f8326871b361b080e6399792b44a9791d4c2ae761ee88ac21ad954a46efb3fa11e39ac9a6d7f7fea674c0b8feb44233d216e49b58029ca595fba52846daaa79426499652dc5d210753d5f31ba8f5802c43f9f57f2705599ee58ccb81a9a3de3339da0fe8349d1418251643fe6732ca91f58044251e084b884e05e178520621e5eadaa0c2987f6f108ab65c35e5d84daf8234eeadb642cf06ff08316c396f2b5c8318689c9321c82a836ccb077d55537057ab96fd6db67c5d1f1a893bfc5a93c2fead97aec2e3cff77be1affd83b5063e8ab764e1536ef9a611b0098064e3499c93167981131ef931a63585485d0d1c6e70c888ff45aea1711dad3c918bb4b5ac5478a1b94cdb4ab09e70d55d2685c11e06f620c7747a34eb87bd71414c4fe49ed9602b19dc381d3a3d7863949fc36e27e1bfb5a263237721daa3d9504e36dc144d56d4a1f1dfe6e3002ee2cafd69333572475638ad2b0b4e1eb7f2e02bdf7536ae252bdc66aa2359ae6e4a19e261184ef9a58ebcb4a5874bc7808ed8f2fa7582cabe2174ef91a7f83ec9effbf2d0b59ff211392e2cb66f5ff54aa68c9ebe57b544a02f41ea82234a0d8c201d9b5af4d92afbbcb7ff40cc842ffe354647edf3d630c4e8f016d3f640a5b59c176d7e863e6f09c6cea09f3200cbf702089ac1994bb3753a08b748d22e5fe7104f01e114c42be6145687c44281d6ab2e7a4538a9e1d97e89135f92af191875000ad85e84a4ebc08655a753fae32700b3ec62602fe912eb0d542219d09a288d3d5d9019e3af174d7c3a0ee3fbed84905b53cc6150f212b965ea20f4d2ab44e6534505095b23ecf71ef42110e703e46c4fab0de4118db2f6546200a0517438258aef7db5dd834f39a8aec6085ac533143be2a0efe9359387642bffaaa45fc4add1f59889bcd123d646a3148e232ac22ff4aeeb4a2925bad2811d425c003a6f6d9a36d83a26a8fa603019f24ba97120a53734f13dd817c7db470f119ce006866143aab6c42c47df0ff6be354aad13823c2bd96f64a19eb88a12466e08a6aca2b1a51745cc92b6de0e700f153f85d62da49d3b1f6d98ec245bed3102e58927304d1613a6673f6dfb8cdda78f18868d9dc7f2cd11b5d4824320dc44e5177f4f2509554ae1ddf794091d3265d9810817803a20d1179133945341b75fcf2d6488f5bd565bc2379449c6c02f54a1db329b2111c931df48075428d0a23f30201b8b6d039604af8d60f2b96a6584663a289f85a59f8587da38f2cbd42ef82bfbf2020f54fd19c5511e16183a93164fc26c12316902119317c924523651def5635bfc4361ea3e8b24393c3040cabde22ad21fb748dc4566058de967acea23b0e80a99e5694bd7821b9cc5d1fcf778fc35a1cdbb4ba062b11c1c7f8b3955d61692e09d9a90f3979f44a39331b9a44e5db79a0ba8681135bcd1f73bc804c7a6c1ca51f2c9b97be4ca192333a65be5a3014617cd69a279a902c209fc97c4b9d6c303c592fc4136fd8821c4591ecac9f5722bccb89de9d13ab12ba013d892e2c07ed7d6dc7c47e508f55f59a279c11f6c664c2a2f7f3faf24929a10fe5c8a57139ade35818a6ced9a9fa3c517be7de6cdff877a581bae46b3a913ffe61171cd22eed4fca68a034b6e9a13f80f4861066c4c737ef6493a361047088ab77a5e613c0cc1ebb8fb0d1480cf7d9cf2dfeaffbe7f7045c4b811ea51a9795300f4b4fc6c9411832d00ae7bd997cf71eb093d76c85decee676d1a758bdcfab32c4c38baf78b67c13e5cbf97753add66c1abe0b06957e13fcf73e58663fcf09e38d471d773afac7deb601dde815ea29a678809884b9a876a4069aa9c9ba2a4ff6da286c192d72534fc293feb124a218e9eddf0e21b95ac78c5d43803b47121e099d3de5b7480aea7dba70d7a4f300771d64d9876eded81471a02ead03c5a42dfff664b5b8639f579c1d39bf4fa1eef0ade480ca00ef02f1942fab69830d18a5ea45ede1f3b299c34a214dbdbc08f9c1730663269813187e1081ecb42a09ea2930464f5d67cf21f4d7af2455ddfca1ea824341fc25ccfc1a82458d189e10d7f21f01b5307f6ecd2ddc16f707e1109bc9d11506b6b4b8a4d95eead75534fa53918177c5438e638062b05129233c43e2da55d817bdbe4db4d46860ef5abaf43f00b193c76e45c66912c69abed7a963838cad88118c86fbd32a8cbc7cbad2af24e9d45b3b1d70570e0e98a0e08f0ff43de291d4ff2889def1935b0d3acb864d22293e3d0a2cea2dd902335ec2ecb2675a026f521cf2402d53e3941d8bc37c4c08386ad6dd095daf2b69f41ec982b8e1fd971c27db65f3a163387a9df3f701c26d5494604a9739b9c6ee7d134ba1153106744d4bc15a85863d2272f3ff81b3ea8dfecdd42804f0a52d5553d7a2eef42202ee22b3e9b385339ef0321cce925c344b4c12918cf14ae432c12bddaddc438af5c5fcefd44cedf1a41c01fd066235c057bfe1650c1a156fd1d1ae957cad874abd562a7b5bbd50d347ad3b401a4b94e2a7348058f10caa2f152a456c5c9a71762c680a62a08a1b63108a2703bf4962d40a441b2e1d211226bea371c484214b7881e851b85fcf6061390c9013835ca55c6473cb4e99a6328e67e955d92f4884011a14d7b908b78b84668eb0e19064b1de225b4f62632557152c512cf4bd89afbfa211c3f10a4002a294b5a962c722f0112c51d4474d5a8bad7b51ffcb88889d86b252a53d31773c8a4f71c1b4ff4efff54a154dacced351b6b97a5e1db9758df5b85858f48563011b70148292cb58e4b15f05bb5e38e7db212dc69b5854961d28b102b3156a10aeec3aecd728ca209af83a1478b5c55684966ac8c42482c3d49507a1ad81f87dd159c4d2dbc9f453ac60037cabfbbf8b1c703d40944048a6ebe6aa6d249632b64703ffe9886828ada33a6886206d053fe2f70fde533d0d08a151226662247bcc8fb8fbb67ff6dadbcb29098b98414544f69d16f5036dac8a5dc2709490dd8052935bb385f8f7c0e0f0531c4d610925acae483d7d700eab39dedc308f8ab0e3b7675285293c990d9d9c3c32974158abce7d72be051fab7030cb67eb40c037cd2a950d089b1c8383ba2b6e2acff6d4bb620be993492f8ffb683131fa25071470b64101b39a3f33725e91924a59515ae69ad5c2812bd9b3df5342a1201e5fa31e1edb430b1526be9c0a7a8f1d494859941ed0c4f21f1fcdf2d3b163a8858075844120c805bf52efd231a8ad34e5166a3bd2f25519ac5b4380aa2697da77eaca7aadc7913f125c8406796535342d65733011c4718241c79069691d651d503c96ba9fe2eaebd547ec4017213add76e2074bf1de5d808881269a1a5259011ff431f610ec7de7ff9ee1e74b5b112bffafc3620804a5cae30dd9e76cbb621a2bf4a7959a00bd36763289586be04cfd96496101eac33949cbcbb1dbb5b25a74e72b669e2b181f477f0a7e8692984ab04f3a8b96d49896c8af8301ca68614045d14c120c0f18bd0a9ceade2f35bf9e2df6eee242f01eed14a7d1104013ffe1ad3e2a0a4ed46f118f85ab90fe883b02cfbbefc1a500c93014fd934ca5784e975ca98845c8cbaa5c4f1476700c53ca014b8a289fcb398d3082825e8594811dbce8a4d701c6f7b795fb8c46b62d17fea0585dec32910ce33800a00cb7c41dae301d039cf3d132a0470b9b4a3ee3f41822921aeb876c5df369bfbc49d21ea8a0963eb934812ffdcbdc387f9ccfc679d1d5ec950f784a7b2c739237d6f42ed3157992ed644a1718a5e434433a49b51d900038d96f8cb2074659b6fc9bd3d04ed499b4f78c53da693e18002c386a3f18316d8343204a399d7de22153d4c1daa30ea38e8440bdfcc2650982f2f13813505480af79c2ea876ddcf1bf7edb0362282ecb675acf80a31c968a938f0013e90a8b803eacdb79d37b35c584877058090b83e17eee7a1aee211e0e21bbc60d8a6e7c48012be4408a4a58688ec0f17f29d828aed5b3b6709850b4c25323c8daa03d819683ba2ce351f1619f70f40841a3025996f99fc6b1134e7b81a3853d8d270109a8eccf1158a3a045c5baa4313233827320acb8838c98eee84d7b7c32ac814f5981b6179032c2c06fc1f97e2ff2da69b596e10c95188eaae932e64483717e81fa123b4276d75e42a1595e51d143fff2fa7ef8b088585820feeb27ed49ba9d220de332c5cbfcacbe9524b04fd7480594f97a8973a973595a8feb599504e572a4f868c0e9d695709663bd55a75fdeeb35fe8f8a4580010dc284af8d6f5110eb6e62ebf1143fd3b4a172d97ced098408300bba24c7c5bce27798817bdc4a54bbc57c52b3f2d9fd6b501ff64ad9f198633d140ce886109c3d709bfa268b2a7805a6edf0250b8f5c3bcb4ea4d9706f26a71dd1359be3b843f11c8584b09b01915ddfe16f666c21d334309592d40180a86f8fb5b356e42a7332c27573ef7fe9dc61f16de2574c8ef8571677d838fe130c6ae8306f2546b4b7803fa7b6439a26bb2a391726681574781227b2f7ca86c3384eac253242e964bdd2eed3df8624798385a5f4896172df8ceecaa6c335fd01b3371e2f2051be9094d93083219edc76fd7747f84da30c4e5ef4e744db094acbfe86347d00fd3784601ff181c6d508c68925bfa3951c34fce3f25dc9dc6eccd2350a509f13b80309d8b7a5ee447e919dc53c7d016ee65c3059742b70cb9c9440cec401af1464984498a17644e21bd755f08682ed713888299b6a2d7be448e92a3fe531b35d7bc48e4e23e1fd0c480260090e4ac6d8dd16b42c7bdd21c40972cd80a1c402170700e6fb27cfec3b9836e725ac1d56054a83896e3f3a3c0ebdf9305191ffc5b09b3f5cdf5ec0bc7118e3147d0d28d72ca3cdd28431308c32c97e6f5d395f4f16b559a04f80c0e19d77ff168b78d78b0d24aa001f3ac57560e15e539e5707966494eef91bf7cbb93b2b7154fed9c83c4730d487f96cee3463caa768300e5a40357dc5e83a9e5b00771192befffc601eac6eaa2d3327e01a4e57fa302d2294b9cb20402a0c0b2e84b85f71112c476a4357adef5a7cea0c7bccee7588e6442435d39fdbf8548b92b65f17abd7f807f9d6686d2aa9a2e7ea8655d8b02d482fa83b7ced2fef5107785ffc60683eafc56c67707d6bfccca744b925e621c5cf00ae0e9adbbaba0304cf3349d17ea77a84de20cdd10c1d0ea78fddffb628e88e10ffce9285a551e16ed0d94b5ce9443cc199e5e0588302382775719d134ed034aad019a2de161422c8de77d2b11ab881072c861e0a41aad1e9c624b46cbad5ced595b99e793c9161e42cb235d9e7520927b4da461362a5e9562d76dc2dac7e4d4423ab9c7fe93b26870e31fd7b891dd16d38a7632e0ed19509f067f933c6e8481467c8d9e0dff3ff682d6deda492a1c7c6354386637abebcfa80e1d259d2bd2f89ea5712ee20b756396266b4d7c3496005b5856d82c755b5c563d562a34911d954f4b330d468b13412e0a2eff40896b5ba8062cfeb6d91eb82c5e38d60afa4cefd8cf6057780f80835753168ac145b23b2ddd54f4bff224877410bfff4ad6e04262039db438a5edfc840708977b29017b89dc427e1daa591b1b4474c293953e639138132cab450e36f8e59e48820cdb3fb5960b2ba001e983a60705e9278cab10519438de41437aea08f315ac67e57a247637cd094fde1dc3f585f5967820acbacf7760919817e3b5b175a26f828aef9fb08d6efd7ec19d007a2bc545aed647cb9f280719bad4263f19f7fe961f7da8c564ac7252edba80550b93a3416e81bf5cc23e89d380a430dceef2cc1aa851538c2a0cde2f8a825a529594c3f844bc41b4e284d110bd022d78a913cf2bd55cb3eab92f997c49f55be1716dffb9fc39843eae632eb138935e47d9c4c67b43d7f0254ed51a6089539d7c20c47d79a5e7ea968a28f8301e635ae3a5da51939bda3cab6ea08a23ba9d3f69b7fbd981b483e784052d335c5d8071e1c06e944685d31cc5c5a081388707cd4dead15916a4c01d88b75751457582fff39493af14b95ec02a185294ddebc0edb5223f12173d3e04f50a9b801c9afd9bef3e90b15401b45b403b18c27f4c491ac8fd5e84a3cca2d41610d986b4ce46bc8654d15c6464b3df3565eb641ce5c7afe3743f322b3cd7b016ed152b57965f3dc2aaef475d90e3a6cb9103a823f593a7b88a1c30464f3fc77fcb3a19a59362bb5a6fc250172a433d20f4c8bc615304629b7cc7b8eb230ae60b37cbf8998e59bb30e0c729f3682bff8a625b183d54daffbcacf421ce5689441b87103eb054714a39aea0d5ce5a7a1f01f9d23032fd9768e9b6929852819401ff87d847b6ff270a89dcb63b16b4d86caac42750905f706d5f5c997569ee908aabb10e616f7c21ab93bb9ed39e10dc6b531f06a9714057c4a9df76c9b9ba818d276b3f7f234120449e59486a8d0a040b07cc6d56a10304b0b24d0f1ad4fb410c711386000dad726330c6dd8ed4c2334ad4e7b25633a2df4a903aec6a2644c1c2960d96c6dd4b1fc5fa5f5bb81912631b5a585b4bed091ed7711f1b6a01cfdbd04a0cde55c8d11a16235840fa9f16e98a68f2ce4c7b91dfae67a8ddf9e8430546567f8d3a216a4d3919cd64401dc0e27b139cbff9b4fe4e666124767a3b854ffceead061903975af805869b629b924abf5e157b3b30ea13fc16c7338b83b822492865f6875f4096a59850604daf7905e017af0eb16f319c4f567be73088a73f4c279477264a8bd6011b9192538c9959730f722af85a2d7ac2f55e526ce01290067b9cce4e2c285c557d61721318df1d1e5f85e233f85aa36d68a84e9989ee2cd284a99923416b53303cc27534c61698f3c64adaf7ab0306ae35d57d952f4cf74774302e7c521a4d2e6f1fa0a6f1fda2a163af4b457a37f4012e89bc383db5e680c03c422c4dc391c3d6c1b783f886324a656caa0638f48f614865154e61eabb558d30842d9e23ee85e8e6f81aee61c0842c4a39c732e75afdb8b1ad34ff0d0c0db77dab249bf5323b5bd80370e76fd6da75e7d5963b534cd5ffa1c5ad7b1f7b3be911620f3ef7bca04c29cd019dc0dd003b4e774deb38f5bdb0f1d3911e8ba654a487ca8002827d38a09b1cf874ad49e76439dfac78f99aa66b4e6bec13f1c62c3e8b7db2ea81820d7942b67ec5f87dfec837c9b6b0af382dcfde25cb10ac4672482e93636040741e8797bfb39c0a62e8c3effc4bc665a81894813e850c28b7e2fc5a6bd2f79067aeb0d564409761124a3eeb34f3cf825462ef38753923294361f11084774d49f358027951ee6d7f792d7a6b671c369b17cb0c12961ec52028a80861ffd5f03f711f36004fe5ce3a17c4fd5580070222e7c7fa60f977edc30a12e3ebf8e1c2d8dfbed98b5ace424f0e3b30641dd8aa6a4528e744c9bba4e15a43d627c05334b8134d54ac6eacda4137100e912d3357ca24389c3faa85f52889ef435d2860aa38e5e1fde4a57566996c70b1869f6e3de1533420a32aebab24d4f133e102136300649a6624f2e879f8e5a7844c3c43721c68146cccda8b4b94056565652033fba58ac900ccfce1617d0024e5cd9189a31c551a88a641966e96867d42a12f8a9ef8461ee33d337cc287e0232985e29a22c4055f606a9d4eaa59b53b58d4dfbc4a3a568d36aa0cccec1a90a23d4dd09cfad22bad7f324d09eddf1216760834179e755ce839d56697d0deb5563aa29482611645f4de03aaff5e90b2a94c2030613225c240003b1ff421b1938b7c69821cdd8c3464ecb765a4bd38cd95a3fee800f73223607a8e2833ffa96071a1e384880a9d6f01502d62e1155cfd71538a02e90a8674c3b1320a9240c43a488fc02d26c580514b9dc4f000898f2c195a3412e92ccb8c826f7947edbb97bfdfd7bb11f665c88c4761fb6be281a14c6ca79df38261a1083feeae5be1d06658bdd7a172bb12d24d594ccab9387a8f2507933984d2380b09bd20fa925b03132c2b501fe04d1f4956d7fc0acd60243003b12ce91bab347570941b6057c564f0d33a7fa4ba3ce8e943103c7631c3258d2907bed0dad3e12b87a3065618afffed853a492ed4abd333c76e4935bd0d0fa86d5e9198ad45fb48ed3183ba62608ca39a9c0217439e9c1d091a17f489c3d8253b51bfb7ab8ed1e6531bcb68e046d48f6518db07c2093400bfe8defcede8c9de31a194e596efb9505373a147c8d5d7e373424ab3ccab5f203b4a8243e531026f6bdb9a40c1e8c52f1efd680462b312955b0334ad32ef8ef53e66927df2764d71950a7db89030469b6552e7ab637ca50ed0b3784060845b410eb0e76074c5c67bc39ee7d0648b7e8130719315a71af62c878aee908f3988b3026c8125a6a3dc9c4dfc3d2633ac9a30ca35152d40bc94e4aeb1853081dc79bf363292604785c517a9fd5b0739426ed7012b612771fe620fcae243a32008598ae6894ce8c8d346915386c0e98d5432be64aa97b56d983267f28449e8151e4bce602b47f0f3ec8b42446487f7ee4fc80e805ee1be05110ac2bc3ec2fe049d0e33417c0024e6b4dfd0d803c740fe42c1b787565f7ef6e83e3e780fb1322cec89fe39d354e8da83c47043c300fec7e6e163f74cdabe4147d6f48cd25682a955d622a9003ec0c40c484a2c4b8616331c5de56494568a4681e0c645d9de23a136d8fb095c2775112210bfc3ebd89f972d6dccadbfbe4441af85026ca1f738f4d57b58a082d92aa972d0a4b888d2be5fa4f35315ce298f9d2153f1b6274dfbc9182316e286a0fb47724fff60bdfcbe18655eb4e436f9329755b42d4cc7839304c030ef9b483661ac9b063855ff5645a1ca47d15b017a0face48340fcff4eeeb457384d903b9e60fb343b77d4034a1fc4ebcf7dc0538a67ec39e12261fe3e45784f669bc051c25d8b1fe03870beacc22ad2d619fea9a7be7f097103f95fa0160655c16229afda386d75862a6e577838435b64162387324f53d7841d8f8dea791795d57f104c5fb445a701ba66e65a636f2400a008c924b21f92ca974f92f06f1278ac3e1db1bf7338c8eae96efc7f07b551983386d1262bc90f92f9897465554eacbc16d21cf229e8fd5baa2a4afc85068905edb6fc96ba3036c7b65dce1b8cf959a0beecfdae0d28bab69493455f8f3f0b2e836de21100078ae0f4e744bd2323d992bef4e9fa2a1690df72ef70456fe1cf1d8c0eb53463a2e8edde2dcec818423c71ce7a02f34a4c289bdf5272352a097d2afd1e1ee1d8722a6ced3287380ea20edd9ea8f54376e79397c2a542de4acea4300ef8e4c6e6c0804fd7f268ee2923467494c5ac0143e9856a76d7c9141eb20435b4c1b2b7495223624343c34f831a3aae13b007133b1fd76a68d7a5f6c897dd0276744db74697eab1c571bb018e41e2174779412a8afb84b1234f9e09f432d8fec489c0d1e8992f3d7e044ca0072cf1d096c443297e0958d8f99698795b81801b204fbdf5681d0c3bb4aa73324758e40e5c6f75f5cecfdf19b5e73c5e6c8a1759f0922fcb8db16bde2d315abfc45cf3021edea75d60ae6d02b01c99eb52a8f610816f73d7b69d9472de3270a3727219c674ebf4562b6f9694269051b38caa2e59785c0c748bcafd37bf6f885a00684b0d88f2a146bfd3735d926b09af81255d340efceeb7a5273194715cd8dab27dc2415365c5287517a53ae2cd3dea9c234cc8a23db37724ea430b760bd78966b31d506ba99954c38504606f58185a88c36031500ba8eec66ba1ee0624a6888f4c8bc0a4761996aaa96093b38b46e71ffe6e687851baeb8ffcc54b542ceba51655db7d013112c1fd5c315298d399325dd936214eea9f80388b3e3fe0d4d3b0a1e767d8b5739eb4ffdfeca0fb05295a12a99b914f9c2e876dfa600e2f248e09536e9a5b366d892e02330fd243785276431c17b04d9d716cc25accaa909916e55d1fb3b0376c7cc69448148a644950fa860724e910a0379b2be9c3eed9ca5c3729195043e67c7d40fdf7e2d643260d86bcaba3bd1154c6ac2012fb7c145452a7dac9886a3a5aff4ae00634e6bda15663223d974c1259c90fe268d60eb8d9f7aa528807e7c83a898473a8856f0772ce32982809b8b44cca81af352405f7d93005818770eb762b67666a358ca2e2a0202aa15896f7b2faaf60408c17937e541b47239c22b9c4ef59868d765d7cba7a7458ee82a1dbabd029c361ae9e6541c1af7fc614a5585e5a04f0dc8a98c297821d0067ab928b3c80bf0890cc826c4f6add9ac897089ec6f5bdc24a4e6402d03daa46cafeefd1ed28f98c104ef264a07c6ff8ca58fcf8e18458de79f7ca9b95d07c3ae39a0c8712ce88a77c99f15d34219c71fda8edb5ab6d610401307a4ff04cf187eae7027108578031ad70a6357c4bb1841ccb8c30b929b288e7a908cd3fbb11524f43e31642470f4910ff15ed2064284a67dc5acdc1f13230c771960a817ca0ba9fe3ca309fe86bc1e3451d5e73067d3204b062da2cbebb34047e773ab0f9ef432b30da746a3fb2d48605506bb8a2e514e8d8a07c0e7efd6c09d04465c9a633ca314a719621dd250a298599638b7fb8fc8eb4c030be9ef2709b06783a66708a4a8ecfc6d9bab4ef3612cc6e2f0ccb2433d5072f6b15a23ba7f2b644065750128545a50265b9c8cd38b66fb950cd618e5aa49b8368b54f4e0d5eb60e1986615a3d4d4ce91205f2481fdee4a50edf94421abb6ef31a0405def6790c699014d0e7484bcd593d1acfcc852e0fb92536caed07c97603405514ad975704b57cbd205b1e4af0f7ca7b3c9d4772426b75fc96f5a53e52579c76d5f249264e702401e86a9a4860d0fa1b2825a64869d73548a39126a5a09493f0e10e7db2f116e8c2db17ea367ae817c83d83009dc990c097358198bde237d4a8ae0f26e75185456f2003492bc50f8314422737f231ee53909b56a74ba6b5969817bd32645f04f0287edf3f14e1728cc98455544327d93859b0afd6446704a86bd74c5aaa080d68d028498f07e596077ec6947db8bccd2cb7e5e9bfa18e6941c1934c35d61d649e458195a0c5bb1a3ed40607a73230e380de1df2882b75a18165396ee4c155f6da4935580f9d45fbfaf7ef00a7ac618dda0e45bf688fee12134d0581a7c081659d0301b6839ef34365e0825c16088d1ff88f3fd7e122a35c662a6451a7b34da58bc98a57915cc05516bdf2c47d1c7c9f9fdc9454a5bf6c59ce44ba6d673c111c621e8c89deb000cd18a306a31593a9105c83f6c17962c7b6197a87240e3d5e5bf279fd8afcba5a1b17dca8269283d80729ecaaaddff4e7b30cc4c06d1a5f89aecf2954bcd638fa1a624b4f802c28857af62b4bcb248114cc1ba8a324db7e7a28795d0b9244e9e149a254243eed9e57928257620b55d20b0f637ba1d18e80ba2829b8db9df4c3dca047b773a5be5f27871552c0121954fd436dd10ebb14f4e0c7d218bca1c3664db2187838c25172a8ac4f636c910dfc1f86faf900ceb6513e0e8321ef023ae4c0cb2dedec591393a25338b72c098b753a762f80eaab14f365ddf35663dd0126da6a062ec403c147c35dca77f8b7e00c01b08895d613d0bfa9fc032a2bcce3f6528820eab2cb9036939395408101c7896a839cd00e3d096571d84f6a6cfb05c3ea9647c1e3eed23995b29281ea89f477dfbf7324387586af53089f0fbaed7a9a6147ddebe7137b173aa88da2a6e38d5b044a0bf1a37c720ad3d6e977a750b46f49a14077aee2aa9126fbc0d41783bb2a7726baaf88b3d99a26c1077dee0bacfe0366df97c4ffe4c7856ad3627a7b4a55c0299026799dcd518d5d1431a712d4818633185f3611df2b8ba51b2b320184bc113ed2bc89b5bb47b347517d92663cd426326d6573102f515e2ad86ea1b05fcadfc972b3ae836e115fde2bf0a469d2dbe1a9f7c0b43365ca9072f23e290b819fc0b650e68a5003ddd38b583fa27729d9597ccd058ed7bc06d5c75e2be420cc0aa89a3e547479925d702b39b18532541412c70beb5ade2265b92f429afa072df44a289268083c8f236efc10a259768ad38b56c1329d0422f11b2b05aedff8b088df01c47a21d7dae21aadc84a2e9f665d10a22887ddedd505fad5b385a8aa3b02872f1be9f1d16c2a737ce0d75d864725829904d8d74c01f9e0129014ee007e56251ac02be0655ae6531782cf47171e9a3b427c19548a59fe3dfa8cd2733449e766c038e1dd734c1bc0c4d8167a6ad59e3d0dfefd53c47313a09efd85c981e7033be03ade99650fbf8c76390383988ffedc3b020ff9e5ce802fe1f56d069c7a75138dfaf1103380a3f96e851815729b71dc576e7729d59dca4ec7ad195e4f3bb170ede43a527e6e68268ce566bee0c9ae4b02a4aca0068b82f51f8b0bcfb931068d5bc40620d5b0f577f57a1a0065f4d0d5a61bcc66eeca7a8f3baad2803c09dbe029d476fa0237fd42f454ce199fc61d8825e89d3649b8f7b46adab64bb2881e0198fac42bd554ea24902972e1b97e9ddcf12984571b1f55635e4c3e8ac195111afc1641179784c0698a8b547244868a163a87f473a6ebaf5460847065948fd00348085d88981c1cf0424fbf90d65f686577ce6c9f8c827d678179b03e9bf41a7cbaef27c9eefe967721b5e1a93fc6b273b46e2c5e2409224f58edd86796a00616a2cef9248be53a49c9d6f0c6e23aaa21accd14fc7df70ef399f79b92842605899c56035c9a1a3639549e9154c664ebaf244d5cb938b2e8a3e9592b1184510e337a713dc1caa1e1508c84f357b88cf19d9cd9a709ac9ddc168eaab30d3f057ea4e5dd765b6c02f23177bb1b3031dbcb66084a57ad2d4a2579615d24a88ecfef4cdbb2944ba82ca1d31a661eabf19264194b3098c8dd9a8620b74af417adb3bbeb3e794240d24b41aa6a9c389b8f5d5bca0ab1397e5bf523661695473f2e4371888ec92846457a8e825b26ca64768e19ae11a45b297de4075c2b1df8119251cabfcbd3a0541d5e4ab0a0d94aad2fd5c0b887de48e5f70624c8e8731c2f55df906254d2f90eaf7a334934876f4011f25a80f818551a1142b25d061801cff634eccf01c873d92d3f314b125dfa3e36fa0588f9a3af985b86a8545b7a4a063130b2238eab9f333060b30640b94107c0026927a1b5ebf26b808349347d1ba4e43b23da78095098a18c30b3baad119c83054db6bc71d3fc0569ca05b80b9b0ed66d939c8e9b74f9ececbe7e611ae7a4b2d83267411856f1421cd86cde75adc59ca2745abd6c6532075191376a7ad75ca564a45e19e6ea8badc4ad8fc0ada105ae4edd83a88fcf67098dbdf1ea58abc0575d1f9dadc82881da42945934e5349331071f5e21e74d12105ed4666a99978874c8c61dde1dcb98d8147a3927cd06e0e2394c097a115e0fd8f0d509a388f13e4f44f56c034a98d37821caf8d6c494295ca7a38db04ee6c03a7a32604c9f651db0c08cd982ad15d890108b48e45ae161d9f28409d2fced8fa534fd9d88168c89ab62ec669b15d45eabb85a893a9e60cca7d910c22bc36d9cc7b1f52d7c4c673d2f853c652808ce2b42acb4e9887ed5c21a13e82ed5d30a57aefb5903231a64e4fd9850691511a405bb6fc19088c12f80b589771387b6f2cb1cbf64d3820a8050f52047402a9b77e4c7a6eb3978c6c268a7595f35259b721801855c917dd9d37a7d7ec1324ec00fb0861594f8500fbefd834a69992f3d52895a1286f5794a54eb8f1f1df7242e7f430fea2f54964d89a9ca253c3a80774ba4ba485af2c9f77afe7895e292c67767bf9bc30dc470b89c3346ae28da69c48d0940896f6e4112dca2d58bc2e76281ea3037d592cd65500c22397fddc3d88c54f588b8d7d6618c9bcbb52eb7b970300861b327ee649d44874db3dab730271e4efd13afb76367a6c307b641e2da45587032a4da920de7fa49798299eaa722596ef6accbb83e3651fe90747c44646b4d6b468ebe543ea33378357eceef276f51f8709c1ead32f4192c2a6997c726c57ddcc5d9fdd15398fba13125464e252cf5398c6e14f0744ce609b27782563465719451bd628ab5d01aa3ba5269e351dade1b82cebb8ff1eb51347742934d433b10d734a56ba3117a692225ddf506b4b29b456b8004e8a82dd9abf6e2327188bac390e1200cca51e5c63a2db966ee0092d0c342e2c90e44d8bb41a742192b4e1d352ffaa815d4d7d3f01befceb0eaa8367da774700329ce5a41d0351020d3ba7921c97d34b4f83a28f5f472dc522b6492c4e616ae3fc3be3f6d29a50487ea7822f7f8cba5370aafad09a9821fa6019cdc88d85c16abbe72427f21ef80cc713151129cef9efec722d15558da60a83ebb5412829c95a04dd49219b605086454cc16f2ce8db210b9c1082bd1851bf107b4377e4abec65aa5bdb9fa7938688b60e9bd1b02397e90956884f4638348cb4327b10a8695084a547a941c65584638a011da57bae95b93f520a11922071555789af5776e2112da400a698c1b43870728b4afc2a0af7e26db1da26e34048c072831637ca63cb09d3e880486210531756661a8649d0db4c4359bf3a64ebb1c23f22e0c9ac86d7424e2097e681bf989acb1de38f37c8a229d2b367fcd5bb92a6fb9ac485350c940762b558cf312e0f25851e65086985a78ace08bca9fc9a40fc4945860d1f07ae9e0b22f02baf1520bb98b59c4f0440c002ed16926e71e7b821c2e8e4ca5d01a80a1e64f8f613c247d78c7f37ac093ef131e668f21ca4bf9ae86276026540c3414851e0ffcdd4f9bf1967cec466842a5111dfc50875d3ef1cfedc05e323c6c082ebd258244f35584df4be011e7ce79e88d5e6f5451f749e045207ca5b06ce4cf37d028ff21737f3ef2e8b7f36cba3386a99c89228aefe7431d8c34775ffaf717460e0b3c71f6a2c4da84557b3ae02226cd821ffd189e268479d92586dd24c0ec44d76c4d8f128159484677c6f59312e512b4228150077075dec9715c7c1bb25d06d5fb085a5f0a5cb725b3f436b374f10e8854af2e652e5efd27b7ad8372abf52ea756bc8c7718ecde0b74ec06590f1688a393e9c89d7d59407aff4577f114d1f0ad56c82c97f6ce72ad8ed000b229ebb1f8a47e6dbd5387ec1e0b5d85fb590f62b27a830762e8d96916212dfe415be0884be5cb77a849895b7ab3c6f206f2d244c4edd6f1dad9655ce4ad1a1375ef5ff37a1badf530a497031fea30d0fe8fbc2bd59dca9fbed26c4b00da5b25145fff370ba18e074c96ed3d01c88273d480f4b680a0ad27792f5308b835d1d567156a351be5ceb86f9ca4dc472346853431f65aae8df0862f902a3f928fe8f967f9d1f0f81b2a6830ac32d3b3c352b669bf11047c21f8b627580696007e088eba1c909b3ef109001968393e9eb9260e48d7996b665393820f3bdb52bffa3798c00ea0e0ae0f5bb88cc1a4e51fbfea49d49352a343df74619639e452b4380d6b6225ce09bb98b10c34ba42fa17c8f484bd8d01bdc14e9687a2097e58c6857ad841cf7d218aed4195eef1c116d5915ed909121d9c48bfe71e22961ecc4a7bbeb64f1029b78f89eccd4ab83c5c28d96302cfe8f9b94fc8c00d40748ba609f6ae0e8166cb01d67227ee8d5a0ef005866b2e6dc0f69b7a12d6d239722afc0cc75f8dc150dc37bafc35baba23e9113666c94c0e5cef02da00fe665c3050c24a07b686eff9fe7be36964856de2adf5fc33efcdbbed69642a142597d22674705fea3ccdcdfefd15080883c1bfede2b8cef33e067fbd9737697091dfa3f4816e0ed28a4135c172e5468d4283904d24217befbda5945226296584068e06f005cf9aefeeaee292513b864758b0eb8ee11126a4d8402814293e528f8f4ffca93db0e5e3d8f0c499534a29a594f29347e06afd4ad197254f4cb264a162c7cfc05a2a2588b220425b905aeb916d891809f2323ce2253c6282f008520c5cae254a5da1121ba8a1490cae90020597276c506485acc80b36d45a6bbd419665052cb4233628410576614b75414629b51264062ec0e8a0040abe9821c2a523e2c5852d44804011c9b2c296d48ee111222e46c2a8940812220a91972486e8a20591d760060f89d4c044b52534c2c5de760c8d6041bb64701eed2327af61c5c8272b9bfc068815fa62cd38119945281c1181798dfbf3c11c3026c91dfabddfd8a71f0940f0d39db86301b973bfd2bf3a05fbb402219120c9543942e8e903a560ff3ebef5e7b73a70213347e094b2e51fd5905043c28f20773eda34e7a5614bc99011e679b4a5a71ef53f78b4cf7e7ab1e301c29f47e87efb4d03f17cdb51bdeb1bd4c3bffaad924f9db6fcfbe42f9ed23c555def3bfc5bf75bb7e99af999166af21bf9de979a291fa5674c7efd51bfdbf07bef6920aac71f773aefbef77167fba96f4cd6af54cffad8f1dc5f45bf99f2bba21afb413bacdfeaf7633e4feab3f7ffc1a33deafd7d9000b43df7a92701a8fbdcf1a878ee7bcf6308bfc73d7e4fd7d0a73942c16fe4ab3e21fa424f617df2575f8db522bfe6afe537f204b97df8f831c208efe3074f0d09daa73ea5816cafcdffc15343420a48e7fdd437ead357fdfd4df5b1e3e93cd557333f6807ff4653246c3cdda79ef270af7dec78b28ebac61fd5f47eb3695f8d6b1e717690e92ff88b3e83e4a79083eac44b6c71862c3c852c04512da1620a8b74b18512d5c215162993642d9155296961912943545b48a0458b169716d890284486e43034801dc3214384d0c043215f422162b0d8e25cea42c85d2a403660055b745589c0102e8ea458614c15499439022b31546bad35e8890d5a98e188172260a0816361a59a00c9142a2514f2836a0ab7631884043658cf2d8fa1c8ccadcccad483b86024089115ba1d43a12db284429c844178505171424828f4c410550fa150984d770c859c5e494b5d1c352d75f1e44f3e8f4c2e9e6ef0e40652364c29a594524a29a5d4c7dd55f7d0f7138236b537dab836dab035daa81e6df88c36a68c36acd43458adcda2ea87ac7ddca14d4d8b4fe3cea4773af04b0d62d963bfd22f020603026398ca07180f2e1e7870c518e92ba33a0f8afc1d467daf799fbb2fef6ff7359eafabc18ca70e5b74a968c8d96a30aa6ec8f8c1d89a11cccbcb776945a55d6bd09837f52fc639b75aff1ab6644f969e37498e64efbdf7031aafcff540fcb27beee37b519c8ded5d9be6e3471a5fb03e7eebf57f505efc8a95697ececfadf9deeaa3f97ebee6cbfbe256fd7b8d17aafff0cc1f8cc67cdd477d1398affbdd97e3138147e42067dedc9fda5ccd9a83ad1a84edeeb9d760f7f27d60db03b0ddc3bd46414e83b0cdfd8d5feb571f7c34e6cd747572769fbd86f7f35b9ee6fe82bfbb2eeff8813c76cfcd38b0e6f2a4334839a73ba5f553cd90a3ca498e1ac4164441f524c7afa888bbc9f946b59ac518638ea07ff408a2b0a96b59c0aeb4312a107d4a5dd564dadc125c315889553264f936f315ddbd1539884f73f8a19bb2387cefa53fdb122ece16543664f91163016718651bfa0a2242554354da94aaa064f9aa26395ab6cf585327dae8500fbe7266f873b74efc58870ce6ccc2bb05f3e90a21044c446122b67d605e44982f54d6e23eb9bb9c1c9dd487592c55940cbeb42dee2124fc2bfc4e2a7b4e83369b067f6bee9313029011444fa66c9ff825d3a9a824736293150227edfacae13735c76fbc32997a59643056914159248be635ba1aca949aa9b3e7270f8a5c3f078f4a4ad600073a2064c2049a38e0c41a8c5ebcbb61f50fa51239a83f3b28f2a0c8d55b5bb54306e393093f471307ccfef5e5938903fa7c90a383b54f54da120725c4386d9fe8b425ddb683b883776ade33925e88ee7e23ecb5a99a3c58abbba551b3d83855933c416ba7473a9b3cc6f8443a9183f8414e09ae11f8b868bc5c4d24f8369b0a07e9d15a214568929f94f2b545f0814da5f865cb1ca69ce81444a50f91b3e7d7eac260a49113593fd55a1de94727a53256d4ccc1b236b1c1a2d29e5f82cbb563a491f3f2c9d971c6199582ac74241ea9475735512165d78462db6a8cb17e4f047f7cd7a7512543cdb5d6aa2a3af22eba70779f71c6a8e37c2dd14269ff8e4b366081ca921642966e20b4b445191593133859da22ccd2165296b438b3a48597a52d8ee4b9fa9285199ac599253ba997d182a169b48efa4ec7480ffca5cedc41196f1fa44ffb3ecda7ba1ddcae5f6ffe183aa53b1de361b474cce5b764e8547d540782fc9e4c77dfc95a730ceddf82a15352831dd7ddb8d5686fdc1735cbb9bbd380744c75d5b3befb15f552fbfc81306c4e4c3e086353ea8a36f0fe1c2e2727268f621284ed2c9359d63df5b9cf1ea4948cf4c0d3200ccf0973a2b1c990c145c61fae02f7338ed3944cf6813f53ea1afcf7ed9b40613ce5ec34f3a1b1b9077d68ecfca907615cfeee41baefabbe56e4403eee40e0be276b50de6e07b7b918b4899bfc6d1f1a3bfb94fe9974dba764a4075cf69ba664eebdf4696b599665948c5480ad2df952e6cbe82f8084113023603c5841ead2a5051e98881c21c50c12d3d4a0a421d25191d912134a094355a09452fab13a057c28af56c84e29ad7f42955748f1b2c1bc0398edcf9a615c514b3921688340003bb652a07ef1c6ff04f9f3572b64306f8f3b483df44fa01a0402d8f2e5fb64618b1307e3d734fc1ef16b52eb4c0d8c7f42d08eda6775f79f1e71f6f2a376adad9552f7196dc8adfd0531a53eeeeea1f5cba4dd52bd12387577f71dae6cf72ade8ee10e471bccbfe56bd0050c9ee032c51151762a912849e0282b38726b142e5a9422b2283ce42846a8284bb8d58ee10e4c3215bc2b675a466aadb5aaa046072b8ce84045eb1073d90006a534cc0b8a029a773d7d4a8437e4a887ee48ca102f882830d831760ca39ce1c4107941f8b7c35f7a6bf3af8766fab5d3515fea9ef9ae757cd00edab2bbe13fbd46c77ce9df0ef7efa13fdf236b7271e4044a0f5e09bc24283b4081e2557128394031f288c8e06f075bef7a98e3e0cce5edd873900225a6a3b4e74f60f2e8b2a7174f2983d189beeb804f3d21b2c592c1fff9fed1a5dcaef99a1e963c7fd21f5cae212875c16056308651712a302a5460545c1e0f4f6e60e1c9912650c21bca147950e80d2fa03d0c99512c8538844fa27848948510872316bc1c02b06378c3961b4ab0c1fc61a5315f8e5361517274d720b765a47f657de9ed90e353d7645c2e1d2875c160de11c6b018231055784064eaf27080b93c1c60154a788313cf86549c3ea77c7963ca1778347834601df61d040722e2d41871688cd38319e38c714e2d260c5b4c3d91278e7dfb3a3268c3e574e9eeeebe02954e44448964a42f78312fe6c5bc9817f3625ecc8bd16a2fce7013adf6e29bf4348d68b5d7263dd16a6b12ad54c6a8c3c0e8347f4e4f05f91337c18cbe6cb0b5cb782ce4181a99098dc4d420c21184a9a18c4724c7d088291c8119a3a41ace784a92c418e97456a6590ac9d9964232f684e4eb09c9d61392ebf68464baa590ec5b127942f2dcde0bd91392a52724473add5b52ada7c44b8293c848dd3d2207c14ec9608b53024f6e208584354c41c2850db408af498c71460f06397f98425e933cab9063229e84344c2f06afc863e22df19478327832784406f83800046c097eb0630d463450d9b10b429d52f79064bc63484311cf051a567857e884ccb63b8634086df061f387cd2b922318273063c480710273c64c97a62e60be7469eac224e774a7b4ca39dd29ad1d704a2bf8c1c514639f1253ae5a7b2fc6d9c538cb346dc35ca669dbc6711d93c66d1cd77528548ae3502822b2943de79933f3c82472660a9d31d3d405cc972e4d5d98a49423e944164d3733664c07c00f66171a73e49cee945639dd29add5d26aedbd18671ad5349f52bb38cb346ddbb88e769d4fd9691bc7751d0a95ea50a954ce2a95e7ad58ac172f686860b468abe553b67cf356a04dcbe9a4dbbfccd77caf850ce26d25ee9802b8d81ed0c5993367cec0602d1a64a7a24c9e5380ef44cc065fdb9d4801b34ea2681283e1c9a536c822733b864e9850d5c00912f98b40e2b99559ada7ff9c43d1fcd7bb5e3118cdf71a5fab93a25dabb4428c999c770c9d1079391172bf330491e18cc5028bbff7de2222f326e2288ae17cefbd48ecbd45fbde221af67d79a4b47e8c261519d5221c9010e16a71c8e0946576880c62ac0c645cb8a2092b24942b963c3dc19e5c302c6102850a263808a98289932255844c846cbc63b8448b31ae316488a624516ac92c668aaced182e79c2b1448cdfd850490c9444b1c1874dc9d6c2205b6b65dec48d4349d2bc895b09d3b6a112268ea86210468a3061c2b8c0c9c995844a8ce905b1a52151c4b20c45112b62481461ac877d770c634761ac684726760c5f489a35f3d61af8ebcf88d826bb766d31e579336d9324b3c5391f47fa81a4333b6811c315474f5c28913911836b1f5866e57c0320382c4af4964cb36388c4850de677337509a7ee1489900bb9e565b67b91837a43870c624d3c846e9c4629fda1318946609373297fea769be6ad6de31abc5f3ff59efafcb14b659aa2344531e7999c74cea094f4160c11434d56a53f35aa519f8c30a39e035d14455139e2466954d59103f91ca6bb7637b2ebefe3da2eed67fd43b0b162c50b50d2a5c018638c2ffe8b31fe8c3ade3efbfb6537bb599665f8add578be6217b5deedbb1a7dfcf5f3806bf7dcb7cf59ed448ef355756ea1d55201c6ad1c5629da200d85400a8570220495dd9a31218c6c0f8338b3dd6bfd49abc6f3e591c9606b0849fa9230882e3b8655c06c06ec185689b2a50b4faf05593eae1afcf1ba44a63f26f3e8518f36fd2934f5787bfcd9e3b7d90f02e0f7f6da336034766b8379d78b51349572f7d7b671dfb53babbb8bb1ddbe8cbb7decf0663fc319ddf88b74dfcf86fbfc7bee9b9bfba4980cda7099d59a228336dbfd3d1964fa9acd7e7cc769b9dcec3b30e77cccd9f797ee16cf9765cd97a6f37cd50c7f3ead6de7bdfa87da5983da1a5dbecd794492f7440623530eaf91fddaa72f8b8c9ec8a389b375a82df5f1552a954aa5ca397339e7acf17ca99e53a93ed4a73ed0c7b555afda72563d4aa2502815eaa5ac299cf7f7aa2f6bd0e6633da7c1fc9c2a7f208d9d7f9b1cf7c5f9ea3e306877efdd8dee39b97fe6467171be366ecbf16690e383b22887ccb9a599a4539e40f366fe90097e332307dc1539fa8dcc7233b2d5b0cad07dbbc5a94f90db07fd2b41d03f74683c76fd1f3e2414bbbecfed0f4a2c3a64048d60d7c711a1d855e30bca3f2108877ceccffd06e3ab4ff3f9b7b2b2efd784e07f3fc6df1badaf5f7c56fd1839a0f403fdb31df8cbbe21104c7b7bbfd17aff5e7cfd50317290fdc4dbbb0683b60e84fbabc7dfea555fcff6aa4f7de0f6a9f7be9ad6c74df3343ffd6a5a0fe3e3d65e67c678edab0961fb18bf7d0c5dd3d23882b6f73521c0f8fc303e7ffed8f118227788c4b800b0be7d198f617cded37cdebff8c0eef1b3be1ed5c72dbb1d417ba5c1edf1ebb80cef73f5e0cf1ac46f3ffb72be9e4e737a7638ee635d43ebfb7782674f19fe1fbbb3ff91fd8fdd9ad376ed23023beacccbc98e02415866e0bf5d05e8dfaff321370efaf7bb4803e6822a3f236883aea983401b47fcad33678caf48754f7cffd6d4b8d41f239d52aa4116d5a0d4f2fa471a377dc29f08397ccf881cd48f47fc720a720730ceb9d5fa7fc1268fd7a0202c7ed9f3a93b7164ff8e210f4d3d9cd9b01dc31e90d854ca0021664b5c1f83114c0d41db1ebf7620dcaf92276e8fb1883fd7576a335ff3c56acaf261600e18c19440e5a6feb1e2165b74dd07374fa966fe5cdfe3b4c7820cc69c5d7fea663dcdd7e7e9e1c1f8cabdf7f575724c1ced6b7d1399fbb87770ffe275666be2d0686c33715e686ebe268e12396e4e73ffde17e70bc6176707aa8ffbfc719fe21ef59bc31fe634b8bdd59c9337a90a526ada6f52dbde3f1f71d3dae701d80679ec1e4dd3206c6b7fa5ac916ba85eaa2f7ff1f3a0c8333f17b739b58e77dba63509a33ce4bceffc4c93510ae152babbbbbb7428e84f6d1d8089282a682591e33d3142490ef627bc245cfa4fb5326943d9ece8dc77b74d6a8bc11478e463ed53d8f2037ddbdfe8bb7d97196fba6773fab6677bad03e7d6e497357d8c374b5f7b6bad75b2c1fa3f734ba7d75a9e895397f8eea1dd0e70ca987c307b6b35286376d33f735ffd33c14c5b0b5ab7f4ad0625d5353c9288f480bed54e41d5a37a2ca62a8d2de52cd6ba1b19a5db4729752d5b900ab0f7abf75dfdd46779b6973f134bace99ecb02237d6f5abeac73a335f7bbaf2f5b901ee0af5aa76584f9c7b77cf0c7f7f6f5b3f73ebb61c913a394524ab10c42cd7c254c35f241caee60c7704a991d4e510aa73809a778d9dbe69ea42bda50cdfb1decf87e4351da377f3e4f8d8c56f66de3b22ccb7ab488b38ce362f470af61e9e0b603eb4d837373af335dbabb7ba7411f1a19e8aefdc1cc37e83aef6a838052a8160452edffcc1e9a4f61fb07faf69d8dd1b48c67bac77f47f6f7ed6fe0cfff4c7f9a4df3b4ad6cc229af20463032496d37cdf57ae567f934af33e595495ee3f396fae8355615d0b47f600c9d69edef5b1eaf2163351a8411486020923eb8fce21403d12771820895448a988454820149a252912588a6107549b420a24940922824134411062fccd8175ac897b263181e6d1a3b864b56ecd8e9b0fa95a3ce66801c3239d93326a5545eeb33840c6cfafe815ac7b77be8cf2a7fbed5597b92959895182ae704b9eaad5601326ef94a05998a8d0039d2cd955b53caa90790a503369d23b5d4ae9ac85fae223c8d3f640198d970c81d0000e4486d6ab62124f9c11667c874644e6a335f1c954cadb555fe9463b6e8aa311467072e65adb5bafb277f3585bdb2c568e5f8d1babbbb7f6bbe7c0584cdbb5e30324c6eb1d1bcc83eb05cabd96a793d3655a6b1c5d5114152727ac77029053b02608b11ab4070c1d17cc525a62df78a2983bfe58a4b069f834d1cf91f4c1c7ac39692c6966f649b8e9341bc299d383e6b9276dc74cf12b294f76b9571fa8c61cba98caaf66bf5eaf2fd5d439958a3f210d2fdec71765f461cfa370f21c979adaef19965ebf21012adafb7382140bf86a49acb9e829412d870c45c1379cbf78790aa7d106bd1e5b299afba0262beacf2fb2137a5ee7466193655d870c88d6be4bef4e334ee21e35d7d7e3fe4aeb56a28daeb4c4a77f59b8790b28f4d11c77e96b56f08c9ebfe9982cde621a4398414636bab39521a23c69e8790aa5ee1775ab30367f990e7632d5b7445a98090cb991d432e6312b05f67ce982fffd77cf9af64906bacdf0f3935949029b6e717432e44ecd8593d730e1b0eb9658e77c32177ccfe2fdcf76a4a5e498192353f098a36089b11c19420028c06103b5add7231c95edf3ff7cc98385467a32ce39ceeb6a2404e91a37c116c69eb965f98e7e31ea531bb355ff24b2591978e6c90db53898b2d3feb39a7d370c949b824e567a80466535a45c85213f1632ba8090caa7419420485891430d9b2056a4b125194ae442488a8b04105235ec8e1c912a5214a36e41d43a5244a4628a5746514634402062bc218e67235a1d4452f90c527065cda90e5bbdf309b5221b39080090d4bb820c508872856949461418b135bc06899c18a04445bc6ac60d0d2454b16264c5cd4c524d412665929118096a321ab245a7ad0b2c312512cf630725c455c63939ab0bc60e5020f4c3cb1058a31589008932439bdb03a1266194ae2220a180c09c63023465cae214a5d30d84a05d8aa052c472e6009820896228aac86743b86585480854b09c45c39b32a22854a60666825a4082a3bdb312cc2e93edde46f31f5f30342eac16ddbfced33dd03f5ae81e4e72c8389bea67d9b309ee6c5c3f8170f84d48325e5d3ef219fd2979fe91ead96e6a181907ad0bcd44030bfb94ff330348d06d2912f60f7595afbb6eee3341052f640dc6b9fe91ea947692019f39bfba9972f35a7814cf09b07429a1a480af9cdfd4dc7e64b0d14fd666a2021a98134e037f7b907fa0c537ddc894eab8f3bd7fbb823efebb8b6fa80907a6cef6920b9b37dea551f10eeb5cf1f10a41e9c96460fc4484652b6d16fb49ce237f7be0c264e0301421a21eed4b71f77340da47edc01e594cd11f1b463ec189a40686f71c6898252c3c33e0972a7eec85490cf1b05b60ab20a92aa22bc02668334bce205ef185ee9125e1943916c716e7827ea40711ab62a7c503dd8a8cbafbbbbc6f2eb477dd24929f5f992fa88c09c32cac053656ccba4ad33371e1476b5b15a2b8d511aabb14a69174cf46957238f06993e25f9e18b0f44d00dfe803e34c6ece9944c7885887008fa449fe495b4cab358f325e506b9ecf3bce4ec416ecbf0c0646e4260be6b5f7fab9cdc5cf723ccef74d0ceb4df3e50665fb3c7415bfbe2979d7d91f57306314e393dba2f712f8e0431d5df9276ae805e0d72dbc68440f6af5b79ab59f661bff1a4c8e0ef97d76f928e7f8e093ccdde7fc66c3591e547d7d8a5eea0e90addb7f56bececb572f7508d3916a62471338726a59492be0e1399fb9ccdc5a6d66c6a4d2007c639d3604b83ffaf176ca3e037f36bcdf19e184124974491595864b0d56ab56c1354ce8982bf095fb2dc3fdcb61feb856ae449e9c4ba355f1e1519fca62f43186dfaa9795f47b421b7b47fe50474a20d196d48f0f65c1caa43e5d7b7bfad3edc793613c72ed9f56b42c06f9ff5d57bfb81f841fba88b3ffae241fcd60a955dff5a79b2b7c7dee32fbfcdc4b15a3aae3b8238970a77deaf30eb5f7ca07d67e91aef6b425875dfbdeabd0f47d056e9fcf5a474dcd997335f5273dadae7a28d13e4de24f7dbc5f86fc5f8621336be58031be3eb8f83befd2deb72e870019b81a8442e166539e910cd0800000120004315000020100a8744e2905828ca6379903d14800a8190427252960b43510ea33008622086410c0104116388310618a310347625008071888b7a3cb869337ff8160ff440143d21f2e4ee39749ac58f07d2733efd7824fd66e1eb998eeb330f7b1f63d820d7838a7a3cbb6d328780b71017f67a70ac533197c7a0358b9c1e08bd8b02d703dab6b81e2cd6e3e17264c603bcf90b625e0e8d3243ab23e1c90c0a522bcb94624341ef6ee9755195442c8a2fe502db7da8c6cf031b88c606c5d42e7d2af271076d0f47bf244e34f6736512452350727498b6cd37461f5c2a7badc36b5f58d55d0b11c7e44406772d33e60149c4aaf7691f844b3ebb0f0ad7efa03c7aef7a350aaa4d9a55ba4ffe35b21a006ad0b4009f16ddef75307a801362f958364c3678565b9b87fd2b100e10254a16bcad490dda887501efb26f13b26324c3c4a57a2b74dadf908a4234600f7bfe4296c113cdd509ed7a73bec3272bfcbd0bc3f7fe9ca8721bad77e624fcba213676c741a8003d2fd5c8082b808f21987bc50aa8b0d69ab7c6005523b97a5958c413b52ac39fc615c1eb1ad25e8b209d5553dc305eca36044144c56eeea53075bdadd231369c9079522228a4f4fbc929ef199fdbc1f8edeac121b3240e4f2cd0076aa59bea6d78211f884cda2ee776b8ddf2785d1f3a3c79f273f797bed99094aece437f2c87feb11a83230e67d7208d302f31e7cf74fe3c5bd6d111e48511aaee0c2b21724400726394a955623593a722d4776b80c8d207da89237bed1a73df29a244c36ec251f56d5b16fb213d88c19f8ac25a79c36e896a5d56dc7b168db1cda35b03e8c594632d2f7f0215b7ba4ee413d125596d2db6cf5a449a5664ba8a7ad0bd72069b0023e5f49d1aa53482e2bac0b36521561d17ee39647a2a5fb050631db5ba9e3aef5a65b022b66a61e52bb6edf37ba7c927efe2e2c37d5711fda754635a12377972ac1064a4ff55e4bc01a74704340251639122e12f3a1135873b055db2ef008a9478b8d3a373a757166ecb626c752932fbb7c32e0ffb91a08e86e367901c8656958a7c69406bdf18c0f56b096a887ecb8d5e5c5bcd17ab8fe78a0dac50b65822a8e322d7c3a9e48ceb3bdad780d37893af67540f1faa05f236c176dd02a34ecbcb191686a89069bf9ffd8f00045bf695b134b3fec1fa78fb966912a05877f59e627903cb0835990cea53fe981f29fb36567f176003c26210839e18038e4ca514c868fec8bbde3eb033f870a5c5f37a124af303857fb29aaa25569e38e5f718aee33b0edd112fedcb599d7ded75ca71db82323b0cd3085e30e82d149326ba6119abeb6c18d3e0a9f467d3fa6feb403d3f6596743bfdc93f9aa51f92b1e27d1afbe1073517401c9a70a60fe3895e4243fc305de0d822dcc645e9e54318f9e2d4cec6df9849709c6f07b996c886774150afefde0979b90a9af9cccfdb6c1e865c5288ab0b50576b62b0d8c709567e36508c79284949b1097bc91b637480c4176431b5ad0d9c9b115298e465132de052cee26b394e0299fbe6a57fe78350660d6a4a797b86eac183991eebdc258cf733c7df202da0b70adbfa94d72b745b18b8b7bd8f4082ea6d6a88d644b07b1fdbd6b63b6a9d382616386d1cb203fdc69ee6ec337bdd00bed0087e780c1a503088a48feae7768b316462aa167c466afc4300b6c590ef02912e9f9889e427442a9ad479118440a37316a222d160a65e7f4e7ece044f08d0974d2f9939726c86889923a2d683bada9b23c522493d475af2149f4ac4eb89c4b4a3fc74b0a840062476784e1a825538dbfe32d6beea3813ead81b17afaaa45695b6d989e2785625bb1365c533ac4f2edd5bb43d6d3059bf90861e221cdaee85370bf322bda8bc387d01138912229542736ff4cc64ea05340922ac2c907e8f836caf24d405b27c2b703a456b991a78bd89c4310085cd6532fb734ea2b6a59e5ac5ff4e4418d339433f0bfa292692160b57340a18fdde2ebf703731471cf96898ce444e63de90b900c757628e6a03c467de70c132e151bf780d61d40705fc83b777d238e53adc4f0725bc6102e5a4e5d9eecfeb49e45ca5267578e0636841625caf0ad6b11e0128fc3a883b4ab8e7ea8badfa25da2cfcdf7b491b106aa70fdd0fb940635914f02f72cb24894ab4f1031705c784e4e666283a011a2362a398a8af71ab982d4c9dac72bdabd216f8177207481f9a9f4d4863d07f5a80cfa2dbe12dbf6abc35981c7b2c9ebfe005a3e52f4a3d86208a579efff05fcf9f710fec66587c515962e278476074cc551ab3d3f4370e51e0b49a552a4d8e7b326d92339c1ad8b1a82c0c502c369a8026baa08299b4dc99255e0918e8a8cca2d7a3d64793956d9533d3664f837f0d16b9feb1097bda8cebfc902dfec3d873826a015d3fd911f5b936e17a57be347c32eef82341ce0c4ad6656baccea0a8c2c4dfbfdba9711e8c646b93387d0dc4cd3f3a59d5e9f869f7991354e61e199f3ad0c89ec364c034e47af6b312725eefeb457ed0161468886dc5e81d480b28c9bcd3aa4da59b430a3400633a1644990b75bf711cfc0c75d099b15c4eb71d06b03dbeb4bf4c2991e8eb0f017965b5cfa591b3700bc1b7f525b49bc4f9f9631a8ee0ee092cf622d5f911db05e1c4dbf8551d14fee7eaf1027edfc2f261aa47f79a248bed07208f245b41de34e6d18aae6c1184639a9bb6465b6f46c6849bcddc26e0285632ca2599714d2385ff8428952b13b9634c7f80c287c9c079e9693d445431598b27facd25e8cc22baf91549336f2226feb7856d83e94b2e6d9452883a5cc1285860cfd63ff6ddcc3e003c39c5a170046bb2f0bd4be0239c2acd947b4f4dd3e5d341d6e182d6436862cc9bcf065c0fafadaf15c6c4d07bb53f1351b7aea962f0b14fda0279d28cca80abb304e0f38c1dbec01a4ef110c28379153fb8fbb27d9c5ced700d9903e06def6e43c41493c19f3b4d82bb7a59e9a51c6de90d3a6f4df88362c4651f4af0595d8a05a1b10a4970bb0d493e951713e3e634a64b9cf8758bbb214fecc086dc9833fc008fed620bfa86af4694184ced271180995adab2cff947721073ec4f09778a1598d26b39fc6dd05b5b069548b58b784f7be83cc66d1172d0e04ca7bba00947f2811bf7de80a00227f44f8da0530ae6498e0fd07adb5a1e30ec85d8062f8683ad37dedcb76fa14069fcec072237bd4d5b02333a8ae1027788e9467a07c63a032cfe1a6769c08d117a7d4cc2be05057eecac9aa28fd5679f416c8a300784692804e8d2e3bd0416b9088fa8753e17cc0f301600ed2bd521a8adc25fbd6313c5277d8ad5143fb24d610a1b4efd0a4e02234d33d48982f928108bed63e9d909a714509eb91d8fa0e70c06080b543c5a0af216a5c868c4595eec90730ade496552d721e5c9428d45d607f48691b375d6f231e1d11940b99efe05b4071641b6d52459d2e8f47563a1024855592bee32117a09d3a21006cc98adcec3f248c2bdf80927a0f957e4b877b6d881258f7c24d784fc59d8052b6b4a17f2933c1f448af2e39f11e79bc0968c6be7c9e8239612f51ef1882fc81e47b761cf47092814139b3d5be336d9db5e0d2661a3eccc9b2db4cbeea3ba94c605d4de50f4b488376593e0d7db53fb66bde341f15eedbe6e2dda77a106347a7c19c224d02f72115ebc333cf0bd84257377acacd70d094871eaf771595be545707dd826b3127b8234cb39f3edd6d8e0be7497c4da217f1041f43d3b3c93d1a2f3c38463fd0283c8c1e8323c1bdc24b5dc40d16ba22eca98bbde0128321f89fe3dd9750a3eff38fee30ba18ca20afa0a6a373a4afac35ad65b3f97b998eda2a24c2ec44695947df0f0d1a431907df86bb15914df3673e62033d858e36cf8c059643f9daf12783f6a15c4568555241630633035885dd98546d789c92cd52f54cb3bf3bc61f99fdbc0bf97f7c06177a677a1f203b2d43e3ed9e919d3f0d15964a8601071bfa5e6046e56e68ae5204357ba92f729cd4bf0840ebb6cc80616878b8e7ead6d2b524ead0bd5acf9645d3da1308f89bc59fb712caa3b37bf8b76e1236f68f2f89d0e039bc69272cb037cb90074af9e351878a31836d2c618b6d0d2cb9ec58ab1598040ee601b2a457681c22be69144a9a8a54479b0ddb26d17ac82960f11f8efcc7d5b8381e159072eee3e8c2a42f652e854080c8b21a70219e4a9840ec1cae965868f8f7e16ca7688ff11ec0c043923aa81aee78cfc17a8e8701eaf225019afc362082680d9942ca8a0fdffb74314062a2e88911169af8c05473e0b9e32c3f08d9335d7c6ac6e47e2d7043b1349c43a9349e27fd874a31024ba3be833ae7762b4ff9845740234236750d058e85932e36de3c8a64fefe73cb02366c9289985bd127bf338adc8a26d3bccc45c3a2b13052c177348fb290cad84f3bdcd303a312c94b90618b498712c60cdf280e7530dfbc52c4addba8a2d6e7a43571f0c60ea977bdd27de8f7faf169a60851b4207dbc79fdd3fdb8db29849d2bf64326068fcdfca05687914960b7a13a54bc90bd79ad43adc5d578c9a77ebdda4f11c5c0d6d8a60a9ca52ac97fb3d49c043353e57c122fc841476364b40ceaf85b892136c5a7a63fd1654932d2669b1f26433d11f28f9998b9e6a9c67490b00ed6f470b5e0de93cec22365a8dee6f6a26b5f0bb055ac0ce26384180af958153961363bedaa0dc642363a44b2ac8c116f61d8a74cb99294a592dbc69f2686df9f4ac8e8f536f713d04774a62b3db65403b976de6c76f919d3e5c1eb9bbd529b08fbf9ff956697644c54531c65baf720bdcb69bb505e38d723753406b9404a45db8a5ae5f5346dccdbee17f9b9843d3a82e6d2214a7f7e1558b9fffbdfe8389452b83686ce76057e0494c5cddc7031360d82d47ba966633fd181d46b936e9e1bc2f9880f7b55356974c82ac8cbec4c322c2c0b9c7d28912d0a8b5165e625f5ba30ec994c2d4c748033d6fee648b2cacb1bf425cb4e471ff463c849dedd39c7d571aea727e0a21baf38d818bb2d059c4d87e71cfba85b4491fdd90798894ff0d599fa18f4bee0081e0d9b09302459084a164f022b00a7e42d0886b5b8a8904ac220ee7de0157a7dfd14e6d6d35c80dc48b2393c3b16d87ba5d46ee1fc72c7c39282f22d6aa051d1929008f74d421180adfbd628c4d489825f2739ceb1355920f3de91b88df8794211901ea2a37daede2cea657c4c9a786556d10220aecfcf87d42e4a827393f1d0ab781406bfd8da14528195a1ec43011e56b4d1a5859c1efc1751f344365be4ad23af985f9941173d1a3c1fce849260e082fe9231382137f9b6c190d497b928e8f50405f14eef6682f71ac920637cc7f0f9e36426179eb62d0682785f355a045541d19b33a14f4b54b02eb50c2273b6b726ec0b0991c06c58ab0c1292f6dbc5d514ae0571c692eea5d82816c801719fc2e6bdc2d649daa70078c4620eac57c13e8b4245d55b17092c61897d9b8db851b82a18a2084976c3e14fb82c23eb13db5e81492bbb9a4a2d9a4465a0f524762c899d6343973fcf512241a43904988f3f04d7f1240991076b5b4f49acd88433a155a15692841f4b015e28bcee35d6fdd7c94cdfc302a6165c6f758d9d7685100e31c68e5f27765840d5bf5ec6b18d2bf0deb8f2cf509d21ca12418140a18f4912279eb33d3443e46b868d332de4f6ff7b05c00b15bc0d9370637760177fb4781f4554fa0f580a8625faa7303b766426f0286e63cb75f8996ba54ac655436825b516e651ef9d0a497a02deefcad71aecdc08232f1bc3c0b961ff30713520a1216e55798acef2a2ad67015e056e68406316db9a2c44ae59d2a45bedb72d68a64486eae7c2d4ca9836cba3288fb09e9902ecbc809a817e994d5855c31908d3b612da68cd8923621c2c4775555f79bedc0e66aeacfd9f47409576e51cbadff20842014f32cbbb4b2789c6de229b8ea41eddb8fbb266aa9f3b1b6a8507aacd6bbedd916ea711a9bbcbce8f21d83c2b180953c1c067e7360157f0a77d6fa7ba953d7e5db012eff5d0c7b28d5c03274ec5c72e8534a10005b8ee7d726851fa3eba2d8ab7c2d3998eefd8213602904d05ea31aaa6f97960e0192d54214a90b95339fb667cff71d5a922131b989cff4f85f4c2f2f450517f7e51eb016790df158be793f225163750c426e1cf756f2797be2b39ed662406546114a9691510503ad79edb13c83169694badb464a55538a2baa2c80c211673ecd411cb3cbbbd1df8bbf7e44157490e7f1fb9cb23e66d8410f6800e1d94482988a86811d1f65bc9bafe84a9428f2920753412e2b5783db3cd7330f74103715fe0aa9aaf3a1ba882afb846039ec769b94590a6e0c43481fb0c8ce0fc87a9932c7eb2eee3147c0f4431be17d7ee1d907bcd7249ef522d09642462a91728926afca33888d87333ceac1f76d6a3535d1a61e56df3c241043c0beb6c9eb0376b89aeec5fb0f4f157e3517547e976b92f032cb9c9f26e028581e97adc473b3a8a89bc340bfad0c3317983e84130ccc849e6d4be0c12e9581bfd858aba7fa96c9ba757c35674c9cc5cb899b7ad094f0c7eaf55a4769f1d086f2dddfb9748b6baa040f3713636e278ead41aa5cc309e3206053cc631a883d85afdfb567777e059982f44a9fb907193a9fb3ca0b1e2a0443c774789295e22dcdd94d819c8ca07ef90d41845336f16aa7841eb68839fda2dc58ae8e6dba77ac4d915054db31c27128003e435241aa18ea5968541e1e20326ed13b3686d5f7e549da56d1c5aa37aa50fb4eb1c022033229ddaa65165cb3394accf5735e3597c66de2eb260628cb21ad0d43a8712605ab4ddb02333e82c182ff6d47f4ca607710ccc91bfb0f2d6325cec252978a7a9d0c1ce326c61b253c1da998f7cd9b124266059d1b369e17486014c90df3ac625008e5cf7c3b229009f7e6179fc0f097f53374514f43a912b5a5673bf00c89c192c6d4c53ce5eb717ccd9b75783a19eaa240c68c7db7fcd787a6055e4d7e57d723ad14e63d6942348a40b375c09345142c1e3e3f7934584fcaf2bdc43e16817d3cc970d414b547f8798d3c0738e9813109dc885975330dae244272403b79f3fb4d55de02334a6c05c851d77b36e47b78d48a1412178f5b69947d9f98fd58041378629b7b4b99391184ff926c10dc25415b0d5c227a201035448aaac0a428927ec5e8a15e884cde16127e784a9d14a022e8ebf8376062955c2b508f44f9c0c8874c37b60a3d2d319ffcaadd0cbfe61154228e397dbbf8452f69bb0e7383c0fdeae62e30ddc485e8f54f1378ad3b9d2d175808ac3ad1f367ffa69f2a88cd822702eb2cf78001a54d7ecc1417590b33ec288839fb5f6eeb9b1a9d4e48dd5efeb2a5102cf1cde6716692c685c852e09378e13af62af9f29dfcf52a1fb62c607b31520aa83070c7ef4ab93c76b7358e92eb592c1e56990c3e1785a568dd92cb3b7e7fc8d047007d138d99324ccf8fec9713e1b2ca063fd5142567d6c6d0ee602eadd8a59da2c51d3747f351ee1b9162330769b96d513a5474296f6120e40bf302f392e8ac84f8ac65020b14475cb44e08ef863ca47ea091a7aa728c6b293004253affbbe18498f76764beba41baa5a1f85da5d6fbb0c4d10121eb0865e5a8f524c08a623f7db2a67efe5b962f788fe840a5bf04997d5aa55ae4b7d080cd10db76e7f7949bb34a8896f4e59382db796f03e062f496dcabc63a527c50eed4dc3b05b4867cb353e891cba38971be20efd9e7aca86058eabce65c19461074b9aff2c96420310994dc5c211151822992c813b4d1485c4b6495287893982bc42263031417bfac20dc71dc42c9a40526770e54fee1819a41c30661947a484111c9fd5c6f3b9e3a15147fdb60750128380baa047832a47e3c56a04111ecdc3e3494645a24a9df77cd5d1ca52c4923d1a759baf27b2a0b7bb58b94374bd210407593fa05c252a0d71846030c1fa56abbb854c4eed16f81ad0a4ac09827fb15ee0b5d30f1f1ef4807900af40f8aec2859ab8840aa2455bd3ba92a29537613151aaf35b4141ca54357c1a13948921e50d3d0ec89f6cc51bf2932b9f7e7aff68fabbf547fb3ca82b47ba84be8a8b197bff2434fb78fd4affa217d21a541aa66b276f9d833121b10228226ac5fc1f4d3c29f08cfe3a7d50e42877d3862410d5f81da41dfd47e2457d9e14d2ac6c8444b252019a55a5008274f34ee0f867032cb4cc7072a8b599a65350a7c37c59245658556ad28842635d7de5fb5a2620527233c12a797119e2dc68d11bd779c0e0d8d7acc51fca8c6df350192b2599d15ec802054702175b6ba1fc2f76a4343063b76202f2d0f91794ebac40330914c49de4b12e1aa076b3a502b54ddd6bdce0d7b4d63134d7610a9531d23b5f48458f4cea92a1c5f15b66e05ac7ce163842c5c7916c1e73f7d2d13e250ef2e217689450c8fb492813c922d148249cf4da1120d825852756ec8c4714bdcfd3c00f0c5dc6a5721dc275f1277383127e0631fe077539d242301f7195272f9088c009426b71452c819adbb006d76a8db2ff3a8a8b24c42add5c2ebc425d7d5f0bdc44f94a4c33ffe3c5401351c212fca0c1a89646770b8ecb108def7201cf0a4a0994cf2069485866c4a3ce38411d3a65caf8bd260fc80da00afc9b9bb9f0dbf43848036c04a002838a2ebc5c5fae1addfd8bba2403ce6006d96e7b6a808a401442b8929b557f2e1482165fe3003bc30b6a5ac9396fd0c3bdf14cdc49dc97ce4c7f2513b436d18073f60ff890c1e1fb77509c1dc7e49e76955207c1734354d54d20cf0a1b9cf74936a36b0cebc089f3571fa3831d9167ff0306ecdd840621caf616329363b73b751ca639a409576e8ab6c9d7e2364fe20722f8f3b524902c9c96e64b6ee668da141a65caad510b81334b36d9843026cac95a67347ab3c5885e62ad780aa6a11a965705fec878ea5b5b849048040af18e61cb52f59415d544f545505dd2fb2a0a24009965c819787108fc43c05bb99514c4cdea95180e3f98ee0df5b18b41f22f1788741749defef33d3d31d856c5354b20730e13df69dfe92a747842a3d7824ab1fa83af442559df6ae3b49ded48886c87dfecd89d1dcdba7309f1623b51f0fbbd1e70d39a1844e1e4943523452a24f0b7e6f923403c729f9dbf0b52dbe608122850fba268875481244d6b0dd22bcad3db63962eb2070012761c641565c93322ae78e5d853eb2b680de6773425e7f1ccc2eede1229deba41ad57733c3a5a7182af86526813e64ccb47723bded866c31b8ebcf783ae42551409e8d61e9c4a1b3587abb61c8cd6fd463931c618d6d49e5b2f09c9a8899c4c549530f8c9e9330f406ec78b7c0ee150d9845c350e314f0020f39f05846a8133e0364b12f00c5c7e4956acc9c958735edfbbd6df71e30f4e18bd427dd9a6a061ff7049db46691a61708e269618b1077a4b3842dc60eb6981ac08859c61282c0d605036c7efd83e82ee39da13988704908e5096405351e0eaeb0c69fdabd3e804c0526ba750e91f4a33bdf0697cccb247abb035c30a39edd1303efa119bdd059bcccdf23535833e1ec8f4a0c41754089866c752fe1a196a3d005cc602187133e7b439e17067a7b8f0e29af526fa817e78f0d891575afa5add24a7429532b41a1bb269e988aa1fef70c588eca16e934f74e79ed46aad59fdacee75f3c66849814de40644e7180573eb0c66a40bfb28cd3619c28760ee8d6b550d75e13d3d0a414af25b6061334a6d20f1f6d7bf0510b1038e8820daa9753a3814e953401887831924b739cb353f1fd5b33bffc22456f8eedbe2811aacca02add967bf18466560ff1385ce35eae6681f9f20ffc285ec073721cb3835ef3a2986af68a1c2b972d1217e923756da129f0e31190b816de4861b8282db9f0db98518064288d078e22c7c872bcf57893ae70f4c872c40e856553162d3f12b406bade7b661d7d5652821753b116b1f542f476f24c60f190dbed229c61612e3da3331b86de640e377125d71eaf53f02b433444572a82763f1b24a9986f4ec5755a541a6a554214c08ac08b0a16d159716f57a7b0c7464f5aa8448be990418ba42d3bbf50731a8fcbd8c4f416b380a833c814feec684a231a058d914eb1ab7f355e3a626d8a3445f4afb1e5871a8e31ec5e051fc7710f927f19f816f9c50480bcad97d9b12e5cf12904b7ed201cec186beda8046712629de986e09daf339963304beb5d67694bbdbaa579113f75fdc12ddf00d75e4a68bf951b29c9d4f6c8d708626b625c9f97ac91de05796ccbaad02aea03a58d3fa5ec4ea31be72334377e7b0e735c261380f2ce041dd25873e3fc5470a2a6f1981dfaeaa84fad9de2ebe7b296dbe7b681ebdab6d8b334554c128ae6138a5f36caae7f16e6156677a363ab84cf5a912959939e2493cb91c56bba1283be82032d36130929c51a1d721ae097cbe531ee97c7901f56fa5d38cb32cd6fab8012393e72adc66b9e6c432cda72ab9e677220dfce129f1a6e86201ddbdf0446e95c9db154b92b07b99397dc83fef7bf34851bdb730a0b365281a8a2984fa1a14bd49fe2b583dcc0778779c09a5bd352d084f721ad263610621ae40d84daf9bc53d8c5126faa775c3fa2ad49f5baf462aa14dce2bd6d83b98bea030aecd49a163f288ae0f48260d5147569b6a2044370efd1f6b3936f84d2dde4733d510b5bc9dd8a9a4b04ece9835648b62a5a29225216d5e445e9a2854c23f1ef4eef7c102a1ad8c3374a5dd3c2bf7aaf93e60078cc6737eaf7ef25653ca5ee22e4b942853205336da3a8b424cbfcccf3ceed691a0f298243dab5a803d3190aa140c45e1afd502d60ce99c26ace5db60ef0affc1a277a30df4f7f1c5e86bb1f47380f3e6efe8f7b4fa44f4658c08e05a444b5d6d7f711e6bfd6c5612309bd8a2fb8ebe6ca8a49192677474731103cbef3bb2ec87ec309992687005c8f4ed69306a0ef9108027930ad0b05cf731e4cf0213a92b7932027912fb616ba32432ddc5ed7a904468e96fc24f599e56c1e407fd174ff7c70c1a50481b429199e4af367f6a51ee60a38bf447629016fc47eed49494e4c90132bb32d3f2672d43a8eaf60ec536884e2dcd8c687c3c933763246ebaf5cbabee1ed1414d405fc44407abf7f05335fd05736b39a56763161182eb09a7d980f296219d8edfaac02c40561a62e6cf99dd1c5febce19378977b8fe633b8892ddba938ccac4d628fc84ce3e8a94d224d71e7291bf7013979d1ffd7b089f3bc21a55524d0cb2141a567323c18a210d89af78ca456bc84a58ec81d9b685e3847a7675beed43ddd5d09fb4bc01c94d79cd1112de4a591f1fd4bbbf3091c13aa63163135c0801235cf8045e2840d58f219c7c0a697e1024a2a12d179c8a49355e4a1b31860fcb145613f7de596a139f8fa7491a7836bc93840b4c59cac213dd7121779568221ff26bc6685c112a20e0b705b537d146b723ca54a0b86918c9ade80faeda96e025e4fb3542cde072b1283525428b7bacdaf468857428f1e88886c95f40ad10c4e414b20e48c948d1eb6f8302cb0f94f7e10754f1893586bc187854762443ba3c1efe2b146cc7b82da3ddbe41042b6165a431e4f55e03b8fa7b4c04dc9e32dde1e4ec1efd7dd63b7caffc80360757e27704e4f40bad3e3ff79f8991f5e83b5498cd67d2cfccea451c937e1ec09c6c4730204212d8028b41133695f31052017391c8183aeecc80f3b383cd02f41989c6f8c8421a3821378b93901c8162318c35e70ecef6171535d6e47f92254257ee11638f0da5c88c3bff7d5276445d67276d15b195c33fed8b77df0ecc891c738578f1dea1d7320cb0e01fecb3eb3244bbe0b2a21eabe9be829b3e0d40a7ac007c41f50c85d2bbdd5adf8e60a3c24ba24ad305fcb1b7f7d4c1c2b245a2daf854b98a8b6ba5a1c54fcbeffa73cb5713aee380335665c25daa07253ef9fa0385b5672ae6d4073ef27bedee99727f093201abf7de2ddb721c07b93500828ed280114622810413744a0c719d0a3019c126700caf418af22025a3c8eff7791e93f3c0c2f92e99542c3914daeec8db88f9c7e82bc6de61ef78c6db29e70c660aa88855182b7afa0612ab22fb9fbe91fce65a95b861cd747fa30f7bea508bf66b059de124c82a64f5c7b17eb33639b0f54147224445877349f91ee3df31c479fc6eee21efb71c09046465e8cfae162668d9bfbdee543e5e877fa3059e2ac600eaa13034d41586c5280c86bc79ecd7643eef8b2385b78f4046dbd0153cff4cdc7742597d1c8904881313a0387799499a32c54e48e5502576decfa7547b3dfa9523def77a4a54fd01147e468cfc4fac857c5eac4c28e5267ba71c561a6aaa151dcbe169e5a0a402c4b961247c41243fc77bd3abc3a6ba9b6fcc522e22b1c9f00c309d943283735c5e6db2bc548ca53dbea76f6ee843146ba6d1585e5df3ff0974ebac69af32b1500a797de015dc3fd01e2381eea79f5ed755c8eed012dcbe7e8a34cb4af46c310e757cdf3782929f7b70838ca555d4d805d4736bc495bc25620ff705ee49978a4773afe723297446a98784c0960731f3e21dbf6e9efa8cb672a55150a7e2571f96078ac2fa02ad2976dcc116cd59c1102daa43185dbd312a27495143441611550ede11b2ff2c4d514f5b9523161e8b09808ebdc324e1b910b69a369ee566757b63b1eed285e0eb3f423963cc36e473986773d5ce72038c48663dd01289453c32cf4f6b73ef0885333fb82cc962fa043d1f799f81e78e9db0e838befc38372f4182c59d68a89d78e535f865e6fc936bf68e6894925a6c2ccdc80daaeb654c8f34a81a51295ca8ba10236462ccac4bd99582e03f2b286e54c3dde8486c81392b519f58e046d4a0aa8ec4fa19645cfc0b8763ff0238772dd4312760201e61d0c5664f3d6a38315e5e3031ef15146d61b1a579ae06d411bd485ba346c06cf236d60f74541cb5d98f99bbeb01f36b6504a56301a2098e41f6987c2c231c86aa8e4e223a16ef77c54071a07c74ac076d1aa640828fa06caf3ac568ff9fc55f8a961d4d1ebd14099ed43eeef9b60048c378a75a9630864398662d686b6b7ac90a4ca9cf47a193c03e7adfaef97456e546096bfd497cd980d8ad61953e24d5f4c78b0c120abf3836361a45ea61b36ff5852841386461df9c18a081644ac7ece371e1d77f11688076d823495c5309c60df220470a60017be39e1004a898b1121af28913d2b0c3304fc327e86ab3764149df4d8a35b0aacf7318438d39f08ee077fc1f9addafebae6333a10c4821e87113eb308e01cca079b217f226310dec66ee25f48b7749b404f197e09c3bd572728950dc0754cff0b78140c998739293a0f90187b0d6ff305ed74ce51b9211495c17056729e8d7030bca6749aa7f168f81c0c8d08245822e2d55f3605c8ba3b55a58254bafc8a17dbc9b0763c0ae86131d6ca8a05047316b3c014b9614e333f5d9322ddeeadc1a729b64d26891349d9ad0bd72d5728dd9446683fe6b83c8a0c2890b2395fcdda94c9e8c235698a14228374b3ac01cb8984844b356cbca195e665bf7217317ece205068e4069f1ec9ccd934d240ea0f5183b9ac472367853a83762ce275134c833a2a52408b39c8767356786337403fa553f1a8a3be9020cd5ef6750127b109c08b882c517f87281a0ac57f52687d07984ef40b7b89b47cace0c625159852035af4e229f5b090e9e750af851299f453aa64955b2895d77b54faa0e2d48815f24096e5c1ec24d812043fab5690f2e27c4c1957cd3da403c5345f2751d150e1934eb4c2bdc32c525c8cbc4b970e7e48964458b09bf8aa34375d1e762bb4facc29972746dc648e5f6c2e8313abd8fc9e101b86634af44dbc7469603aceb20ebd7e08a3c0cd3aa56c504604780c925b4a2e25304dce03b69ca960a3236743aaa511ef4666138538213fd86e24d4fbf6309a9959ad7b5a505982e068ccac6897cbcefb0754a8a3c2ab1b63fcd84b7342a09a648354ea4292a01ae8bc7c5a10ab11144b10a9172390ece4d9445f2961a725da4fa7cc3c9efb912be1bede0d4222199c9995ba2b8df5a14c847cba1ca0c3752e3eefe82ca9e170fae23bdf05f1d6fff884779e6b0499afb9c581ef1356e15d46bae212eb52a8cb4d55727c835b76bb9b94156333ab25000d62e6a57a7e7350f9a940f0b0c5b6a85b9264c0ea219191f8b6e857704f5134c6ac95605249163e90ecc6c5e1cb12c2429fed5cdce34407af62cdea030496ccd4ecd24f0b69084cc2ccc3ffa556d04aee961fc047eaf03e3848d878d25b6019476b00e11c42da4ed902372acad084bba84bf90898d171ec3d3f0673f4493051c8fc3652da828ecbe301aecba3ffa5e24e2023e35b53e901e16ec7b1c40c7e39259887e25ae30f558fe164e2a648068dd1faa102ecf6c4fa800dfdd530ba223e20f658c71f79db9dd44575e7c5b832bc1f255c2e6307db04639a945c659ef77f9f767737f8e492c1f6a75e7ac832059e523fb03087605202fb6da60063215c9b125b274b638f9c3dc20ec5488c5ec8c5f1bee2672c8387017b19a7dcd9e7903a2ba41faf801d27366dd30afc6b3d9d37d22e588c07e4ee2f2c7f4bce4ca42ef757a9075bf96ee0c1b6b025ec038f2eef2647fb566e50fe39897a8a8713d4814a9879c55339a7195ef84d4ee47066d588def4545c5b6a52cd8d5dcd208b752166305bf8b3f5109b4cb3ed1b8108c600b3e7dac8ba6516821b568268ec0763c6b4cea97d4dff9aaa5165d7007ef0c200276a02f88df1d9dffad5ab70fcf7531e884a0541c3fc35e2e3b5b78da2509b9335782972ee9b72f987bb523855b116b5eed68680a3f3e157d392e9e7b11d28e274a36ccd8100a0bd9267a496d585798d134635587416406fcf087d51e1ba51d158471d924e828a6a988c9b5e7d0f88d58cf61e0aa9333ac4bc1a5d3c00f46f081406274b3c9e342598da6d2269d84bf1201c90b02832d7aa779c7c4fcd97780b216529aa1bff0021d39dd31a2be15a8d38a9ae38ef635ccd56fbb2bd7cc55514fa2405fa1aaeac0e99065c0802396a105f788eb7af8f92f0e2a8b5f40e817ff3c60cc939934259ff5e0c2478122cdd2e0ee4d6b16dcae892cd62507efea0ca3a2f65529f95418846bb3adf1da06e5e5d6a734b224299b9435d771942e82db2ebfcf24e718709c2a17c83dc90122cd69bfe23ba2964cf0cdf1067a3b064fb8397b0e846fb01ba6d2196b55384e52033e6fbee0ea340e745aa2436428129fc5119bb02a4d2b06cfef3e88751b9c75d44347ab469c50e28cbcbec8dbd4fc674c9ca1ef00d8b2e035f6a011d7859b60628e891270ba32ff85fac4b3344fcc3ee878c1f746b337e59a160adec68a6bcfa9c1d4223b893ae601c320468ebbf3de21d86508e73f496507fbd389f07b76e6604a7818940c37865582faf81a72277b2729432c6cd6db10adc99665e44bb6e29ee26cf1c0df001c157fd7da0d5eb7c8f0b355309ef162e4b87433ee0aa030dc9ca9e3a4815e43458496b4d39e74dbd70b469d5852f828d8ac2ab7396c490e476976f261b6dbf46016a4ebf77b341e17ae7ecb3da7bdfd398a8a6cd3be0a6e7ec2977ef4bb5fcde4409379f33b2ef06a1cf292c59ecbe6756fbb20722ea0d5e51619518e88cf538308fa7c00b740a48c61afd2dd7718d1b3a4b9cfdfa590c15a8a4792aaf330ac4361a909e978734a490ae9b96d91502b3b07990938a02848e6bdebea7756aa1ab7d22f165ec95bce641ba8b60e6eb1ff66252cbd6065014804b150fb3abc06386d47e5f6421b793fecc7b24f4d8e9b2468df7dac1871df539a9ee0e15009c00e3ce84779e76d4e415d21af12c04acb9e1d92fdd900fd4c18c8ac2a4508d16bffd1512a64d4af3f37c2cd1d389283d44d9d00f6571c9d6ebf896a6728e53a8844ba9aff39264fa08b40ac4aa70ba781c01e68d83711a06f7c396721aa983f0c46e156646074e9f762349e9bfe366cf5622bfa946bfdec1877c926cef1025ea388e787cd3a07458921048e230acff880a07474c7bdf31168aa08a33db465d5bf8e5d5def483f104048ebd899255130dbd4cae60e527f4f7fd01f2757f20832a34ed3c6ac534e416962ae1fe2a9a108ba1900afb00caa9835103074b97495d758754abaea27b7b96eb5823c02407d842ce18640ae9dc5ece2b4cf6b05e9d7f23dfee2b0973613b08bd902c8566e70ea9f34b9f8f22fa9201a66cad73bf8377ae55f05fe2daa57ab5a129d3322611bcb9e89e54b95cce7fcc6d46bc68f6a91183212d8f72f369a672b8fa2dddd7ed3c88f7cd0104ac24566045d1d4b505fec980aaafb9302c1252587250dcb49988b2ef30837ef6adf5f0f210848855b803a840d549ff2e5e5087229ec4579108d514656122c9a4d6b2f3876ed4c670bd4bc7f0ceb6f62892f4f73897fd4371bbdc4e3128b7a4ed8b247b2d811488f40684bac2c04cd8f02d34c0862241407e2dcae51d0cc133f3f73beaf7bee028763da5175e66b82ddc7851e62da48a0f8e38ecab0e5ae314c95120bc44fe8fb7f63f88d5c094d2be4c5fc0b1ff8cba83c140570370d2371e826103824ff32e2bd820e0f543c1310401fa059dfc7aa22420871ce351dcd48c79d957adcb19d007df7208ca5555cfa71c01844fa4b1e55686c23109a0458df14b09d42bec872b6138c4f9a6567d3a38f893e0abf746f71dbdd1754949d9f902ee2ba57dd9be5d77d8180e3b77feceea883b4ed9194d9814faf325c37f8bb53409fd2cb50fe620025d96d12a2ff815bcda80f7d7615b118ae0f408bc39964dbc961a42f72d57168654b18fb2bf6ea25c264cb622bb40e796d6fbec65e7be3629b6d48e22f8acc9a60b92f38efd319bd0574d5040e4ce7bf6470d2caa790307333415392436b365ca3f92c51704aca20c2a054075773d012888a11d3cd686413ebd8db04e42e2648ffafcd500008b32a5908605f75c1763718e14ee244f36750bcf3d7c71dc299daf0ce5990423f14081408470279a8b57ef503fe9355fdb73497f984b280a1a394614a7bbb2d904ee2e77fa793d139b687b0710d56f133ba78e40722bee6ec023d9310305c43b72ef063ac86a332828df103bb7e081f61ebc73aa85073bf2c60e341f1a70a350802b24ddccfa3bc068d6c34c454f9c8183c54077f0bff51121a9920265a71002239cce3ab05c55d07dc9f988825354a555aa4564856f3173beaab456680d621cf19edbf27c1fdfc9538c99bf92489594fd9e999b399055a136ef763b7aced22e52aa7f6b276ac1d8d08435cc973654fbc670153009cde5090ecffbde51f4f1fcb89696b8ea689d1f044694ec819c7834d6e6925df9ef0707249cfe13de3aa0f4aa0090fb600e8019418db6d40df49f1d4e5bacad38fdfe0af0db4238c90b8d6021f09e3eb8cc0d1949d2dde24f10761e21da4015af1670436cf1d1462f968ed7e879bcbe43b6f4be3ebe29c34c06e2dcb4ce5fafb1895a2828d66395df877284c1439d5e7a542da38c9b99505004ea124616c54150d93ec3c9c0b02f0b40f9426604e0e4eee6c556489a6c20b3b02cae095c110750c51eeff5d54d95c6794e419c434ffcae390327490d917f61acc43dc0bfc3fb84e212b2395957a515ce860350b946102b006bd9100c141fa6b233b027147fa7383ecb9d795b688368f1558efef3a58987dd32b7ba78194a5cbec914c883a6f4bbd307080c2808afee1230303ba8a4f90093af02301918e776e1041c012e724752375d4a819aa52587c7b93a45c2aab0190e78115489daa11474ba028606f19768bcd59870794747ff7f72acdc7a167966e789d4b74c536a6efa2e74caf8daced4bd06dad79aeb9516bb3a6c0a684efa3aae3860df0d2a41c75d7ec9c4301f09e316ceb7ee9ef216aff7baef760b631edd01d3909886859dc9c8fda15cde9bd2c02474c3043a87da6b142a61370d2b210040f67b021579001c66a1c32b2c3623ea4df7030875aca89093e7647fc67aa2d02d4b3eef93bc827fad5ce261c0f62944168b52f1cdfb99fd02b113d883d3f2bf1cbe17b87187f2d8874a0d6f5c80baf9ef63413f0626ef80691f59d740eeb76c4eb24f866a0f06b81d2964f48fdca225740ad0b83f0c344e0f13315c75ccf1bb5c87265e8721d16b78901b7cdb079e04e8db707a78f670842f0013bc75f7bed896eaa688f67b88e2487778a73df4da38dcf47b8546ed91c39d2898c17f048591be7010589a9c9a8b63408422115e88631478f18be226a18bd416b112e77d1581aec7ac617d8b7c3f76c595b4d63bd144ddaf20f37031918d61a91bac9536a969e250d95033d343ac5ca7dd573edf31b4c6c600a966f0f32546a60c32c99c0fb803e0c6bc54efb170066ce78f9bc9dcca03ead270645134a64ec4ea2a8c1aaccab2857d868f57217ac47b764ebb1dfc34759d32dae48ac7500af58c9dff6c554137f4c26ff6b2e717401454354979df19d06d3c54f086588fa7e79c26b89996a8b3b1350d6862c5759cd7eb67d3bb7b910fec391ae63d1bb3607b9de359df22985c599629b5b846a37b4588184d9465f22522cff025d9dab83bb40e850df76711152d41deb652f782970d79ac02bb13f5e6dae11b95ecebe67223dbbcb914e9560df102fd52df5ceffe6d3fe99e43b2147d9ab43b8bf4375a832074b0775dd7f9e78227824519bd93fc4e394432752c4e85c98601d1323e010679ea52d367355723236efab3d24b145b6478884aa15452e130794c218c94cd57f8af149b2ea9bb45a0d652b097e7f3488bbdf7e3d51ac2598b5b1cb0ec8d38035e84575a0fd18c81744e5fa90f346a555d922be985c3d065b4e417a067360bc0bcdc3da8c289b907ce606a313dce924f7537a4040925d3c22a6413330099dc012451c62b4ff1e810ef7e716b278ae33be4d74a11ff975e4040814311d886dd0e7f53384c2b9251d45cd562576620f2268a58403a41145a64742ddf72944a19d404fc02691641876c6f3d6f33b30e193a6bfb17a10719b0acaa9d571894cf9262c1368f91c869312a2307529badc2a606f96bcf5319482c8e3e37c2cbd1993f059bd48598f6e6437931eced6a40f1369e643647cfc71e718e92d12dd4d61b1e49e1c153d62a511fc0d08265d65d564c0cf5cd5d4226dbf3673c3e722638e4ded9e296e43a984fd8811668f4ca83d324b37420d7aa204bfc1c37ced5ebc2d7525c69cceb092a0d1f51286462572f0b6bf10bf6088cc3421494e361695147bf0ad18104ac2166d473bdd03ffaf0ec1bae29ad8836903b753269d9d393702c825f7121a276838f0593551b2fdcefce9d121ff2a03e7973060c9c64d5bfdc680266bed913951bc5b6de8612d3484f735ef8110bd350c289b489913f09880838b0056ed2ffcd8bed7c1741234ce616b941f3acd122e03157733e81c779f90529573bb49ba571aa175656bea6af5f0ea442148683aa4b9a41c62311573e7d70bc47b9d35b5a229c4d43ec7f0da7cee827e3b1addba4cef12b411e1587d45c9800d9224ae63f297cd1f394a8d9533c08a10d22beb496f07533b2c81840be3fdb2800507da4f33e41022e24fa7f2266ef6fc637fc4d86151c3a9563e6992c7c30af88804188730eed074ed6de15047527e1c333622a2ea0c50fa26bf38416d2a7bcc5cd17bac60e1d1de0a254bc6621e8d92ab98358733fae58e5d146e72cdb730b0583eec231030b03a200d765bc4040524ac39b14f01b9ea881229e9e4f5ca6001c5f8199ad26ecf42bb38db50e83b12ac65847de4c0b47034eec9a64be454f808c1ce5580e465b52c0c4e5c591956f38544eb934c942e13e1dc91a1a2b333f94d0bb9f0aff3b38d932596c3c644327d77fe70e6a2bb0a103afe3f7f21862a3230441e69ee78b0bfc4e6c9ce3a3bc58c3dc5e13776c12e3bd54e985622e0eb108ccc72e65738dc7458d4fd2c7a89b8e730b97aedce1abdcf53c761985b5625c49ca894d917658416e5e6e6b5370436662d555a79e1da1270eef8501c14bbe9dd3e9c90c57bfb352e7fe59c5b72b37b0727e12a03907c4f5f82f776b884c684edb60dc43712d8a194ea42b9b21d6757748e411fb02109f55cf7acf7de0975c454b39e8b810e8b5635a56b7a8b089518dd44275eda8a491a9a5526e10e87419013a0a8c2c7d789381e8964cacd7d3a72a98a88f8d0f436b52a9b349a51f6301d1235049323387c4e7c5aa79b2d9cd1b6148ec556690186943eb8ea28987522e875af4c1daf027f759c07633e0cd95a2152019e9a5e04c13a04540a3432881acd08afbbeb4f6531a59f338e07188a7d72da4963b6ec42ab553ca3a5d7cf935bad77a1cde44615e0580691323ba0b8eda63900d71dab83aa110c851718beca68e19d3140719854ff654f5cb6eba00c92321c9691261169213dd32576fa8ed823eeddec778082235623234d5ef8645b4b6782fdbe900ef80d7fe26964d628bb7648484a4a37ef5ea2c4c3190a67ac90d4ad82c4ca7a897b83f45bc04fc0d5a2e47edb0b47a26876aa7bc1f0bbb5f5ddb52b543ae2db59457eb3d7c8313193ec0e09ea79be362af4a90cb3dcc2d865ab19283e5a6fbcc9681283d78ba4690ec409f3564eacfc8fff79cbedf8da72276da862f106d5936621ab81a0eb61e82c9974bef6059e1f363e02bf12e9b028f70a9ecad43899f882856d748022d66610d2ec943222d118041e71fc8037c72aca02a22b9352317ea053a03fea2f82a1e863222f773648f4667103ec55faeca601c41f547f7966e5e9c876d18b1f5acb5d0a1b1dc6581d01ba0f965c09d4140170d2ef73cf8623e89e8b6b3bcd11e1db046f3c80a3eb595534ad8052c68b78ff2a8f23462e5a2fdb3adf7b52b54479e79188befad9d60b093a5e8e57c260a2afa06995d806c9630315e963a954c3781197b1263f7abfe49d5196b5157d99f49dc1ea7033b97475a025742e1bd0322db4ddc740c8d9b48fa2d4c31f5b24667f40ffa43c393cfbe386598f7be7f794814ff21dc4ebbf9c38b7d92a196f1f3d33a75272f6e6983a608a163ec710f7b2a5bb62c2ddeb32016a1f01e2e1e6f02c1d32af5c16dd1ce04fc7438354e68ae65a2b627a0914591b155f95b69c6bb62df38fcc5b61146c069b2a2484c946975664188664617481149fed58937e42a78143909b2331ce62a0c2fa71e5e9aaa4ad7b530613fc83a79c22c8bfccdf46925783d508ed1b53da44dc50318c1e976e3dff330042244622e12c4c66d62901e10c25cea5118456efd3e211743f71e368401a31f6cf63c5f3232e445be55cf116b693b516f5035733bb591a365a9196cd7e54d8097c928e10ef43082e155c48a84206e5ba5942f355395fa8d7bdab0efc16a0943d13def00bd7da0c79859c3ae6537fb76db7c5ff22852ca6c08f2ba95cf538c2046d92d0814e1394bef1ca26edecda1d14d16cc28a14edf78eb1abe385b08693b8a5dd80b620ec3c303d60aaccd8bb909827dadc0620bef3ba5375f37c66b2e1cbcd75753a88fa77b5838951a7cc7f385b1100cc8cb819646524f6745d76fa51f6703e50182ef8cdece842e18abe1bc3a7d805f31e7b396dc04b20985b021b1c776eafac23b7680257b0607276f1158b527152fc92d18659820c91104d21cd7937b22e745c1999eea08a826dae65dadce6aa99724604052c08784bab199871b3055a3b662bba573273c3ac70551fbacd6ed39512050f29758a52a4125ed85351cc80081ab5de8374f0824e5be668d5de7b77ff7a304a975f76996c5d0b68929b004180767c235183729423f4201fe111461f9f8383518b62a2e552d3d7206c8832575e7a45c4ab15f0f3509acd8790905cc68b1ea7a3cfb50d4c07dc5d2d878b7dcd1737eef52b5423a5904b857c0d54fe2ffc3dc5ce32472a6549133fb3133387c384e1df89a41a51675d25c79a25fd07edf14ddff07fae8b7c5924c7f266a2082241a014c3fadc43cee07ef07f971bd14e3ff64cc2ad10aabb0632ecd5b675a803d12ba7dd0c8ccb01e6e5dd62a30e5a146669bfa43d87551c634b69a0a8b890ab8fc851e8d66b239c749dcc5487a8e045d097e242a9173da7614b4c97e008232b144ae2fcbf212a0feb713ca38a1703f26a0ec4beb8ca45a73c6d9ff0ba493b3455f56b1c18af90278478aa513de530fa5b79605062c91eed499ab1915fa515f49b27374910a8f5fef415b244edceaae104d7a31a83a33a1c3a660137989514a74aaaebe9e6067421e8136d8f0166a82823b08ebc2a7bdfdf27b02bac425694f02350f9e80104c32ce96ddc3c01911354a44fcd8204fb5903b559b768e7383b11ff3c69627224ef45116ad351963b5497954a1fbc0567b9bbcd0b158c34c92fefaa5c12834780f95c4b3779e6df76fa8631c6697d73e10f1b3bade0c0ca452df82740e2931f0e5ed375e9a2d91a361bbec431c969b86e623d90cc56c7532d19bcc162bfc5a8d78bf71d03f12ec9a976c6bb136be1b373de1ee013d3f3ac5bca8184e85ec3bbc5d71979cab53375a8e352c666b3c6f8bc92f869dff71bf5cac658e4388f58b3d3153448363088d4f15e074fb61b2fccee9323b48e5c1668654536a4c76fec77f92613e9c3ab42d5e156e81a16396067228f33b069160cdbb7ec0e237e468a870344451fca5e2f55167bbc11fe540a94f2fd40fd302d07b02d3ec4e04e4a906e6f2bc2d386edf8cbafbc4ffaf98d56793527c8f08081d4e257f8858229d47c4f5445c18ae894434da3c557037aea240ba9e1d2abe868b84a6d07ab3cceb13421c9051832f8d87e2288072863bc85c2050a63a51015010b4e7ab88845a0d6804f0b8294a8116987568e90bddbd5b4ece4374de97293fa667318a3906ea453d887587b744deacd7d236b879f237c6cc5a672006ff4a5982394ee918e8485fa22993addd9b81c227111714e1903a05e57b442ed9b76768d504a83351655b1a58c0e820ffeb82e5d8617c6cd0f35cff268cd39c03923ab0f47c8141afeaa7832039dccc4a0ace6a411f704d2e93b4ea626d9a192ea004548193410303d0a0813e06687ee18dad9938b22341c063d25ff7a3a7c2b7911758d85af37fdd560350e070c3c7a33c08326f1b0bb5c918605e0c6b85dad7978b750f881f4141e1b31438707671e0427defbb81c478b6a88200bd73f737923cddf683438fdc9f253da573578b379fb0909e35c4afa4fe6c0049c87888187ec0a341852a4a7a3aa7d38bcb10bdbea33cbbcf9a01667bf97eb36166feaa5d0d9e98d9e5d0021a94342d1cfff24a3f2273e9fbf3205b95300daad59fee913467f91395f6185ee79b2573f01558dd7737ed980535999f10a60de0ead31099d5a500057a54187b7f371b9f4718bee7a836150d1057a0380e0ed6b6fa45d6f0dad3db5b36c220ec2b631fe32ac58ee89f02c421672bc6c7de6091e3c3b234bf9eee2b1ee0265d17fe288315edb1cc17bb31d8eeda3ce47708c9814db4b5683c803547902fa00bfe649a7d6fed74213569c5488ffda5d5471509fb9399ae01b21e0f0b42912ff0f01a4ddc8fe91c94c4e01451bbe511342033dfba4f0b7de7d107c4738aa011ad6abbf6284908a7691ea1a8572f41fa5306d297106e428da9798a05dec434f8cf11781ac8f75d721f5783e5d36d3a3532dc58d05a722a6f49aa2007f100e46e2fed9bf630023f6d8c807e594cda60811ad31d35563892c68266f8b00e938be1713f5a41b4f207cac2cb663ee263b330c5ca161dc81d52f8d10e25837cd5386de2406c3fb3fc5e6a0ec36a38512fad6f4c207ba5632b4898d513d2aaee7ccc76b4707fff45328851a0660ade0d00ad4c3ebc531f3476e96dc4925a7f6eb0c1da34d237dbf956fbe0f1107be7b864c02f8cc5f30fae77beac12e5afa7ce0926f3a831c7d39f6863e03ab5df7fdb32642b8cebe96c037ee51e9c92f9caf78fdcbf478b210fa3d3c1a4f8fcffa77c361821c70817d6e89fe43d815cc8b3de8e879e3cfb2cd9e87d8ccc4d1aa288324b613e83fed7dd09c333de878b80a461e7b261afd31eb673b376be0c2f5884dcc5a53b8013570cd0ab4104582fb7f585ca909152f997143910b8b4579ea6c31ee8bce4facb94abe3af0ad0f50c66391ffb9df7c74fed0298b9f033bb147e115c804fceeb4f59cf2147b2f3caf48d97f0b4e9f49760be0d2b86fcfafc4dc74eefc86e4973e78b53877cf2ea556d459bdabb9cfd7640e9a38ffd68bda63b36043503c81e61a7ca56f313a8b1e0eecd77395188e8c553d8b5fd752183e593266b1970d6686bb24f09e84e2972c8ad57b56b11dd03d21aa6a5a2d5b49b071b3a27ac083428922adb1433e965abbcce161323c035f358b351d22220f1862f6b8412337a3448646175a604b11314eceb8d376ec58d1680540b1ae17ab8d1b833b000bd6b69ee3e22ede09e8ee18dbec987d8250557f4a25a6b32f772b2850b98154583f3367c7a76e7140319474bf5c1a0433357ed39b1ee2b1feea2f7edd1ca6db767a84c8ba65a5330c492e96e07a04347bdb215f1174785e907ac5f02b6810543ace142122d22af90ddd2d5a9c01bad59adf283261a451e818e4d080633eced017a5139475f60cad14a07f166929b900500408204b67524cf19b6a07868a08ce4e8ed3dc54133312a72cb361cc5c0eeeea9ec34b2043dd5980c7f91363a9d99f80a61d09617f230e043c3f061b5d269ad6c729d6f7b92bd49902444cabda5947b6f29a50cfe046504fb033580017fb21045099da240284640204961911bc22345200a36c4b4301543051f24522e9848a9882106344215fa4c21b304dc697261e199483803cf462f7a28e15842238550b8038cd80bf00c13176498ac705591016f74919a0a8d9ea090248c9110871218c40834a14718c3e11a4303744188058c3087172a96b800c72c5911ba20134ee9529ba27a522309c8831118945c608cc02f3dc21b3858a0712454c2005dbc4841898b1e94ac0842263cea129a30054a799224090c23a00fa5908751f8410f57181ce0121aa091500b305c542f4229512e422a512bc014c88021746132c5f32454214958c30838a4043619852bf4089fe0008368b8cc08854a30c0192f9292b8c892640578039970459710680a9cf2c44c12d71623534a2f1881567ad070842d68844242200e18ae322f5c5d90b878816405d8c33119b009c75d421b57c22f51c0a225e00a4f21084b58905404096be8d1c11e477274f2e6a6da2335bafdad5a7b73534712f703543dd1ba272510b8a71d62db939298ad12f3b253d5c2ebb306c502ff686ae242375de1f99abe84e0813c3c5ce2a1087c49d68d4e522e38a7a9d9c6c530043eb9279f109e62c49e5ef8a063c2b1d361afa9491729ace94ad3176badddb858ade94cd775170f79409ece3967ef73a2391571a7252729a729168bc5e29c85531930fb50588c2e561b709b001f04c36d7c227a7ae18b7a3c6d938f164d46b1305b930e2f1338242b5cd210210ee90987444545380617117323420069e8c8c7eb84d00b9702fe6002eec004c53115e9ab3e6b4c74abb5a61a33faac35f9741237c5faac3195a9317d619aca1d37f96832fa689dd20e5a49eda9ca9397a72a27df0be825abd5d4546d5b8d288665c4d04c79a32a09ea060d54144c25ad148c946a20f9800c01d151036283062a7fc0a6a657b1b6b444f14375201fbdbf470ebed7fb7fd6f40f1567769b29419d12d05de3dd0f3535357fb7cfb0d9c52a82d4e4091d92d9c69c6edcec0edfacdf0b054e5f3e03f8660d25b17d3062a3a02585534bdef47e815a5299d9678d0a1abe595fe9c7a7a634f4ac263ec7d78b9b1a310473032ee0042253c0104c0dae497e001962d2e3051b1e2ced90c980c0ec0519ca2265acaafcb0cd86ca2ce5910725026649a504b31ee8ce48ab80994740cc66134a837a31615ed9b2628b97f206cea7dca19c4cf0066c2822b392e32788141d92588c104441e052ce224cca086632c29413cc521cf9525e29271489193d53b666744812520ba1a01f31caca80991033627cd0b2294839a1e4c844c81440cb1290fee05086b8a16c51f2d90ca9a43a0c10012b6500662266f3c945c9533e600665a352ce27139851aa16ca29a6dc515e9d183d847a7634c120825091313c327828954a9bd994ea8187313ad49652e0910392161732b09434dc6c01b3f9c06ce64075904d250098d127f4832822538b530ed388862717680c4cf3480886726654862e1b6e94a2036653660f419c783da6ca04cc58002a47cc6a98414352da286b6638ca5965d63280c3860a3346b3a424222f846a5471a12f547022801965316934ca44a2525a296f664c10cce8ec92426943f6a566a48528a615945890d180d96c868171c7d029da538685843a7d59a11ce1efe56e77efbdf7de7befdd9290905ae47c912652d12cc890d24c8943544980d95209a49c640650eb6816d86c62995129f30c2d9a543409cc34a2a48226d1b3590605252509e537932a97941298650a6ca4d0c1828f274382b6a3242b65d00166530a8fa50f19d81194b6d9258e4a55a22a1211d1e7308a497aa5d771637db5ce4e5ce69efbfb147bba739fb1be6376aa44a2b8b46550a5c03ba174fafb57fb52b0ef272b15af36fb33c0134abfbf1aab5495eadb67a7ece4795e86eaf9de7bb39385204a6b6f59ff5841f76d5270d6061eb75fb643f37d5ece39e32fe7fd61bd7baa57b7ac538ee33c4c72dcc8715c1e73bcc7cf7123b9751cb7b90d54f377d0b96a39ae6e1fceeeddb365bd7b8ce2d2ead3d10d72ad61383b6e0e96476bbfeed811f6c735b676bae5ea733b4649704f77f7e4966d9cd673acd6b5360c1fb45ca5ff0257addff8658936fbbba569fdf3b8ae638ee3388ec379dc3ddc8ed5df25ec8aff07bbd493fd6c354335c8fe6ccf49fe93eb48f7def9b9eede5a6badd4db9bb3208fbb8786a0334c27ed5110e7b9c6fa15c59b8f6aac77fb49dcf5eea124e8eed9b2ddb3b968008468d9e9bab3be569a96252d3f3d0b952cb42c61fad7bdafb2ae7fffc494529a8329e52a856dbd83cd2ee3bae7485c657d1b7330a614d313e2d6b99a6e1f4ffd15a67fb2ded3e1a0831adb2a593d58cefd0efa5657ff7dd5fb1aa324ea7bd5c77bba1a73bcbf34b58792c04fb7d6d3b446b256191fb7b17af78478c1a59d566047dc5810f6cb16d4df30a8318a71ed5ec3f6c661fd366a5647c3b74a9f7f1ba77e0e1d49ea6d0c74af5f0117b7ca32d1555affbceb791eaeaf298cfb15acfb12b6d61e4a82b3a1e409f1824d87e38d05617fffb423c071137bcef6dedfedf1fe6deb7b84e0ded811968bdd7bf284d879d9fb0aac16fbd643497823994d7455d6e9edc6da434370522d25b2173c4256f8324254d4160569a96f484c234c1dcd8d524a29a594523a371a1c2654d566f691a41adc6e9fea6bf1ad19e371daccab2dccf63e6b5339fae76d1379e3d86efff326ad765bd9b1ebf21ae21bc594d4501f1de9c495b3dbd349d2911b3205e3046badb561aa04a6a99284a910c018f8990ed6ac40b18204856fd66cf4f5c3c99b7ee300064040bc6140cd4a906efbac5901d26fd0d1c99b1d31803acc0073c088a17471b112820e2b2990c034c9824394302a2a8c6204a42581456e782a0a673668b400ca8811eef884555c803aaaa8102226744285c394284bc0184d43888425188155353899c1a56508144185904809210c5444905161f10219d087cb5395b026e5c113d843911970c8e203dc82c3e505069718193cfc80204c1921f4600a085baac0f410ca300596e0043ce1888ca5d0ca102036804234842ed4088b84c02b283c91320b9ba4ec409d015bf80256c112fa8012d290448a072448600b1a086347d82343100b5e8042a2174c5178402a513c5811c6d5831627292117252017a625252541c02c3c88aeb8d025855046821228b1235056805ac68036b6844954c21f4c40224e36e410f61012d503e471039cbde03a13140e99102679d203b278f2c108658c74c9c14a8e2658a0c2143ac8500369f8017e90838a4678c20a3f27b8be38914171d2229c6126d4c10b58e60ad213282420093b84558ec2214040201d346208b5cc2861802c943b9a84108ed02445dd67a12c948d2ae21c143f7c8dcd6b86cc6d5911e7a0f8e16b6c70700a8a1fbec666f76c1f1a5fe2e0d38470daeee1b49f4e561aa7d12aedfb68a227f2dd23d523467d3a1d331d41ce6fe8ffa8bea37ed180b1d85f39784e7eeea3453e288d0aa9223a2274a98af8eedbb747f6c812b95fa2d2105bcff44bd88ed6a836431f1daa226a50a2d78dccd1ee5f3b38fed9493107a79d14fb07ae93b4939a47cb7af758ca749216d1a32a82a443bd876eff83cd52b7afa3db59c3e2a3e8270d41ea1d0e038ec66a91a643b61671d7f34612c525391db223ec883b985dd22604b93690cbb57d38972be6da402ed78eb95cae2dabb177d5d88b2d1a3e922dd787cebff5b845b3f1ddb37b76cf8663e4e874d6678d4bd0f67b6cf1fd9cefe73f3964f7bbe37cdf9d7fdf47513be65df63aeeeafd9bb75abcd5e25fc2f2fdb09c15a769b59e73167fd66eb5be44a5593d6fb1589bc5baad1f494a43c3da1b979fffac3423c96f6b243ba04343c37fe3fb599bf7f7577bdca6bee0ebde48769f21a88fefd871618238df3d9cf3df31cef98e71ceb7acc6f88bacd5e61f306b358222efbb67f7ec9edd13748f74a1ea07e8b3d64548ff58355b6b6d0e797ffb0e3ae5f6c871acd7ac8dc9add3cee3d9cd626d16ab84ddded3cd1af7d6fbb5c71a35b09d4576d0732806dfef2f51598fa276edb17ed4ab518ff7572bd648f26e47ec71c47ad4f63f98e6a121bc71ab367824ef28da51767304e91dbda37ff48e96e998d6f57710ddd95bbb7eb7b6766d5de98ee611394dc554f6b33657fb75dbaf3647030e743afe6fa39fe9e74c3fe7703f3baddede464bb7dc6d39ea0ae8b3b6c5878b2c7349b1052a67149f9f3c21b2727dcd9f45f3dbc6c9a923493dbd1a69f4d65aefd7b5d64a434353697e454333927c64adead6df88e276af8a3cff08d231bda3633a1644e21c24c3746715249361ae619aaf56596bbaa3b5e6d13c9a47f304f1da8d21daa6fd8e6e55e31dcbd18003ee31b9bb9fe4d6515492daa7f2e90be8b3a6456a0b0baaa8fed98da9887403f459a39aa141d6e3fdabffd1b756fef5b6feba3e3f08f6fcf8438d9fe641d8ac205cb059471034e309b1f39144713bf64614b7dfefb3b7c71362bf1f0ea9b3bde7593c76dd78c1d7396b8978bd433cadbd3b747fc5a3793ccfd3b19eefbd57f304b5280058ac28f571c393bd1b4d7972ce34d63bcad3c5dbc95076030eaa08ef5fccfb770622b739e76c75ced6deacc71cbbca4e9444fe8b1ffcd548d6ca5d8ee32e776dce5068bdf729f53e335112f4bd1c756b7defbb7b01ee73cd50bdbbf7e7f53cf27a97de4b4fe8a5efcbc082a8742473ade14862d7d8aa99e966a89ba1bad7ca4e34844714d2488d24e65ef7c94ac5a5ee2b1ca7a6d9c9f33c6fa77fd65a9b9d3253bfd4fb6f2e91baef491534d649593b6db5b06abbae5a6b3b6cabacdad8aed6f9d7832ae20a112c4053586257a268af241d12da0f75e1fb0eb6f3147cffc379deb8655c0445b54605613fcfa83640f4a7072723d035026c0337d262441dd6672d4becdb1b567bdd7bd4b16ab34d09ec530af4c1686cc7072759226b4ef0f773ce7befc7997defe7f673bfc7d57728fab7dafad3e91face271ab41db8b075e6778ada06875d7759ee73dcef739dc7b283af6aed5e9187642f76b3b4e6fdb564154a7075e66388963b05f6b156b6c10b091b97bf4378c1469673d857118ceecfcebaec0dae7a37dbeea7ed53def4ad4eff54aecdf587b6888fc1456c27a79bc1d076f2c12fec0ab8a93367d83c2812294f17bd8ea3f132eac9e05ebea3681b5d68f33bb1e21d89fa3ffbe1e757a859128ba47ebe79dd0d5859da760b55510f5ad0c91575995497db5c662b158a73e36a0b1251642f48e8ee9c84c196ac747e79c73ce39a7884ae7a4242a9dacd9e99c744e4aabbeaaa02a59ad2a45bfef95a1ba8f3f4e9bf838fff49d93f41ee3dc3167ccc116787fefa81f775c17033045e4b717b675b18a17cc2ee2d7f7fe47bb91ccf11eb39af0593333d4f17b667e3eeb3d89e9c6c1ef795cc77382b9755c4570a0ceef784e30abcd9cb3f3beb50206dbac935212b976bb2f981c0416d05cfb67c184d1eec16aff300568f7fec3e0f330dd16d014293c0beae371f37e7cb3d2b7d65a6be7dce61c611ad833df2b89e379d36fec8857115e9f1b2b0c84b5d6d26cd537eb98a13e6b6272f43e6b62807eab9f53e96b89d79f2b445114c5a8283ba71d5f4a28c6fceb8949eb946fd65a98a23e6b61866a60cad4c4c46a61ae68adb57662b7096cb558c2e20c3391f3785fe7d75ef7288975cfb0ab84db3840ac61c21cf5af6a917e1d9262c96a8f02af249d4ef798022c62703fff7761dd636f7e86755df7dd08e2c0e9a8abcdc4506a607c6a5f9e767a66ca4e46dfacf938383d8a67cf39bf681c8fd0f5bd8d76fc2f1ac7db575c39ae6fe0f6ef6fdd6f18e6e9178dffe3dfa84859a002dbb6c0ecdce3efe8ac2bced6babaef05a87bf1e9db6b11ff772bad2b7b7f8e1bbe71f2596bdf72db04255174dc7d095ba25e92cbe1468be59bf5a6a060cb9f33f377a446912fd5e91d6cc31a669b325476f256ffad6038b3af5effdc1818b76fb55aadbe5b7df7abf175fae7e9f40c3b21763cee0a83e97cb48aa9304c73ce8f337b1e21d8f26f9f379dcec148ddb97e75fa859dd0bdd3e92815431493f9c42ca7639c25b2bf6df6c2b426f1a77734cfd08c6a637f5e3c38d65cf3681e1e445d8cef876edb0677cbaacdbddbc65dce8218c96dfbb923098a24fd49c1ed4943d40a2377ac6fdf6d76f7d0105bcdd1b9afe368491dcbc1b87b6c0735f0fa1384375ac743ea0768d431034dc811912526a8970e4e69344ee3348ec3fbfb34937ea8548cd9535247b5011403170000280c0806c462490cc520986ee60314800b73a63e6442105045711c05510c03310883300cc2200c0300020030042144b8f6020b8abc50151a2d81e117782c33678ce177ac405fa1dd4f44863046ba4a4214223cb60dbea442dddcc68e56e3426e7459ad0e3a7c56d7125705f2089c53b7aceb185518a9100e40a9179efebd876754969999f36abea163949c46e1a70ce5dca9d92afa38efb0ca63cb42656dd9a6837c0a9bdb1997a44f209df2dea5d155d8e67b9b31b6e6b26e9242bfe90af69c3a9ebd3ea2b7e85a95c102669b6d46169c031a960f1b6bd10dae2f7c3e0ca5a66d2ad8e2b01c92b074eba4dc49f9fcc524d5bbd60a03bb903dbbd4eb17dd73596bfb055c9b472301fa4ae28fdc47e1935ab749376236fcc2a083907cde65a51104ca2a92102a153860193a74cc91005bd412463d1f5a9c21d9170de72ffd6c484be55dc1c2030c509746bbd30563084aea13c3be47842f62fe22932fd06fab41928f22e162da6f454e4c43528411c70a7ed136d7c3a55a4c1fe781539cd807e1497121051811e9027ea13c9c034911afba77d9d8613626519d6055096fcb8904b9ab695c24b485d589604673bd5f95365155e435ef573b65d82b2bcc3f9bc103e6fc3394258669fa24187192d50543b1f750a4f967f4a6514dbcc797f4fc424c63517664b3fa28f0aea90a022e74125630cbe4f876ddedd393c024f043bf49012d0694112db30e0c15dd963ec54e7292f95205171597517003966d935de30bc6e0b6220f7971e7b48a2b8850834fe99768a6b1e9eb8facea425e734143d92d158d35aa0f3e69ff409ec348be365b59166b1f70a2aa30d23f144978278a7f5719feb19f5d9ecddd7dc72f5ff1d8beb4a413e3f31f7269cd5069b154fb281bfa5796da62aa8c50b0786347433caa22ae8371ef1dc228a4a4cb328ab56914a26122db514180397be68f6e5c8d7e0c1168cf31321fca56c9ca72b22326ac91b75e1eac1dbb43a9b03bc7ef880004372fc224ae813700678d5ba9d9b37815bc2c23dd314d90cb8140c4530bf2b2326db5e5cc68e3bbd979e260bd6d4db943d7d615b32a58cade5dd5d9d0e8db014bc10cd57c87f1cc31a300203573558d84231b2a09a339a8a530a460e7c0cfd64e096945f5299fccdc9a8349eaf49ded73d8b20a75967539b967a802ae189e119aef1e7a5eda655d778df0921044bafe999a2c1c2b5368a4ee775eab123130d0d384f6d8835c12da512b4b3fe356a9f12b4e91069e177ba51fd8269a4129344379b77d26f3282006374da336f903dac1ba7809a79f1264206df0783b48a335595af0e320eba4ecbeb74d70dbd27bdaa4bebb05138f25b3b07203b7f631e0fef884d3810858bfafe1b825ef2175cb12e51c107cb1c8c58a98a902adfe73bb2559b262158c344b1ab7daf59821d6b1f3ff083202f5445d2240de2fadb257fe3be80132abbce6d670ab76a31d521b6720e70ff9dff198812f463db60e5a32d7b47d73fc41a31694aef044c58a66f120d12408e2a3daaff79bac4bda907fafc74c7c437970511b98ad9bfd955ff5b9fe20cbae45726addc2f200ade52bca05967ae6c433c8ebe61f5f5d4bb8763bec85dee3a22461c0b39538b466b357e7750e7458a611a5f775091584ae2ab1af04ac4925631dbe7c60b88588c0cf88e573da8e52b8bc3ad7efd58d7d34cdfde87d00c301a81922508c8935c734edad8e71d5f16a0d944f9a5729c909bb6c33433d557832eb125b9b6da52e593c8918242ddef2c5659826596a658dbc0458b95e26803dc55bda6490cb099fea80b7103d18b90b95518749e4fc8e4cd727aa5e1e80363a0bd5aec2a8c45b88cc611510ba063a119262425afa4bd361c50289519fba39f10d187096a6299cc348cf986ba3af0118dd88b74255213e781184243869d082b6b0f5604016989370a7cbb0c1c9802b82c983c0c524de61da98edf503dd4b38e3a8e9d6c9305171f956668a56949dbc0c9269ef8ab96d27c3da93bb6a91aa1de74e7266d3a4969edf07dd03b771ba71426633fe7710204761eb5a9070b9a9dabe2640e6a280836179b94952b6ae94d1daa28ba534d4b98db33fbaaab222341c4a312c88aca6d024786ec6f616e3a51b510e269b47371e2fe86f2c55db221d3d5af5ece8e47ae1128bfa0166059c641f5b842d58bfb99238d9ec2a22eb44ad07965e97dc56f9e39d0a87d52cdb010b2d370c57825fc792d99fc980b6710a25503d23f35dbca12f9f252b348af9c1617e9d522958c9c1e748ce5906749595a4011b2c04c9754913d3ae70a0be9f9e6f95fbcbb1a3587eee0015b4db8d5047c04f69027fede9babe8843f3c452cd547a0a37a2fb3510f66082f2ccf152c52200ce1e2df031121a050455f4dd9def67f1dcedd7b0b607c881672ff095d1c3e5875cfacc605ecbebbea419e0d5d6244798a304c14ca037c17f363fdb704f589dc1fff9ebc62c886b7a69ffb8f997a63142933fc47f3fb3d456ba5793c8809751a912e51fd3225b482bfe758b6ccb8ff100996666b7863aa5a7299226fedb2e38833872dab86a482e46e025bbab61892b754c4cc732ce7d6af42beb0240f7685d17d816b763247f792273ff506e7fd8a44825821b22f234aca2060e17330e39ba9b2f16fce1bec66867e5dc6981c7795b28445001dc4e951620b8d18ae2c7431725ec41f50e0112e2ba1edcf7fd6d2bd80abea1a6f67ba2296f134e293eb52a476d20bc4e95300606244126e118bea9349fb23aee8aede54e00eb454640f8c7e413cfb35dd5c8e35e461aa2727cee5b195353c49722c0a503021dce68b983e56558af9db0852843d16c770936ab5b63e9d8c87d75f30475f7a1d8a3643cb8061dfac5df6f88cf6c814bddfd770201a001bf98292a6961b04fdbd5b49a13026235b4d48325ea5796129b7161899e06e6c5645ae1009a586d5c525af3c7154bbb7cb9e566a5f4d4241c47affbf1c6dd66d9d7f35cfe6cb3b8c82f600d8e33d9ff4a90f521b6ad99d3c35c2641e9841ad2107f23154219cbcb6fed2219bf30ed7c972d0699aa7b5ae8f867bc0f589831f938465b6c207375ba626ec56ea7a39e121bdb4d10a1692d8eb545833ca6341a135c2783e2352c1175bdcc0547a1cd3674d489fa4ab21251870620cd0526ff1468462cc4f8f870160bff3af519618c09a30226413a7df0c8c57d5891a2f86dfe658fc9194fccfb43c6838414bab546b7f677051da6b5a64d6894cf7f32093f165721a4f0a0f77b6b322b9936fbd97166ac9d2ff7550d2215dc1dc4bb4ccf14ff9bee7e14fa49321c62925d160c89e4b45aaf8d934ba163b641ffa29c8f1b8ddcbeb429304f714760290203195f619818a9807a0ffc4afa225a665054f0d0861a1f3745103f0b1f7d4a9b52d962f01127076209caff14540396a27ceb1ebf701da75657f03026fcfe30829f3a088f9ec2de9a173822fe4e64511a285b22e4f47eb9d8c2dde9382b77656f498e98b32fa9e570b416ead398eea26686040f989a09c9f7a5a03b70e0038ec153ffc632fefa17c6ca79208b8efcc2b01e8295c6c4eca842b88ca7dc2e91ba8c9a4ae6711a7d0e166927775653e3d671a7492f2b6c3d80819e99322bca8385de6f029b227b6a6ca9b007205d30c22cff501bb8d8437e475de03a1a0804a22e1c68649c742cfa6110c93d2c020951b03e15d3e5059eb1c4dac19034c4847f88601cb86efa46fb2d2c65aba9b70dde067329994063ec49efe5f3b72739c6ba720005b8fe825b3f4a2ed96d1a18b48d1fbd176823f57c931b2fc681432dd304bb3279698ab6a3b21c6540594632bfd5d1293217e3374d61596cc4d9066fc38861852d308254a8101dfa786c5444fb028dedd13fe88fe8bf84b7f349aae33caa36c6f6e4575e33768e93598edc8202ae5808b8a53e495a339b503fdb155edbec2e04e2d05cbe1e3869a338d7dda3cb11bffcabd5cf3332eca338683f3b1544143747023b6a2150d8e91cf8650b7401539b6fed1b4b3a71f7a910da1a8f7f42b774d34ee107df0b5d2a9e59ebe0b6f0cdb5f5e58e8bedafd353a5098de5607051ee2e88b7752ec1587f9095d7ee17067f2f8d6d6f75bfc75be3d9d18652253b32f04d5b2ff0829dcaacb82a1d486a295af17416da35ff5f9c6351cb3880359605175cf97085f2ef94944c86ec99dadc036a1432bfd164975218dfae5620448a42fbffd39d7c23f8db4aa4102764f8a55d291a42e77df276050e22c163a7681c8305d1c91436f3e17426bce07d99d03168e92e35afa7b748b1680d22697331900becf28b264f4f9392cb970073d9e4622f7560eb70e1860aa76032a240b2d642de466bbd1f36b4391db0475787888d93d5a690005215e56543c9bb2ed74d0d97748a4c299e2ad3515b00aefb5a74190a9b0c2cc1644fc6fe1305d06f40aeb6f2edb89183e7f13bfef67121294d8bff4690a97cf5140141ea0284480a745a672aae86f3bbaffa8f9f821d2979738417e08961785bccda7641a845a82252f7ed4972ea84c2865cc30c97582a8a58f0d6fc99eb56598760950f6eba95979e110799a31305426c96b3159845f9727c88744ac49793509336a2e459f6ecc92edc705bf0c59a2d52f2ebc8699f1c60cc1ab8c25969355c450a9f59417b65428fb415f15468b2e2f64f41fb842cb5aa506ccda17051a11c5a536062d28bae8e1ebdea4cc9ae6beebc76ee27f503350910834b354b2be3ad8e990152389b25e5a321db28199257869f5aee0309a9709b61c719e25430b72402f97507981f4c271c26a074066eb9306e1239e7b01c470115b559f7568a8cdc250621b0ae7321eb600d35a8e01840a64636219f3f353d907f5d65b544e2d725139bc300354fcc3f4bf229fa0b748c01a9e0a51889bd8b630ee3c0777dd726b1f2f2a908261d5250ae2d60a779c802a54dd986ebc356a7843b6d237ff54e4772ea449859864ee7cdbb70aa508292084a595cd5f48e6d09cd21c7d93379675d3ec9c13b1b02cb1eeea75f9b64d790a2b6e1036ce5d1cb6a763ca709b05be0b4444b494b6fdb47a2e0b08abfa757ee90726499b63415bef3430a2ef62778d20c1a13ed7194219f7d9cc6f0170bbb64d20d3fe3b1c82da3f031d4583690f1a4fcc8277caeab3feb64e530674e545fd2602b9d71b1b286e9c763faaeca0604f3f23845ee8981b8183beb9dff44efdd35e20cedd48e4246a60979e99628386062214a7e16ce2168ed3e38e340cf4ae784aeb50dcf0c738dd6800fcbf86463c1d995ec812785688ecfe589b087815ea733038e2077f0e820aff279bb470e636d76a44e4e9e195f6a0def0855023b56b6e5b50b7cbd8586665cb6d166dd23128ea2e0693433b8a9d00bd590829fa219ae1bb188ca30c36b6d9ceb91243a91da5508d80e6d42527c40e1c1ac0958761256100182c233fa50332601b4780619bf8e05bdbddc257404f40881788e297b1dc1781ae3842128eb12c84bd9f4e665c7b1fcaf29d297ac8ede65def6abeb5c01c0cb41190b9476824cb8871757215c44b99372e8d7a89ff45bf8062626d1b2cc650aca745f1c13e405415c5d23553c289eec4e188cc98a97a7fb901db592945a5a04d80a0239e0a015e8a60d807341bcf26698e73a6c1d602f82e998c50055802f9fb10beeb11465e9a54feed52e0984fa2e526db9076194cf3f96b1743ffe526069d5de25cca9be24f2fc519262a9111cc8864f7eafd06c5179abee7decc32c54fded320e042728ed5814aca5013f7ce93ec80db8634fb678378059bd01cbaf5e397e320017b8937f524fe6a7629bdd2d8047bedfc06d6a25febda842bb8bf8abef866cd902164399f4e97f2b9d12532bf66e6d4428e3ac44d5cd10203118347d7c745f8c2d34dd86573bff823d2f5530c4951e57abf80c007af367b27b5885f3542faafd45047b1a46d433f63f60c72b6f7c414537141879fcf4590bc3ac98470cf79be41da1a6dd6bd12686e8e611ccdd2bb1ffa07b64102377584e467174c7801eb84f816a11a5cc443d968ee9581e8c5cf398d0ef94183a8bdb30cb0b1f50827de3832005a347ba29c1833d92d4aa8ca8c3ce840a3887a6ad737a5dadad5eb91f7e1d9e39aa24d5a389a39c2e0c7e92331109bfde0b80c9ed7e1bcef27a36e304636bc04ef8196946f1afc3cfa810268558625ecfa08dc754fbfe9166a05f7f522399d362e6288bc38752990d729b512547a6cac1d79bcfb6b8a067756acdb20468ce037f7d62dd7f4583bcb4cab629e7cc1239d4b44945d9cabc10e3befb07b4f4f589abd66c6d23b8c043365cfae3f41ef8deafe01520e4def7b4fdefd94f389db0238be84da70de1928e133a9a5a313b8e63f8fcaaedae4c740536c330e5c3ff7b3f396e244923f258eacb05d9d96aef92840d40bd91415c24bc57485c58a1b06a05e465c06db1125de2158fc161f45d221ce2377835179fef4a67c89b14795a20135e6eb480a992856c4bfbea4d628a23f882f44e0e7b9f00cbdd75ee76013c26de6e76deb786fc0ce0e41d3563c3774c5b467ee28ad177900dad5b51c28eee6b95b4e59c82c4e277e9d583d95ada014acb457d583b9774ad14467bfc815507dce8d9f962c70bc886b8dc19ad37e65595dc41d2163438561a23dafea11defed0eb5a175bb6a802d9c3594378a27b31d12432caa935e6b63a3860ad5d3233aaf358c315875b2f1a91a69986cc0e9fca4d70e6004b9414e125eecf17c0dac62ae11177a6a7241a8729303d8fe5c82a237a4b0896161f556d71ab3cb47bc80c256c7541a00446eb5dfc47ffecb8a3165025c48b45c7e90d47c3ba45f72a1ac1cb3d3766bcc04ac664804358a3985da7b31a94013c8bcefa1ea9e84162bc97e255474f590d53b6e124a636bcf9ce1dd854838cfe814bb85ba274076f5e689f7dc3a0c28d00c5790daf38f8bb7f573d3975badffc96fb337aee1226a2e647d6146989cddfd38c5497a6194c7e08d47c47a4afac09df21d360cae826a51fff7f9603dcee8b9c4c762d472894559213c17f9ae9562b4944cf4bbd63e389b6a4db812fd19ea99faa242c09cab5cc9ca8e53c4eec08a08bb417994041a61945f8adf7f898e4dd660b49946197db34286900bfa5afdfb420f92980193e02f0f0556d17e74cd8ac7273f8d4381870b9eacd5d78f555601492e382604b6d69d3293ad3342866f6ba5ce9d08265a0c5aa4d1431e1d5e35dc4617a99ebee098b246694a45e578cd92b057a579d3f4a7eda8914e6ed06473c42bd2125a3ca12374790fb8cf85778e2a8ced986f10e8eb2e2329ef5cfee0b272e45d12a385d6e0522e0036906d229d47980fdcacf5574374394b53e8d0d9aac3369fd1b5016aa1faad965cd215fb0a21dd22ecdd4bb792e37b8fb66aa4534497d0d7860f0b507cfbbb0e8d03698047b828ef8c2b9aa20234563e1fb964ebcdea17617a207e662566dd10eeef3bc3f85dd9a57be14f7d7304317fa77f16fb5fce7f65da309c014e69352ea8e8411a73a2357bd38c2e0ec0ea0861055292a1a7c029eb691411c2f308413cbd952bc0813c51fb539a88951b758cf3cb35b4ce5097989a9e449c2713f0b7de2ea4378964b71fa12dd4411f2a7080382ab79918268a6440adc62080a596d7580364445fc07a23208241418e27e938298d05e1fa52a14bc095bc000da92400066461ba28e8bc35149c5502f82ac78851f2128752f51571631796a3c52ce22080e47795e8f0621c84bd2b1ef9de9bcd8a5a72c75cc9ab57ce2bb97cac98863f5f827c310b5bad3a6cf73673f474aa2290f19ebfe047b49ad4e6e41857a68536a28ac0bad45c40465bf9cb636df2454f5c7bae31111c7db524db07716e6091289476e5251be3a96de35390e56866c59f84f28085c157301e51797d61bf3dc9ec6d213b8e4819ff6446917c1791db3d6de500d4f49f2ba16dd18159ed0a18a544352cdb71c9571375ad72cba8a97e6e7e7002dbfb786cde9ce53da08e0a257ec3c8576845c1bbbce280ce1e82c426ae93799b7a5e9fdf396c5b03a748dff8ae18be182470f196cd7a0d76c3fa325a068ad34a0effdbb3a96757487c8c0cbd2d1904e20f34d0bc124abbca5e849441ebb55ae5acf4f4e0333270ddc890f5c7aba475d01fa18fdaf1ec40c80525af1227045f5496466257d655578dbffd40f0a1e26a70a6b122df5183d5d4fb44ca00d2ba46b1deb8708e155a3de982b5537e7753c3eeb5d60426ae0e8667452c8322448fbf8b22eba443f40e10b93bce0d47107f728eb8f11084d75fd80f4252bafdabda6fe8f8014493b2bc430d0e235d42feb5c3bfd29895a3a09717ecb635be4be5350601f6a23a56ca12a0b6393c0ef2dc7002ac91abce37908678dfba715c8e66cf015bc7e403f6077d33b0c02b239a21d08511722a3fceb4e7116e3b0dbef5df3d06ad3762c3ca356f48e1fa08c7555f3fc97ff7edc9ee9258a61681a8aeb5a1ccbd53ef56aec255d5babdafc3419ad0af96eceef5d12230f55504b142d516d80b0b2b9d44774e600aa79d57592ed31bce05f84e501d655ef58bfcedaa84f43595ecd3104c0b4fba7c1caa9b5cb6086aaeb4c6608d8b5a94f48bad80421972552da4a363594a25ebaa318babab2d615951f9d3a124eb147dfbc122226bce7e1f0d2232f016d70970998a974b505663100b8a4666ffc95e3f27d96853d447e2c36088be6b8e3eb24af5e606cc5203e02df03a4175c9c5a727e0536f291cb08deb81d3a5339a53b89f10357b4450ea9a958a8e263c4d3a55a6745b678981c7f8e94153b43973c788daea292b343df51e624a376e461a5b2ff1cba684ce3ccd05e843f0afd7d65a8cd00c04b5dae43e0666f7641496ae7ba4ea7ce4762cfcb53363a358c46fdff1730f98a5062c29769002aa90f6a6c18a2113fb526b059c6f0948485606ef9c55f10ba843113ace5f738fbea188d62a40b694a357353117559b2d93b5ca62c26bae59e9a939c83bcfe9cd82a391f285312ea8aa696705a9f5688e8809effc833c033098e90153a81220583fab7d98349dccc109306111edc14fa71535a03c5116a0a646453772c6014afa1d6ddc1ca7de7b57295689c05370096c2b0359b7483d02bbc5b3657f63e8f1190a469102028309ac1ca1d4f1390ad3881bd418daf620071b4f4a21193c1fa938cf095566960f42e8031b27c061f1023332a1d2a10545212598db06c36a26ed454b627ce97e4818ab70631cc8ac58aa63d43b999938e6216d6527440e7d1b8f8e04ee71f4a8f4dab94e5986df67955c0980dfcca38d749a3afd91c156fd3ad03cabeb58dfb7f81c63472048a98f6ffb99ccddc9d5c4171c89d19543546966a71ddd85265a19754a909a823d3b07cf12b0bc43738fce8706bdbc106d91510a30e6177182d8888bd94e003c43ff9a7e15cdc106c9dc6e867378b1acdae8187a576a64870c62b73086abedd86f960319adc33703d90729425e837e6cdaff7eb72c7605200f30275676882083bba677f71d90037045db2c00aad29d137addccdc09c9c8509c11a7dcb9498f73f822a9aa4de489e1dfd7977d1b4da43cf13db32e8099f7216afba4bf273d5cde6d4933fd140360aa71c0842b2442b82dc5e14227acd294275e21d7294f2c472265e55d515b50ae6954692c379e6850948010a81f5f834e0e2c425984d595e677a296207ebad7f345ce1826aab2a914c16fee4f1a981cef8dc66a44e5ba75d4015eb948161e829032f1b64421c653d859526535e34f4870a86495d5f43e5657a7734ebc2a001268354750c64f7e896e81e3875ba374633ca15d0cbe2c7a1215970531705e713e4f5a446e812b085d460974d2113b2a175bc6e328cc3e0c3cd4b520e382ea55202dbbcc55060239ba7d8d4a251e084289982510ee6a61e82ce3892722487155ae1c12d29a8858edd9d32696700098430c03da2b19bb0218eda2401a5e8b1e902cc5925776c5fb130e7c9452646353b785a17500b8d466aa10ad05c0d35acb9868dff702142d19d1c63113c7246422a088d3bea7c110cb373a34442bbe2f5795380b4ae1fe010736226506f0bdf3d55b86c5343dea9e109a40eb8642d8de0ad7d06161344ad3572dc04e69f8beb2b2ff3e54e79894d430cdc1ff1be6742a658bbe89946aa079379a3e6b6bd54e3fcaa0f99a13a7a3e611cbc557a78f0deefc17ee347d297e5ea26334ec19ce66acafd4b9b006af91f2c305a82e1a678ba18c8074f0a4a88090d4487ce787f133f748413e4653031588ef1c11470426024c62565078161bfb9cee5bde5f788ad060894ca7deb5146ad19a37870a3ad96bc61951659dc65dccc68265d6783a21fef14c5f4886afaecbd77767983d27a3ea2902e34ee2a682daa95420273172568612f454d42715822fd750e99828a6906d229a78a63088100dba9168253903ca417beb2362a4adeaaf3b22be8bf70eeb3085100e37f28c80a4068fd0b4d55b7e643edc059e287d9d70c2301c089ebc1a419fd8b83f6d5766eed709fb67ae2ef9e371c4f98ce7edc37b2a0b73c22a9c3a04c8be849a4745d63e4b5d57789b167274b136e3829137a87a5bf0dcedcf5db38557ed7382823aa9469807d9bdc901151d5df93a7c4ae81dc40723bf8f4f2715642ae986a29fd8efcb1f5caeb34cec4652a3909ea323299457a754743054d1a0d372b3d053795cb771e9130e48b084248086fcb9e3071c8869b40e8ce4c1b18f1f58aba0104f4d5b63eaa941631172f317ad47bd073f205af975bd07c55140d4e007070a5757d422370240536b46ffe1cf5d747939a95b1f6c2e54f19321a37321e7dfaba12ef31a3d1f4ca5d2c398068aeb58b2857498f0056ccd05882ba92318698c43443953d405ad2536683c2a226e07a440bfae4c829bc165a4a9eb708b4ab8086a461082da97bea694e690e771ae27597aa34efb92ec5371be862f985829c4863be069f5f276b9c5ffbb70582c5eb751561620b51c712e89f000a0838cce228f8980c7b33827b477c782e5fd54a7f19f85311122ccf0a5d9f5cc69f841fe914d16cb260244bd89d0d0c183783d378ca515a73ec0e98f396dcda49ae6e146286050ec50b10679234cf5f7394976d66488a8dc11297660a28e1d98dce2a147679220af0c40043c5495d6035475c7cd6f0e5a756c05155e4295c08856343acd3ad3e5904414e94f5da957c813a8d3ea603ec8e161c4a64537dab78cbd638a2905647ecb196809467a645048db0893c09bf6bd362e30ec6a2f86076f7475ca484154e6bb5c7778434a7b6b5158d05ac2b2aa2e2d001b95781089f336754f410fbcba881626faec771003371c3404cfe83e03854107190bdecf95190283aef0b20db31d851aef224b9443ed743c5dbc7b47bc1d92f64242aa4bde2412639898399e2e7e97236b07f90e720e4326a1375bea80065eda8021c706bd2ac8f9251556a2c99dbc6612b72f48fbeee5af8ba8c74905d0c5131ae78ef5b1ece3476384487b122ea311316b1a5a913dfe1bbad4962afbe0faa214b264f916c9b3d93fe3cb9915a40809ebde7308c419ebaa6c6324d60df919eebeba2781c20f6238393dc325acab59fdc0acf548977dc12f0dee889238405704cc6e60ecce513a4b1c62ce545b1e3d6a74ece6d1718be03018dff0af16a45e9e74abd7949210ca4e9f97c8b1544f67084d0ce121b2397a83e7d8fd89d14c57cad810c3265fca894a4dc1d067fad1b3bbfc7b9cff2dbf2234674642735671e7e81d6d61f9a281c297e18d8d8862f20d9c4cc36017d74257768f1a8c03499b50b0bce7ce60059decb182655d122140e84c36a41fe4062ca0cc663188c278aa48488596fb8e9c4368ee5180414216e95b25b8497d0c0e756b28ea30b9c5069325cc53977839aaf0506d1076ff93dbe6df3461763a38c196c31b350f061bb1832e6ee17a2c0e405b850b4559157ce0d3251a12d0badd1f292a3df5d3a567cd211311dbc3fe76e1d1255006374f2c16431ba3a5da208eee8b60db36a67b5da2136721d2b550b394d60094d6a6147d5bf03d942f6a79d739338a90179aa08e347e13bc30106c0cf70efd6f81a3ca85ed52135fcf2c0c9a34c8c54b7d5de2578d0bd9b5127fd669e07003a393ca0736c323416542dd66fc4fc812d64bf6299a5e24a8a3269ba0e7227f4f9b74edd313d555fecd7d25685667c36bf9f57a8b93abf8f7bdba70945d1b0b91eb706c3670481391589c22dd135e47709a083d189f1c681dd0b3b879537d95e41c756c50b52c717291d3c9d7ccc9182f6d7a4c986b5cfee10fdbb17797dab1b0307a9269e07006e39bc40d0953cc874d406798e7c37294e38ae6b8031f5f94060c1bdbc416b8dbf906c825fcb90b9fad51729bc8ea6f4f3b1ffd36199c79fd1ca8bbe45f7b01396c43cabedd7886f88ae999d3cb59f395d2ca78afade628aacc5077e56701ee176b5be390749f21df4a7a00a45aa1eef1a8964cd06a05ab3646d3db2480c3629c9fdc9862b5fc6d820b8fd66f1b79da92248a75f28393cde152e5e1e461da5bf1cc60ca5873c6b988391a2b2e6d5b1a73eee641c5ca2c5394bf265047551ba22fa76c5511f86026b696e21ce1af1f5658b023bbf5564e0e0ab62e6cc63dd7c928a92e3cf11f847aaf1519b7f37d429d49e6601b7f7491786be267c02fa19d62fe955cb7a6f57065a04defe4e773665c603096a9bbdb682db2a1422cfac9b190aca896db90e8b9cdcac64a5701c92c3ba6dc43e08dc9b6265c6b8308e21bd587848e054d40704ca20bf4a60b68fd45687d45f92140b4995823cd9f840c63bbaa4afd543206b4380d3719b17e6bff0248077f1bdc68e6ccc7237400682ced8d2d6ed5e51d14b0d2a78578140da9545ffca1bc2d208301b56bb6f78680314305f982a1d0e81d872cd43ffb94b6b80fef11d0530588ebaaaf7feb44dc8ff202e9b951c72b9fb621a19d1bcb1f18907dba2638ee510d2410b64907ac7d2021ededfffb29442d6c568b1705f65399d0430e363e8d0bbfcbb76fba947e3c558dea0a8490eb8592046c2f9ef6bd0f4bad515581a9318620e41a1f9d5a503d09b909c35b10395d5cbf20e9a4732189246be7e49fd25afa147ff31663acf4a6ecca2f822fc5130a09e8e9f0a72f95ae5692ef89244f286ddbebd4e992418f949ed5490df1ea94e9c35a190f8192cca1a0b43e3194edc10c71310d3948c53cdd956a3c1f2052e3d44494ecf34c05c94d22335bb22d4c1e29a24b1e34290ed074bea474067fdb75d680bfe73400ade1a960310d31ff6111fdac3970d2288817d95f70561558ca5fe97da14cbebb775aa9c45aa97b70187cb9c98d5b483c079a80a538852f508dc181a4e86e7611ecfbd819014b2d55a0f45ad46fd5fa48f9e4355a59acd2df58d079d9dbfc4acac0181af38a2636af34e562bfaa74ecda484504594b5f8341149858b851a5ada1a7475113d0370cf66d3a948acb0dbe63762c972e215fcef4a86b69dc91a2f436663d9b7620aefa8ed98d76f8a208f28bc2d5e6057991cb3067526cd99ed318c4f17600e4566948405d4b3dfd8ef769527fa434d3c5cd0b43ae0a2c6955b056a6139ca8881313454da3125203c72ae2dbe11947fa10e0dad655c0b287707d4cec96cb764c330b0fe6b8010bdb25e8a2629565010a03c40a4294d65eabe86a2e761669336f2fd7ac1556fbcafb9e80f249a4ae479e558b3c4799c5ec83917a9e52f033d2eff1ace00e762785e96a616e27cc21214acfe48ab985006454443435a2544b726849a0a8f8509d8b4fd8990b047df05c1adb29d43657caf0884e041e828f5fabfbee1e390115868f516f8c2d54a8eb042ab62e8de89087f21a8776ce955cd547fd5f4603378585adb443a8ede1b01db5182131fcb9400c8f1baa35912e1765e8cb2fcde639e1f1b507962256cb3cbdfd528af11bfbd1d222bb4267cee4a3dbb346a391bd7582e9984778de907a1cadd63e6e1db22e7ca81873b4eb68eb2f30bba864478297737578ad38be32d52d523ac7d016c2b01af16d083afcff04adeaf4963d8ba6d2a41e7e28b3c9571cdfa28b7aad722bd1371472f4bc8de9f09c30936fcb6127c074d40d9a208bbebf5e5553e4411b5e7f253919a2c6c92576c359fcffd053f3743a94ca79ea103e4a8582503e7aeb404434d2f0a16300b71f8f2255f677351e8cbf128292651946da504aee5fdfa637e10ae2a01ec71159126dc39e4765eb6fdb5b96d30a27debb53b3a4f6d73249f0e9b57bc083ac5069d76201558771625e21578cb55c56432b11654234409dd669682ff98fe67046495edd51304e1a892ef38f039f555b938e7782e72b6284a53b9688311158c018942b325e22c9d5fd637a00e84a5a7d2b3e06eeccf33803b9608d6f7d928f3081b1dfe09aebdc02f6eb8b30b36a919be69535738d1ed698d678f8dc98b5afe5dde2d79e68f5e87cb3387a8672a587b8507a46902babe9b13b0c0611c5df836c38f56011ed99adfb59cbb34f2745da43c92d17a2acb687cf9ac5ab67b6ae715a9e7a360b690f25d7e5a1f5a0e4010591f003a23c48e1f6b4d5827bf8f5d08250f4300511e29f9f3d070b9174880b893c792ee3e15250ad84127561703d4927a50c31e900721abc1e72bc49917437671878231cda6fb883b8587a0edeca08e1b3e361a566f1ddb371578390a2be4779cd02e319ec3420b40371a1ef1901e793e1b1df30e8830a9f0759c3e9d1693940c9da536f8fe6866b26946c484fcb179c5698ceadb84530622d8fec4e1f224a88c6a73da0dbeb1e2c961ec14e03a20ba10f81e2a10081d01017dd3c765b10c4ef811d420921f5400c110df17ae0fe30ba103e539ed026fb109fb8f46cc0f5dce0117bb3d041fe94c8246b776e5a5be3b1477791f250de741f5a1ea084e829e541d0cd42ef195353e1daa3ad611de2a2ce333dae07309e116c164c9e9b0b7e187e50fb70b3ddc5c5338e56c607155d0f522d5f102bbe7b6cb5078fd78f0938e330f5f6d4b41a93990f42181f0618a83c77e1e011a8d37cdf43cdcde2d593b4dd97246b94201ac70bb2bdeb193f0cc9dce2be79360d6b0f16753cd46b2ab29ec12d9a103ebb9e72ed9b872f9f9b03f2e17c0f3ed93da7cdc58717085d885d0f28882208e81edc103910fa10691e0a10d03f7c41840b62c5ce43d0a509220a8e27b97dfb6c5b0d026a20de09e5a96d46ff6041e7e9bb6c0f53218a10500fef10d68580e7ce53839b85a6c7e61e1cc22cbfa7259ac5744fdf6520d0215211e222ca93da4e05ad271ecd22dd43950e74ee0cbc47ca68bfed7c38c5072a07624161619aa667497767f83e2b27903b2f08f7cfdd01ffe087c80281e58359284fd0dbee87c50fa91fa008e24294471a17452d0f75348b94a782bbce834fb6c7bcb906916e888b5c0f4a5d8ef77dfb2d5b5e8beca4bfdb72636f4e549966f1e549ad2baba6e7414341e41fc4dac72c874bf120cfc30542e603fa3f8e44b8090f5121d40db132d783dc798d34d6110f14bd6a67b142f1cf531edf48b9167066b03ec62d5c84bc9108745362911b53096aa05a0541b9a48d50c80be5da0d932e38d2bab3636f0ff48749d9a990102b14c5bdbb78f5a4d64951dbf3709e82f089e389b866d1f0d08d5b11e419952bebc003b2e93c2c20a21f083d1cca838a6ecfad86411f65f59acb33d0a307c466ffc3f207540f451ea020dc3fe484d041a43e2136d87950b1f40cd69a10830be262ef4901a782c113b76611e4a175371ca3a742dc17fa9e3a370b73adc3c02ec2cecd1a58de4a80779d9ec5e322fd96cdc9f9d2378e30307b53a1ef39d35c205e103ac03203400484bc02aac0e15c5f400cca9a0eb6ff0385712166015e7cbe76c3514c399ec51f2d60caed36f76ccc27f333d6fe7e1f64a626be7ee7b8bbd9830f0c2ccd8d3d2073cc007ba6c318ca0b109a3f61a60d7137d5b026622fb950d1112c32696defbdb794524a29a50c5705730503063a8fa1065ea7f3bb287a3b2fdd171bf24c2b82409960f4e7044e52a65ac13badf84a62ee560938f9686cad73d679011c4f3a1d4c16f4a7b8801aa30f6b3d7192425130f69b748ee0b438215a3690cee88cbf2ace088fa72e803e4ba22add3ed68fe74fd1fdc95960cf2349c574fae4bd79def028a4515aebe4d6b13de1943ecd4229b5ff7756562dcaa9b1f9f607caf5d3674964eb330cc73f3bf9f859b856db8ccd2e8348ca8c89321ad14f9fe52cd759e8b39c35d5298a85dacc4c1774f2d71dc10ea60bdac16461c11ab3f6da6bad9d13a952a43e2dedab6fa40538f90bfbd7de46e0f4adead3ff68d8fa41a9cf6fe9c0e9109a6a06e76a8c4ed518d534094cc9f7b772e0342f5c0c59cdd43135d712c3294d8ac9ba580773ab0bc7c13f7b4b0ca756c9bc140bb5426d1be45a8fac9bed6bf1fe1671c760ce7971e1b1163a320c5ee4495fcf6b03fcdedea8693fe37e04165b22e0f9f5b616638cb1fdbc6eef6e83467cb605c4ce39b372bc0f3fac39e75f596b43ad3b2ff6b35db76da559e72b23e29bb0960f1c7ffee75676b5d842c359af2929ecf1075739170cc3508b5da7b5ea67d8815d05be0643f1c3e08bd7529bb799b08b69a8b5561d9df69cf3c5b7da7bafbdb5aac0799f2551addb6ae9accc9454cb07fe2d327c56fc2dfa94cdf11f571f18638c6b056b05813fc871c09fbd8215ace053b0822058418c5500df7b3c5f54954aa5d2af52bdfed56ff03d71a50ac150d4d1c12fd673d2d43c4bd453140c483cf509c3992cfd9eb1d2330641ffb42b28e53546298c3df188637f7ad0b19de15481bfa0bccb372bc7a1dcb125d3d092e29fce60830568adf5fe4fec70fe9b730bdb7518771883dc02fbac172c96efeccbcf591bd49848765f630234ec64cceefdd75150ff77439eee6dad5db777b7c7dda281e36e24bfe3170d7c83ba437e6fa123ab3875fed48771905940af8dd7061938596962e2466a48b49aa0190818d87f8109d4e8c0011b64f0220120e0a4ccaa966cfe45bdd65e950abf0a84ae02af4af5200882aa7a9bb89aca1475b340b5c2aa7bed1d490ffa5db2b1816deeb577f5c262fc82d715167ca95423b93b781f5b7cedfdc2edbfb8c1639f07ff8bfa59bcbb0e534ae988b3fa1efaf7571a47c73f1d5c853f431c7624b864f3577c1bf274b2baa32fb019135057d4fd22ea66d3c2877fc27660e9b4863e4b20a99fda02c3c96daded5e363ad1831a8baab1faa5c6eadb2d59402c3727dba7c464244917d558a5d120fb5ead9f6dd8784d20041ce3fde110b4f1d251f74882f6b1b5f8de4b29a6147723a9575b07355637e001b7f7ad1ef8eea1a307a0b814761b2f1cb5ef1f1bdacfdaaf865d51f7ded66e5b63e47505056d7874d3a0d6be0d795a36705ac35e90010f7d9ebd298943771b3556df831a3556a70d5fa51aeb1e497ee3f61b57d7a88193dbe2d89164cd90c602be2bbec40e6c4d9a9614bfffdf163fa0bdf585eb8957bff5d5fa5b4870fcdfdc13e460ddc1fff2bcffea6ab57a19b3af461cfe3dabd7bf1af5f3ef5e47c7a17a2eae4295a8a387e2febc1330ecbd6520bd655694cea774cef978d2aea3dd66ed4de7dc1dfd99431e4ac78ba7deb37b4a77f09dfb6dbcfaac75efb1d6ad77ad7b76f4a7d8b28193bb93f337d5dfe473b6ce700c6aec458d610bc08ac958f7e4dfb8bdb502ef360ebbee3dfdda6b21b3603fed3e3040b4d56cedc0f32471bc8d57cf758ab3eeb0eacee476858dd7065b5a38edb36611771d72907bcef969a6393f157334a4f93f0df2313fceb4160e47c5f5d5c2e1d07de9de2c4bb54a4e52a46ebf9503cf63cedd972274f2d05ae79c3c57633d5f6f0d167510cb9cb3ce3a6b06f666812c96f3aab118b4d7b7b5d62ee4a11b2cd29ae60cea39a7ced3feec7ab0798e367f6fa72dedf6ed48e6c74fb148767de26dc76b492b830ed4153b4b29d5fba92883f57c3359d4dff485017b418d6c278bfaa44b8afd16bd6220c3b21aab319d59ff02d385fde962767cf1a5ad90e9dde591599fa5915a5964aaefba5396501e1983419cc57b15303b06f793d84506f1cdf877ddb8e3cca8bd7e8e0a903afa8bca41ce3fa37e4ffefb2a607dc2ec3dda4fdecff35addc13a16e715351863ba206fbd9f5fdf9d7ff6a460a321f9e9f731925a9f7dd2a857bc81c347f73d59d0b79fc3477770b2c038a4813f8768a9a53be4e07e9d717fb2a06f5dd09f57f4afeb09b7df83df8502effe7e59f4becbef8d249d9b467e6ac77da999a4a86edf3e3929f5d97580e929fa2c8f60e93828cd9452aa45f0f7d6dddf0f1fc7ed60ce5fc89373fec9227c2d7a19d6f5f759dc3bfc1dc6a06f451277f7474ce97e32d3c89f33693feb1e4ae28fe66c9f87d230868eeb09f759753a59fc2632d5bf2775f44eaacffe15092212f5d46727e2d4bdef8a20f54fa7ee90aaff38c8fa3c11fcf00bc109eb2a91fcdefb44b2ebc89d55cf713bf8386ec72f30e785f14a470747b2fbf03bd587e2de210defbfb1af4412e71b3e17e83e7fafa234bf2a531ae1f7e137ceef55df57bf395980ff79a27e95b85f158637a4d17de3ec321ea74e8dcdf78aa63afd5a0e915ae5faad3e9d3b43459d3df5e9ebdb437ea0a3d789c71e1af4eba83382cf7e541ffb2c87d87a8edb7d56fdfad08e629af777dfed71c2ba4eddc917a4d60a0da975177d964952479a8e24751d1d1737e84ffd3acfe902c7edf449d7144efbb49f2f38e7d5992ce6572e24e03afe09d5eb5319fa2f15699a9e6b9d319fbe8c397a4f47aba3df90039cdf8e392cce1e67e89e8c835611721602d5efcfaed61be2a83c4f556da8417e5086ce18525be6b36fc5183868d7ef5ac26b5254d7effdaddfbf9d061ebd3170c2cf71bddfef43737dbecfaacff1f3a134bc3107ad2107f7e79883767024a91d63d0bd3d91c41ac03aaa5363744efb437dbba2b45bda67dd60385d6029f72d093ffdbe0b4cf363d167d57ba561bf5e3107a614ca67713dbfbe02d5f1d31b6addfea57dabfd1f497528a3f31ec787f6f9396ea7efb3ea74fc3e871ce4d7768e93c47f6306ef1fd4ef5e775fe9643159d0aef1e3a0dddbb1e7f6741ae85324bb9f64f7f5bf2b923bf459f50fe66461430eec783b7c7350da7166e8b7afc79e3cde9eea43fbf6e875f2ddd742722b1ceeef117efafe7c416bad4c86b1acabe874b4e0846b05ee437da8057507f6c5e26e310ba401bafdabd32ded96ee9c8021bfc5f372d09dc0b78e9752159d8e3df9f75791cc3f7138438f64cd41f30cdfac3b3ed4e5c4c9bd23a00573fcc2459aa1affa2c91be9429a144aa9541a2b84ce080078439268364db25921520d711137d96418e7aeeb30c3293b5e87332c08891117248141061043410991951c40f39201fb07d9640b62451fe682a6937d7084ac228226020404adc7b93ca78c00707b2a4a18109061e02c8d005d263088921c01b6ac6d06084a52b7fbc60e442fa8795405ae8aa3e4b204e9d7cd937c3a6420c81c0077ce49c943b0cd10118330821ae2032571097118d24a47e50716a82a4c39826af3ca2f2a3341ad2c13e4b2323a8f2c8486904e5e532ba23b8ae99fd5d1a15f557691494e62373ceb9a7bec5443ff8fcfbd375c4e95f1f0df4babbe962fffd70bad0af731e7166a4e8f553f4fa08e838fa67efc95ff34c53c44554f6c852f6c04d95455232998bc7de322084b8c85c42f4c7fa813b1fd3fb6305b37b982b6627575d068fa8b962f6ec0ae2ae3e2dd0e9cfbb5d9d3a7101b942e0247fbdea4e8e09fa073aba0db91586eb7f5c3baeb5de1d6d4161c5ea0d41adb5e8de2cac7e713dc2b816dd5a8f2aadee5c2dc2ea08a314166be2e4bcd17f415f7567528ac32478b3da45d9692315a91ac9d59deea95e4069b42db4281a189a146d3ebdd11b3542959a6e4e372c7dfe04eaef317c0acdcc15d5a83bf9c17cd46b0b9f4f18f4a9535f39b5d69aec820a8569b5b48bad383dddac3869bdbb9bf7cd90e70341100443d58ad7dc9a1a5b69cdfc90946ae44d42e2bcc6a644d245c25fd7752279b33cbd809428c18a826ab936ddf5e28bb1ad147f26be1689837a7dd7cf0bace435d3ebdfdca913f7c4095be98956cb05ba2a54fd527195beaa53af7f63ab311ccaa01d2be5e09c1c5b69ce56e1cce873d529a594d25ac6ddd6f95a9c5a2ec77b2e97bf5c6e2a97cbe5722f207befbdf7be6dfef272b773b9a95c2e97cbdd6e4fb7dbed76dbdd17daf4aeebbaae03b3a57aa5e910b4b9a95c2ee7e572ddedf674bbdd6e180c5735254411b46289ee799ee77935c00ddadc540eccd95c2e777bba81377bbbddc40f8793c2e170385c0df80262c36abd4e5020c350ac8ea6dbb95c2e97bb3ddd6eb75ba65d1a8d7669389c140e87c3e16c36279bcd66b3b9c01790d7899c143faa006532994c866b352a2e87a3d16834da8d76bbdd6eb71ccdd1f1c6edb95aab814fc63a596bb1d8ad5050bdd695b6d786956a708de3da0ad754b8167ab86e2a97cbe572bd3eee2ced769f56f7a6bab7f0deecbde9e8ec7abbb48b746939b0277534cde1ea4e960a7116e7e13a9c4ecfa08dd66c75e773f29e043b9bcdf691f6c706556f244190959303fbd1d119f10c9ccc503905ce3a45a70a3b14058a8468e107d544ecd041080111e11ef9630ffb3f01269484fea00d2d498383807eb8849068265e7a0e0272b263f440c20b112a416c00893603c10b096a70026408121e7c083591f2a1449110b1238904848890a0048917a61ff0d19451164aaad1214c694d981c7de52cfee22cce672eec7986c98b162d4d8e840061a3a515ee520bb3b94310518ebc50c20d3b84c0454b5684f0cc8699ddb0956821530313241a10dc03a9b66f98e930012a85211d822042041e475308231c54cbb8a14f8616b8c4e001a5334d303253078e68fed8c3fe5fb699c2cc1e1f615f4c861c21a978861b1a024a32abfcc5599ccf58b8459c6942848f243903351152420aa2458a609a2a72d40509164aaad5ca183133918190dc0ad4001ec62859b17139e20546de4163184a82801194a67c381282192438c8070638042102040823647001030df19039fa696206ca072c5884a521bbc4e3c79ecd8c0833ebe10725344079267b189319a0a9c44708432fbb66689e31d9e2f1176771ae99dcc0a520a0a8d952095828bb081942822e38043d86c80b9e7dec61af6915ff2cc5307466f6b187fdaf6099fc6020fee22cced19400e8aae0a5ccb243181c1051699a1849024484da4e119a939a114172584a62caa8868209093c8090c814f128c11252d0069a74f99124ca0c1233a03084120f4c679c7ad48b66090f40b58a04931d484c410825b91dc43014c495304ca08c70cf2c7d99d54860822104a91b6c40227404d3cc3229f171c469044d3b8a84a890c54c08439cf3b736e8f9b1873dff1fca7009a1f64402d08f6bc4cbba1764f66135363ff6b0e7ff00234448a8d085888810189a26e99a29ccecff65f74b47972c19439484de3245d42546cc2e28b295b9201e18a304862ea25c1246974c72f8616bb8534b5c866aafdc2c533239f57891b9362534a84e7f2ad1600e1fdd73268b29ce1a9b74baae70f2fbd71d92d52b9db46b7c49ae1fa4a17ff239b2f44fd1e2b88fbb7e1f7f39a431de69431e9172fcf4e6bcc29003fbacba33df3e79de779ef75d2e479f42d1a83eff0409ee4e24bb19b87bef75a8819dd18d17a77b3046edb9d75083195b6f1df66bfad4b5ee5a3fc557ffd6e31e71348fae1d0a0a8783c2bf7138d8d73f5dffd641ffde4089dce58e55a22b61435e4eb7d41ddb672b8c416f5def9dcea666f7ecc75f136a30638f178fdb1b63d4aeffabfd85d524075f301906197450c3060682684698a8930b8720d8ed1738ebf7ecd70fd22da106b454a2799b83ac579f91c73bda7ae9b458755b256d31267ce9b34c82260954bf3e20e83469d24cf55aa7cc5aebf5491dfd9b61d5603e7d1fddebe3f0d19d067db2ebfa2da69fbf6a1d753ea5676a7df69aed7e3b835efd1ef31a9bb06e45efb1d89136b9da15f00e4e4bc1484c0a24e83ecb1490347d39df3bceaac54575fbf74bb78fa3faad4c4eb6aaa4b5d65a6badb5d6f6bb38670d5e71e7bc43191bbc5de779e0edbc241960685fb5baab95ad74057ee18af32cdd7ecdeae335a18c9aa06edfc666aa047859364cddfec70a65d83771ab52b7ffb9c21855e9a6dedc5c4b6fcc4c4dd5a09fa9a95c96a728a8a7a71b4da24a358a4491286d8a99eaf66fee4a49e51631b215712883e6a73d8f738b9de77dde17aa542b15c8bd558d8d4d091b90e59530d16ab95ae0ebc6bbb9b195dedc80ae9b1327704e8039283c14286ca5285080382852a4982005f8a2278ab65271c354a8a8a002f08a0088dd58cc561a1bc10f635c91825006ed7f45d84701a82294413b492bf82aa8c0565ac1be4ffb7d155b8533a3e791fca0e7cf6385ea7724e9cfa736ac8d004fbe59a74a27a9d967e9d4432532e79420215398acb5f74e7902a74485537e504d999286773d6a3c249b5c4209951295282515155a25fa2ca9707151917a51c9dd5049c204c862b158264c20e1804a392a1b0abe0215abcc3041153054ac2206050a142852a4a84282b1554481091360365554685101c2603058284354a122e4b127aaa0b1f20500af1aa3a295332b3aa200980022007049e7460a0b90befa2caf6cb9225543c2f7ba4d09fa01802942825430856948c5ab680a943ea38250f0c3d138a5081ee2943445df836802241e294a1042a1749413a5078e0a4827b804b9912a7a51c91db9a824715bfdde7baf14bf7d96558e948a58b6122bd06c6638aa0153c4ab88e1b1aa42022255d108a10942c02a403e2d3ebc2f423a2b41185939e3e3de7baf1daf1011e52b4084e02b4b45f78a9421f6ca96a47a45ca885e2133bb9244c77d96578e00404944f6c2dc5aeb7281bf863897d244a48fe0de9432fc033c07fee2c15be03770ec7443931e3817ce03275f045c861dffb04d43275f669daebd37c8ac2b72b4990c69db2c5be9815d20ba16852df7de7baf2b068ee35182827237f7594699f160afb5178a981e1d14227aecd78cd7f212dc34c45fdc6229429697b62bb3eab28187e1357d962888d08f10fab69d596ee0d8fdbe957ddd5e7109fc4e5c9abd60801f8aac1a03c5390bb0ffc3422f184ff67fb786316e17e9bc56857f86ee64063a86f17560b704fe1e3d10afba27dec92254f5c953e7a4f5aab6d73f915557d0de853c61ce33bc2afd2fea1eb9386174a2d7ed064371c298b6567b55f941915bf1eb57ccb13b1eaf5ee9a75ddb74ded5bce59b35ca982821d89d14235292ba945927771434db2ba534596beff5a6d09cb3d65b3ad0759de7d952ca18292a27255b2ba5a05939b5a0726ac16d29658793d38c65c2a994edd56ac5b9130d352a7c2f2ad4e688d630d569eddc40af6f6bfb8ab52c6489c2427f459141fbf0bd9caa180b85884bb7109424706d89ad498aed8a1da909160bb62ea58d662b59266c2cecbad3755de77d369c2da763f85e5128dd41b0aa48d64cf4b6edcf4ae742b745ef6dc1e01a3ccffbc089c2140a63a204f5578dbd6c25942f50a0fa2ca1dc7a9f2514a73e4b284a9dbcbd4239022508138e2c3c0dd1ebebb384323b41cc09663e5a9e9086890915218c31c6434b9b09948b9b543122b391bc7eb80b8a7fb61c7769e11ee0271405ed3ecb1368593efa75ee27b5273490525a2b96cf76efc5b829496fd15aebbda5565d3ccff3be0f4df9640aa462794251e7c301a400b1030f434284b0829b18f9e0ac21f82b04de046628779b7a284afa02d007d0a91635fe2fe3fff2acb5b6547405d589751aca38015e7a69bd7567459f4f816e6db54bdfac2a2d94d25acb26a6b2c90630fd55e99cf70814cf9ddc4ec4d0df95c4e0f54fb1b9650330e7c57c1653277372604d499db46047099b1a32d788ee30410a143938276e5eae960956099b1abe5285e0e775fa48a9a57cf253369129337fbacc807013202026490011f1ddbf98c9104318634ca66c6aa17b7d964d566e9eb87050e27a61e965c4a493cf6b70d249fe649e74f2391a289de49f06854ebeeb0baf7d964ea4944ea604fdc3ba3e4b27573af941e5922da512dccd09780853d4660243c42443c7f845663bf1e144840c152535660a4d9f4abba93a6179926de9f36bad069a1a548b029ba2a8642e18252954430400043316000020100c070462d15894864924ab0714000b718244664c301c4623812889711004511485180308410620428c310a419436b6ad51d025b063513221cee4b40336a8609362dcc6c5722a0cead13f1ac816290f7c939aac778e0389bca87ce8595b7ff813940a91ce052a78227c1955084b0d04ba2c46f020d010c6aa2c18a2c6bd6e58a15bc40f0448a7ea6e758cb77bac20a9aca1f571067189fb83ff8200bd183a95f83fb027f40f6eff2e1d20371d893b5206bc414ac0379112e046a272a5b6c349c3d9d72984de1b9320fbb3719eee36021c29c85591141ff83b2ee4593798ce444cd3485233ac6b6dc4dd59e71a420542435129b763bc442ddaf1d409ad3d60a90ca642c2d95ea62c000437c24ded06fa0046b71b02ee82e9612056f452778380e1d1b633daa06062bef8d062e64421ac34372b2ebbfa005cc7f69bb1a73643b066b6e5890a00e6d06b6b652dbbfbb9ea521828ea39ea78da44c75eb71fc0318f2d1e6ce0057b5ce0e821cd2ea6a141328b9953604e76f5e7e064b76036a58e036f01f6a180306e0fb81ba3a4e8e375abb034ba13814a4d599357fbcf7cfe161dca9f0e74e013a8fe6825009a022bb7ab184f2b819b9bc7ce3bfd4823c53576df97352ffcf5d951d87f581e3128be4c4918d418e915174bf1924ec2041ee7d2a3a818508de4e9d557b9879b89a61e3694694c1a1fe7d1acd36b6db39a3f5d6b3ad813227ebe15d9fde45d301ef4d1c60a866567c1310094eb6a8ebc4bd1dd7c1c81b62325fb911e7dfd71f8f36a4ea98db651223f5f1bcd10262fa8bff9a503eea7f090812c38dedc9f063f7ff4024f2800257eac934059941ffff448da621df7d8da45090a784af7a821322412cf87bfaf0f80e2d3838f14899f3dad45d537688c38d2149ea75281068e9185621a79e0620b7483fa4e6e841b9da1342c34a41925f235389f945040ef4db057e4ce35e7048f45d407b4cb5b0180054683d9724db279de648f42f3bc2faf5e9c8518fbb318040201f77bb3acd62f43bfb55f1c355383d740611c44bd6208056e1a001b8f44e22ce5a7bff589460df747bba8fc373998b4e1a235752827d81a718ef09b95a6b0a63dffe0fa9bee9aabb5dfa4fd09f537a6ff63a98dde448f2a65c384403cb10ca23e6fdc51e42025c27a16633948928e98a582043007df9768529a5d5df92f850802bf4c4ca285c3ab2055c57c8d5abb8cbb1a0de1400481a0863a96732c2f0f15324daf40ab5e2b6705bda4410061b38989b7390543d7e416ff5eb7bae5a0e39be0a860372fcb4cd33cd54b8714469349b4d8cf09f5545d31aa88920656b5a5fed8eb3f65232a8351a38188cca07554cc289a2e9bb4908217d3bd3ca9be4ac389ab2483886873e8d6e01d08d6131034747c3479774414694e108b92141388819676a6af305fa711814057317df1d51c451aed23ea28ae91bdd5f60934ddb01d4809752cd27efaaba64a2ce150761803ad1f4ddeaa46b35b6ca4cda5a9838197903ee19054a10590c0610d410d9a01c0a0f0c6a941234006c134a4469a80190cde20356804cc20b8c6d44c1ba00d8b0fc922c0001968ba29e3222237c025864b61a05fbf3739418d8d64dd712b3e4b4db6fc647b18e09a060006da9399877ac6a1f08ce6481b203614cec8724a0380c3c31898232d401c0ecb688e3401725838325e80c04d397a2abc808f964a0b0ee8260b2b25940b94ee7892b73ef2cda28e4ad25b17e55e5947454900858f6a6968124a2ed3dca570318566d9c3eb72f9b2e46c3739651ce1f01e7b7a0a5ad208abbc5b98fe8f6a325cdf76875fe298344c2e9ca6cf8f938442e824ab2a43940e9707c2c34417db30f97135efed9254339a461302f7dc1bd69bb0e4c45e153356879f4a47b39bf5954d8a0b0fff52473f7a65725198de87a37e152a8ccf0ecc673ccf4378bbf48f5ce3482260cf51f2dc91a53d2ddb2d619f67bd4d258753c60661db92f3bfe313798e7cd101f785e515c07e0eb0445a65418051460954fd011dacaba137d0b07a24ecb579b0662800135727294bdbf783eefcc81eab7f1729e7078d3177955c16bf0ad930d37b0fc6707a49507699a94565d2ebdab4042a9392181ff410d42ae5b53a20938deb785b84483466a46c6abfad73ef34cd27040c2ddd6a7489340ab94461f45a377609a4a6d83ae41f867f20475f649d2b3dd987e51b837403ec272afa664aac8fd6d5476addb2c903d352cb8308ca461f8ccb0090b86370fc1ad439c229c8c59a9fefc718beb4a57592ae9b251fde19eef753385948c669e91da9f65021198eb0c45afdc16c3a4e5dfd9189adba8b22ec82892af4b27a02c8d51fc4779c1c9b0d104ddd4000c1c5dc3c7f0f82f23d73314385c76ce57083988c4ab9e11c7f4535b4ecb7420c25c2f4d9425d1fe539526323d6cb98f951aec8f222e50b437875fdfac4bb308860681a8cfdeb4202c2b3ed5cb49482a2030b9f5477e14a4b48088a5c6d96678667df8b7f7394caa398814ab09781ca27bb2d33f1a653c6de127fb4fd494403552022d3fc047bbd4a98ac8744c6065693d6c4c424a88d90fd73091a6d9d67661f680f35dc3ffc9421be3cbd7b2032488c02e75884073ccca9186f2fec7a9e69356c081beb74a487df85112d635e78067a1acbc37a0ef2526433a976e91896899db1fa2fe407f7451a11c8c0be012c05e9d8777f143e1eea20f384fa25d8fc135acf467a043fb9cb55a6b566a08de1eb863aa09d30cff121797f24e674b61ab4889e5e83ed7a2366a945e0312e150e151c612798adf9cc3f214df8ca1a1378608b26e45345a6628661bdc9d8d26e3a0fe90801f4a12d2cd711e9677bc13039f24af4a80d86b62ed5486339f3160a505b7cf9ba54628129cd61c734639d9e23600207f30784b5089039e737d6dedefdb5eb7c7151841e35b73b22469b174bc393308ba85272df3bdeafbfd3b7420387c881be1f4f7896bcbb52509204c4512a184323f555e58d4cbde924027e46b8839f062ad2f7c8dcd3e2c53e7b080081aeb708a9aec033be89a9ce8fd9ada26581e3290fe00cb85045294ccf7c1f639cc5bba60b4beaef2dca15ee20ea2aa03e2e9db85534c980f63dc5da87d5c1fd5708f8743659bd1b4ab86f8f6cd82abcc518093fa9a87972d84fe2f851f4ea76202331de4bcadcfdf2c07d4f2c2d5eb081929482113f621fc213efa8e629118f98ee779c3c7c25463edd59ebc637db7f895c8a29b121f6956216873bd90d5056a1b230e758c88d1ed3423445063f8d559df4e31c0ae6e75c6e4491dc201f37eba84a74d84d968f8acb0cee5b1070f8786cf6ea8a2e4b082ba276fb1e0a8e89b2f6273d6a8d3ce8fd09640258aaa3e253c96712bc23a5619a00044fac221558d61441bd5c7e02497c40be28026b733c9dda332b8eb8fef4dd8c8f180f93e7e449c3423e30c71e04b9bc528d1e9001556b270249a65a7e103739d3833cf833fc6521e58256423d9eb43b7bc18ce7d020da91212f544da2eb8099df431c45b76b98d23d4d0e9f32196cd54bba83f808ed866b01f8c748cd02b554968e13a672f21847aaee8a5b0a95f2075ee2b4e186d0f892181faf939b35904fc8349b9e164bec270de8d22d715f52f133629dc5e604c72c0ecdd957d76675f75f0a2256f52f3fa8f335970204c0baaac5ef0c44ce9e4a7668b9f328a75baa5ae76db9ffc1a722bd602057a7ab524bab21d1326b034c1ce5ee84e4b4ac93cb2bd0546106b313502d00d09fc16e92d405757ece6d02ea8502fd3dddea4b134a76ac5b71020f3648206ddbaeb5d4baab449ccc3156ca86c96626ae16fa58c6e1d5b6c4e762add90d1c397c104d161267bb9606ce892fcaac85f1b57e10f33044444cfc8d14b537575a355dcd36934ba17465bf533336ac9d8b2f2f2932f126afa3cef6e2d28ae735a5b6bb3c7f794a82a98e75a17d611d88eeda87daa83bc292f9f2a8f09303bde8bcebcc27a3afa4205203f6dcada1f31955537fa26e427241672dbab8381e6cb12eedddc47578922fce6abe27ab83e64d9e04fbe2a0282afcd5dba04b1f3e4166bb90df07db0f65528ae23dd57cf3057af1df386f6126d115be1c4548c478bb278e359f16d0d9c3c22167ebfedd784bf6b3146dbe42a9aff17d863ebec19cdca6b7f3d989a8993f5098c2d30a156e7488bdf8427fd71f4a6820fde8c162276086cc7519f83de5f88ce4568962b138d841244154c2807f21911c113dc3695f34c5688e84f3cbfc6cf7f5a1d8bb3cf2949dd8d86fb031fec039c25df94131dafb0ab88f286264d455c5f53fb3f94da64c272a55da56ee32b8b4a47a26e24dcc4c3d858700b31daacd0e667d451697c4ed45c0b231b86520598d177969c8188c6ceaa175acab4ee680452eac51654c8a51ba385c29eca3790c3bfda5e7721ebc513b835464000d7286240d5ab0bb6909b4b752e0f1922e76bdf6e8cfc5ecaf19a84d8baea2196ba251a38c3266a4514618359231e3463362bc716a32e5204d9470420950225f9824295cd52a0e572828d5af74ad1d9872886af03523801bc51c1a75ec87f7a00df22645104932633aa838b8b582729f873a92e402e3e74ac84b72d55a01af8f063387580cc7228ccd5b2a62563a258d8bb458cf87d0c61709cb04d8bb06a0b415323fd8a0a7b5d78dd4719416111fd908210f40b90919cbf0164be0cdc715dfea002e4ab718c20119216a4f1008212ba75cc0e4cc384035de5e94df4a473c95cfe353291234f52e304fe18efdc76463878de238c50578124e99c1afdd840057f10847037095ceaf5a269e20b8c7a0289d16c6edd68d483e4b9fca8adc485564810869ab23a01ec91be56438d8fe22895ea68a9634631571ff1cc5a9990f7150dbd357e28d324754b6ddcab0683a5d3a057fcca3f811492f2c37fb567657c244399cda27de28145ba919fc2408630d0183bc1f294dcb1b256ca801df580becf1a56d89e092ea636d7137ad41aea8abfa7396be3c06272133a899338969f77300dafdb62422da2dae95efaf0582e3f313d94cc81cc9d43944985bd5273e9ee4e858307aeffee53d5a9cbf83fb61de33fe9ffc68872f901c70a80e0c48b2ae1773f1c39ef23e9b0a083fa9d2b25924bf09a2a2ff75feab39a35f128aac1bc8f214454b5910494ff39008a6e218405825176c6542a71e58f92c8a2d15a3ee980427197d9add7ed06422e534ec83e34adb93dc388d7468ba953711987a832611dbf18afe6fc03f9d0e4c605e3b1a18d9b2212aa700b01ba24153a75901686605cbab809df4968d9e5d060982362dd98ad27c49feceff87bbcccdd26ef4bfb4d5d4c22c37b9d7e4305fae8a361fb3113762e01ed59a275a0a74838951fff64ebcf9cc94aac516658afee005d73cfdf3801f9141ff3d816e63ef5d69f49fed7de4fca971cfcb4372c45e84e41b6d15d5640b72befed58c688230d5b31e88dabf23931c9b8cd1dbbf2a901ba70377150c02a011be6abc277e28639ffa6a378eb0e9585f85a919dd79598ab2a169afc140a69dd1f888f26f3e463009734685fe53fabe7641e3f067493dc0887a2172fc02cba3014369763c314238c500b82050f38d873a150f8acdf568ac5e533a770b280413dddfac66367be2903530082e71ec14bb99b912fa513b97be058cd648a1dad676f4f3440e0952442a3277450e5e1b0e2c87bbecdf7d1ed5b01498eb66ec356343c61c8a16aa5256bf1c5bdbe6ea3fb2804d83cfed3b113e975fe86ad4a2e64a2dd797f08fb82173d39bd97aed4fd171f3471cbeca9898db377c3b0306ae54eefda383998c001722376c33a22a449046aaf4248550464eae6508520690ece0681b341fa3d444a94516a647e5f414e7ae3b33f522026e79a61beeb239aa6ce7f4cc13c62ed4738bc863e5a49110c25d41dea4bd3b045966932a2569947ef122cb866138a0525fb37fdfeafb465f3cf580f5caf2f24f65256ce4022226c8d3479fdc73721e783142da1753304c0635a42be50b4b9d21ddeaa7071ed3a0eb8d7d836317db5e9893a45ea2aa5f8c4c1ef86584115ad12094cc66489796344a203b527049269263d337f6d12c4cf616b646d5f83734319de5082d0e0253476d3a8dcb1d702252c8dddf24a455d137bdb79a15df345fab8925f1a36f563b07273af77b2224818aa8235639b45945e242da16cb849666f06081afb205fb27712899002e238a426aaa44b4f973c6103412ea36bc330b2924547214eb4512cf75c6d8916b9a124acbbb2889137ece04cdbdd9dfccb83479ecf4a33d91f63aceff279fcc283f777e36f7b697fccf70eabce9246ffee970a877e458f1afe89825bb54815e5fa8ed322061bc4253ed9ab73b274817692a092a01d3a4cccfd27e8815c98121bed9249591313c63d9eacb9a01af7c56787334e947a8bdd17548b267295d3a692199ff450ed48fb272fa39becccb5dfc0cea4af8cf093ecd86dc7f8610abffe39ee54056a243d62428e3e0c370b9089449e18a88a444d2c0102753cd46031137495cf7b0c23fa94b6408125c678a42e4a91626dd8d6172830ddfbf7a46edcbd87dfce8c70f0044c1fd252471881291dd3a70cd14ecfedbb409612ff116f63c67e45d4693097c196994f6680c25a319524b258d520dd1c8e0439efee73ec0e5f7f3f1d3626ff7abf6e4648d196ecbefad7670f0e2294db25741ea7c248db46aa9c7c33690b996ec1b163f9c2d5361a4a3f96177f06919603ff5f869c799676ca78e37454e5e0fda8e44007d9ce452eb98c341937d2bec8f9a63a5bbda3b411894bb60e25096936ac24ea57fc919e387504d8e58f632e523f12526194bf1912f9ac15aa7e0abd6fe2510ad4d3bad180593aeeeb4e40056d5fcd6c67f8c54bc13ac375b162bc81107b0321e13e41946803b9b01d3231cab3393caefb23ad3bcbc2edc1d361ded0118424e1910e2fffee183774ebd5097fee8a6475d25e8104c1ecd3d7e5b37228186f518cfc6ad0ac971a0d562cef64fe887de7d30d814c876224505d73d693a3d34459b3f09c6ede904037ce49e3dc32b0a9b39c5fb189f1b656d24251339b0f79276119794ebe1ff6edcb8cf8b5c4b7518669977c5a3c3d4c7e936b24372b74b546b990c8c064b72a9ff4a07a14c3d9eaa68b71dd7c72078265ee92e4869e031a62a6e45e4df125a2cd4d7649c456ddc8d4e55220f7603f57c82b3d9282d6ee97edb22241932fb4eca3400a7cf0140e6114d69fdf6df23c1b6485fc427e96435ffa59eb3e1327ddca1d22f3c1e09377d7197dce12167c6ad79b27fbfb797780bc9b44d31753f0dda6bb41902adcc05dac296180c35f00da5c9f2639b6bcf61aa6b9d77ec60080c78b1b29ec30fadfa38646dc238aae2fbaa06846e1dcd9d9382af0dca0c83f3b511ab0ac3f88b9cb1d2bb3ffb9da1f89b3608154c4b5941f6ef20e056212ac52dc5bedf361c07d640a06fab9f086c2f5bb73df1874205e201df4ca99ef4c80676dda285907d241148df79a3e0b49cc196b91e19aac11126b6ca153055ec3f7731e3293ef435f6f1619327b54212f51adc359abcaf0229d160643d0ddb4178645b092e28409f632a3e64e523af30c3420d07fc99d63d5528915872d5ef5bc7b2e135faf57a1638ef983c7782be016e7fa370c68992bed6a7655a9569abf849d8d82184617654e9edfad59a2bd256e7571b29e8c39ca0ad76f8bab9d51b2b40aa4f30c70cb3dcc73d098431dd413b07ad7f7880e8d1622afd05eb78a4c5ba514db155f7bd72ebdf6cc329469d6ac927b2352b3951edb1a559dc606ca41798088a5e2fdeeadeb351b2237dba227a7f3bfa7439498d1ec451e97924488d6209dc954423fce58e4107683f32634cef5908140ff85bfa74e8faa6166719bf393497aba21a7c060731f1b7fcf6f9a9f950a5ab0bec02fcc6addfc230ab67e09ea61f5c278bbff318aba6fbd94f8ce06bce7a3133bef40b10b577c5269734f3c7d7218706a8a434bd81487a80145e3adb0ed8d7502c11331525adc3394a33712d7a9a5886bc567a3c7b5834901d0ab499f198080e76c55e45b7339769e2063c3127aede0d8d4238d7997c739bab0755eeb7cd7d8378746f3c50248908c7d0f8cfab1bc6728a166832e38bb44096e667c2de4ad1c5d2f4bdf50f8da5077ceb1f704f6f1ef22d7e68788d762628c3d2ccc318e466d008ae8a722b278d00f343497e671824a9b2bad7b0446b5195aef59f53f568e0e0e4a731dc1efac245095fa31fc10ab61e9a121f25ee16050fa9b4feee70a7f5f287994c6c86fbd218f11a3ee6a7e653fe7f80c700410c96e64b8d69eb375a5ab713fb925a8fb44dea3804ef1332f4d2634805ccd17fb93214c35b18bbdc16273e880679a3001d33adcd757f2a8ab4b771d5b00f57eec1a4822cebda8faecf85a490603814b3099fef73704996d088fbd550e3bbc671530687f7a8a7b830ff34ccf1d2b575756336fcba5050b20e16f27f8d97507e627a5a30a9379c57b0f619e11ed0dc761f776487955a2d13d7043c0a23d3c22dfb11f5d98a23bf4f3de8ab018902cbddcaf0b6e1e1e98139a01c5f9132b9cf5b792a101cfefea113197ade841482828654838babf6f318f27f82a786fd0aa350cb48e270b67e04df771c93087623eb13ec6c3afe85cad6db39305b3c92bfbf92d4a4ff20f160de56bdbb8ed537b2be77cf6485b7d25e30881c33997a3bcc7aa38c462d755384333a846ea8c9afcc0923054612c3a037e8b1d809b47076f4deaf6997b15531b19d2a306594f314372f36b9f762f59b359f02cce4806889a099c6dfbc3a06e989377d5e8cf654f5286f5ffa9a3e8e886542bfd7a16244c1ca5bb467fb1a50c301b687284cea20c0be205ceaf66de6b358e43e7a8dec0cf89f23ba096bc401ab37c648736bc0393a257cd6495a8931a25014135c940b9098887824faf77451984b626b2f8179f993c23c04aecfaea14d0e8a0eb58f6d7d0010485ea704850b4e3be0aec9150737d4d01af39c5a2790b473b87cb0c1cb38a2cd9413dae2e15b71b9e2077d1e49dfd38d6c2b87773481a8bb2c78419b38d73849f91f228859ffc636ae9100234df982a2500055146c46d31f5726992807ce6f1f654f06ffa63049bab58281349bc6f0821ca2ef0f8a309a2d2a5aee07315234b22e07ac4a7915cc130aac012bd301d226596e271e2be88afb928bd2b5e692ff3be6872d1d5e7b314f6b96fabea8a74f03e170aa2357a24282606ae8e3fd68d3fe1c8be1379c58e27771f8468c4e9be94532ea80383d3128a5ad2124ca42ada76be390911f5092072761bbe1be8497113e920eb03be697fb9021bc7b3b713e963433eecd4da8c52070ddacba99f885ce1ce92c53ea485937b460f17318bbe09f77c1241c715c5cc72747f3de426c0041fe19afc12734d0afc728d1c6ecb1fae4e7c9580f563f86a9c07dd6de8e08794d72a8a7a64446935a7cff093526eeebdd13242fdb9751509715d81cd981524143c27592deeb0bbab226d24dcf6b9d1a5215a89139c7e70e916ae6954cc338cdfd835a1e3a1da02e7415e30184d32dcc5710355f3a153e56d04e915440aacfc9e3193f27f689782f4c19c8b860dc5c8b37bb1e6715dfd51ada4a693217dee6d1d39aa72618c115df8fba303ba99c6682405c0cad63d3098ba72e4e6e12dc12a04c8f3c695500051b5909cbc088271e39310131e330a635da59b0e40162c572dbf216d3534e391ea930c954a1b6fe8225a36f07e73617c1c19b3e2da1762ba5504378d13e7711fba69e3461bb1b2a13dc728bae99d91d854cfd3d51848710d2ec62d8539f15142a72a9164e76ee42eb6c1a65db080734de3a906e3246418431d36d05125e593283f1464f2e59d0f9525a035dd3105dd73329cef5fe046545d828625499a2d5c3eb134348264585dcbdb39e1c11975c6ec501b2be4d26f7589db53e60cbebf4210aebe7e6c0f38f7ba246d141d4630e77eac052b0f7436df966beee80489038d60a0660342479cbaf3fa410eb92245aec80bf3d986cef97dbbdc4149a9d2840262fe4baf20379dfcacca254ffa997a47895e615ea38efb3e94cbebba3284a512a7141d2068844639402991c43a54cbb0991b7a1aaadf3521c5bd4cface1b6f2830cf10159676c185ddf3a878861adce148665369b833565ddd8b3943a9c164bbebd54b3d554ba760a0ba2a1612f64e7beef751df7538ffcf263854999cf394475860d208a9f8df90f35eac9d1834abe2d4ac19db8736f3a1099d0d3692dbddfdb0e7fef1be0116a03177cbc910d2d9cc3a9b5957f4937ff6f50c1bbdc90bdc3b4418c3070baa5e165f6f9d0d1e3ab1ea8e933100423cdcf5f4b5cdb1c30cb476039d6bfce8c6cdbce67665f21a756f2b79179ea751d6b80cd17300d004e0d8a8fca33578b079ecc46a2d11f71f3a2378e0a453267f00226fb1b3c9dcc378eaa5e9a7ea85bb4dd7483b8da4cd820e6a8f7b28e2302b9f16743e2be54fbc1a7e506a2f02755bc449db582141e61a726548f93cb0ad8543fe1c9581c0f9d9ddaa519284803afc610a59a4f6fe008e2712e659119d650e72d0768296da245e6a5cb7e85853e0ac8020733923a02db95fdb159c825e950d625a8255a20c20ec6d4d8cd033d3e7b2e81b08146dbc47e9253ff7063db43d0c11a08e01a68addfd0a81d0aa6ef48cce6408a9ef6df612144dda7e120a1054a43bd70f2f9502556aa73754f1455d64ee9ce985d119142db0466dc2b5f76e6e86b96c90e042c967b109abbaca83cdf2cd5cc4d6969d38726079c0a01dc765cb6692defb609f98a3b5c669af7d12d2c0fde363e6e914149fe15724b58f02822f674669ef4e84d06100dca8aac8e0ef54f2f2f4fb67953c76d4434ec0c8d16eb0b8d0e29740d09d4fcded02161bf9c1c89d41a9001c9d09c79150209a523443756de4b7f276ee61f510639600622509724edc2c50ee49443df901c43dc73cc636277b2a3584112e4090a0e386803ffaaf1ec6d632089c710a76320844448f5caee18809b94fe4540e3041e681db88959a8ba503196a61dd75031d6034766c56115d8ced6329aac6a4f416de4b1d3156e771c0a809da9d2da602e0455cf5e820b3118169cf3606f27611d955dbbf8368c5f8e8f922995f136094b7e050a63146c7c35d7f1122d490e3d30e9eb10a42f73b4aa1ba13610bde6338ad2b65833f526347474fb42d64d0ec24dd0204faaebf6361957bfe98eacd2e0b4670460f7241d30701d5a521d8d3245deb2c48c549cafe3b1e33fab0e593f4830b169c8b6af2a5a2c7a30bd151b629c100900520483325ca889185df5654be33cb0a69744a00e93e7e0c6f4ff3f6bc2c276d65ea4d2b769bd147e79950dfe34fe7604e4bcdf503a37d8312702aebba5cc5b9dd2f394e85b6bc6858236d3dd42f473383e5f11e614dc298d4a4cd5153398a669a3572e061d4fd6fcadb8ae059c5509b6de00b5d3da7838be10783835d7700b9e598dc3b8728dabb9fa78839916c37da849d4677a80884489a638409a112f92bfafe451665ecf8ba21595d06974bd7eb6df88cd512dda30805925ec749c3525d04bba403df8c7b99143a1992cfb432b9813412aa54183ab2ed2f7d54e3ca9b5806d947b30c58e52bf163505371e023b961d82e8e146c18aeed25057eb8c88abf309ec2b6d7b2cc00e0626a7c4b9cd51f871a35d51c492faa006793461b69a13f322e964fa575528638245340fc828073fd820af2db37ac27feb36cfecfe9f7879d2a0bf03eb9863dc35cbe9288b7e782f2d3f0dc556203489b6fb543c6f4122680f52119a981dfdde60b8c6285f37e12c97ab7a4c5ba34ab0402aa3c783b07504e286424dcba9836ced3e31ad907be1df4b08b9183694d2e0a5bb2153c0e6ce60a521a561690d1af9f0aea7709fe1beebe7594e790cddb5637a1d8998cb4a4101cb44165593bcd31d24b1e218ffc9456a19f8b8937994873421af33499e25b59a9e1fe0c1b195e3c2c3ae58b97b969b8856e7df164ab3cc03bbbe10709ebe5cdce875dc04795975f474d39a282ba2a720028c61cab2f40381150abcc17f91bda7112640e66045611d02bb357946f9d0d1ba421c987c1fd3549e37180a184da41572e470aa65f1a2b5b5fcfb2af33e0aa753559dca6df5e1ac63fe7a63d1a6314d4d16650d5701e552aed064a21a979fdd003987f2105ea6793ceedb2c390b841f4e275d421f37b14385eda0d324e80a45552b703fb04fec19f01a6d5475f89dc56aa2959b9cf12ca0b8bcd7505275e36ab8d3bd4f8fdcf5b8e9b6080d00226697c0ba9ebc5ccd239992bf114a725d98319d65605fa93c527b56a97b4f078c8709157d3944490819060cce34b9a676e19bd8d58143c06df807328a89b14088e21cc85bb1bb4e6f7db32d4902ab259e225c2200c577e2f42ad7492c3c8db5b312dc4670991ee7238b8ce6649d63892cde94b15b91cc831e40a3ab924c5122654504e9069b85ed03eac3a11c7e810202acaabf584831b5ae481027264de469ea36eeec4062f747080d6dec9ed170d06f343cf94ed59dc17fdc76b91978b6f87eb4a512a339f2fb8dfd5a8df587707802237412d2126b497ff31f242f7fa9a4bb187b7db5ab5e724c298fd869404f317f87786759286012eac6a0e6d2640f29d8e4a8494148a5907ee56b60b63fee1f5470e20ed2c635a67f8875dea72fd4e38804c3a087048b87582f3c43f711d5223c2d9a5817eafc25b6e96500a6b6eddf3fb904494f44eb0c9c50e299b76979af52cd0e75511e760c8014332b7685f783cbe0be9b8e0e16084e222b969c27e621e2d770a8da56902499a18a0e9562937f94a6637da9d8f8d492136dc0378bf61040e67b034659f33281e3191fa96068f358e540fa83383e8bee84c48d8866eac904996aa7cacd5d1540806c8a0fb84bd61ace1fb3af58527752dd8f9374808a4548264d02fe624521e49122f96ab8b6396dd45364948d3e13c46c6b8bca6538accb5afc1da306c801724a3973925d6d3ed56c9311793f40f90c80963411a59ebf0e230736e7aa8632b8b41326dc952a6dc667d95d160ecf18fe9d704a2aa3c62a90c2de353c29588b5f7e6cc69bdf0029875c79764e74c7f112864d59d713828c2ba14203e3215069d052ff3bd204ca44d59799e6403a5944ecc4ea6831248c3aff6f4fabf00f4755cba078bbacb745e913d9b19a8863b60669db0e2aca198b04a7652277bfa7fd2b64e2e8fa800786ba5bd2b78af6e18d397f8d34c75737e7b91a169ea5cbc156f78808890b4f1774b1729e3071fea4f58a4788bb983ea81605dab84998764ba5c3c1e12f618a77fc66fd8fff4ce93738f0a54bd8348e5f431888546f7c9d32dd01f1af325450ee8cf8f3a52c7f72e47188ae92048a5835377848fc05e71f8651790d4d894dc24aac7d4a0946d36d76683a96f3731eea2654f4c38210dd2fa6ff86054ff6befee895e630f0e393d06088170a1f0fce036158330f8223e021e33ec7a40de8e6b92c5d8cfe42c68f546ef1fbcd966433f6b9d78b003995e3157ed196814cb1a7c16995bc458f5e513fd430b5ffcc295ff704388cadaf0fee2dd0ef69f8879ff024c7a5f9d8ae294cc0bc63d1068081ed99fdf253eab414545ba10d096564b86b05a518ac44e2f37e1fecb3a80e359e93d1b8115386254ed0e0e3cb802251a650913f7620dba781f492a0fb69e2050c5351a7495616dd1b9fdd4ddf3ca1468905f28b1b6e6c26fc0ad62f4c6b676662fba5ea240f9067bc704a44035549dc2d5756f91249d9769df444031ddf1511982884b4bf93cbd2e478e7423128dc76885341266bdadb3aea865af00669cd18d526d744562e286ddd9674d5b3ee3d1fb0e9c892dedf0b9e73b3e5555943231bf8bcc2525fd8846761f01babc63e62ee6f5024a27762328be4407386b09ad643f7c86cdb72c832ce3403139e012e2533ced5184c6a69721f638fe8609eb21e5a967204e99a74604e98c857c48b022d70ea6b3dc8750beda1eeccf99b1e236c53a168f670567e19b4d355eced5a6691723ec8d05798d2d0a5e804ce546dcbd1981dad1a0b0d59584f1c44020cc9ddcad9ac2d64ea4556dd8b5872fe31279c8700883458de1dc55b2ed70bf067a93f6be8c5f6200c49d94192fb86d8716742205f1c8252da02f34eead8922f969f94fd4fad8f11a5747fc00056b902f5b3461ea31fd58726550b11de9141248d55b544427a2911348e48e946791cda31258374ec101f6f20521d4f8ff75ba2283c8663c930deae0758e6411435f35d52a734fd25ed17e307699183c8f4f1c7a2497e288a024335399630b623b89477696f651c210cbc24149106008486fe123047fb4149d0f622027d295ce0802e1d91b1cdae9345bc26d487d77918f90a87d1bab9a472abface7936c5ca2f78ae1a52dec163213a2ace2e8fe6c38667df069c180875a068ad1c0241fe2c5c580065272e59a69ffff1ddad746a17c40c004d75ad5f01a6fff86ec692c04f62be0f9330c7dd5184cb7a16195c42a60af38796b5bac47900ebf5850e776504b8d9b512993c70e1bc8f2e1355e05041f8c29134e0fca31203c73eba854cd562fbbd9092267c7410a5a0d7e96b5a7a128b38182faf24adc9426472d76ef42dd1a85336d90c1015a5745bb5bde524e6750e75a964bc15856cc2bb93feceaa004ad3b52bd81de54fae0a0ce3a773812575532ac3389a4bf6e4626341154acc01f7f06a94d753d0627418c313e656d2c03842fe11bec3ff88787862b96f8dd6f46549841ee120a9e32bdf5d12b45e47780a0ff8021a3e48593d1415ade4c126e839a09e1639da9b7236dec7fe0249df78f5273676add6d9b7b8bc2fb8f8a19c3703c57837dda4e4c7bd711155e744c283516b5f71a3ea1927a1e296572b5d632136757528a19ea5eeb015728f94f322117ca6e308511f69693d3d8fe05710c401d51680f89e092cf49a551978b71917e274d60e35e26fab0abacc93e629bc0d59ed281a99771de9df23a5fc9184abb33987fbbb9f1b82d469cad82786e30f2d590519986e3440c72e21680c7889fc6487cdd0ea2a352087ef1cfa9e29ca81ef536f81713a77d41cdabd8c0875d401bd3dee87f472d7fe200acf31d75e646bd8b14a02481f308f4080508bb4f6616073df1ae7c294375499225b5e1df024082b7fe4fcdd367a1cede83cb613fd5f1d6bf420076bfd1e2684ffcb0fa350692df0e2076edc0c095e637a30a92a4f26cfca29504cd29469809ce3573826a22137cfe392bed12d0df48eebddd5458edd18153395e1105158714a01826077f4d1b5cdaa642ad1cadea32faa66af3b47a36f6d98cd911c8476baf3ed289fc2001b5afd78a5c3f7262d4aab831398c4897d2e547ebb9064b712d1d02412b332db413b9a31ff63a8f887bde8a2f51bdf60509d39b3880a0c27474cdafba7e718ed7dfe7ebd15537b3291f13be5f6aa8fd002d178ef5f42310c693442fc180216e4aed09d2c312547e296d0e204eada88a6016862cd0f23ce8c604fdd9ea8b68e57ce2aac772058fd4c44a7fd283c1703aa6a82351afc58567e9ebb36e0e3fd7a2e658332e4b33f12caf25db11ec7cde9626696502fefd86d01d335b0dc46ddd5541c0807735d576f7e1cf462d00bf4f2cb1fd72fca2d6e276e5e2aeb05d262a47537c4997b1ca21ef4ce03b02c6c878a4f2bf3a9bc6d3a0c6fa833660256f555c73525c4f93f3399252f5e713b5407b4a3db80bc31030c58936a63fd9071d0b5b1229d23925f2a8c3fcef63688cc509d1dab7dda206644504fa60e4eafa87fb3d39237af408093bdc083153eccf71f1bf50d81e3f09dfee6380689cf37c330207670dae35f2ce3eaaf84a9a1473650a48ffea36e930fbf4eed38b2ea7399e213dc9e702fa00ab151c5a418759311416620b5c8e2043c035b0c7164983cb1a00a23bf3454259ca2fedd0847898d6172fd1c319d010f90475b70c4ed062c9ff05b979fa22a0307fb508e9112e4668c6b825721c0320b457103cb9e3256a7e44d5d3934ec514c2181ab8ce1a2cc729d620937544337bc1825ea4c2fe180dd16336542373fb33a939efa84e53982aa9a842944371b60c2bb5f7e4cd8bdebb44d48f1ceca8f8b4cea39f9ac436822d149463bc3b3263b89ade3c36fe0b54be593be154427447dedea77dc74bcedf877ca72fbe6cb16d90771cebbf1c711eaa5488713b21465e8bda53123f34ea1b633064168f08c73f9a5ca7ec12c413a6fd75181bfc2e217726c02aad7913b39b87cbd80bdedc97ab94065aeb1d2ae6df41359a70a8a259570eff7bbef305b86dd5e57fc0ab2643c07be5d84efb4e6e3fd8dc2e9517d60f21a98a99be38286347c9ac8ab6c018aab993acb4e00932311657279532e091dc5d3ffd97e63614321af9697e965f749b5862e3d9b29eae84736cc756ca523b927700b92ff6cd8271658ecd17d7802ff8bef3cd493b04c8f05978b25651f5156e5b86dab823c3d790d24beded347b7bbb0aede3edb76d7d841ca0e7b22b11e8baaeb7733b42c579e5ed3d37dcdd2554bd4d90b9280fc9458c380bf7a799036c6277cb5577d85ecafb86158a4d373cbe1c32b51485cd218079c49d7a919a0ba8e178ae9c589db221c92da12630825c9eab6d497d934d4e037367a432f1003d4ba9a6271718a8fc117d574da6b904b6e8418aabd9ad360df736e084ca546f2b97f31308500a07a76647a623e77104410481862820f8634ecf2a25fd6747b5544abb7c961d88e504acdd61a636d988f4d07ae5274d4f0babfa3ec2b178f30b163d6db928faae715de612218e62b3819b7b6ac06e0155edac76165267a51a07c1d9fc21670e2e69ea8686b671c1837544c12b99dff6dbc8146512a067219ec57b091fc5d8a53c5235c1dbb19f2f636f6c3e31118171c0fa4bda172a7884962d54fb9737bd7b7cfafd7d20ec14b7942c4439aec67b5de5fc85c729a8d26bfb33c3eda85e128ee74eab1313adf5331a518a87e7861e1749372ec41a89139f319c5a29f1f3f9fb83e2908054bb0fbd327d3aa18b54aa00f05eded7cf43b47c1aab63f072eb56b1cb50bacae09cb62c4766b07374681863ab02609df5c235eee0b18259ce22a16ef1f1831cbfa449af10285526c535556b6a765145302ba6f68af2c72bb1867f732283f168eb065aa405b1310156db1834aa67b602e815ef330cd902f6a3d2490c8c85ce8b98834f80331d81a4c1d64ec215b83b31338973ed074ff23536ac5b73d83279e9114e0acce538224ed0c3a1b280172d201a4911debc2a160a5aa3082c361290f3f599507dd2fb951e649d5f925aa52550e51e335dc0f91ccdc99cd3c5eff6176ed61d914968362667f872cff22884552c267b4c8f0ec85ff9b0f23516803d36d20f4e4fc7fa8a0c349a00f4583a8e4b721fe5ae85a3958690f09965a4205d7aaa65efc64c066403be8ee4a59ae493f73abac5a47851259f1e6e3246c0e6372c2a5944cb646da78a3e14a07a0513e05885192522bbfb5834aa9ffe1190152579ca5c3ba470610bf069934c905d84db413fb2b1b594a4997d2bb35818cacca6d24a0e91e6dc4ccef7b5117e30ac956beb897a58122f8ce076a34286749cb8ee64fddff09a27a2071937f9e78a21dd59fcd9d20ea39de6c3791b5281bab7062469c4c35888261bd0ee22d0d97afece00c4e5b484f1a225a369adf6e7587621204dfa75c871c7687003029c12b5472de8076b89f03a316ec52805b5642bc2c592bc0818ea10ab7f0a549428976d89eac7228d7b69fafb911f951bbaa22330665bca470eace85b910a1ae2095949bd16e05dc1cd27049a55c87f1965f62b2809de7cc458d4cee60ebc285756585b647cb8bdd3dd0309b824c4969a15082ee50f5c632a3ca57427feab0d87ccf0951e8cd57bcd88f4e266eb4e71e41236dfa2062f14019761aa4eb6287c14d406a08df039e6b6a036af968f075e67ca2e233b1be29d68349bef5c8e3c63e9a1e5e36127d9c6488481524956ece963ce24181b44303eea928a0e2d5da5bd4a3e2f3cfaa6f3cc506b74c1c57266340c5df20a3584d54ed6025b97bf460fb5c939362fab9c8688b7b44e4f66714c77f8254a026d876c7f4637e091aa087ebee456848848bc8141b6e293a491c3ecd0c8f396175071923fbea4eed654def3b7af314b82758fed87b085ede1b4e48809c8f18486877905df415a3238f049803c21c2bcada082cca26eae7d0a0bcbc944e31880e0a345103c627c1edcf314c9d78aa43cf33fad238eb88e2fadab33850f1b353e4c2a194c13d116539d14d2636924f5cde81e37bcf723bd24ae7e6d3ba33352af8e5496ee2c3d6cb3abd4788c813261661090f3c85a3fcdceaf0f816938422d3b40d93e7151e94d78aac18e4057717dc1b447dedd3d42eb89b19407282793d625bdb1aaad4862dd31d0602883c183aa2f02cfe4da3b2ce088a1279bbf3edbe758c498a6c5393646cabca3a02ee96e74fdea630159e60be3ffe114429c21ce6a311b8e1f2614e1deef074880012080b40130b41138da0d1ba1fb23e6efb839a9d6b3731aa62a414ae3f867770df88b772b772980d07176c2912436a64f996582041b52766431da518afee859ad03bc6ef5c4a748d4f893ddcd380d6a561110bcb21f8ecd68d86b8e714618a24fb289b57ba4fef114e75db2e789350a482d609fbd1948df74fcee2e44f8b79d1c10f99c3c74491ccbc54427410e897bc2014f63e9e16f5fb26aaa4188ad91a372663edc02a8d3b6cf3ad2072c853873a6f51a8e4dbc4a07ed6d111be1746876e9eb041fd1ec9f314aae299247cee8b46a9e2c0f18f2e5de8c24b29fc4527dc8c86d5aa828b19928753452a64267cffd2d804c2e60234abba66b0caa6ce427022696b17c34b4d9b450946ab861aadd5b2ba1100e76008af97a175460fe1186b3aa8db52a9ae5ca8cab82c60db8ecbd35cd9a3ecf6ca0f25d8a7fbea16965ac23db5b33d793b1632959832fc31fc436c7cb8bb110f5dc1dd5569b87973923fc63977ef1f6b1b692026d7b8c913df4a434a6f4caad83cc06fb45067ac53d0d17e1f0b0866ee700eff35950b4fb562665ff4424fa5bf6da5754d378cc91de8d7f0ba338b2df9ba4e1ab8e5f70fba80850f96d91caf291a574f21f1693a3b35b7323e99a13fd8103a14c44aa4ff2c71ba4aabffb41ed3d096619d50673a132f2488573f73f5529424f6b368007572eb0bcf218cfeb9371266bf15d3047623a878ca4e30f62532e015831bdb88e1f92fda20480378709649c9c1c5a3386614b95749ea09318a0165b0d465a09e93b8ebc143615a5671832a64ed36a57be0c910b88744f43c94f9a75652bb0364dfbf20dfd32dad19da345f905a3a7bd123476523b34cf409fcae9c08daf822395fd1d8e8081a73a2b7c9a0c228b96125552aa1c158e23f704504da96ca65ae09ff16902c57e360136d53f74dd4b24233c72769a152e1a0dcad87b09aaa16ecf8cc8515bf741da9c2d50a016c13dad15ae86d44b5144cca34608eed800a9543c8fb0e8709d95a3cfdb6a9b0237fa3355e2aba010e8a4988cac89c51bef9aa5fe5c86f56180b785531d7c9bc976026588380cd5a812d9eeaeb643782a8b0d2393e76c063106304d1e758292291a2d0f8af002a6787390450e70a4094bfa7198a3d4b8d586fea8604bbac4f12849d8096e43ec9a7551cfea64eba19e415cd2c02ed63e27d6876819b73f98024cacb25ba98ce8559edcbd7388a6623859e07e3c2d1bfab8555ba6295dd66a4149b0d1c6888a9252b02b72681efa39c2404f9982d6eb4908676775848a3f262e70098f275a50987cd6c65587628e9b195e078f3a7c9dd5b8ae88c45fc07747f8e1acac6dfb5a16346c63e71a14e7d16180e3dc890c51dcc34baa9525e9496616dbc8815a59110ed274e4f269367e46673d486b35a8416664850c4332483dbd39f77d5f8849fb1b9628f34d02c7b92eb872de6ee9787340456785c036a7f7d2430698900714a2749a8766600aa217d7e10fd8802dedc39aeb910f4e779da9553f29b96521b466e7809129422f7aec9888bc8545657dd5e93e64a5c107de45017ee6b32d38459ec5d56e09b9459132af03484ff615abf175e0b4a50ef4ea737f005e9315b86c844276817cc7612d1d1de40ca8965ce4ac43ecfd794f46377a8526b5b84250f16aeeee99ad9487bf5b1b39e6d7ebe361099b0f4a4131fe46a92763486bbf2ecdc6d2b608e9148b70ead89ca27377dd0300bec56729857e78bbed9286b6d5af596dd9b38adc40cc053c46a66e3b60c9dee092d76b28b9edab3416d5e2e82ff535005aeca7a87db3dac90906901f079338a8a5c3ec83499121fd5b37d8893304a8adf1a580b9a6d5e99e9a414ccbfaf53a10fe9d14e2a425cbeec27e83505c7c3ba1223064d103e59e7171b9e12ea862f4878ded48f7e03081627195ba41c023661aca5005b8f041e61b3eb9c159a0d84803871fddc77a8b94bf3adae8f6c4e21f6e04b78f831a294600af897ce24bac77c0c8aabaa8aa414703cc3fd95ba097aac1677bec95e22a5e3cd5d1448172dbc1d013942091f06b96477873cb4cf4a0ca92817ca5904d90b6655ac6a0598fb7ad1f61ed610d746b4eccd16e7153d0fdd3b63c666a008986345c65fbe80fa3882b3537d17d65c71c0eaea90c79d153ae915ad8e0ad94e9d5fd70707d1050d0cec205ccd92bf1d50faecbbbd69e4ee74751c0fe59fcd4c947ff9f6c9088d544b9d1ddcf224c0551db3c9a52c3349cf5097a200fb7da373141cceefa25eff940d9867b3d1186cb516dd4e2d47c9a4674b69fd28f032c436ee97c03520bd8ab777d785af8ef3898b3d89fe0dba29470d021dc554d9517849ce2ed16d9182c6fd037ebff14b708c9697d762ba1c4232ee0b60ac092e0888ea9ea63778b57f86688fd14c29486707147ae6cfae2bff8e68614eb2e940a54b5b67dd7a7609d9c9072eb2ae8264033e6d868cb79e7f4300b7d41b9430d438f2bcac567a9edeab08968388aa77ab97f253df6fabaf40ebda1b101c5c0af10cb537937ce9e2ca8b60bc656d18c52791dcb2898e85169cfa7520b63c9fdf7b6e61b30493bd48b90eb350d4b0b2e9ff70a32e1abcb9aa86a03129fe236cda4caba66901429ecda21dbac4a7fb64d2c88a31d60db4c92f06ab97dc05a6e08c0c69a9596afe41ceabbe2e7cf4f948db5b707013f524241841f78b132f9c90e3a8cf76c7772b107210009c2ae65a455320342e5620de42dad83e8180403f957b34c6e0c64fd0d8154e09f0c10cf4426fa5e3c1f48f0addb6065b74dc6a69394ed0a20e8178657cb7fb63936d4c2e9a6854f4b4dd97b3eb4eacf9dc8d557a25a3f8a36e4c83f76091350b9012e0859275269e745b568bfaa6211b653db511cf0cb676826714a0a50fbfea8725c827593ce0d81c892dc959bf1ee905d8e1cf81088295c9b3036946317654e1020a132c4f51cbc65b02f3e4071cb7329ed53cd6403e8c1e29d70c2222c9325fcaa8f498722963e8f3be3707b94b97457c2ebb091418f2bb7919b960f2ad639535018bfb3fa638ebf2118a14c3e941b8d207150280cb382f97a57ea69f29b9420c91b494d8d13634a458f010991810de5bc021f0ca0d9cb055360b24c22934309cc92b0e5a2a7ac2f9a82d6d18532eb4753673dcddbcc974bee701cade844020732f8342ced812a81fe4500a13e9672704404346b81598d771e766389eb9b7a5fa08db993d746f118b4fab48240bf29ce13b0ae9cfedee7a4dbc55fb099f15b42e652cb5fb61a349d159281e0b16f0fc3cff260e7fc7e2f5de1a2d1556f757be69963d3356c780bcca9eaa1ba99afda4df2b1f447592949aa12712d84905aba54b44f122af713f4c88085ee4a062f370d6f3f25f14325dceb8a9600d4d00442158e1670fa5f27dac5d65d469a79dda85a79f5686526a7999373335f6dd909f02c68a253e6aec71298ac7cefd1a9343e52bd1ba3111cbcbb5e7bdc54c87a09b793227ef9c26a82dd89af3880f57e5805dfd6b8dff79f8682dc892fc4c8701c32d7710535528bb3c12d31a7139da8fe7351bc33b17602234400bff23d1722327c315a21cf652a7d9995d27d13717b4d5fdac50f416fcbfd5d9af190094f1e608dc2674bb7807ff89bfeb72cfd3814c7c9aa0aec6a481a1745f131e12be2e1a755150c4ed605781329ec4a8440ff0089efeb20c24464365af4979d28a6736aea7713482db60bf4f86e8c7d71113026ef0f47320e3db61ccb89e327ef5aabe5d08e1cf1c712263ecda5bc7b2284ee55110c4716b216e293531ba9b06e2a445fed0b28713f3f29933751c568bf9e8482f4d1f5f5472681a6164bdbc92d9a697f0009297b49770cc84946dc56c28bf9dbe5c209314faf9917c0035cecd239af5c73a5280c4014ff21efe7f8de987b2852be199a7796faa61ce3c8f6c4e6c2680b5207dc9064738a7086c00d5f8ec506189efd7254f5195287bd8169b3faaca5c8f74a2a8c0572fea3dc33bb0029952a2b7fb0a6fb4ad7310940e80701ee1953fe435475d7240be7df8c150ce5c4dc021add3c6d0546caa7bfceff53782e8ea5faedbe48f6f8e9bd6f15b89082c51b3ac5e088ec8211182e738e46a4c4fa83b0c21c5a27f4ab7825d09ba552d73b1d5658b011add15264c3c13e6a43fe8378a2d3c370c9a17dc9b90f63887dab51e5cc9d61af752685b65752f5734e07f5a3238062c7cc9a99f542713b76a45dd7141dfe4b3e4e559971b2cb40bfb57e4978c8e2107779a950050090cd1e32e6013ec60c4615667e9fd1a7c743997e6bc0c8f92dfa0a7fac4c9fc531b0b1865ce534eca83d8fc8a85b95758d64f38b8fb7f404bd6406d3885a5b2bc84fca0ad63ce69b6e7ed567ff3ccaa183fea6408b98ccec5e84f0cd2cc70414e8178310a3e9df6b8e42b12042030faf4e59baaefe798161da4187219e89a0f43d9ef81b88cef554bfcd1bf3356f340a3b749bd40a3828baa4d5616d19a400e4c0517704b8b591194c0800833d6528b9d26223ddbc59a24c3415575a8a1d1fd8eecd84d9cc2ae940719025b41a9d1bbb896aadd321f23fe82e4e0699defc7cbda9884f2aadcd1024bdd55d6a143211848542a0827c7a7d159866bc1f0652eb6b4569960a2124458d67f5085faad6616acd6020ae7b5605e50d219a70daa5e9ba8674cb820920a034c378afafe363266563b9fb13b5ac273c98c57b836521f06818a9cbf7d8bad2db0b4bc260608400042084035807e97432bdad6d835d5d3ff1c63b931924c059cf6b715ff134288a4d0caeecd953b3006d105f305f1a270b52854bc95d696c770ae3d8e64b5478a97eac6187ddad56ab55a59986dbbd841682d8e315ebbb22bbbb22bbb6ab9f5e9d567c52ed5de9662af3753af74e66bbdd2cc62b1582c11965330072c1ef017a3b85472a7f5634b5f62cb55dcd95fb0d8c59d3b98bbb8e3d6373b89b6cf39a7d378ac185b612ba781ee115b456cb5f2248ade7b6fe6d8d578c3dfb4f26a196635be6abd58fd5bb5cd6e6b4b5ab1ab3d88daf263f6aa6fae5953fd42dc1e76b3da97c66e88705ec65231e6544ee5544e99b6454d8b9a16352d6a5ad4caa25a4e23513aad548b484bd5ea69c529f786c3217dff394decb9ab24eac7aa5f13f5db327e3187a5c34ab188b022e031f19bb8b0c5c129a4546abff098f830ae8aeb21adfe6634ba34d1bed9c0cd14dc112740028af481141441c80e2785db0197a487243448921a82d7a7309ce0ae9a348413dc549386c0399cf0085ca1624baa3ecf592f33447ba6bc9962a101132a9dae7932b4c8f8ba53f336f054f366e8482e2351a8a56a1e07b4d5bc1b00d0d9457c1c31ce1e98f82257786992bcd0cdf65a5af102c3c284fb9187edcf45b18265da767930a1739609dd7c165d888b0266b3e8e6c374a2959d97ddcd7fe9462c3f566c9625b6ff4b37df85658992f6a45fd102c4dedb9732cae5daabad469be43212853aff5cb4f2b3c32b28e32cef457c0365484d705e46b5d88c6a61a12bfc64fb73dda63db16512cfe19294ae326a5bc11837a3322a0413b3137ac38210c56a8d3685156a91ff60c7971dccfeddadd8a54dda2bfa596a7973b568ddc0182f3336cd9ebefe6c052cc7a62bfa39b41494c137ab93686f372426382f145ac118d9fbe7aca32b5a2c7b456b050acaf88b501b88f356b450db5ba0600cfaa2d08d68631ddc79c32b5a2b7678216e2fb4c237de0442b46136758bd6273fc3787c61b95ce15ef24972ea234f8b369ca9baca50b6608412d0e1058c13526080037c7ea2cc5488c3ee8c314a7902d30b1827a4c0801d9f1f5688c3e6a4c0a4540213e8812a182f6620657b2f010a446002a8fb02c60929b8184001de67fb17e2b07bfd904229902a185208234112d28221e5236078882898edc927b94167c7ff08c8c839264feda23325b961bb88795312174440cec0243d5cb0c5f2239396c020a414c258128288cbd1694d5f290f5178c0f8469800809120bcd892c788ca48101c8f0ceb35220423537460ce49ea7124c7911f3f8ef070c40547861cd939f2736489234e1c99822407121120e901c911244e902c81e40848aa50758004aa1d725005a12a420504554b45856a4a2906f4070d04218220253a9ed041084620df86861b478c28108147e80434b64794315e3a424a086b85109682e020d49e949307ea53248aed71a41c8a4c5144097bb4218f111c96cf5edb3dc79991354093bfe739e08cbc91267f2a3a412829517edb258ec7f84acf8ec5a63fe847592c9614edfaf407fd24655116c5910e6728fd284bd60067ac0f68f2776b3f8ff1bf97e37070b6ab328e9ca1d447fce839a0295ab79f673fcfda24dbb31c56563b8ce503ce40882367b21ca0fd9c063305bd14121087ed875d6b2423702b2bdbb66d9b9ea94b594eb312e5027152486fda1e65799b556d7fb9c2fac179dbb71d082034158c61df1d07677b38073803a10948d240997d30067d7fcce77b1990ed543e8824850392b7a3375026bed5b58332f2c7f31c9b640417bf9ab061748de5e36c2041214121412141214121412141a9df77b224289c3753330585f3cf3f28726a2762c61afd4a3506f6c5833c9f7051c6f751954a06e909e949aba552919edc1b4d90492bd26afec493cd3d491db2fc2c3b9bbcd577163c148281e138699a73eed864ccec443a82f342d9b59931b3817b4e782f8dbecd94428a728be0343a783c0a3ed8f7e1fe0b2ec42a90841f62bf6df34676f85a8135ca0edb58a723e6ce0769b54400ce4521ffbdd92374d7a0d52ec4ac67cd1693ddb5b1ee7acced5890f5ddb58b57c515c2a8abddb683214db7f39daf7cc17b69de8d7da14cdd5807c36364e73b678849cdbb21bb79c2fe429a0a004376737bd5135e0d037beabc6f4c1c56561d329449b880c80b7a5c903d84433401841cc20718b87b15434cd94572906a28624311204550241a8ac000872243e0a0484f11248a00158912040a57b9fc600792920f241f3c4300417da0d387e861938086e021bae401aebecc9f71f6d79f32ecefc6f25f38f60cecaf3f611a4299eb05fbec5faec7b1330d03a66d58ec4bdbb0d8daa3a97925162f25a5205c7c2f0529057147a1beaf14a414a414447a7c1b38b50d8b2db5fd2143179e28b565bc52d3cf695c3ed21e70e651a61863cc32ac36fe94c748953449baa487a62034d54abd168ec0cd9f9de8eb72c4a84acefcd3253da0c9249f86a8078c91bfe900c6d4dfea6f990c06e8d831fa1da2ef338dd22714fd0952f4d0a57bf1273d0e1446dd8beb171646eff23546eff2fe2e7a061f5cd77079929ea1f42e3f03a9d489be2e66324a3e38fa22ed42ac22c289df129f65a5cbe6cbdf584ee3f212030034c9e71ec299c7d114c7435d4be7b5d8f5593a8fb4ebaf74a21ebe37ed6d3ad8f2b5cedb3cbcda5a22d4968f3b4f86d56e81a6686adb77147cfbf20160ffd238dbbe4b473f18637fd441686d4987f3b71a4a93fbc316686afb912447648852219997b0d89f9fe1952da9ce864f5190467bf8f406483fda03d6c4d72fc4c0511f1bfef6398da629cb63e4f6bde042ac42739ed8858ecaf9210ad77d0cdb503b0ef679ce8e04f0bc878f1dbd952d593146c7c18131ec86b663b1298c917f2ffee6ff9e396ca9a9b66f0548d2c81fb9c2a2126504da64c476dcbe0fc8962367e6eb89e392b7086acfd46672a9a0ccfcd20e17fd274babc1cce98132d3c3397b7e1b2afa20be903ea7c9e4b4c675dd4ffe2ef1767ceda96536afcbfdc50b9fd9c9ee4921a594d228af365fcea03ab44b40380f4b61e3d83093215fcea053bed4534f28d322e569e5fa4bb38bf5a5d989d351472853b3d3762f99a580730d5b351ad7dfbf598d4bc37018573661263f660b807b5ef9c58b2d331a5ddc0fb834f4939d73ce79b3d3fc15260c27bce79f70ac221fde0b65b2eda42f6c2bbe106bf4259da1abec1f329c97839af6e891a9e6e1f86cc6a40151d0b1237bec77642f2c648f7d8d4c631a7a4c8dfc6df8a7bae79f649551ca7ddd7ddf3927a594d27dbfd65aabcd4e75d3ce5a6badb5fb7e89078bd56ae9128f2b5321b4ed677c6bd5f6afce5bdc77c6a5e90db46101830d8b6ddf86c5a69a45d533253b7f5a654f8a5377a6426fa48e5bcad9b1d80c701a7a0363e4dfcb912213ce86bf7f747d4dc037d46f7086437e2e925cfac535f1051b69b69cd390aeeb6de7c28d1b8b3fd75aade682dd8ebb0a09102fd791619602dcfe27b85dbb369962768adb4b8dfbf669e070e8eeee515eed34317ea15fffc55f9ff03e612a32943046172c212288540ff2acfe5344122949807424a1a283122018e39c95f49029d9a9d71132a98a6f478711446c6c439e1dd48ecf95e0cecece0ff42af06126825d28eef4b03dccbb3b3dd80102b521939600dd330c2e09dade5cd2da4b96f08004abe41384b014e31425462845299508b104a76a67d149e9ac3a0cd18316a08068304283c0711f3ee88c9452da81276ecb863c4a76b004097fe1eeeef1dda364919c7031250f5e488f51484ef4c0c50d8e0e20df0d8e0e484408ba43553445895021684ae6fce5001182fa72807c3d3b55555bfe94d24a2daa838e39ccc10f36c43c6cff608cfb516c095faae44e7c02c6a8fe63870d3fa296781223bf9cd5d21665c126289034511b204250f5cba9403e38736da17484089142e90841611886611886612bacaaee4efdd9f2afbaaa3d75479a645559abc3ded4569d52836aeb6689a17484089142e908416139e79c33cdf96780fb5e141622c4969f53281d21d284ba321b0c0863612b2c09ec075b65386706e79c79667d5110db159659966693b03fd264614409b942dc144a47080a833a6ee0d417cbb795e9d8f2b59bed4eb941b77512edeb33bc2e795d7e5d2a78f55c3bd2242f0c9bbe441ce56a4358845f98dbc31ff4700e068243f88b98855998855998855998853ffcd14bc571a48d3ffc79dc4ffc45ec5d49ee906aab15e9a5ba5497ea525daa4b85d5bc8a5f4e0bd5d269a55a445aabd56ab5f26e0506bb92bda8afb7755b4e63572b8e23915aba52ecd2ec6e638cf1a22eeaa2e0f6eea51545fb5a7badc5d35ed445390db65a71a4795101344af73929ad93d66aedbd97bdd78571ce18ce1896659ab665dab671dcca0a0b4b4b2824128d462eb1258644ef516a386424000d628cf1ce11f0d4c0a734a434a434a434a434a434a434a434a434648390db9ee3b6d792c0c5bdbd7737b6b96c5ddc5e6d6157fc4bf39d8972999d5ca2ecfbb585dab1f484f3306ad381104208e963fa174645dd82b4afad05d78e75b9d9f2fd29690957014f9588701e558954bbfefde4cc68cb2cb5ede22e7ce5ebbab4cf3e67415cdc1a6d656ec3fad2717b0ad211d07834879b89549bc3f495b3e56df9dfcb71de62c7f75a68a82bc7d32d3a251cce6b59a1b6fc96d5fda4497a6ad36f69c1966f31ed72034594623262725306356cda4d281323159a7af1228a7b5fb8704182624e17f0882522002209523c61e2060a1a1e54d0008a8e1b20a1841aa131e4a6084094fc180105040ab0d500d596ff39bbb7427b33dbc0db9cef533f8e9f218cd6f667616d7fedb30a71fbdf0bec187cdbd05ef450012cef33a377ec43efda6bf96b03ff7cdc511ec4c7bfdaf8473daaedcff233b877edb5e04f4fb14a96b567f81380fdf68e75f659e72aacfc7caef3645829207bd72fdbfbe39fddcbf6f9e7cba66df0e7cf8f9ffb8c3d7f4d21ae68ac6d60bf691ba3f7ce9b5a8f1efe4843918ec137cb87f46cd131f8d656889d77637bfedcc56c866309eced6b36632ac0cb3ebf17836f4d7b1cd8337c679de9f931f8c6536e8fc1b73b1238f7546a7bb602be7efa8acc71369cf670ec6edb7ed3db9fe0dcca6fddfcacc34e902bdc6759f65c763ddc59dbb81ecfb834be76f6f8b807b5f13b363b2ff3b82efbf93303dad7ac6df8e3c7f86558ed955fd1ddd679f96797c99d759ea62dc60f43e7e5f7ce936155dad16517fe1b597b37367ef8d877715f97055a1840a1e053524143153b7a06e29654d040c58ea28d4314371c38c133044f121e1b541e102c8167042a1e1d18e808a209124d82d024094daae0d9c16343131a9ad8d024a7090a9ab0a049104d8a34d9695283264e980081873319028e6482c91349a8818914dbe31e0a93540dce24069209115f64e2c323c424cac61bf2303922c98e38e743082184dc7608bda32119188cd6bae6dd6831e3bd552ca1ca8e617edc9c8c11d5ea756af46b6623806daf09f56f6623803d576cd39e7ebd7aad4ef57dd922a041dc0c4282e336e461828a7167ca4e508c514a261f131c086594a83ae06cc035e176805043dd6102654412447670e2478a1c31d00952a73002172508eb63041f4b70705a33b46dc8b3a4044ce80d38271c5df2e550c1b9f07016280957a9fc7042e0a6929df9ef428993383779efcb494e7ff9e5f9798373e62d4629e529ce885a5fa9e54b2152ced3cb8c39fd469e73d2971a954ef927975149b5933a76f9432bcbca18a5749f93d208b89d975e15e799b3cb98e955b1cd17b3f9625786b52bc35ade302e6f1897ad682cd84a7c96083b2fcaa0294153825a3b3d3b3fab9d9e1d55041273a20c6a4120af00d20b708a3046d72f60942e7d523a69bd98bd974dce38639896699bcd0acb0a0b8bcbc832ca4e2d2ea4ec24c24a23166c25b3815d4b0e612d994ddca2f93e128d462ee38892fcbd79298dae7936b66bb9eae69c9ef5c59ec9f0399d7a66e3b2e52a9371b1fdcb5a6bb1b5d35a6bed75edbc927a2df80ad3bf191c6c094d724b9804476da4971434c76a7ac762e31ea7d1a6788cdc70b496d6d25adeb2c32585d6f218d9826a6df9a31d3952c9993a922247407214458e7eb6fcd9f1bd914f0b95969ca14172664e91335e69f51bc7b93aec2363a4c63d3dd2847db456cf96bfddc89956d0148dca0ac68072356a1919a9e81cb23db883fde56fc68ec5c69f7f9a76dfd354b5bea7a9ea1349b6d4542cad16950664f4c9196f51b5a85a542daa16558b6acb6f69d969e99133d567e7a7d1f691aa479eef32c487d15debc9815bffe85f4aabc1861b4ae290e9e76d9e328d98c1802135b9fdb55a5f8fe168765a298580f3b0fa83f3660b08b8100d9cbca2bce0c59a7caa4f38f6947306396f527b34b5a94ddd44b64771aaec1d59661fb39732ebdc3d9b73ceec33c5b08e524a69566badb566250f70f8edf5b1aecabf9645b55611e5558b0521d48600b8217168524425fbf9344585a0f32911137e0f1bdbf56b4fd036c0863c4f887872c3366dc8b3027aa2c3ce3b7f4dcecef8d64a6164ad354064fe48afdc305fa90e69073a825a2b0cccd50a980ff327c858f3d9b75f3b9a1a85583899d9d094d4ded5a2f6487bd214b771cc20a5c7811a2179c27c0d9058133fd7e82061606a82c41af9f505e6457b72e79a9c5db9c9324373349ff678f9a91d571570d52f19d39e54aaf96a8054296b726a7232cce3eb226a29fd4a95a7fa2b60bb3ef7951e3a49c3e655d3b373c639c3d400d9f5e94b97fd8a2e7fb4ddfd5247eab4aee693268a591ee3efa2bd3bd2de15e990f6b8ed24d28a6eb11da3385455138456fadbcbec543766390de791302be36c99a6b68da9e70a71d32ff6f3d3cf694c1ee3cf7ddb392238f96dd415b09ddfe434b407843c1c91ed5f1324d6e4faf8afafb96a72f6adb5d69a209100548b56441728a6383182c449122735f081131638e9c1c90f3e41f06939c98145e8684539420e24d8816489130fe8e072109cb4f2941c3750820f0e680f6a143e346c1f1e3e1ef001e243021f94cf0afe5df8c0204a8c3146771a0c84a5e0204c25ebc83700d9127f9ea3438f3f42fd90dd270dacf5f518190a711c75b7a7a9e7ac71dfe2ebdaeb25be0d9ff49338d51aabec53a5ee4a70de9cae71d43affe45a77207799d6bfd6e66cadb5567bb5de92119c77f7c809a77dd6329426edb3d66dd1a5dcdc7dfb39e7dc9e524ae9566badb56e9f2da675a51f0efb8ba25a2d956acf8f65df6abaf4c3ddb7d9679c7ffbfca74dbfccb85bfbbb35edc1b0b3cfda8361e3c7b167689fffa4e9547e9869fa45fbed5ff2e3d89b8641d336a29d556d23da72959a7f82576f86d56ec1fdcb4134842ebcac8a7345136eaa009aa6e7489afa79cc4449d394f5070861cc87923355a7aa00ced41740d39c9f298ae605707ed5997f80aae3348ee331f375e48ce3fc5075f6a4ef036acf71f47cc701def7362a57348a8c991f250a109014294173cea95dd3244a45705ed5c1d9b2eae4120efc8bf1575eb2c1fba494aa54f4fb6aad55a5b2d65aef64dc7beff5aeb482de2dada07777ab155551e5c5cf7bb1571c9c71cdf793dfe06430d88864127266fe2a4af4eebdf7ded19e5aae30952c6964c9713514f2591dca4099bbebef7861213ffe1a195fbb7ede484a7078d7520e9438659fd8ae1f23c7494d52e2ce78a1b59a1ee1eeeeeeeeeefee21e1f4677776badb536eacbb752bacf3929a5b4d65aabb5d65abb5a499444b55a2a15eb0698db88a0b56eb11c3274ee5fdee36648317c051823bf763052c830606c9a824c41ceac006902006324eca971b3b5da80ac26b8e503d8f2efcf4e343319d586ffefecda9331df69eb092440111445129430458a299640858a2a68959b1c34d4a063078f0ee0f4b0c1c70d1e80325246d4f5035046be8c58718032f229853b3246becffd2101499103684953909ca2a9ea87a4add85202025484c8a1870f40e083204ae88cf489eb53c4490df7868534825e3a299d1758c2238a0e537c504c8043115236a9090edfc018f96736b39ad130790cb4198d2ca3d909fb0ccbfe043933184e7867303c667eaed6de4a5714c18532ecc68c86d41e7bad6afa42194c5f2863b353b4d763ae6c6218e753489ae063d9c914259e9834cdc734969de65368820f319c9de68432f9ca301af3f1b3003d067ece4e1662188661515e0dfb0b65e6631846acfda6219499afbdccc07163dac3c0ceb4260d81b3815fd84a3d1cdbf52a2743173c45a436e4b1c10d3c36d061e3d5f6048599e0728850f2435c96b6db5650c629cd22545c516547b955906f5fc3bdddd96d1888f3387cc1eb76de04c2df6a8fe6d812ca9bedd57f51c1fefdab6ddcb72adced59b8a916b56a15194ae80e8b28e2676f4964114e8a506d12bdd9f186460bcc027767e8218c51cb1fe873525aaba5b55a7bef65efbd2e8c338c1046082394114a08238411c208658450c278619c338665127ec6b06c93f03d29448311fec6c9087f054af810c2168450056104123f18218c104628238412c2086184304219e10b18a5749f339c98a8f4aef416316434230008405000f315000028181089c442711c07233d51cb0714000b74843c665e38160a645912e4288c72c618030831040018002033525204024a0fb26ff31005c52a52c7c6129641a4167a760829f59b097c1aa303e9c32e4eb8b70d0c1f652190fad9bc65158f793218028d3524abd44b89aa71851961c7f72a48fc32793b24e27f71aa49c6a7412eeb6b67b195cbd9aa95d7131096ee4c58f690b46a6555470f2f7b574d22147e606f9a49b682848b01ac5651112fdab225e2dcd080b04a74cbf14b23341acac8238489de505abf07dc8594a0c4100c28c988a302205fd66a6bc4a2080ca341e77e2e381021bdb26a299d5eb5aac7ce33a665649969c091aa18f31072f18b28e475aff9f8ee6df002fb41ad13d470d26b8b4ad01a01589b717736e79ecc16a3155fc361aea986e4fa607677a9fa290aa4e4108c0a5f33c793b9a9a670bde4dd3dac93ee7e0af4b9efdbe47b7ce7fd91bc844659c449940925e1ad02014f8ce1615551955ef6f5bc996043a3435a8fcd9dc318732c8dc72036bf24990c2a262857169759a097f1388923cfb0412b14f868d83b98b24f0b2bc4c31cee0af6d33f5501b62cec77b10983496ed92b2b04794f9dd7df3a9f5b10ccd425874335b34a3d44a4c6ba28598584923572e07bd9382800547c905b6d26f82659cd5aa30c19a0d934f1557975affad16e048e926295fd3d708bf95794c4d0180f899faa1ab7453d9de2050ff8ad9af0b2ab8b3300f9f63a563e8bb7414397ef1ecefde805bb7f12a182828d5a791a5e7ba8282aaa1dab74e4e53b92bb98d4a324491a9618b53fcbf455e871baf103e213081beb4739bfa328f3be2be3625effce213ba3ae9ec8a5a9b46e46ca3a390a6d243952f9567e418dd3f8c2970ee9c429a73f09885c865a2d07709308d311ad1c9156c1dc5343298709b3eca2055014ab8dd3e6a802c5c5a8629b945da2656a8ff73fc066b942494b640de573eded4c3e8db031600fc290782461242e5ed64221f596c229e4572d5e07fa6a6398568cc9d1ccfda61993281f40890aa90a04b873874b120dc647200255154aaaf43912b31e9465542655a2c5292f60201e30482625f90d4ec6cd3bcdb5e138ae242db698e57f4533a3d1d01b9b0d089e82692d57844caa82fe6d4cfbac0182471fa8e2d0acdf26a539896721e9c647004c7b9f437b287bd6e797a8e70e7ebd9ee527c3682859ff3be401c46f7892c317061048b25ff5b30dad1271176cded37669453544792017a755ac63105fcf2bc7e01b5a53ef930e31dee34797a3c424e0deb6d172bdaad6720dcdd4406d90468f3d1b0c40abe5a40ea418436af7344d28a3c12316063c7c35b04ab93a5da4a4e4c849d6529a9bd9588f77461c4a4bfc3a59afdbe8217d319311873c32ac2901e9080f37a8c58b226b0c25e1dee63f3736ef53fafc0ec2aea89e020b86c69066f4478386fe234860a604abe9fafb28c9eb5e9692fcb2cfd2e4cc32be58c62db8d10185978240ad81b4916a3b46e78e9ff247a7c66aaae074a705c6432379847b096a8aedbf84b2ee8291ca6567c8551c2ce223ed2f39838e5a05a9bb9fb330e46dcbfe6b2ec0598cad15f44f1c2f310f75c6f4d3080744b1d7d890beba1bc8aaf30631e45a9c589cda01b6400a44efc939461287020000d0ff8d6b242fb49a95be45dcea14f292bac3fe9e32186a3461e4f44e1a6ec53c4fdeba0c9114b743cd9a73c5a533aee61f2aacfd25fc53c428f77734ea63964f0da375fdd005fa6dafe674d085fbf861081d15a1502acf857a15a2579b0cedc7664b2b36e704e6b627f41fcd8f4b81a6a711d153ca0864c9dfb656bf801f64d2377b3924c49aab7609e528ce86e6351ad0ecf9e09b1ffec40d3d2442dddf53aa70dccf534694d043b86510d3eba07f050ca51aa1aad225df9fb226ab68f7d8fc8cdc71928bf2cb70e0f0328e1998889cf5e08d503a0abb78d882de15235dd0a9d8689a8855f376c772aa08eb7b76590f3433757586f2ff45338c49aa9958a7afe85ec5ddfaee6e08ebc9017eca7b7dc1b0a095c7a26b59a352f5293401122349168dda1595c6103ab60c4484dcb368bd7ba8b0552a3a47cb9ff049438bc611bcdcea1335e6b4e4caff5ccd17b568aefb0869e59e8b494711e52cdfff0a58e23a3440dae17fc682e6902f04720c8771c0367e2324706153d2ff039b4a19991abf8f660d3725402694ef35897e3dd150a5f3d4b14cdd5105f93870ad6aecdcfb302ad8818bb8d88fd68febab65c4655ff44d1db9d1768773164a8af32e10291e21a037a7742eda5391d57c529dc501696a05d0254a26565854bb10a1b12027a77cbf2cae87254c06b1e234ef2a53e18a07e59a2c44bc36a8bbb60d687a332ce1768ae2b3c798e143c4742fb44343c4cbb69aee6f110d567e25188a01b2b3989d5d757f809a1711f768344ebd76931abaa0282def5ce4978ea42283c88d72e49e82e0d390264cb337cd7cf50de7c49696adb3d1dcb941bde2bba1fa6a34b51bef4a6fc8636f68b0106baeaefa731845da77792da53bfa8b0939247290c97172a11dc78952780f8a0e6115d69fb6b76de0a72faa2681e66bba4c322930cdc4224d8e441fa729d18b9f639b5c1a2d0faa86911cf3787aa6c8ed935f1e332e720be1b11df6d06704726055a220a8c78b81bf0bc13a6f2db9c4050c4623e57fffce2a1c4a6d2c6fa80a911d5345eb80e45b740e4085977b44da459e759d82a8bcd0cc89d097ba951bbf772cd7e55f150643462c1af4a00145820b9cd1b526e091aebab53dd5c5e3c9bc3f7c5baf8d02c0b53ab09caa9049324f95dd69d1533a1b569deaca32dd5f6ad07b3e15135f0dcece52460ac0eb6c9dd791b2ab1d762efbb14346d0d26aa35e98646ca860bcd1bd226df5c72536b9bb05b2309926b37938d7ea7cb21f08a45841e772d83219e2c917444ba8b1b56bb72c521def17a0c03ac88a2c8739a0139db7e041ebcb843470b66f522824c5c81d3b4f80aede637a6e566fd1dcc73d21f49ada3db18e557452cf587f306c54ea9366de59d6e68802d771892eb626eb2d3086216d06ddfa32e254cb6db736deddda60f0d636facc4bd103c96d83ab9c6ac6b93c1583b533b654ee6cab3a4d1a0b4807da3252479ab4089ee41b26e1822a0ed20d34000688a8e0b46f7491096ba9f5349ee3c37dda3fac366e27ab78e349df32b96a4b2d6cf086694fffb90708dd138695f6a62de21be8f63540a8451b7adb0ff91fcba93e677838a4ddedb961a4d28a2d35b13d7561903249a80199d5d57626627da3da0636934eee2d7d26f9a6c24e256fae51b4a6c232e4c420a1acf3c13d84c86155f478aed8053608fb8efd1c8b3b5a10dd5e3f571ef4bc51b5f3e898447ae7d1f44a0a1e082b9accac17481a7834f4337881173dfa264070e726dc87ee3e1a5c907b91e0f4fb7985cc817d6488280b9f32a4553a3bed7e4263338975c0279e18c31f7d8c636e833bd980b7aa8c7e8a048b4ec6ada42c42f13a8a2048f2ffdb98e176f83aa98e60be9556e998e22c40e13429ea6a189e0594a3011ff03902ff80f0225729caf662a2100ddf1295513b5e9a5b97a4062ebb5b674a8280f6ea08724bb25575adbf898aa8afcc9263070c760317665b3c67071eacb2781c2782fff2bf74c4cd2d0896846705d37ed84ed44897584941fa86091e16acf12c2b369333a376b8659e19f8132a354ec10fdb4dd62dfc7d3d0a30b3c769fe2cd7552bf4dcd0832a989e534268438520a9e7bd167896f9e8e204658c78d3d8e464fef470025e04f96ccbc6c657e5fd521e5c7112fafed3247722ecbd17703654044e68e0d55f9cd0e544ab7b2a71757bc28214a110042704a0bfa0cc47f837a17c2b87a4d2b88d6dbffaae1dad17e5760173477807c0b752da75ed02f580cf10edd9f943e7c767dc627803b658ab4cc2cad0bf32fe22da5355d8e1f687fd96392a025ca95861c406c36d5bc5a9e79b61a2b2e0e582248c9f515b04e508f072b91604c9d51526dcb9781db9ce1520467a02f7adec128fcf71a519eb4f76c368c63a26dc333eb3de89a3726714f3fa09de19c1b47ef2b78d7026aef644c908944100cd7fd63337406f932ae0b2f4d6c0b5094d60ac77747a229a9ec5b5e4af31bf5bb2cf829aa7d7c2eac1161635b6ec1a5baaffd3ed5fb974085b6ce511b63ae8af4fad000069bffafd2080516ca2354f77442ba5609b080a418a8fdfd607bbe2d19f374437718f2403dbd963eb73545e80cb6f64ded27e98dd312fe7687064f2ae03843a9a9d6c7bf32944b565702eedbf56bce24bc3a6aaacbcf4fd48a1a94a8a75a8583c938f6bd5489d50ba89559b6867a308d09eb8334046e6692030718c9a38365857eacc31e934b6674c28950013b172a538e746e891e757189e2b100c4082ed4ac6e23fa71d7bd5d6e70f3a668081bd5163fb3054bda7cb4835205271f6ed74fe68d81156a4973e47612be9549c00be4f77df5da1e5799fd3a0d2a100a8a54d75e37332241000b2382c0f57a169af457212c0126810c6aa38fd5ff49b117b320d9eac9e7f50ae5adfef2d59109a7a06a2aad504388a9b89a6dcca95a2e29751ed70920fd699c197f6990a2dd9e69bb9f5fb10b3d487f1adeb32c09e3112f08d044c6dc295620d244a0891f9cb6ffa73da4d2304663d1da6de73f44c8695572f5bdbdeafc9f65a81813aafb12b2bb0ba059fe64c9302b2a73b62df1b66ac8590a24b7c780eac59e6fb8a3be0a0821090b7f894d137cf9444cf683ec9d0d936be9b36466fb7d3e075aaa5505206ff27de0cb7e93399b1ad73d00b959eb84a0fe6d4d784002c2a021d5e00dfab6a16d227b54984fb31358e85f82db0ba04c9bb1566e1581891f649387aaf729f2444a092aa266f4eb7744523cc188490ac2f60cd77a60a701d8ad69e48d02a8c3f2dd85190140260953161361d9261e8b278e2205fa1822ccbd604767473846dede918ba1c8581e3e6180a66a8e762c4dd39b9e551f4abbb1191830d99a14661bf96ded06fcbec815a2ea44b8c69749a69833ad38e0e60e78a5d2058183616dc7b38b037396d307206639a913d4c02a63182fe4d30cf8d61c5d8c388431ae958e81ee286b25376d92c16f3efab7ea615620bc86f912c857945bfa79552c1c7a85ef051f8237ab9d62c840da0a0955b5383a187d5fc649077e58a7db0c2f809e1a50e5d4644482714e35720a35742d4932421aa48c459e96fd07550ac462e88fa2fbdf967d0ec06cc6c8001d2000333d00c9854a1fee98d74f4745eee8f8a1b9a76b9da1211a391111f357f6cc83b0b23cce55d8a10dff585da7700e864a2250f782de28fa1a9a06b2a3c7ff846e50b2b55e133c797f85748a63220572d59a937b2d11febc82d83be41bf7df4eed36362d028f3c0396099693af663c9a9631836f8385118c107e117d89979dc7bf2586eec4d9b5d9a8e62c84140cf6102e6c1f2983b792cce044d45011ce723b30b2c03941e2480392ab83779e154bd051d0e6cc76c4d762b58eeab5ed2abd3f4dafcebf5f7c336a16da800d018f98b7a77fd11b3b278940ac77d31fafef9abd0091243e452b493a90f3b3ebff57379fc3ab90c639601c82de6ecaedd0018f280e472eaee2184055f91862b60288a83f01b9d5c62de5a5a39df7becf65ef22d8c7eae8283207cf2ea44daf48ef9d4280c25b6826037b5d8eb372f4310a327842e56a4a528038427a866cb40cfd8d8379f23f2b82c58721c84f727d0e60665d005604078ba2d2959fcb5a52e088f51681b99d448dc76f19793905620861745efdec4c6921f4b937620845572f71c4982f01b74cd4da5b9f7f4cdb886c2b06e64e6182c9957152487df34051700d5dc6b4a66b682db38ec104ccca4a43c6b3b15d806e1274170e8efd37759c50068c900e1b26a8cb560f234a1d9b02426201a919432b433530fa1ebee691e90968729ba0672660d8ddb20206d8f69ccdaa3dddabab3292e5e1922fc8a05bb357637035cbc3b05782b17b9b5ece66648781f4e116be06db3103e1a774deac45458ae2d3afc14cc8ef36d7b0d4b73dcd6b2c12489a462d60aecafb3739bf7b4e74891ce12d1615804eb173c23675ba1dcb7052729569b911210854db4c18ef98bee94006df19910cd827db853129de3d9011984a3e48d118ab53f8d9210cc2cc8448c12aaca6cb724d482ebca52a66af850f52abbd8ea9935587d4c6040972647c0458114f9c1266b9eeb454be9aa45a4efd904f1bf3c7fa5787b60a811b77d00d7d12f38f1532495dd4ae492d0852530cb3dff9391110309e41d634fb704653da024d943890143d5bf38745d0a0f2c17740affc7ddd6685e7609230c94dec449df0314eb946c3b25ced9bbbc13613725a1d15892c72430d9429c072c2d41e1d9752ff51e6b52d14e6c92ced94534ef2a6afce340f895a756bb26fe0e7fdb975488a5de45800acc5df04cb638e22f83ad5a8266533d8f23ad3d4483f78d0702f5c8aa822ab36d60bf3d5c263b8c28c4487c12f08f12a05ea002f74410b566965f78b2d2eb656167508eac36973ff4376f3443141f6af5e2af036857dcc777c237178ae6b4bd79fa6b8164c1fab30863a86706e2863be0441b97defc1fa0332ad65cdc73714e053d6b517cbea1b67a010d84cd5c826f96da4b4e0ab7b9f544dbf15f0148bbb23e1ee5cc579bf565b6501896a7555048d4be4c631ad9cd4b08998c111d8ae06a5465c93a02686d47ec12410befa1a606b2a7ca7b5d02cc53c070f1270c4df9e0b8630c000087275013ff921f25da43e548dbba9f18b6598eac959ce8f09b0ecfdf5aa2bedcfaabc8a57f82b3789be9a13b3406dd3dbc6784f4723ee79ee90730d40c0fca0251b1dd1c940138bf40864bfc80c88ef9853dbed7c1f782fdd47b5dea362f357b48f4e9419e1145a2fece1dd1c46bd4f6e0eecd0d1598e4c834f6e75cc9188ef73350b4514267573987f826624b6620587fd01d4cd464b76e7851a955c39ba04d66657678b032cc163f376ae032c067c09b0224d9b75913dd25387770b27d02b01dc050a817cf0260a5ae1b56d03beb878eee27d543c3ca0b11033fb93cdb0081faf47a10108e9fd81fd695184c8da8c74f44a54083f8b44a4347f76e5366c46cf99b88df242ac3eafebc28963fc0c7215a3d56978f72289094fbcf08ad5522ecd24f1fd4ad10bb9c61f929284bdde2aeee2b3611c4b94ebbaa1e1109dcc828050c063bb703465f60d21bca09dd602eb2bc949cce91597e08954146af5a7493d28fd609a182c44105a241723e6e294d0ffd9e21de85de6e2f69d98133689226993fbe95f092caf7260791c9c9c5abdb7d8cb27f272e8b2ff979404d2074b933717a5dbdaf92a5d3004defd1764e185a4751716163a2d28f97540326736bfe75f42996baf022d2f97f2821c74ed606f7e1e8f7490dac3c97b4af0005531dc2d6962b101107edd002f569b18b1f5ffd6d5231604aac5537c6b2ea95c8ed225bac9856ed4b322532865eda24cbc54c8da3d5fbfb22ef55f4f0b91972a36a254f35824afa71bde8fcaa31204d5ca1c042145ea80f94f672ef0cd03a0d2519120d478eec0bece3e0be70fb9827165434df52d30caff62c09270f20c5cab62014400fcd452ba4a25e1cd4a70a906896829363fe94180f4a85db6db5fe8ab70eecb293211ba4a2f71481f3bbd1b1c29b3e8c1ebe8cf234a7a5abb9ec50abe5959ea61c26858c7660fffd3c44b20160e9618f7b2d223d0210ba00cc1597cfb5d30ba7a9ae306eba9c49568b804b94c51b5b122eebe096df12a40b804caf6fddc0854e491a9a55922848217f64ab69bd17344194efdc28e721a0e489538ffe10bfdf56b6f225bcdc232aad28ec8cecc6c65bcea4a3cb65a7bdb032e308e68acb7e843eefb5e4c8317d57fefc74d9cb14fcabd28f87755c437b5307f2a90040253cdcbfb0624b0c32d4dead087e6fa1f3f435166921c27d009791567453d1523915eb00e848b6aff2f95f0b792e86e13f25557809f95ee967b4509d05a32c3b05eb8c6b93edee1d31c225cb61d20200944693700affd2488c8c0236d93753bf065f554f6653580ce98f14f7ccd2c1290718fcaeb7b437c92dab3732ab8efdc3ea1cb36a1bc0f9b80d30ad8f195e21ce392d64bd6d6d6b283d66dea53fac9ebd7cae1df4de4e66b0c5aa7a9a23b873de2a9ef454a877811bc9dc233f864ae5f803aa1ef3aa7820b558d61f9624b9020ddca42cb64e4a78fc86d5d2b5e29c591770bfd5e666e5dedffddadd7ff76ab798175e458b7fc65a6a97cedcfbeb2b372f6fdc0fa78b7593623a69b928443a7d192879fa4249ca2716af3821506ccc7f0d30f1f04e8d750758782eb8fe089f9c755a76bb4163ac004efd1f7931c266fcd955cc69b803c94704f2a5718993c30b8c256ac0d888aed4ad1ff65b20393021868d29893eebdb64c0fcc5fcad103cfae82cc67201d87ded7bb22f342cf46a32ad3240722a22998b7cf554d82d0bc46028f24d50c8c07455ab83cefe6323e72191c8189f071e49dff1384f9c1711b9eaf100f855640fd20d89cb7a749f5800c6d9d054bde08949bea986fcecb0718dcb5137c26c4afd9f53f931b4ee926df6d07b8c1285a528298065985542ab58fc61d7d6090fbd85aa4bd4f91b0a22f4301e7198f2519b93eebeb1e5f78fec487500f1a119e8bd528ff4fae43b74312053d08ca89393421bdc69e128ea3489de02e925eec72ba99ae1c2a8152c9d0b6473020d0433aed9858b3c9744b3a4673b588ce581e60420bbe01506ccc0bab957e9972efcc971a7770c097c3d94315dd1620d1f4fc90664a825fbafbea5a41ae01039b19f7caf8c209e361062b065c616e712c1784871ab89ad0573604b9904022f5407e2b7d95bba7cc618b16ec7c88c1923371f7a79aae5a97549e450d294e2cf884a8a64ad66f7ec14ea1a26bc5d80fcc956aee7da79fd98410271676ec73e286e807d38ed751a85775620b91005ae24e1c2f972e518f6b06a9335d34e609888ce5110512b3c947d998587fbbe26a09d790f5a14c8346cd18ca84214d9e9d344ccece551c2715b32a74a9913736af301546e4bcc3623e335e1a7ff4700784eb4ebb8116c3bafc0aae7d8d2ef65653e3458d7c28363505c83750d4854942938b4b975506561dfa14a22ec78eeae7ed29f29d3e090758e72654193ba3134eb8efe28e8362880a8a5b19a9f2fa940c6e12bc60d1599f1920f68e3ba593cae35f8af04ae8bd6144eb96e379f77f28f3c9944bd14f5a1dc455d7233b078acd08834b7bb43fe9d04d996aaa9990f8f1abfe02ff8c084682d4e9be9b98862ae012f5fb57f1be18e2b3642dd209210c982fd766392433d2261dd97efa322b16c87488799635a588b68ea8d18d628d1bae7330d036dd752a4dc2a32c3ad952f7347493a86b6adb2fa50f8604dcaf3bc1170c9834797434646a4490a2bfd45cb0d2e07e01e27e7121b1a2c34a8368f3f0b4b1107c2b1f7daf47da6bbe1cece8700f41998202c44d0d7d6b2c4b1812a6f6cd668858a0a0388f312b36c3ba3389e956cf6b11bcea56102d66bacf005eaf1d38ef70d07c4410fe02b465f1770359ad87180e35c1336f2583156cb4d6e57eab6b6b7eaf2c4dffb686a894138c6bee98f13afc01f91678e585a9e6c66e367ab0cfc7d0f9604a806fd398e3dc82734589e39204214e1100c6bd086b3f76b0cd29faafb9a470b411ba3fc9adbd7dc739279fb8cefba04eb21dc21ad4d077ed82f4ad15f7086790804e8b5f12d0124f2fb2a8a899c94ffd93c70b23390ded32cd4af671a640ed4c7d4471ea05d3a7d29904b3b3f02d0ec1a3e368fcd9035bd680b0bd4af07129031127e2c98f07102fe079c36f01a22b8448ad14a6832dbbac712626b9e87c94051cfe1b40babf86dda69e1511be9c9f77eec9a8655cc8056d795bbac52cab2b69911d617da5d349125eac5caf47b6cb9b7005c2a48d354b8cff822d9432fdd265f47988f6b3c6fa02af7d60785fff4485677d197bc20e0f0d82c09c054581cb05a46f25221fc72d2737eb9ffb46340ab57ed34496cba1292debbae033fe4d7cb8627ce9bbd1b03cf9b960d18c653357914aa0d39c18203016e6854b5e693ddbad2e8c737804702bf2d1f8c98f172285bdf0fa89833381933849b2263c89cf176adf0ec71d4938cb405bb0ceddd957f7d6f6270467557f85770710fa6897240ac57a6547212dabc428b98d5c5a2b0d51ffbe73bd85ef21d0b2aa08be794a6e5fea92f2fc1a65d1439fe6ba9df9cfb7b940c321ebce5f133e0e49ebfea38642ddf7ffffa158477ab77b9b559a00b8ddc95335f029905fbfd46496c328d8b4167ea7a342e56d59292d920fa59d2b3bbf23003fdb3772a5ec876e18f50750608337bf76ba6ca4b3343acbef9d9f5c5142778e238d313f10a3226590bad79117e87362c2e3a2148e759a0a7e7bf69bd8b94ca6ba99a4c1cabf71d4e0c5f746e28985a73684e8841b88e63127f2526cde6aa48833698c32d93caa81b8a0b48c984e661bc0fad49e0dbe8259cbaefe9d21088b68e3dec4d0e7504248ad4fb644e982d28536dbc893251f9df51269538ab823364ce94d926541b8c7f4f37f9322d32ffb48bb85c736d3dbde61552bef78ae184dc58d93c3ca05a60dbfabc867a52edc5536a0973f0236fa4615cc1aae4e99f21bc290b7753e41a8e9b5bad2082a8bca5a0030b39b884489826bc86dd1f0fcda645144fef8e34f96074304ab79fc3e5e30cca633b1364ab228caa9eccc939101a5dae09825e46ee7cdeb2bf4132d51ee7b0a6c1a92a49098e0ec0003fd1b2cbaf0415304a5b71b68998dfa6ca71606269c57069e712e3b83a303e74d258d68aca3e5f412cad7a77125a1abeec67ac8ddcf1fcc3274bf348535cd071c0e26069be7269e1588f0302b72f4686d1ffc6bbcc397f96811a66d501f8cccb9d2d997ae77da1c3647fe6380422446a5c6d6003860e77df59e5de2a2a7a5fe4ee8c9ee13781d2a72971ca401ec7c57868376734f79933aec69da879669255d1f1920a0861a953c189c694cc1dc0a73a272d5e011524353469464343623433bb5c983af3baaf903ddfa3614cf6e425e5875de7eb0a364ff2319bed24671cec426435599067eaeb988672d42f643110204aa5a560d9214a382c31774ebbcd5b29efe4b4d9c2042495b030262f9f102cfb7ecef5604309af2c8c0daac9e964b1a0c54aded50b45e8633a58140607d7e4160e608cda8121583042405d341c0a24d74f9880ab568007c86e8bdc051c894cd9246a2e53623eb24020472148f7c5459c958ed31fbd2f2cd606a9151f8d939f6ba7d44c97e493b5ba11ab376c28d76d8c9f2c5c4cb4c95627558f7cb1c28c201ee85bf8f3817f92eadb31e88b0c0adba73cea3bb297e88bd08e06c4620a519c9380faa36fe0165289c6f91750fbd1d7898c31de732f7325d5a8c67d2989be04017bb1412ec0b383246de0a4ccdc7a08056a7005a6c54ef81a1a7e0bb81223a95e286ebe800e8baafb7db238041b242bae7cb224627c2a7dffadecb1687c8a3d23caffcab9955bba215ba885edafe6e52711da7dbf277dd3e9e1df17c8dc6bd6a3c8bb53a73413841778418e46a2483dad34fb82431ef82fae5e53f3e24be16462f1d6951f11d748f956aa314be919804ca901fc7488b81c5bcf824fbaef8b800af471d18e8843118880eedfcba05d802522ce963cb014b028823757445c4b78c96190fd6b8577892adf26b04df765299f88b8189b1c654b775b415af957943770a51d45d8e7f86880768d88c38e3fd62aad231e3668c01c9a9fd385d9105e5bb0873167367e5eba83d38818b2782c019646b01de663c6e6a30d7500389cfa24c799e03bc41adcbda9e23e49392021bb0da1527a81842af6c13e7c5e66a8fc197cf6f163b3359ee9b3b57bc6ac3cd62a11d47e9e29fd4e8a382313de6ce919ed219471347fbfdadb1a00fed5645bc06db12dc00b8c5b33d8127be55810b534944fdb8dd0f3fa41bedd0c6dabc28ff264e2322be798c9095901fbd56357c91359538d60bb1d6066f3dca8d4b99e1d9abb46b26e4e701a15c9c102ffe6702731a1c97999b42d90ba21c4dc62db8e8629acfe92acae31688cba2401057fb5204a5b63b0ec5d95f0297a00bbd46443bbc7349f53418d67422c93b38e0682e8488a1d138ff3cb8486a1d033b9e5fa91f256658801cd3b50e041291bbf86c9742f1d4b0d2edb5b3d09ec8bfe7dc9b0e498a753c61e59810bb46447d8c6fb93ffbbddef30e6a78a6b619fa4233eda2327653346d774f20034f393c48b5e4061b5398b38e9aeb68913e9028773300708fef6be0d99085aca88114cff058b95e832ae692aa866747e364a2aaf4a1249159a92c43c6a89332b078e127e91caab39036f9a1ea1d0aafa4d2b948509fdd4c730a7828f2e5e08e32cc939bd9ac701299b63986cfb9709edd8ae8705cfa86b56b323180b4716d8776abb466fc335c4fa68d3cde51c6ac4d362383d3322f460e27a1d1d69ccb9834a818ba0c6c100157f0cfb7e5755974020140439fde125b24faf32806672e62c6b62e0ad27b7548e8f665f3808748aac43d7a0dfa61ce038a9c251b8b05baa91605e7341a7226d439943d064dc126b19624d6ce9a1656ea105d977da578b7bb044a0c42067034eca3b15beead9b3e46ea5bd764ac1274be17cd37f49b321c9482026f56d0f317aa372fe2f4c13d4530a6dfe20bcca2ace8280d014a9a00a336eb5380985274bb670ff9b26a166cac38b8a5db56cf4ffe40b04ed1e606b7fbb12a2f8dc295e1880de7ed194448a47bbadca81ba6f89651cb1dd0c18f579cde89d409f058ebe13921b54ec01964361832aa05892726ab6e222c393741ad44ea277f5a16c835f4ff9fd81b3cd663034c140d21641cd4477fd7670094a33b213673525f3e5e1b2a396d6d7025955d9d7cf7a1c46cf932f95650d9ddab61a753404374184f509fd3d21d76af4796a843e08fea7efe338627bb7589f54489f073d809a04c11b96f3c3bd0a2539523181e441d5c5bcdb5e9be880d619027b348181a7f2ea136aceace3f42d1d5262066fcd84ec7102af33b154dd8ea0552a544919d06548800614303722e0ed6908404d988f918581f8a9f5aacdd5a7db420be0a07e76aa4d04e3b29be1bd4abad30a24fb6711c5c58a125863371a1bda9b10420ed438c6ae2b10679d390835da6d1f5ccc26cc65517957a826a9a412e149e8a6d82a59b0eb2b58b9331cb53717188d82f4f0b6136004a8dde0674a681596369a166b7071b1833cdd5630e1f10071f1b0ab553d2a9ca1072dfa78b78a53fccbf8723d27c40a8b9c12de5cf61235cf1402aad6d593789919808aa976135438bc5ee20ea969a5e2fb00402259c4ab4e4291281330e12742d3eccbecd8d173e93cfed6065e18748bf6518c3b62710518fe337d2e0d5dba32650b4283ccbad3d2126f0f771f9c80dbd196c4cc7d34e418d9f4ad843c7839a7f244a16851ec141f57beb9941b3d49270cb9a0a796b53c3597ce14e67fb8b484b7cc8e4f11241ce89f343ec72184a22a061007ae7f0f8011872d294d7ec4c387d189b478852b75e5497338bc70683d368f8aceabfcd960189ae423b3ca499f4e8f17a295d2ea60c24b41c5c56c2eb360881b9798bb0a6c0a8c874ee23b67b04a0b0bcc8243dfb00661d1deddf77b630f9804d142ff28f0865629409f8b7961efd53bd951cf8b49281532897eedfb7bf1579b6dea3d88c273039bbf68427bd9140da1939c592ceced814c5606e7869e3d058616728932d133ccffafdc35dc178a7ee7d8659068450747375a97ee6f24d113ad29592dfeddf86b39ca8bc067b23cb9f170072ccbfdc215472700b229da5b971f97561ebdd34b70f5205d837c213cf81594a3e830eb4ddb44258a9efb08630b42cd70076456638df1aef13e2b3b9576b5d23ea9ed577f4403940f6ed78489d460d494bff7d805351302fec5b2c93feb71b5385105c620a8a877106a1a34a401cab23eec0f73c6b9c9674982d831475d75fb7185137ca56db570e91a23fe63021f752c8ea91ea05af5865be634e48bdba621b0ded3e95d0171f4a4156fc44ab7a8da9b6a74d538c0a42cd3f8b4be5e71b5abe71bc763772af68f0d89e3fb06917b3d381b56ffe6b8b59725ec13db750736446a673dd7b5b816add283e683d2d5aaf72b529752af5d180005af528460fbe5996886b429b96a1706c37c23f8e7e4e4cfc8ca6863cd8f90d599ec3a842b2d788ecae09105d51d8eb19e35644e5333dd0febe6b7798c4c8e83a4bede8985b82ae506e074ae2a99364e255b32a8b76f69bdbe8be45870f4609cbf44b01a3309ca5a0ed806df80919997fec8cc7e10ec24b8573a799a5f8e11e64709ebea588f168286e775d180da985a90b80adcf96314508ce2baaa3fadb0a3b4380be4903840b34f86c34074b9ee93ea6481e21b48baf4bae9f06cd880c5a4ea19b894fad881ccc9c77360d7d7f41495e258f5bdb8b47b4ca7be49f1108f9495451a6f6e4333c74824303546029aad0cac06259ceb515ff4c337e4735b23dc49495cd72b07a720bc9ee1ed9a30e72b863b31fde5b3f07802014f77420d57e0c94f35cec598bd50840a4fdb3ae9d6dcf7f20b734ebebcbe8cf4a178b852a4ba13cf2317b2e78314c5df5228adfb58d1f8c77d611fea88f435d2053d3890257ca2c7d2fbba8208ff357a3f7e9af7bbec0404dff2aea525c4353f274b8ea6c9aab55ad38e520dd9f211691d75a3d4ed4199af95dcdad71b5237ccb193648989059f18914e33f0a0be8eba90c4f2757fa312de0e23ba4c4d763f170379399a56c91826cb8ede09a0d8b8432ff4c729d02054cdf7fe43ba1491f0e69c14721139fba1748b9306441cb0a460e19124a7c5b0facb4f51997e07ead4f910528a48f0f12a6126300aa399aa55acc0e3809406e07d49bbe1bd843723b832d858e2c4bd1c1ac8fdb019175beb2f3258ea4ab2c81dfb3772b2a2fe900b598d2b7155d990d0c75799aad07955e99498fa1d418583fc96ff835d0fc6929fa26a34dd7cfeb8cd1ab5b335d11eef2b3769f71910d192e5f68a98795499113e8f7889086ca7cbcb11c1a3265f17c398ceb875329578cbf9945f1dc097add07ddb5b4911a440ff964644eb121c0e3cd52ba61fd0d3ecb4b0a932c0b409ed763f8a059ba84a2864bf0b4147e0d129dfa43c020b39a75a284b91b9964ec29671f2c52ee362e022ca72d5c59bef1c061030ee9467da8bc502df12a8693347991eb858a30c4af8b81e0165bcd3c68b6f1148b1a0d3236cbdd6b94d006eb374cbf6e79c5153e26b7439b9cdcb745f2612134bf071773ea5dff1e924d001bdcda529b0c2c1acf3029c5458e99f9c3ec8749352356096116b9ffd40f849932da85db9e2fd7658094cc5e6243ddb8b23870c33a3a5fcb0cc1a38d87f4bedfd589138e75386d0c606d24b31719c24efca71f8706561d25ee2a9816fa9e3bf5f840089f28d0f4b9d5ffec21ffb2398b05096752bc668008c1bee773ed7802a728cd005b079975bc6c880779b2d9e5b07866c230fa5456479e759e7824dd3b3a800ae7660dd22bc8e1f382586084def18b1793525b25e1d5a1c135bba8d261fdc2b7dd64b889dbd98535027f2ce3b38e0f63a0da5d648e942f307cee69c6e47097ffc55a0f5c881b882dbb30bccf5fb4ecc23a2abc6357363058dea57daf5a2fa55c8136272eebf65dbb01230149b93f464aff75ec87782a8111d9bee29968241cbe372b8659e1869e7daa138da5febdfedbc1d671a2d453b33bb6741dca61efedce4ec03a8084afb8f173b44cd9ae039d3d63e50f425b57f638b5fb9d97250aa27e191f7df72120487ff03b2077101af818df6cb7b31854e1b202d27092d9d6eb20e887e7e7a7eb48836108e24e3e63a3908b079cccb5ff740ef7277a7eb987522c34f664f1c4e11ff3bc4d81533d818374ab1b44c57dd6ad8c275f91b11444bdb3c132fae189d9c330f578635f0cb495e4998e027c087cde784b1274523b96e399e93f88c171036c256602ee8c6006f4c7d15e30dad2411e5445331cec35e7cba5b407a250402b33712832971e68e858b2f6e034fd556b265ae91393676aa29d907774789f99d12bb4d2bdc2011ab94d37d2512c995663f33f5efd35b6dc0a2a0cedc5d18e1da84d2a40e97785b441b1731ea0c46708c135452384ef971f10670c8c4168cebc1614a7e298f62148de8d0783c10830dcffddb648885d827ba78a8e4efc7cee28beb417675f5041a49ec4904813e413b1589ae109e37faff011eee6bc62fbad10364d540284266a2d93ea0078c9f239e25db03d6e0049a933ab2e4078aacf7398613aa1c94318a5ec703b8f46aeae379def72680587401e27835074f19bb98448456ad1ab06475ac6ed8001ca050179b8af243880b7b1fb3b3ebe3bc7854a64106b6fe12856f3c51694c62d876636cefa4468bf7404cbca7fe7a85cf4d84e789572874f0e76fba17e67847ed34872c08a5a80043f50800f101e0f245777a17844f149a0fbed9b9cc23c3db748271874e914641c56d638b581d0940b263dc7ed0b437a72957f18672f068defceffd7b6242ebcd88da519f6ef95f92478617ab8f8ce9bacfd7676bd162635081363bbeb77c3f1ce9960286d3646e0deffe6e25bb8bfd1a9284aedbfa50a46f685609e6e764941cc392fbeb211486ed7799f710c7f24a6861c4ecc81569ef333157754592552fc046d058639043c79ee8f0f16296255cb44b4a1f70af4cd807486cba7ab0840c9fc49cee22a6c8ef131b2a94f10394217ed47f7db7111c9c3747d036833489396843e3e63cd339310c68648e9831426cce349b36441e4bfb6a7073c37f34db2185c6bba62ef080114f440c53ea0cc281b61f004e88814ac9a17ec49fc55ab6d3d4cbdad2f9966b64c8ee161a8544b1b33c8449416201dc198982e0e5be95c8929c2ce99c58d6ebcd3c799721c448d3151d6f27a6f95ee3079deda31d4ebd9c4e1585ec0f83e8af7bc79a9d97ae768b002fae086961c9163f6f30ff5c2142b39c8b5ae32d5acea8880382cb64912fa018bb0ebf4c0096a58238fa6476c43bc2c31f9c4a770e2dd200f6bc024d1a073913d1f9bf8c236faa7443da4a612cda98818b03a35d17b8a01a6d7d11068e1a50dd3421867a74b8d64326d1e2bdbf11b8d6db0ceeea09d29051eff29d58a9d429d2f45415326faf2bb6e02fe8c2e19c1c3e9b478b0e2d7f2e2ba1d81012aea977604dd6036934e82f811219feb18d6ae27c25c2fc34cd1c7e71baca0d24f46a874255ecbb3db50cbef4cdb7b7fc530843bc57d1345ac90251bdaac2ea77568fcc47e68303b874252ec1c990900cde3bc720850379ad5535cb9285cec92b9207645c845138937fe7a358d1f3e8a8696b4d28a07cbafbc0089cdd7045142826d9dc188f986e15ae5bd7c5ca07d59a6772ee2ea26e2c682e0e071c32cd9ef3bd3dc0bf9a9f1e1fb161d7550f71ec215db333686074a4e44aabd1171ae2c3d64eb378a64a0480166f1c80134e0b2569887bac2f987b3e6d35e3db24c956c897a16948faa0804b3aefcebeecbea28264d628349d7e64c2ac5d52573140503288b33922385168595b6aa75ddccbbfd87444094b0df58b01f4bf19daaeac031333f029e6a117bf2d1938eafe830e412c25c3089f66be537d75d59caf940d48f3e37be478b7ee216f5041d3df7fe24be49944200e844b80a4d51e56eba536a085490d03ddff4d11c89a150d31c996b88207d7c92bceeccaaa4a33036c219655a5856fc00febb7fd0e248381397e8fa5d0b987608f9b4d85b5304402454eaa9f6764ec92d5ea60bef23249fdfbc5c547ef27d4d938947133f72841c78e446679489b85d8cbc1e8adf3ca97f81c13db337381d28b19f7b0dce3d4ba82c6d38aba5966436516157fa062ff4262e9b289901c107cfc6a24a9720bf273b1e066ecfacd141687233e7129de74f791776642ca35d5a8ea0cd5f5ab12dab65ae274266d8a12bbd306f58f41a6fd051af647c5b948306cd91b16938e455bf213f192843131e918cb24c8db842b282d4c5049082558102909be88850421c11c4161e8c5d84f9328323c7e760709bed8cdc2c0398509fb2f7459e8e1eeab349b803fbcf4f1c0717c9bbc72217aec4cd9bd76e0ccfe191813360d608f0e881423e9a31e55992b8b698853ebc9393e15f0294df3201cb679bdc4e53e7ac3aa7f08567c3ac91f3ac4afc2f92f8b05f2473813487505286556570566be918c8b3e510f302af8768a7ade3a90416533bec1b6ef0aea7e4e793faca480cd2b1c2d48df1e9950b40b541a906a76e6e8c650af9f6442a8357efaddf250987bfd79369f9bbe4bddac2872d1ba890d35b491788c6e6387807db1340969a2a63e6dc9761f899ea7c6a4895807cc0cf776818218fd1699372823795c2c62cffa00bf7cb9bd3e960ee3c8a506db9168c61be5fbbc5734d723aa370b87a4cd9aa70dea64c1224e21411352dc2da6311b241f4e2126eb09f0fb08831c95c7344fdbea0d92e2b10ffb4ca224859c23fab2cae73f8d06e51c719a256d41f7cbc5f54eae1743a4162328201f165441542a8167b50413bb5524ed7369651bf1632a14e42c43d820c4ce60d6af4766e79182334e137793d884f631cc9b7bd7464772380a64b2bfb2229f0327112f7069d4b2efa367e46ce918415bfb6499392e16470705997e6d3c78018cb202e7e553fb3655f27c4c88f108b73a7ca5712f91e9a7512d9c355a63280275bcdb23b612e75f23f3c108df1cc550b90af17de7e0a11931bee7a1259ecb0feec63f363886059fa125036818d3d87330afce1bc130ec037688943f6ef1d7fe8bbd775286093c363f1e7b883c3431487032a47087c9a24189c05305e2bd82ed2822d4b3aaed0749ddacee72f6543cde5d6eb114719bc7ad34bf1e660ee049df67823c0e727813798e945fe72634ec125d05d488006a581076f29e7054dfc2c9e3e7ee7ef417df6a2c44c028ba2dd86e043f6b351ea6a7fe1d9be9bdddf3653df4c1061a6ccaf0fa9117bdf90df13dea2a7dec10faac5557260e79bada4b4f4ce8d97eecefd4e17cb3ed93f1f5dfb73ac05c3aba8e1e7958e94b626d1857cc30f97d9df3b08e92317fd9b677499ee71fa260d8a75da37a3b2e6f97f28022b8183de8157e70a87dde49566a87e5730451b79807c0929f7ec4be26b67a0661cafff442b0736e61598027d903cebec94c35673c4cca6a7fb3cadfd8301be19ff6b3f58f64401c861e5c39b85992d5b2f73f60acfdabc4a9d9ea0c6e35150eb07705bb2c1fd45c2214ad9026e3a545585b2dcf05b36c18ff854f1c71398f1cdde247516a46692c9aaeaec44511caf4288508a5a7bf5013e57a34a1d6270dbd93966c110eea344dd4983e46bc366fadc566596cd8a0688c1213ed083da3ac4a9a25e11622e3600ecb4034441905722a3ba844fbed92c742258d1a25ae381b6c739e9f0e88c2692763bd48b359e705a81c20d395a5ba93efe23dac0dc89c5dedc215acb7c0102a0bfcad2624c08c97543d81706f0107fae1cdae3d275af27efce9f0517bc45ef23205d844db8ae2ae47ac2e4c5ccfd316ef7b54351e5810e3079ff30f71fc69aecfc4e2806c3f4d13853c75f63f34d4cb85120e168061c302d1733ba4e0adf4d391939d237f3b96cd5e3922c60495c23b55ddf76cf0d81ca6d3de49fe00a51299aeae1e3d159fdda0b2e429fd08ed6cbc97cc0a3748905e1c0a5ff0d729c490c92fe5f455579331a62a7bfcc229036d94e36234d4471079089be21eba48fbe4a929cb9647467c7b160d059a9d482d8a0bea7cf3dca9500e1222a480824f0a13cf1e545dd32b3112d1446a9095b614d125c83ffae8dcca04014ec76050c359410fac8645b6dc1851f6758d35e117dd331bcd79d360900d90e655142b7cfd985c3222cb141284e01a09f86d73342683a409bda0ba9269e144540a610d0596f16c0dc6095230c4d9a1061e72c5a780ad66cb4872a3d16eb3225bf3d5b0e6945f0ba387db650b4c1005f525fdbd70b75e412333392caf0462e4c3282bc669602139e5382765d3bd1a5ebad33db640d5f909b80189304ab5cbf5669e5debe6a4e8c8361dcb3dd03da5d0045a718de9db8aae2b3f1582125cb16cbbdc460bac4b86f2478d501532b46b7819cddd21e28d7bb4f7479173cb64776aa9c3c95e089bab0fe91e0504f16dda0510d5a611b24f708858db36209c5184d645330435ef0c46e857431c7426517ec7bb26f92bf5bd3f4366161a94066a10988642722943be8b64badcaa8a5b0de3989dcdf95ddcbf5af31079e21fbaa55b4bdae18bfdc87b952970dc78566acd5a9ab2f31e9a9ad2dfc02eb963aa9a504efbf15c692bd8ecb57d445ed82621afe4a9847f81e97a7307a9fc7449b11535225f9fb52174c762a3f988dab50c21abe161603cdca77e210afcc18840c58e6af57560afe56fa5ff82239ee6f5ad8ff917165b9f6767c316da8aee2de7289083191e27a5637c9ae634f89009c00974c2a9337b234932b850b4ddeaddc2596845db459f2b1d2e97e1e6ba67fb5136a1dc5dbcd100b5c88423c39183413a82a33e28e67ced040c67353206176c69a2391eaf548f742d486470ee641c5965917a90c7ffdd623940a2984f7f28617f01392b3495e96dfe86b0405a6e7fb7708e5901d2e80b9346250568e0aeeab8b798b2b3712d7f4247581c5b1ecc3c9da5e6ba81115d64e59073fb0617005136f891cf102a0fca13030834054c72da860785678671bb73f8606efd075276d3f11326178d91f452a28eb4174a149a535357882741efa7d505909616e33f4f321a377d5036907a002786e7ced04517e9f197705741089c49c94af0f563660365d4f9c13984a918374369f8da3152acba4c34b5ef212b6c9dc5b12f41182984f1dbd3d476fd892e22f2804e409a3ce2a85d221970fb6fef568836fae7d94d8b9cfecc6291630e86236e73b59091e0c60c8524f648e84d47cb71709aea3a3e7eb6f864bc1a4dc66263b967a0f19d2a7f4b611c09a4f27e0e11749c6f015118957e97751fcc02670da51685e77a4b6dd323bdf1936c74ac00498e75b4dbc1000dc1fe307b36c6b15ba78ae3e82b44119810ef7319107ab4b1b349bbb77c3aef97609d2281c8b9523fce8977f0b5a58185987211d7c194db899f90f06906b5b9e48e61c9ede82b42f8f275b8d82c13ff952fbdff1427dd42b4eae443e8f46999d7c2d7760d819af6942527305989c0d73697c237e1a448d0073f9953a8c9cbaa93e5cfd40452cee147b30bceb5ef32a04e916d853293cbd9803f95abc5378e88a82261912760d0ec1827b33c24604bc641c1e78184215fd421e0b37fbc5f63d89f4e86cac5c19f3eae10ca7c7c247c52b9fde76ee5cee746ddddbf7b55b73e772ab7fdddabddfabb53bbede35ee54c601ef55592de8f9e8a8ec07adb62a7ca9c790fa0b79c62cd7e255b3e8cbf7a44b1a53afa0015b26ae18a72078fe92aa2a662e4f114f12f72bd83e636605ee838ef1995596f2511e9b2c1209f3ca9b1575bd229f9d122fb30e771c8d2962edd312a824f3e675acb36fd61bc5148cc6520d951567964f56a411d9975cd047646caddeea013c331217b03603c7de462df48db56474a5aa7780ae4d87aec86c4acb6a6ad569de1407ef6d53d0830e9e2dca9e7e07064f64a221c7826470afcadaed0ab7f9338277099e4ac0f0c3b5e33996b149cf7084a3548cae07989fa2a88eb42967b40e855626394fc44a9d8108cc9092aede8f1d3050e29f08ba948d78d2d30374c8cc2d14d93b3df864211cf6956732869f0ac90eae07ffbde507668507e90f0cd5fc11d99f4049595d5baf08ebde40721460ec0f3504d54a78ca1b9be34c87de15615dd672cd98c331a29b96212bf40ace35475153ab4c0f30a387eaa3dbfeca90905b11e1ed2ce378ea064f66d2e07b388e50a89663937357d8e7102dbfffed4d4288a5aa3b8f30faa5959aadade8f9a6346cfa1739149191e16734fe8c218feae9bd2b0661d8f26cb61cfd4ed2fc2c7502e1e8c132b82cca63d4a1c1ab53f004b63926423a07ae0a53d1ac93cf084ea7224339787e40c0d4fc6a28ac57e62f2228927258d7a1c04af2421ed6cf6c2f5ad080efb7d1f4e638a9d80b55d6e67803bf09381417951c2a828769456c2cb1a75412203861f2ef6dbd8dfa7a8943b1f388083465e7fd4a64188ac3ba09b226ad1462502f4697631eaa57731075a4e4b52b2782aba85bb20886499380717a138f1fa05b88a889af1c405cc1bc747ad6dbddfadd49a5abed4a9451607c4862f80b3648568c198a09f756bf511949d5248c1fae18933029e10bc931836282b1b705a5b8c162b463b591e57cd8261ee6407db05f367d3b481e8dee7001abf4b2017c9c1c9ac4fd8c75afc9ccff1ae7f8da0fc9f9ab034e37a801df561906f5e55578e49c277b96d1707744c0f7a4086c8047d8e5025fb24d716d913a7a59159dbb6e8be2f7f23aa03890047a6fe99642c4a608e63164711c53ef28b3a25c5a39d265c3a773a01a4a007cc042632dc0508efc35d983d18b792d145f08acf6efc77170360e75346ef89ba078a1fc8374e296d7f7e85b142e6dff48e61b88ef64a6a3bf738b51242e4c3e020ea58c8d1c83f9aa8f1fb25d06b136f8f686dc44838273807ebe0e578a3bf17f4eed460babb1770504ba0aa641dc55c7bbeb216138b942c309aa3c99a6e32bb866a3e3620d8e098ac1f0973942ee32cd1cbbd25ad43ff15d497ae8cfaeb7452edd0ee950a85819774d438ad946fccce8f5a1d45a61328a86d4ac581b5ad7bc75636c2b3d51edced7c85ccabbd92ce3c554752787d501aa79282007569dec6e28392522883137f783088ab26bad1d7232633a1bfefb9907ac848d6aa548dcf7ea3e9243d6853a3f605ad37a770eed6829e5212e29380d8f42226d938a3b13f0d91863ce9194ca0a1783388b4b102502c01834fe8dd20d85e85420ef650d42db3e5ec20b50ebad3556388435a749f87866b00f8b12641e12448a4cb8693401ad73db433bd79a8aebbec67c46836ebc95e8ca45449a68508cff2d6341230302fd5c50e58ca614a82b2045b4089ea87434f27e4bd8f49a89498ab521af26eab698e02f55b36cf4c89608e0208747837ab67db7d24f6722da811988604f3531192a0a3ce7c0c99a684cd8aff3dbd18bd53d2f9c445fb0d53bc6686e9d6049cdb21cb63caaf6fac0760617ea1bd4f4c9194f53dce55b57d761ef480f20576f860f1353be015789497eea029ff216d138c80c008687b4bf8ed111625b82e0beaf94f3c35c92092c8134a27d56380d210c7435875104d812b89239a10c39bda5189f4df9b9a618ec46c8641921bb9aefa6c6a644679d4070c155714766b83a833609c0d0a1a509c25ff7c32ff2c204154ed608ad9152c31a2fc818217d071a21ed07e4040100d0ffcdd52e59124296ebbd049183e41a1eb9ecc516ca1e7fba3e2b44553c0cab712cf9f8648e81e367cc9ff85a19eb8aa63c16a93c77bbaeb2a421b7797d84e9566c6e550bc623fd9d4ccd4eaa25706d9b5dd13eba96ea19416ec10e91bd9711c902aa237824b3af34e9a5166d1be81611cb573e7b2b7371103c3f44606f10559bcefb3dc66258dea7ebfbbe9cc2e404f648252df6df1f2ae5a94a3a0a2269afce148aa4587eb9adc148328c7abaa38c73114b8aa64aa93a62f658486c3f2114801106b9a9a607f3f7976b5ffa801890b5de93d704a9f3665b257f6b9bb8efe04e819c3ee8f7a95e5cd00e9ef7ad34f077cdcf136041f770a7cccfbffcead9b4ef15e60b69d784b0cb87dd321c6ee474210b7f4f04e00594710648b2e28622b33e03df568841bb7aac18382db08328ebfec07cf25c63590de7bfa8384cf090b235243b7acdc17738291ccf315fc62de34dd1362b13851ec482d2aec1e32c20c20dce2047e3b44350e56105867c53963627ea4bdd0f70f9f3b58af1131738180df7774ce40e2f5e1edc031e1c1c98be54fc7162d6ba1128d1d2fbb2b774b5af354fc224f11c59bd3a3fd735ee2d6cdae621da965d1ef42acfadd6f3f2d2dd929e20e530e460de6f77d31a2b8eb5319995ff73d71d7f761d0d7644564763f8eab150550a6f72723559393d1c9e86474322a7930e0bb4ce95e4868686855e4ad44d18264820b5113972998607632c82666e742e4aeee24438ad9d94e46a62377b5be15118882a35506866230822a0c1dad3220044f248561188634432ea6e049c941522a6734bb8ed5a572c0f0a35932961e755a29a259924aa5c2265a7830a1130cbc8df41ef4de444add94baae7b100324cd10aa0b9d60ba819422d306d3b7c0c1112f98904695aa540abb9c50c5f21ecc01c579f0c612ca5338299be9575025f24f2a55cbb6d512595285291faa27fd18a66eba9028a4c283f93e64e21e0cc812b26c39a02821a56e4c2c12552a752dd405c89750971269a0f2218652bc4533d479efe114485b0d9457c361ee4285503493b0921aaff0711a47d0c85ddfab48e6f7a4efbcaea6c9c7847bcd6ab582d3911392539037f3446762e230ef6d0e059c027e111e0991d4f897c3f34ea7962d0794516499fec41adf4bb56c260f9898b82b2432512d5b181422f160c227b17c14c129e338be0d9c623b792f9ebc13cb88e981534e4226efe3c238b2803c61e139fc3b3a21e114e5f4849391f779a71998debb9f5c007e4854349258272b9ca4742cd1b4c2e90bd3934205d216169da47c394e58b843a991031a3370c114d3fb90a848031daa6b028d10cd1250095d17d339810461bc4e7ccf0753e9bda71182afa01b5329f48430fa0c4fba3059a66ff1a4c81c3bd42b486c892a262e5248e1284368e486e4520512650b834e2523a6d83a3df1ae0003146a1865d1448ba12d9059844fbe232acd10cd9049e38446a8c9180679add08b0ffcbc2fe53d580297303f51143df10ba5f8c2ef0341b07b6fe67b90f5bde781dec77a058d20e8b15e42ac8f08c9f4de033bff56be07bd99a7c2175978b61c504cdb06cdd713af202f08560041a8fbee5140e6f7125a090d79460e0bbb4f0612e9f35649485b382483c989bb3c19bea1219216434a485b4844fa628ab05841b1826205c5ca83c2c587228a28a610bbee43a19ab1438dde81de8af8a56c61d1cee88160387a61c9c7f799e327922492582a954c602b5c25214f46eeea80c90b0990b6d0c8ecdee4d574242f4cc248a38937ba54c0cb6107e1d10c0c1ecc13488f647a1f3ef1e2260459a016c8efbb550a48dbbff7ef7d788484ce5c35d1ad9af0be8f880804c1300c4351144571d50469d5c4aa092952564ddc9420f0419030816202f5a1d01733a67ab8c37ca920dc634854b8926a79a9151212d57ae921be7fdff7858f5a79140a85428def2ba80f59625864a24cd448431c5b28d6f8e1c9bf12292cfac6f7c63f8d6f721f9ff4b630d5433453236aec01fed80a8d3c98eec716912e0c72188915865998dd7f2c910b425ca852a54a952a55aa54a952a54a952a55aa54a952a54a952a55aa54a952a54a952a55aa54a952a54a95f151a81eb6952d892826d8b285bfe283fcb06724c3307cb0d5b28d28969b2b43e309fc18e0ab66540fbead649bf1a51f31fec1075b9e1c3ffc91258ee3bf007e0c9607c9d147d785157065fcd493ff8dbff22208e3c36761d99288f263e5c1d60bf9e08f1fb25ec8477df842b67a8c8f7ad48fcff228962d091e3e16960df5a431f5305a39a91f5b3da9275b3d2f7ceb575a2fbcbfd7a5705e68f98cd6fecc181ffed8b2b5b44019adfd99aa0f3f468b655bc20451a8111c4970e5513faac00ff7ef6f0c490f06d400f97de39f500fb24e1f9e7e5cd9c2219385e5bb540ff05948f2c91649a328fc15560a068be5577eb5f22c2d5b3864aeb44ea856cfe9c753cbd6a14ee018b26c3442d6ca10c9f2e94c9627a15a3de08fe098441413c6c36881246b25447dc85a79161649b23c73856553b54ae3f8da4812515cbe204170e534da9630bf2051e390994a9d7046a6b74f9288427e1f0392a004b31bfa1890842484453ff87ec0e407433f0882324535ea6e6cb96441e592859506a24089a2528160aa954ab1540f92372e5920415005058a4b166eb2e0928523ab235d58256085801e2f8ffa9df14fcf44077a5ee923c1ae0b451f602b0c125b6150d779543e2a1f15900a4805a4125209a98454422a2215918a4845a42252215121512151215121512151295129512951295129512951295109592e5448ef3f2a27f07d945a464c2f15b65e704a1fbe8f92912e15b65e4a6ffa97f08d98a6962eb57ac4607e3f769f077e533e1304c129a009866138253441511445b144229148a4293e4826e83285f4fe3b3a9222650af9825332c32fb56c3da6f860cb470ca6188309dac022520857f0c113cc0198be450f9e98a3ca698668845030822a172c7c20188661288aa24822914824172c1c1d4991d21175442e5820bbf70ff43e7cd0fb3e6c89adf0c8077a5f0b2c2249194754aa6844b1587ee599205f8260f995df6139fdcaef90a757fdd881a017963e91f4e1260ab5227ef8289c54ab0ae4a96533bdf7dfe979f83c23dfe784f9fd12a09193f719414a51077a20cd50515151118d121a219a25488872e4c184522892425151098ca238150d75a0079e3e7c09915e4224f04d204822812ddb06c15618f47abd825e272a989827a293d069c80c5da21006bd5eafd7ebf57abd5eaf571482c2a0f0096f262c158553188b8a4a605464847109a42d7432964a4ec62027491867844625de8c28c548e4cd8c239391c968058d10cd121aa12fa68c47a67c311e89e2648a132e9e7401c58ba3f1883763eb5c8c600a6986a23899e2848b275d40f1e228094e9c70f1a40b285e1cd12ca191620c9ae2641c9ae2840b285f8c41e3134ec6209a254e8a8a8a9cd02c198bc626a11466d7ad7c97ea5a247984d3e9742ab9288134fa62be2f954e21910b12c81ed387e31b9db23835114f5c7833e27f2314285e9c5e41af24ad93151e0c130fe654c4e454e4cd90ba5391cb11ba37bd5e2e4c2049ef27264820bb12f83346af242f255b3c213a31f1666c21d1c98937633b3131bff72d9e0c51e1e5e86abe3f9db6c0c117e6f7a790e864f40affd4b275ab964ddbba5792d311aa0124120ae5a5502814ea5fa495b04496be0f552af1c8f7a107cc95d69744e85b61a550241209f50afa5e4221e90351a823d3e508644f572a85a552382485297ed87a05bd58582aa32fa62bfdca91bb6e5648c8ee6da7221f78c0ec8aba4f3503b36b2d413583ce533e422a5a21d1ca91c34aab2d485f82d9bd892c2aeac13a89456f23894a2f52e1c1885f6a85443e6a98a517bf24aa9abce954f4156989a2e8328e521e2a0be28f2e46207b481f9a6268925e6cd10ca16478088e451e8c1896c0143b93918ec8472344faff5a3946c270c950f8b14c1d8944ea4a4f23142ea11922b142d63876a014137cdb498a297660d82a9d9cb84b01a4f84dcceebf2fd2021ffc300c411651890ba4f8126261e9bef44af212229fc4225b3623af24afa0d7132fa157922f470c186249f5a5d66a0b122c025f49460fbc82669072845593d5939593159497d04a8b1517ab2e564d5e49a62051bf9a027c5791226009ea6ca307cc19424766385ae9ded682c50c414226f831583560b0fc8b498d6f23452083147781ab264126f8ab079033d86a3cb18d484cf0c72635a0cce004922794484145164d9abc845e498688981419cd2005d5051c3431dff42d6c6005d3eb8c74375e89f4259a2115c90283d4ca81c142aac0ae5b32e4cd94569ec45a2995be4bdd9468846894b8293ecd5089e5df4842953cd2ca8b94aef522e5cb3196c6a31729b61a37a2f89d009e98dfc474317d8b1e50618e1dcac508644fe943138623deccbf4c310243903723b63cf05face0cd885fc080c4c88b146f4544a27e4544dac621137c6711ea4a1e89c508c68f475f8e194d68d4306de3910d156482305a0260e22ef04da66769d96a902d1b0d72654613db8c283fc55de0b3083d383ea965abe1b56c345a36d2bb969009beb01899e0af1c408e593c1513fcd38b14137c13cb26000f98e08f5978252d462e4c10f4c204bb00bd1af0c7b148cb49344b3a3702c3262608821df802208140aa52af52a954a957a952af22552a12f952a2ea421824f90a22fff5040983d5b3a26251a960a81e064992301e46cbf612ca0183e54b5f0e19cfd222912a19303e060c9614090c2283564141af24af24af24af24a0ca2331610b1e40d9a20b2d4830954aa548a0984a81a64fa94254ea532caf0241d5d30881aae7e153a59e85d5b3f2ae82a152a59e45f52c443e182a9045c5925ad948e08aea554faac0a75942b3846609cd12900bdff77d2b61f81ecd9215cf3b792b2acf3bfd0aea573c6f8566a8e82bf28a52aca222ef6996d02ca15942b3242c12b1d8a2074ab6e04194f0fbbe4f159250a80fc354f829d409954aa152ff4af1f0a14e8f5a41a150af4aa55ed5b2bd846caa15965f51a95a2b2dd4a350af24af24af24af2442a40d8ce2472344a384860a1a211a253452d00cb14ae2a9683cb55a36232412cd121ae49116509f48123ff1133f929122a457d08bf47a05bd5e241269074f307198bec50e8cba2801e9bba0e28b144a8607e3a42d48efc715d3468de338a25a6a18944aa146d5a9b541d3d422bd92d0204b4242e6f8122a7da597d0e925c4f2de7b2d1be94d632b68547de949967f31a5962dc7114b0b1564aeac902ad3064d12ca34b6d430c8249dc037993ef0bfee95e495e4954428e5894a8e4c12e8d10c752c1b892a79adcf0b3d8f66c84433647e6f64de60fa163a40b2c50e986cb18323de163a9062d260fa163a70e27d9742c9d8420d8b4e2712e93f53eba35942b3840b30ba579397902983c80c7f144f4f1452e1cd8c2f8a3284c413cbf4a7128b143af195baae7b05bd9ee84ab6971429560fea9730bb92aa334ba0f8a9d2a794a454af24aad4a33a54ea5f42a6f85dd7427562d7f5a41ef5a2281a295222955e52983692f74b98a2972a9544960d34497ffad7132f2526a9947a099d6ca596ed2564927e7bdf97be542abd8d047ee92b954a25ef7dc0824a7dc7b2bdd87af9d0891fa2f8af206fe6f4a57f3dd1d1885f12c597d04bc83cbdc924b67ac4f74e62e9619c4a3158fec128a5a22895445413734ca152e283668a258a5ee9c5948f4e7cd477a437b14e204bc6fb2bc883219da030c3a390893743be0caa284e5084df75a6b7e5c811c5f45ab69429f5b6d7f7a498e3c8145b24db064fdf75a7ef3cf1bb8ef4a22a0a330cff45024133f5aab7e58062a25a2b1990eacbd8600e28262985024560a656524136951433fc57928e06d57a8dff0a1ac7979079124da2288ae29ba65792ce06a9141b77c38f67bf6958efe9ee31b87f48987172fce125cf9ae27099453fa7ee15aba9fef2d7f431cfd51adf1e27916a980f20384084984468b6446130d4ddaf9327ec8ec3e7f37e8c5e9607d7f2ac29dba28f71b9fd3c296dcd36b8c56d108f55bdded84c6331ee575cfb7914ef13e380f0dae2ee0dc528de57c52c8bf7da661b9d13fbc060b1d989874031bab6b90665efcffa937b40f1cd10285e85e881a6eaf55971dcbde6a4e9e6eeb999c9643aa178eff486df88c7b51d93c974da2bf6b971f79b93a52a984ca653a9d3da7e5a36994ca7181bdaa5f78a7db00d544ddb990d7d66d4b5a6f76623a765a9cf8cdab001d3b8bd6b3048e8dab92f4ea7a8117fcb5bb7362693e9b4c36696bd297bceacce68f9cd077257b9773cee0e8493a4201c168b01c9c1d111723344ecc6872924674727168395b2d83e5b76eb359fb2cffb518ca2f7370dabbe3ffbd6f6ebf5e2dbe754f5b6ba7d9dd6769eb5a6ffb8b6d1b5cdb4c7b7bb7e06e2c2c576cc85c32d6e89c4702494bbcbe0a4180577379d14af707792932207dc5d26fb35a79ac53e8f792e9bb7febd62966dcfd73e2f93fd9adedae95a73be8cc15fc3aef1a4b71abe76a6b51f98d7ea5d59bcd7f43566af7a62f4ff01465220a2801158ec9363f84c7d58dc9e1808c76e2710ba629c6e352eb3e8add59845d55cd398adeddc3d311adb67ca6e8dd9d84f4cbd2d9afaa4e89ac680ee2d86bb9d4031bc2f8a6b6f27900d6d0387eb7602c562ba55db5b7bee15df7237c8d5eb6577300f7b6b369a2d67a96ac3860d396cb06106bdc1c60d1cd7861c379c38a037dc80830e1b700e17de97dd7ad66a1b7ab7b9e7c4b5d3c64e796c641ef69ea58ddc4ed98b9bd9c0b75cb30183e1d29a66736db737b6b1aa5edc66330ed76a17be5d960683e15bbad79605ad70f767338de5496f9fd767420a2378270f08778f39090ec0f7e5497d2e6ed5ebf332bc6620b2bfbfe697c5c0e02efbb3b630d89ad38dcb913d8a55f59eddcc8647e27b6df3f93af0f815abb14dc36a0c55f367c512078710bbd81a7d1d74f8189815abe5c9ea062ce0c6bb682ad6af830ebf6b3c29ae959807c549b8bb114e7a3cb8664b8ce6d506c6ec9ed9d06b4ef78955359f366ee01c709c37e480e365c38d1c3768385e280e3a501c39dcb8e1ea98dda063a6e3060ef4bc01e77003878d73eb96b551801d1c1b338869f33b1e084d1f866235bd347d4b3a5a9cec8e7ca72a4ebf6c5fd90c273b197787e164570277f5fae41b66dd3de51e6ea0b321bb1a777fc1c94ebbbb0c27bb98bb0e40185d5316eb35d56c89e69b8d13fbc4bc4e617ec5eaef783c7b546d734d7f8cbb9bdc3dd4dd6938d9819a2df78d26ba7be79eb39965f1aff751bcb2edc6ecaf39dd77aff88655dc2dfd9d5e763fcf9aee7d6f6ca6fdf5447787c14907727716275d89bbff6495c6629ffcb99d9e17774fcd9627f689fd5cd6c6c96a1b6756d56b23c75e7696aaee1e7ea0bb7b3b20e181094ce0c3f442132b62503083224184c0821d1a0e7060024abd81612941c793183fa5520b434f00a23a418549472b0603379ec4706140f9e1740f33ec600b624203a51d9088c0c5e84d8e1c31fd2319e18bb16ba26b024950f74dacb4287d39461aa514aba6ab4929b184f7a5d611ef3b96d7a0506f229dc03fa5589ef73c78200b09f8a8ef584a98bef34ca9e7c1ab41b18c1c31b19ad8a1e6fb130b495057f37d133bd480e0a77ee743fdc8f29a91954afd69fca0aee684048504f5a9ef584a9cbe3b7df74a8c4fbef4f026660fa9d5819cf762ab03b9ef7728057dcde94b2c24a92ed53ad242a2c412df9f5a473e24415f93fa2f550479e4c8912335dfa7584a2cf1fdd83af2bd17446ae77bcf3bb182ba9ad39b58415d8de94716922676a8397d505733fee8b1529fba790902fcd417f13dea4b2c2426228cd4a45a4abc12a75762fcce6bc4ef6a565c9044bc0ba6d8eae940cefb0ee4c007ff7b09027cef77be20de975841c0f75490ef3f4fc4820609b25634d831ae5ee082150c48af277cb065e4eb7e18dd6311f93cef3df041100441f0bbaeeb7a3a5be94944c622b6ee0960447cb0888ff7e1fe3e7cf179f8c22f2c4200236689d402593d618b4811d3d4ea11c3075b9fcdfb8ec4ea2981e0f77de0078220f87d2cd577a91f545ff7a10746efbaeef358443e93f4e3687ac7f9d80dbed8f2f15efc106411a161f678adfd992291223e7466c9d4b281dfb588143149ad1e5164b5887c668fbf1b2975de0ac6d297a3489125bcff7e89eec12f72451124415f13ee983efc254a7f7a6f1569e26bc2569125c43fb582bee67b536b89522be86b9610bb0f5bdffb2f2176ebd80579414882c0d615447668e20a223b983ddfbb37214235d208d1280969846896d00c855ab0c2269f90bbba77e2c174ef7244761f3ef97284459d11946e2503f2f3586116fe42df158890c5108accf05f412f93c9739228969ef47a427417df4dacd00a0fa6f348620bf46040d02864852e45f0202fc6bd9403ca97a37bf7bc15864a9e80818ca396a32948a48f0ab2333ff14889a8a4c89d845f510b9471645231bda2a3294e4e94b454471d206da41371c889e9a98a607a27274a7c6879c26a03a622e3932fa62341d71185a2e7815e4b0dc1ef523d3e13740f6686d1c9136f060f669c81771a18b930bbefa2985d93195653ac949c86543974e870c2831892c252680a81c250a563b5011d3b80483e45f4292e5a21161589454e565a367f42a9443a71273a768462492cfa62bc8ea8138bbe12f8a158641e117964140e903386c4771f73f800c50754ebd47227a5968d8613b115b66c3584a074ded79a315412323d9952a9542aa118d00d8168080fa8c2108ea83a4fe84b26195d0c962030dee64f48b26423639460b4b4842d614bd86a61a13c52a82864b9a9b6500fe67b1b4985f93131bfda141e519137e3dea130407a61249252372d2d945051d017e3fdcb417a30442b902c6f2b4909bf08c3965618b674acd10a1ecc374ef1603eff564629422d4f5a5d80043d1816171a2cff4e2409a395bae96ca5182c9265236d347e9472d3f263eac60b432ff4428f145339a4b7a9157061f91713e2e0c17c1020a57833de7f8f3a125a610a0a092a0825048a3f486ff3bea525bed7b9e7e04af8238d7799d1d170791abfe3f23468bc8bcbbbb48ab89042e690c3bc2f878b2aa5fa140d97a7d14245cb9037d322450b9137f3c27fe214329a38cc7b710a29e4cdb0fcf7a4126fa6e5bf27874829a298c2fc462953cc2f7c97b0f512048d77f91d1aefe2f23476564fe369b48ad0f855d8e23571d737be6d94627ecfc2228558a41272480a0fe6eb5c582fded360bd04e1b5765c7ef53b2f4fe35f9ec6935c58346440626199c10adf532c2d2d2d2d2c9bf7a487211a313d1843bed611e114777defc2128fb814728814f260be77a1026973293652c87bb2e4f236d224fd7b61390d1696b7b914182d0fe363b048a99b183f7ead20972a90e1b39048dfd2d2c29211b2607c8b0c184f82f13c7c3160b0b0b44ab630c809a2cf09a251860bd4d210d03d0f5c0941282d5e8d20ef7c250513a8573d13a95f7925ae28bd12a857bd98fa951751affa1dd4ab5a3ba95f69f91723961ef46458800c997ca5960d348de3e85205f2f4de974a25f04d2c23668904be08a658ac27e0cb11d15671ab299acc7802ce2802ddcbb1caf1f2fee40b0be5c5ac64b8d702a52544cd603122d97c0a8b118b118b118b118bd10865460b9416282d5eb41cb5446979428b9496291eeb73272fb697263d264076a91bd6878f504c5ba9ebdce589ac5a91e77d4b36438b194e4c10156fc8b1651b57ff42a35bbdfcea775e7eb5fa17185e1e86d09321e385b77d66cbfb8c6f5981355e86172dbc19f05f8c5e5e9a78332e307e75c4623403fc1925986134230b6fe6f420942298e014f15fde488d27b65e8258fdcbefacfea5c6af5a3bab7ff9975611197ed5325223c2785b0b94186ff329338a66946086910703fe8935230b0f06fc3a301504498d97e1c7951443561fc30f79791894b862478687e195a8d17a113f865f7d0caf840cad97af15440cbffa17b1b513436bf5b2f32f0f43cbf4a61144d16089ef29d4f77de29b3e7572f39432c93eb41b8bdc05fe0b6bfc2c40b2fc58e430a32fc7cb8326219ff1c2278ee3f8e0474adda4825caa408a9e675a79d47f2c23a6b762428d504ceeadd89230bd154bf52fb06c9f39a325320989cc16d68ca2194545ab2298e0b394c4200f86a56289478e78302092202c3c067c28a088228a29a6f05a5e02f0bb23dedbc420d48a88b4f994b09b51f462e430d1e43946285f0cf8e108e5cbb1d2b2954628291a35a06021b65e8c2440da7c0a5091206fe603bf7bc29b11df45168a25633585cd69ac2a40aefee56dfb85f562f4c580bf62f917f3d2c4047f75e42e25e0db6640f1663c2f8ebc9928de8cf7046f46ca38c59b29bdcd6b955a1e8c7b5e6281ee5d07ae88620b65a29e4b7999e1bd10848486dc16167d2b0f0583150a8d7e934af938bd08ba9fc618bfc312eec06885425fcc8a98ba49b588745d70a902e97df81dcb96c414b0035946cc4e85fa15962d871313353e8a65025b45a19107e33d2915165181f45e2cd9c8928cd5166418d4b54adfd18a679a4216ad800cf2669e20854825aaa223de4cc9484df7e3f8282335a4962d07948f25767f6ad954225015b9cb33b56ca3d078644432068d4f78301e05c8f104e514250c9af279a552e93f5668c4fcc6d183c8a2908b714534a4e603103e0441c9306dee84b4b993aefb5651ac86c88e54e48d2552eb250893a974fa53ab88a965a466150212fccf5b4580b4b913182240da7e48cd07207c08e2851f7de00c8883e991bc100ba3870a8956a8b8ca63f2c48bb75a45aef02f527a53cb96c3f4a76e0564e94d2b53be1c5ee3bd0ac90ad1498ac90aa629a62fa874442ddbca14a6f73690ca0a91bb3c9314931493154c534ca1108b345d450466600cbfeb3cd5f77d200882611886a17874b4b26265c50f32bef7217e46cc2efcef7d841f2907ab2a5655acaa5855b1aa6255c5aa8a5515ab2a5655acaab8e28a0fac3c00822bdc93b1aa0029ae3a9278e4ae4f1583090138a6af0f30d84e4ddf5aa6ad383dc0603b2c4657ac7f0c71f2078cbbbbf9a384bb3f2610478e71b85b5b73806802930131e4eee7ebfb630231640684f3b02d6ec5ae35af354efea001f2879abb9743b099cd36b2e7595355bd677ab3cfcb6e20fc4309eb8bd913a33f5955716d870048200051897f369e9d18a76f77ddc14902ecdcf2a96f0d4dcfb4d5c9e11f78e4700f0fdcaa77881cfe61c78987c061a6c5683e719ac0b90147003ef0c007277cc0e558ec13837d52bdbe4e1f063b757a83c1721ac369d96b55bd27cccb62746072640f53d57bc636d6b1f59eb2a701c974643a3f80c73a3eaaf828f2a1ba7b79d9f63c598caeedeb1cee99b5badd390b611f13f135d450430d25504ac32c4e6ff66e9dc33d7f55f5fa60e991458f11f4c800d90301ee0e00277b18a0070d556d697f53cc6e22be4457fc5b639e14fd1bef2a634e8ce613e6f14ed99fbff1aedae659b1fa321bd9cfcb626c4a1946f329cbe8ef36a3f9fcc13c9cbc79e25ee22eaebda661aff8b66636f559f1e7d4d90d6b6dce30113c17373a7923c58d921b06e0dcc68e07802ce6064c8eec5d3c763c004af2c607554d7fb879ac43f6c004f79dde7ad87bc32ceeb93f6eb0beb52058df1a8ec7ce8e130fa1cf1497f7ddb787bb2faa597c6bf59a4fcde273cdab0d0d0bd17bc5e999d268adbeec0d0cb683048e1b501e3ada1d271e02091b703c8d8ed608208caeee2eb079826bb6bc51de50e27065da9abab07a4f7d7fdf20b773088f1c186c26071c3ee8686b90a0d115d73ca0066622c19138c2ec802924737f4cf3089374248ee059d3dcc5bd11479431b2db39045db18eac5df1a66598f5b2f8e735c63d7878010f2a0f34bc94c508791914074686d976fbdcdaaf2dad456964aa7a6d647fd776871bec0054ea5bdb01b6c3894716f7d97ca6fbdef26eef8a67280f04f0d861dbfc79f350e990021d502f779b1f65f3cba8b816fd9beef465569e35bde5d521067247127648b1d53606af6c9ec1fc4ef5ce6a2251c3c91d3c68a22071844c0f38461c91f3ebfb731fbd3593c60777a771f752052d276151b8bb104ec27aa8edf4f670f2c503f225c50b081d5670248e78191919208c6eb5d529aab6d987933a18a00307bdd31baeed74cde99a9ae54e1fc56c5e73ed47b7fad6727c91830a248ef8adf369c411a5d6adc6e58de2ad714b04b3980832c71239761c89231edff2b9dbfb43cb3733334f985932639343157220ca0108248ef8ccf33975766799c5bd4e57ecc3e2bdde95c53e99e77f7c89e29c3a4bb5cebacd2ce6592f1ab3db8c6fe9cefbd18b599812a33955b739f5c12ceecfabe23e871770c8020e44ee8ec411798de19ebb655fdb69cfdd39f4a2eb25715071d8e18ec41132357d6b6fc411b8cbaef7965ef5d4c16145de10c51d89231e4ddf88234a145f21372cf1e2e40de70d2a1c468ec411e7fd979141d39731e28872cdb816cff2967919f6b2f8861fd7f6ed775e35ce288b53b6b651ec93e213b3587f8ec52d911b1247ad44f1c62c4e9de9e0248e77bffba29f711ab36c3e1f9beebec3c91b507cb3d8674d65b21b41babd39f46256bdbfd31b36b09996d2d2bd6234fdf58a4ede78c1dd8970d28626ee4ecb9fbb3f9f57998bd9b57d7d7f6c50ddcb8df18dcdfba63b45d38b43591b6cb001c59dc5345a3b3b2f4e3f2d7fcf79d5bf1a776b2c0eb2a61fc3b3a6bbcd6c89cb14e671ab759a318b6b3b368a64650c8a6b5b63160784d392a7c430419cb4512ad7fca84e7f3e17a3aa17e6f38a6b3be59335bdb1786354d34096435ee273c52ca6953cb8b358b7afaae9d68fd98b678fe29dd7f59e3d6756d7f6716da7a4e1e88a75fa3afd1cd205c57dc578f6d8e7d65eefb89878c9e2ada634d2852b75cf7a6f9ff37e7d6bcfe2f527ff0f275d34d25bd379d7cef5baa4947bc55a0606250f1e30180f9dd3797d7f67c70ea05cc363070f1e31303b6ee790db39848789e38696071028de01946bb6c6e84e6f291044d400821a64a5dee9e7fde87af3eed166cc49c6b8c8181960b8f052ffd6785f55f6ae12a3cfb3a678f63aa565165ddbdb2dab6ade4138490313569ca42108342441d2c0d2008300b41000060400847b89f5ad9d6c8bfb61334426b7dea7a52fe3c23bdf30ebd218d5698f4ed9df17cf3e776f6a7a69f9716da7b298ecd94cabf1b479c59ff7e3da9741d9fbc3661a2dfffd9527c52cf6c9fa716db39846068005013803006486293358608608ccc0033903caddcbf469f96bc0b7ac6ba05973bab19a53517d7f7235ecbcd6a0d39adad2f49b0fbbd9c9015262f4ded69cd79ebbd736dfeedfda5b0a746fb8b6b5c66aba66fc7aa7b357d5f4e76540f726fb35df3e032973aa7a73ea9a9fcd9f53f1c62a7abe8c47df643fcfb3a63bd51987d1d7e9ff6a962f836219f5de078003dc5dc74900c04800acc856085a4bc8160eac2190ac03b06eb0c0b7c2dd779cfc213d38f932cacf5d5cde6b0a7395b9fbe34b8c6917b73f77d6f60def74c5ae12c70d28ce69ca7ebdcfe215f3d0f29b0f93e5d89b9e290daf78267b57097363882c26a62c615e66af98bd4160700c913d9e9d292eb75f555322bed41b08ef35f7f030d9d61895bdabfc6133045defcf65515ac6ddb3b6f5fd15f7dcadaa5706c56bdbd6f6a368ea93599c4e5f634cdbe92d556f78a7b118c634d9d3f2b3799fd8e7655a86d18ba6fa31ee51e6adde33ab7ae35bd6bfd98cc32ade216b60e1ee394ed6b091358a7077214ed6287989d9546354a77896b2a79eb5fa732afec9fbcfaccade556accb3dedab95ef6f260f675fb395a8a79d6ac7e5ecf74b317f7974d5b225888bb037152062848198048198048197e70f7219c8ce10a5e627576758aae2fc3b3a66a7b691885c962b3dcbdc9de55ee9c85fc78982ccbde55c6ac3f79ed595b1c3ecfbba65b63f4ef5ef189d9df3adffe87cd1018dad53aaa7a6dd0340fc16255bd36427852dd02e1d865db7b59ad63e72cd3d63486d3317cbb2c8d27d5b99daae916a287db39c4e6760e09027473d9d6bc6c6b621d36efabaad9c6d4f85caf7a6b326dc5c1ddeed6f896ee04b9e1ad733a3dee6e4bdd79643477c7a8bb9f3377ef4e4eaebaf01928e0ee5d0c27572c98a53ae4291c21024d70f78f49063c1024860a9ce470f76e0708189123e48405b270f7ae014ea811c3863b3ee0ee1e10373b24a1013434200beefeb53ce04914263094850edc5da48004a6745dc0aaf0e0ee1d12ae0045912f2670841cee0e5640468aa256031b11dcbdeb628623064738808810dc3d366b6b319dc33fac39d51aebb8fbbb7b5dac68b8fbcee8ed5133ce356b6b2ecc83a6eccc86b6a12f7b65eeb49cd99d55fdb9ab62f662f6775e6d401bb006dce1a00e076d802c772780932e3067aa6a77a70161af0f098fc7dd33f683d72e07ef7ab8fb10275ff0c1dd75b0ec8decd7adb61a0bc9e1ee3339b83b0e44ee7e83bbe370f71bee6e83bbdb78e10bf205292e7797410dc0dd6b7018f2052bc8178804e0ee0128b9fb0c369436dc286fb84eeca3aaf7a66ddc8043c7895f33f4f5c231739ef886eb96cf72d6d676ca9363b74e7930eb382c77f761860c1cc760b0db098462349feb4d0f687a8360dca3d41a97eef3e26e698e96aab8dbc53fbfdbd9cbc864f951acefec71b776f6f737e6c11995c93a5fbe0c97eebc3f6bf5bec6a98ac3dd67718a6bba7dfcf3f85c53bd339097c9644f133380a76171fa03e31e5fc30fe031a6c5d69c6a98d7e171e98e6dacd2c4e0d20d73aaf78ce9f0bfb1cae61e6fc3c66336af3ca9ccd62d2b93c9be7c5cdb3c6b8ab6eab9a69f9bbd4c0c2edd9fd7afedf407e69348b52ba7b2574d6f6bcbbaf69a59dacbd47b63db53bde7555b1eccae78cdb874ff555fa7bf6fedee59febc5f86312da6de35a5c91ed7b68a4bb7dade5ea72f933d9bea9c679ff7b770e97ef5b69b4d7d5a8f778bbbe5f3f37e2d532fc6e5c85215b753b5bd3dc6b4371f8ae7668f3fefdfb81bdefb3a0dee9e0fdcdde624a905eeee8ee3248b15ee5e9ea95e537603e5668f67bfde73af3765af8f5ed3bbd76ca3aad706d5596ff68a757ee06ee7905b736bd4f4f6d01a9f67ab53ea1f3643d6f479d6f49659daa3f875fa417ed80c7916d736ae11f125c62cedb13abb6a7a7dee6f20bcded7589db519fdac55f34b990c65f389d967b10f7e3dbbb5ab4cf637f57914aff796c3b5fd6abad7f671f7a6d3dcddfa35e641dbd9ff03dddba318c5f804c2677abb6b0ed56a66f79acff6d4abf9e58a7d529ebfbfa67bc5faf1ec737a7feeebf4319b3e6ed9fd3a7d35e7d9ca93eacfed94cd298b73d578d2dadf4757acf18af53d7f4d1fc53e2cd6987d9d7e6671124f83d7fcfbfe9af2e0d96bf5ded8bc3e9b69a5bee19d7e0e37e490c3ccafb7b69fc5fb6296e7f3fa3f99e5798d6fadd6f731115fca72642febc9915dddde1eb3b98dbb69bcef99fe8a6bfb65d4db12c18fd9fb1a9f29baa69f7f36ce97bbcdbff555b766531abade97c9279e6194cdbfa6ef5af3fab8b6f336509ccbde20cf62dce3353f9e7d4e5df3aff7fc8df7e5c12c0fcfc5f952ab785d6fedfc35d5edbe5be7d115ebe49d35e549d99cdb3904bd3540185d7172d05bb3d35b0a048b7d728870f7d249d413ee9f9b3d8a757bcf97c17ddedfc3dd63dcbd1090ee9f0f0efee156ee5f0f17f7ef068572f787fdb019e20af2c366c8f3aca9d6f8cc6c10770f80bb57048962224f83e29a6e71bf756b7b7d7f1eff0f5eff3e4d2e77fd0c640b2ff3ca8373d9f6ca80063260e2beb6ec7e991c6490ca7656756c64379dfaa4288bd1aeb482173f314ea7e7c4403b3d27aed9b0ec4d4fce0deeb23f31880177d99fcfdb46df201ae31eab1042eed609424d6f8f1f3b3a36ecce8a7bee0ed62c467328069243af107bc53a260c5c2fb0c2d73617c31b5db176c10284c06caba6b707ba621d14637576572170760692dbb8db0d1662a3d15ba39381e8fc642074cf9981d0d91bffc03dd0b5cd3d7606d2736620b01662c5b99d403174c5ba89019a0c79d8d6186d89e19dd715f8b83fecb25934c15d36e4308303bda1c3860e8ce3621c700e680e1c341d37d880832b8b9a2c6650c11154e0857732505181cc5db325eede3ab01b7950ba7b1244dc2de005164029e8c2cb156f20fc19489193ee4757048bfbcfcdbe9b80f7753e70770338890511dc5db3e589d1bc46410aee42f0c2dd8b70d24808aed97286e294dd38e0286d70cd50174ed9ed2e014f8191114d1c8082262dc002c53f9965f3ccdd59b0822c54e09e022c3cd3561c143581fce01f0ce40427e8c1bf8b81110ad4bbd313fbac8fbbb758d973de994cf67aedf1e53e31cb668d840ce8fe9019816739b5dcfa02f1a54c6ea76b7bbbe5134646ffe01e39efec0c449b288e9981a07867201e85ee34c5ab109280a4d9125d71cf79676b5a3befcd85f7ddda86c63ee94e6f298b73f7d0c91114610446ee00f87dff07af3c6b7a61408311c4e0227881fb8eaa5e9b52dbe4d6fb23e79d3b6b750ea7a2f9e623008117eeeebea4a88a22a187699ceef419e04f38058a64b86f20ecba6c7b4340c59dc5522fd67f85b4e6a7b4d8c61a5df32c963b37d637b657bcd73436c40fb8fb036376a7c605822a1eb6e28781e08be9abaa37a66f2c56dbe9cfed1cc2e36576b0b987aa5e1bf5dac0602734cd43c06030582cb662144d6bb1147763380d83d154ac79c0603cce549db541703833efc06033bcbe7fd9d6dc71d9f6f28879191c37b430280e901e36ff6cbcaef707a3d906cf72f7877a6f77dd9887bd9bcdb6cb6236afe92d86f765cfd89aded035ed8965da8ac3e29e33abb7730801766ac3b7bbc6b0daa2f9c68387aa5e1b744d7fc0b8dc8ef9a43c1ae8ded89ca2696ce39e33dd5be75b6cdf18d0bdc580ee4d634cbb9d406b4e71769c78081c3e3b6ee71018ec061f94c80d5dd35bb3b9b56b2c16d30014540342a50686b897ad066c3033f0e4de0c0cb179765db9ab66604889e20c94dc1dc7b3a66a5afb79730a26ae773a4b6b99c54d81db99c206f712cda96906427444e402229caf2dfb79a73f3a7d1ef6aa3fcbea4c13f1e049a41908069ce0eebeb6acceb556b3f70727049acfbb6f0f18200203aa0b04e102585c20bd004e896ff9d432a8b971e9be408b055a50ca72ed47f6b9990cc634199909746fe89a671678c27df6a7056690a20b2f379e7dcc0ce6d1f53e8a7d6e2de6c2ec48d123858c0ae4a00245dc4b2d937dde326db3a63f649fa26baec99d36b272cd8f7d2e564bdc0349812d50800243dccbdcfdc92b8b7950fcfb9a25665b1e9eb4c6b3a6ebdab23ad53baf308fd19402efa5fe18984fd518bae6591a8b4551e41e8590eb28703baf510c717721a2b0c1a3a081d31b8b830c4d71d7e990938d733de0fc1013df174dd1f59e3b4346dc57b5f559717ebd5a881fbc0e9d8e707202209800ea5eca767aa62a0e083f9abbb7cc33bb3f4a7c6bf5bde5d609884b4ae0b8bcf52fc9599203298127ee3216d736dbd2709945253023955051c2c4dd4b594e557beeed6f3c2d9b5fae9927b3b867f1d697c6e29facbe59d6ce8bd34a6c9494c8085021dbe9b378d3f0ed964fcc7eeede309b69678b62b68d800e774d838c0e04ae8000072080422006145940610228582874802225f4849c87c9ca7b93bdeb73eaed1c52e2eeed6132d9bb601af7dcfdc36688ec5d5ac8092155680877a739f900292e2befbe3dc85a36fdc1abec5d42f27e54cd1ba5e5075ce001390f607929b391bdd617b7db6c43973f6c866821b9ab6221fbc6f68a51ac5b1e357d7da8e95b4b7224892cc9bbbb03a294b354bf101f7e351de064df1b9b690e282a1d10d493ff87cd1007c8dc013e78e900bc833c11e5d63c5183f21fbd35280e0c76621f180cdd3a86d33c6b8a62ddc662280e9ac69ea05136c0897ba96f036aba013a18400477d7290388dc81e024521df3c9b818d0bdf9b0736663b1bb6f0fe8c53ea017d7623806c43831c59d30f2d689a0f287cd90bde25bfe0183edfce435688b201404c582620c61013758c0120bc069c20a4d10a12c651beb188b5574bdb5c7b135cb1ef7dc0d830981a6307f63cd698c2ce6c64cb6b1ce9a2383f9bd6216d7561c199a531607b9b5b7744d7fc872b39fcd6a58df1a2e89f4cf74bd389c67310ec53dd9674df12ddd3c6b5ad3d70755bd363c6bda04907bcbd3840e5f33be65dd44c99980623241e43f98c644900c8489f752c76036df603eb75e24475eeebc2261a25375070950b9359277dfb4147df389fbec370deb4e9f46e3d4c649051ca169b30260dc539d9380a3fbc36274e3dccb2480e827ab3f3b0900f292cd8f6327013c78a0383c60b09d2331188982911d186980911f233c2ce1842524b044ce122525bc70d7ae72c5aa0b681751c49aa3aaf707f03a303932994c86cda9ac2707ebf487c5b59df3a5ec860ca77f5fcbc4b06c1502b317a7889222b4227f001b1ce0010728e200a924a0248124893209564e07b905e47080ace05fc3eb5b43cb9896aaaf77faf7718bf7ddeded6fc4e8f06415264706f39bc5b593bd587f8ebd6b2acbbbcd397ccb3a3ac57955c5e7cae6d7e79a71be94b1799fb787d6ad8a7b19ac6f8dec61a5ecc6bb9e962f2ddd3abd40172808d08d1f27fcace0a7023f46fca07c8c5c55afcdeb560df22ebc6620368faeb7881fc0170193536eb555af4fda1229f7c5a52c567956ddbaeea3f876c3693bd0a62d122d4d5b6357d954d830d8ec068014522f4197402fd13be819d82e58232c102254dcd1b5a561212f83c41bf13230f4fec36a7a7897cbe52a6f78a7309d7795371e966303e75d255e736859008fd59b7199c5c9c87480ee0f190e77cff2653ab59d672f23a3f5c5b1ae350bf1ae5216a353d3b756d3b71683f99d6b3f1fc36298c7299b632caeed97bdab5cb36bcd2fc3b3a62a3ed76bc3661e26d0fdf1323bb47a7d78f49c59add9b1d734e3f02ddd5971ed07639676cb2c2d6f1d231293774b046754c6b039f5b9353cd3e90d279433d6262e88e3503168de309f619071b8dcc6ea5dd31e25bae613bfbe3f3a59877bb946f13246df1f14ac5a6795ddeddac3cd6e673f3ad77e7ee5c1bd74f70138b99634d0fda1517cbb2b909b13576f6ea7e4ed48be0571cf43dc48c76a8be2daa99fc7e74df5e8c7867a0217667135b11fbce6da8f9af30c06dbc198a5c57ef0ca6367072d07d7f6e40c845aea01424f0f5089e6dac63700a8b75d2bcb7db6ecd60fdbebfdc1b77407e0f5ba4818f1b8d603c3035b0d6c405ee6aeca629f7c75de559e6c9bf505ba496d294e0a430535b4768367093c4a7812c0b37960783eda0768341a0c63019b001f712f6f353d7c5e736cbee1dbafe9bb7afe3f45d15bbb9fbb3f3d6cfef9980c5d5bf56eddf6c0621e9e94dd42623f788dad1906fbc140d69c67330dcf1e4d51fdaeff32b753a0bfed2c777fd41b5bef1993bdeb1f26a46c1f68cda928be38ef2ab1ceef16b7a62cc66519f59ee94ed9f3775ef55ef1ade5616f0fef2ad92c93c9d0c0cad0b42592aa24da04540ad486ca385d70f69c36678cf39b8d6066c4ecbb575cd501f05f6ecda69a0616eb16bd98fdad5b02fc9731b86537cce330ee79bcd7cbde56e662f5f7dd3916fbe08fc15abd34187d6b1a5d5bdaabea8dc92e56737695b414979e65796efc325a46b338b7dedcece2308b6b734e26edf9bb599918196ed92dc33ea97a63388c7b6430af710cabb31bfbdfabac0bb226ee7ee3a4ec00321bb128312dbc94ed9c59d9eb344686cf3503817919f5a67bc55ba740f827abec0f4e99b2b8cce270f7636438eadd794786d5bbb3aaa6258a31db43766350c470b9939323c4a6c4e7ecef2a8410bd667d31db7366204e9dde569c446669318c6918b33416e3084153032cc17de646cb430781c1767600e59a98be271e0228d7a8ea3d918082440590288204cc114f8e3072441023b6401aa1859731d9acd531145f191c376a0822bb11d33746bbd65cdeafd79cfe5eefcfa3dfe6dcd69fe680328b93fd3edb9c73e5d656afb8cdb9a7e1a8ea3dcb5b6ecd688b35ee516c444716c1c5a661cd32dc93aaab10457c016c5000a002c80cf1c1102397d9bcaaa2f796d5fb32329cdab96f8d0cd736ae65ef7a5f26ef7cb9f5ad3dd9f45c531e9c1c5222c206441051c3103b18a20343c48698a1b489b181c9e9a16f0d0c0683c92e2e377badd3da0ecc973c6bdae635b3af531a4e1973f745efc6b75f5398188a650fdbeb7dfc3bafae1208e7d61fe79da96a66d55cfbb9e54dcb33219e10a215020921861062062f6360f48dc16099b6e2c0603b3f00f59eb2c73ee9be3e298b5122de55c6d4f4f078cd7957a9d18bd9779531376072de556afc821d25eefe83933b383b34bc8ced9c85c4749ac3b5bdf59a5e9d29e5e3d29ad6718202d111d26906a253cbe11e213a34dc4b9dc33d8ff74dcfacf52d7d4dc34e3feb97c13ea98af5e7f00f427242821032830c424a1056040114c48d2053dc659e96f5fec9aa6a96329dc33d1beb0419820c52e654218706396cce0f2054806400c80f2031fc7082cb58bcfee4e4f00fb287a1e9e7700f4ce39db244cc7a78974c46a673f8870d8481c85e4646cb41718680c176640fd3e8c542663dbcab4431504a83d1681acbe11e184ce7f00f30d8ce9a711835bfd418975bd397c5dcb0795759d377ebcfa9fbc46c1ac36255cdecdd30cfa2e87d4dc39ade5a0f3837cd279e619d7d621a0d6f1a580d93c33daf85a837c7e67dd1f5de76d8ccb201a7c0a8242f6eb791a0744aa199010000000063130020381c120a062442a158d3b34ee30314000782ba5c784a1cc9e22cc831658c51849001000000000088246102abe7858f13aa6409680e43c6fc32f8d01fcaeaa3a43d4be725f344a0be30474a9631c026c9b5a6b7066497366380cb36085405abd9526d90d5728547a3b3a6dd2d0da04456fe7b155cf8789720ab1c94f29bcbb3f30f31112e551a7d23fa5d0cb843a56545e725f422161a6782c7af504ffdabb0f9a7dd217a758fe95dbc9b25bb310992a26145a4127e0ce9fd7e28ca60c6640a262c4965d8bcaab35c17de6040103d93e61029831b2ab37b25ff76331a2e723ea5f30b532835b8039a3c4935d1f7fb1c571f938f2bdce0650a28d3ff20e13a7963a3e6cea99aa3438c545a22c4dd7b7609fc632fd02d3e96720dc556a66d6ae770eef4544998ba9fff622010b14c2525768f01e11a48c10c40d6c12e61198b91a3a2d3bb4eaa89370aaa430de24b26dda401023f8922331eaae55083c3872317f94bf670c57d82112b9b78cf20718ec8d13ddc8fe406caa9b3451384bb89d3c2ac07d9a42f82aff4b5ca3681c74421012ecb50fd4e2098e102b3be8c2cd268a2d8ed07689cc87ad782062e13470fc2259ab626f56338bc22841e13fde02692cfa98b0879abdd24eb36f8aab0e8e8bdb673362b60cff81053c6afbc8d6a8ee09e1c4dcf8a9fab690dd1fad3deeb86a8eade83c60d30a56ab51e6e808044d6079ac60f08b8e9079bb7ec6f6ace4f9de24729fa2829c525a736ce0384c041647d548c2dd430927b9d304676f88e48a34b18c954db87386c8f2c5f1795e083e5e736fe7eb54301e792726c9ac57e1c95c91ce9f9d7a17b2ee8e3d2bb4ba1abab03851881705ac1c9cac9d55a12423087613ca2da49d1d7a10ca0053f76a95629c40ca7150b3f74f2589e499d5169f89f37343b9b018f838efc97a1f611ccd0d097ddca0b9ff007d5d2a7aaa956271298216adf73ad3c0918fa51f6c89b9e4279ff1be525a67893178250629cf4f3468193d509550be2748b0ed37d51d03192a5e057e7d048e600d2da465b7f37d0b2dd448bbbfa5ad493ce9181eb62354e747c70dcbaa322a152500daf9a048a13ccb76a95510dcf71a0d5916cf188b1819b9560276a7ef98fed67cc2b4fe32f8afa9168394f95d07a028390c2d2695484dd33a1bf9ff20c17ae0c96e4d3a09a64d389bf0b4446af063fd513f204f460320a8b034ed4ce124967b0eab79b181c7dadc1e5559ebf0018a60db4658dbc1945fdb83c92d23d67910e0c454b6e483a68a4abf7c72277d659a8f17b43df6a4ec239ee4ce4369894f20151b0fc9baa7fe57e4e55c88d66901cbe4ae3ce1abdd6ab325b1f5cba92c79be060142e2082ac4f2ff6ad35c01c5fb701623183935929ef26ddea91d705cca1f3edaa969404b702df0ec0f23203c4f4bfa6adfb5efdd0f3b01d36722104febf7c2d448ddb1acf93a84aaf5062226d514d7f814d788c1d60445a51a1abe337624e23568dd11d5630e5a775c8547eb5c4d6031686c7ac11b973f9720967a746c02954fd65cb0147bf33936f9714de4ae11aa8a0059b173351725fa20d9b1d9e39a22c8a06c46cabedd7f2f007ba719d483344b9a2a854dce99872b77915830fd27f554bd2fb0606ee2eab62ec6ec847a188e6b1aa0169ba510969c9ec2a35f7b552428988fcc21e3e2e998c1f4c7b25a76ff14226988f8df24cf13e051aa2e608b86e0d02cb40ccfbc7d265445cb7fa80e2c4bb3aea61e78a3cefec8e92a6809f8e3a542e51be3a10bb01ba454348360c5d1e7cb2cc728d7f6ac310a15a04c1d6438a635abd2c90f88486087d471ab0168e80caa2c8cb0a3dffb344ed3b5456c5274213a50a01b780a9544ccdcad833f6ab3d85649538c87cb952a4399543df9fba3919e5700a50f86923358d3885e183cc762e4046986216e5e837c5ef52a65c2f41fab92445dc263c120ee79f62d456d43663146bef55df7b9eeb639cd7526bb4def65533649faa9408d1d3368188010f9e02876afd3ff39b9510ebb8f174b7bdb413faf3230f49116cdb44f4622a92c21babc443b72be8a78c089738bf9f332110a1e618f725f469a9c0a59f2b012e0dec87d2db99e8334b75949408d5975bfde666c83a0ca7780046bb13862b7c22f4c27d3ba3fcdb65b3e0a3c0490917389094f3cae0bdab9b89499706a956dceb18efc934c894172d85e4c313829ba3d03d05d97015b7807070ac85e26e16282da2c0e2dffaac82cc01bc46e549a0d439427d6f9900beae3ad0c8091812bf66f8e22e8ef7d55b68066b62bacf452409e022dfc1e11942cc0879781e116322674c2a908937c0ea5763ea0a71fa151db219c2a649ac03eff4071c315618d1217be71c6ece53418683a9fa9db5365f7ba03cc3b8f5d8f95717298ac76e8392f9bb7262ad7e03381e263977f39b45db7a885317bf8f3fe7e7259d9ab88ebf6751a2459418314d7301a7e66c82356bde28e86a9d28c93c325c2af810972d835c19856b54615a045555db90b9451b9d998dbb9ca87f6a3a13aeca98e4e279a660b49ccb87dd8a8d2e1fc892154034b40bf817b3f14b24f101ffb241a261913148b55e276a2f727daa40f96d281c40ae1fc4876fea6f1fbece2a7e26e97366e1effacc0fcc4e8ed4976e373f6444ef45c84c43be1cb9bb498d42caa3e40d6028413b940fe2b300371ff3f6376252627913e18908821fe8f3d5844a6cee8ca66cefee62da719304ceafab6412d08f5a73afa8312f8d996cdb103da2fd3f6f316ac63c6640575759034d6d5c084d326bafe4bb780a728c5f466bef3ac302b7c12388be625828d69be8b1a5377deeec904d52894f9f97f3dc4e290719ab2e8daa3e1af645a9044289652642784ac9be6bc5aaaf84f171727bc80f97721b48f9cdfadc1cbfc981d0fead31335b45f44d4b5688d43615e4e22ad7e3a565ce40137b9b184ed32246eafd53a5d7b342dbb48414976c4e65b5917e375442d9035714a9e3f06b86cc23fa633b64f5674f1e74ed28d9fd0d8f084de41f3280ec4baaba2e5bb3a94a0bfd274b1e269efb0235494966bb2646616386325f5e292cede87e9e75b3254d07602782652bc0c2af5d194f3d4dea64882ce873f1db2d3294c9118de813c6a68849539de92750291508b216eade8886f9461dce96fef9b92eda2640f74ec932a372da18e310ef0be0d103bdbe749e443c1fa925be21bfa821887fd0b0cd396afabc7076bd86e99935be42fe69e6ad8d13c76ce17f70470023592a857e62031de75483c9004d5ed8c948a48dbbc02baa520133450f5c961a4f650433154d149d97b309f60afe1f4e38f892a8d87356e10e3c00950bbf02f4e9db8b282782d36d06940cc3cffd0a223f8fc5c31390c174d35e34157e6d9e4d2b774f43caed608a32ec3422e0847e4e5444ecc75d762644f4bda35d7c4a65e0449d73a3798750705d8f6f0e449029dcd14a42a4ee000a7483e3f781f6d24e955f571caf11a551f2cf36b657be1abee727b1a917583eac5256e4c09794a24610c7262bcf5cacec652919f98c8c5dd449262434c086e9fa17480d058f68d41fe3d675463024be2f18bb5d083d18b0bfd5d9feeefc3b0e2922c751626f461383a2e5b1b03ee8f0cc442eac0da3faeb634d8842fe7b85718d14b7a04b1e8c587c3b98bb80f354f13f2ed1cd660c2b432274dc6c836dbc8c60d3a33a7f758d1c2bad328c7116faa07b1f9ab7adea24c92c9372e0a129ee212a90ae2330139196deab4d63d864ff002c8c7cc18069d15d3d635a80cf7c3ae3f237693b9a8b2d5a67402c241df6d4680e2ff37a029a53e5b4a51615759ad84a1e107f273cee3282ae6e48a0c30917d99f604cc1058e0890b98d389b73506c9a3a6cc65ede272fb7800345ce599832eaca37188072ff49b9c3c7edddd2fddef4781da0355dc75e0a3d3c1812c7c0a863ae6020de0e61ef4f127de6888cb7cb0e02f3bbebdac145b101da386e3fc14db6a285ad825123345245890cfb2a8b3f63a44b2b1cf3513eba9784f1e2c8adccef8f05069d12178cac73c22e4fc09b549a088128524b6ac69e9a4d64f17dd02cc0f960edb618db23085b4ad706c2abf5b4e1962fc43ca2887110d6d7b278052b5312ff64af1f06d8b1daa6d89cf960f87f7304ef3895ac66270ee3eb1d46fbd9230416169b8b9a03e6b28b8935670122ecb2d94f9e38841b00f10baaf62cd8ea1ed193ba9e2da2a8c01a033641356dc85be950e315ed076ebd11f00a1d1a517e7d285860897ebe54193c23a62c6cba1ee07f9940bbfab7e13c0f3cfdf4c8a5d52d28c4078fbf34feb3acd2f869fb0f1c5ecf509311709261d7057d10bdc0044d741ceb32db7351ed3e9563643ca83b448c523028bd2d2bea87aabb78f30926b611fef12fa83d99b927ff10ac812a1bbcd101a26cf16a038d79908d96ee0cd3b679df39fb42b63806dd8089b29dcd544dad6df165c68f6c9c4268e160e5a865dcb998970eb90ed0c640f994e7f233896cd34cf7cd71c16352b5b307720d02842747a9078060735886847a5da2a0db06beb5b8e61341232b195e41b8a352da659db0fb322f2d1c7e9ac255bda073958746fcd7254ea2bf4a1c6eadcc03cc783583a421fc73a3abeef6ea4de1b3777b7aac1700af570b0fc8dc0f2381cf7eea01a6dfd362100445b3a9cb7bb92f03de15d0ab4c35f8f3983ccab5804f8dc82caf5d47f83e385073748b6ad754abf02073ca5a12540473cffe883d97a1975d1da2ff2d630585641f8aa286db129461fa6c1a8d36c66b6e14f7224fc168c6740f1ce3ba884cb04677e1211ab29479e89cfbaaf964114db0c8c350c4677dfeb8f05933b661d7ef8b9ad33e800a95bb769b3d9cf20afef638dc8f4bc2c637c02b0f6228779ad442b89933a3bc67fee8c773345752e56b19ed02c5149392accfbd267e63363f46bc7af2208e44fe1b62a60b41d2c35131f2b90f6596925e5c1f6ac6c4b21e3ee91808a880b01519291812a0136f83cb2a37970b1454b54e42cacf283b0b1f9b2d4fce3d7494af0199636bc364409a8eb9047e2ccd6d3d5cd5d962432830665239d49152affde9516c12db454c21620472d835d574815cba4f02b7f169951dd44361759a1219a80e4294af8d8c8918fcfa869ce96b372b461932adf19735831a360c14ab91d5ed4c15e23dece1440d5c91259191a22b3000951a6cf0ed56014d5c9ae099a8411158f4eaf61f1396be5971342ad53e642c909c7c1cd47e3c83b52058b2dc240ec24b550e5fd35e44e9fb1989034f20a022191bfe3c1869b64360d79da17b07476b438817cb989d1d399ac99bf499079fd229304896546cfc1604c6467fdc3410ecf8cd778119c25ff3181a0f95b31633f816ccbd8e6c6aaee473a17121b18f0ee1d8dd79fa384e0e8640fee7ff0edfcf39ff6e4cc30db68bfefcb36e5a85dc63fc81a936e3aa5d25c9bdb84b13b48e60a3a5f846ebd567b96533d01ae3e02a3de70496b3854ff16b3552d78cdfdb0d2db72642007e543ba92cb8b8d458028cd81145f2a81a4ddcf2ea657f7330b8af1e4f0723e29c065c5ab2e6db0a3dc0f229e0106d5954ce0caa899dd3838b9568323c6ea6b96d027346c946f84bcf0f9832f1ffd4b36faf5011bb4debd8f8b5dd898cf3c9e6c7317224944f8e62e9ff66e0bf58eb26ca463bff707d0f367d38047689e4f8ecd47f85b387b843f5c4bc3785c0db277d8b225f2ce1d6fa05786b65012e34a9b3b547ecb173455b96bf14e41321bcdf7ec91653c65d4242d3ca84d19c48ddfff2688e35a4e60307666399a9b401a50aeabe4cd3e71b6edb3ea0ea744bde46a8238e0d859bd8567c2624d20761f94fd136fa8b3e086e9fbd8e4126cc696b81b2372b6a972edd39945a5d1dfcce270a6b08ed2e2e119a556dc2d7147473898fc211a9883f69a67174935d241c39dcbb61f66bc95f1d05d5b9cf312f7f9177a008c4c48461fdaa53722ad72db4ae2341b52056e6c5551f599d31aa0bb3eb8cde4e697b8089980418f8c4f2a82d91d54bcfa537687a2cd73f301e9bf50d3ef4add7792b1f7ffeee8c3dffdb593eddfa8d691cda7b47dc330a47c3a116ed4994f3651006cb13e9af36fcd095a732ca4a82b81ffa391730bee0923ffec71beafb37a1844c19205e0635002bea3a81c189d3664ec24affb017d08fa6fdd304ada5d61d28c8a34afdff13b4e5f3d8df873f4a6c7ab990592a883399f8d0464c30b1939098a391ddb45b4c2d8d9060204c7e42f04b21e6e2ff1b576fc914f352baf7fde9b91d5fd0331bcdb07a6a8d8f8f797906e50194d0f3cd0423d07e253f78cba045a5db31f6021ae4a5fa2ba85067cbf5a7242f3f59c031f18a6a14214e11f9ea7bb0294342aa805b3605427a50e01fbd3aa4282cba8d48a22983832dd8926408582d0c65a02bc289d1664dd420c4f8e81b4b1a5b207459ffe5ad5f65302c8e751b8a8b938adc1d5ad44bd2339a71d8a2d5d5c1ee578f277e65861b917324053924f8d15dc17c9e1bf6646fd2afc0a2f7d727e72f2a2634f5c4d81ff743755e8f0d0192269b2524eb1c8f9b28145cbc48382f9523d04a170826658b7c4ca3297649724d3d4245de58c40c31cc0fa655df2bf1b45446794569b653beec086e6dda0043fa47713ef217044054056f45a1bcfb374611a435db665314b7decf8d7c369799c3cff76ecea2db56e838f5042f14750441a3f86729f5665435472e7bd1d168534618e4128a2e2fcea0f41c947511706590c88815ac9071043dc114da82d14532615101146bfdfe089c9e556eae0824e8aab1eed01c6b6577c1d0e4da957f19dc91b52c31ce9d52523d7dcde563d08f21e5787c619552cde1039f89601a7fcbfe90085365a4b0a25d483cc4c5de8205ecd717772c3c4300e0c7c638c731770eb826052afe79fadbfbfe795bc9374d0912a422bf4814de187011bd30f0f009b63e153d989c3337cf0b292e78d7508808621bc25bfd869aa6bdfc979528d8e6201fc61d1456e587b1f08c1540a206740a1f8a9d00de2c6c9a8f9812df909c81b02efb161fd8a350e564163088beaca05b04a963e198a55676cccb965889e617aca20ec2e93c16001ea881f0a77e0ce7542eee0c3d50c1432be0353eeda531a720776edbb4a8ab1a5bf79f8b882995844c26df44b5bd2019487c00ff579fe145c70288540c0415a945cbda3c2ae89515e4182477f450dd73ad6c118e8ed42685c4cd8f6dd244ff54021d5ee0fc8e971348ed0cf0008550c2a24a5f0c86b5920f4587b8bf8158d34da3d0c92f92cd80643f0ac42d5fe3f0187abbc1eab7922d27bdcd554bb3ca82db1b1559ed05fb44de66a27b1d8d4787a1d27ecc2c8dc8a3bd0ff805e4803899190e3e378689a672d9e49a6b3b86c3f528fab31bfbc41d6b0fcce4d6f5d20c66f0db2c35727f05fc39ea5900f718ed4c25ae758aa762649d0f2fa10027e27b6f58972979b832cc5ddc9fd69714b7ccc4be1cd00fe0c02e8509247eba1c2f4deb3c82e3b6f7a738f8f30c66f76611566be523c75eca12ace8d4ae22f3efd025bc3ad7d0476dbb793646ebeb15e39af5a8d59ccec3ae5e2c02c9600e64b3005d82d6f36da4c24d2d479db891595db33b640233c0e34541ea663d4149ccba08793f0b01ddf0f51a3e586600baba5c6765d90fa32d6d5c191302d254f5d7ed74c5a3a679221df71aa497014e41a73280a8117a07cd647c2e9b1110567a7652a51062a54ec95c23b8a3c55957b09a157a1366e7a3cd53faf2f948ac7edc2fa8c9ccf480f5a7fe15026a092da5658c70e4675cc56d430ba93ca0502e4fb164adbbf36bba0f9536b96f43b7c8f4859d8a3f12188241168a16380e57442e0942e080246aa381e2170434b7e4da677197c7d6747ceac14bfa35da94b310eafe144adea5669508aeb5e6497c9efebe11935cd60d3c52b51abc79e36d3e6dc98b55f24e36e96c9785b75092d94540d364f423dceb60582351894b682c888802ad7aa46680668a5afc2b891d5d94636a1dfe054789059acb797b80ecaf5e155f71e0ff97cb196063dce45c8550a12ebfe059390154e564a3e06a2d8f4771e9cde560523129aaa04032d9c0e402b4ae177ce042ccb561c059670bc02a1abb676cba185117216a138636c084ad906d6c1bd603e6654962d7e9a206020f430a9b2ace0f4cea933e4e3727fe00da58932f3d03f551d13233ab82e114423cb9fd526528e9944fea0c4c0a6d2dfa278483ab27e0ae607df34f4ad83d38bfcf09c2979334b28decc6bb28b3bfe67453152bb39cb6377d4fd2d45339576e262941363b6c89ad8104970ed6662ef5c6bfb1e9a5ee99c9e2afa39f980f44b31166bcc21b6381a85c78ef81414cccd582f89ea2bdf8eb56a954d25600a807a7b8bb5dac730579f8e53528e617495807617ac80ebd90b8ba03e6190c3a84fbc2cd8b7124e1002b348558ebcb1ea7f02d516e7b3da2f59f951dd7c2bfbf0e32bfbaf9190cd2090c8a0bba3cf7d8936b9ed5658918d403d30c43778124692e9b0d38e46e72be771485c223a1462357b04cf97f4db11bf8f96c32776598ab49efeeaf97ebdaec5930f05a84187f7ece6504503f5f86b34346b8d7eaee93925d89c23fa214c10555790c04a088673fe282a4fd8a08a4d5acd3bb055cb6fb08fe7fc66141e6c225cec2182b5fa8521df412891afe5ebb4c45f2fc62d37c3be3c4ee6fb39c4784237cc37d8b26f63dd9a80d186adfb123526fa3333e6e2d28bcc2b88882b2c94a8b6b31a59dd49140c49af812d1c392c8a128e2f691c9b1f2beceb2668821d9ff887f6688a880bf877cd33c35111fd9b98aa7de125caf605d867662e831f25e2a4e0f28bbf78c13854bce3e71a3d883650340afb2cafedcfd33c336b166c93814ff80e0c69f58e739f36ce710df7b91b3c72658cd0c86bce44827f348a3a27e15da354809bb8d48da87a2b9df07e19ec95f5baae2f6fa5ad9d0bca7283f719fd54d4b89563f14e91ad963cf4e2166d88cc2ac9307fcf55ea87113c2ad0a86695689bb4d918e304712d2914b4d5e95fb550a9c3fbeddb51fd3ab35b20f8be1cdf5d1928eb3a80f284515d02a419b481a30e2259389212d6c7454811ab4bba22554599b2e9917ec5a049e60339e00a3a78ae24a062180049061999de12200b4aca8403ae3e20abe7e35020d76b0ce11f04d4dad1fe49f85063a530e230b810a0fc32cec11da83ff9b50e36b22b0d28231ccea19389965be09bcc848e993f160211c59768e7df3defe60d88037d292812ed043b5619f339574d2ef5a081df530cd4cbc31cea663c24bf3323769881073ef7dd8ab56b2569616d7beca8977e725a791e5fdf35641f2b97a9136cc0b7aaf0db1880d6b12a7a7206a34348840fec0c9758bfa9d890f91539d9baf752a6256cf5824d8742b0dc1a89ff0c7993baedffe81246b63f121c8c3e102c424a031b023bc986c46fdbfc4a8499033fc665407cbfc7c958bf4c144c38273808e1879e6624f8cc12487fdf39b47c8a6daf16ba9ca20f4492904e92dd769fe5e69d5575cc61ddbdb0f0d4229d8009747356039bba86b49bd8afcf2f3db2f58993d86d7077d3dd9277e2ffb0026cb4c9c9e485d4eb49bc3c9a104b34474716c389f2a131f6f386ccf80454c5f69138abe879c71da65a037b07a1e44fef5d3105624e6dededb0cf9b6ca2030e116d3705d1d093cf7a583117590a1cd33b23bcb5f6d7e613b75f7a4c3b7eedd0ef9c95658096f915e31f6a8672934ac5b81632cdcdd9b3f29b1c9d61a465d74159856d959d6e7694a824e50106bcd1bb0bfac0d4b5225e4abaaa619ff3cad37187f482f287aef95d50a42bb2bf1ce98c3643f841d2b3b696a1a1b84c872a20548386998ec55195eb7196eab6cf14df04c367948be4e35e018842859cef552564b400f43d1ea51ebca7e47f0227658cf3fd37b9d05c97d1f6d0b627aef0a9ad122f7c4ccf0e190bd33135a16d3677ebe37450cf21b307d0ce7b5f982a1b831346288584604376f5a2966e164f70f0df355efde9d1b435b98534b6d4d6e366d48bdfc3d36e3051c01307f217b6637d2c02dd0ea2fdfde5cd041c10c4d97c520834fd386b07b0c1540bf91e64a109e9e22491259779bff8d015e14c13af36b45d475e357fa39f0bdd764827549858fcd0a53df68ae65797d9bc43b2cbef1367d71fdaa87690a39f0fae00a9c19d9fe920e886608fff632c78c4f901467eeb56d3de74934894598c298c05df29055aedda9e3e90fa645ca875ec48ae74ea56fbd7a1bbe99680709b98a30a1553c267d7a317cc401d1879428d9e1ff090dc43c4c2633551401da7b2b630171cb84eb11d8afcde0ca5ee828a14302ea44b0f60a333b09cb9ad8bb6a1ee2d3e01fe26a92ce14915a9bc21e5c3de910572383153dc53e52129ed10edd024ade57d4a820c4b02f4cb13bd49151ddc5246f59ab54db9e21b00bb934ecf9c08e772b761f3953d4e8a19e432e7d970022f243ef9c77b98b2059d71e1175436aba6873ff4f67bb819333b8bd94785509176f3595db5fb78ae30a60353f9f801c112336a1f9b3fab183b92ea0b211acf3a17f7f2202c7c1588ae183eb5b81d14d8d0aa1e1490ae031eef5758e915b3b7dd64e07a57078e9a66bb515ea19e402082c92f6599a5378a3bc7c163241dcbc1b99a10db3de3844705e2a6b8434ff43a98af229119d75f518cdaf6ff54efa5d8d244cdcfd46fc547cdacddb764d1e9635d8000322b9144e5cb74f6eace54aa1bc73898501a31e3378dd280525bc0c7d28edb7a3e02fbf54557984edc128a2caafebef0a8f8ee337d47b2c64e5c50f0ebb8886ca3c5a4f99acaf13ad717faaec7b172092bfa56e8838317076e3ddd56fb6b8622ef0f084e4b65571d8cff73e532ece9e15f4b359f4b6e46fcdad89d455b333b3cfd0a01a568efb374793a8e2330fee652dc525ff78f9202533ed723812dd25188760da8afcd3323f3bb9b8d901b077b045c26a9568deca1c7d00daafc76f68e56791f62fd5043fcc4848ada77283e2769b0c24eaf8e37f46f61f6115eab798ffbe5b7ea721b901fb6e66f18119e749d4f3261ed0c6128346584536ea57895256dd16e4a3a78a6a53e6fa2cc919287e624461a343bd0341bfd6e5d1d5fe643def4e3d69de4f93eeae74844cbd8907a233bac6b1ada8cb307dd1c056e109ef27343c83b22bace246ecf2cb768e40501bdf4838acb08ca8577cb5a42c38b7599ed7a111dcdfa47062d1a1f5a18ca2ab52146d6113361e5ffc077e4bd8e4d52ff57067f1ba5ddb7dd448ed9a10a801ae39df64839f525fa4b1afa23b1a228fade01564196aea7323e59c00ef69e99c990d5920a4e273e4b63dfe01ea2cc9e37cb4167e24ab04244a52103d1171fd7c844d696d2362465babb93b5baeaf0af4035384e79a6390729cf8d6578734fa8a008d6351363410915edac29e39edaedaca8ebd920213fb14540e5f5011ad5522d141bdc4c60c1bf12f90e8432dfc1771d58083f82e8c72887d37205439f61863f4b07fdbca900e6e4fabe4347ea6647e2230acd0dc994a004c85d2fb345a26c4b112380e1cc70336e02225af40e5a9cf969c0435286fe3083456563051b40b3c3bbb17d076997c6262c91fb74ae9fa9264122285b020c602c0d4f174fbfdea441e26b58db487435c0ded13496b2abb5265e78a62863b68c1a8eb759a8ec0cd5c08d73c23f2fdf2dffbd8c409d7f5b52f5c63ecd69300201488bce7ba1973e54265ef03383973c36b6f885ee016b8fac4845217c23b7de0ef42ed46041fa634f786628fafaeacd333bef28c43415965cd861a364743b136885f9477c6fc068dbb7b9f07f833bf7d3efa09e2b5803e1d91eac9fe69047c257d56cb3c362b452ae61e6552a444489eb4cef9667071601eb8396474f83e6bc96fe92c28f9d2dfbd825e78f141b8c0ba2f6a34444024282e68132cc80a273d3ce0305609db89f465467532be6fce12e42103167c09c3df14faa5e909a9c21b82c9fc00c0cd609184640e7198ba14b9d00c106e760fc0adb19a0803798b93e20a7d3a4bddba898394e6fd007a39d5e8cecc18f3ddd5abdff2a823b10479dfa130e95974be331c252d28fc2db3756e4402dc6d1447e173decf04abbab6836b8478e6337e78e97d86d4d406b103391a25d4472baa035ae7cc7dafd96148d5e2a7205340e51985fae535f381d21e414349f26a388fd5f95104cf4002a0422ce97059f825255d2f4d3d434c08bf6f5e991e91735484c84e5499d355531e54026c969046e3c34dc4a31aa176830c8b70e95d3a9c8077bbbf8b5376f54969a27fa20189c52ce47ddf84b4be2a79bb2b0c64b096e6bf859a3f00813330d9cab35aa63dc909d82c84c1430592d852cc092de3f9c0f77f91bc21b9f507c2c53781eda25448babab8ec7bdad5c57c2f59e016386e23c57594d49b907657aa9744a2db9e4eba2760889f5b5b86047720f255c62346b72eddcc88c22387af1f89d3b5bff8cf2476a3ca47acde2e1cc53a0a00d883138b755e8eb3c92d78ff4ca8d3ed0baf33522756d6b7ca9d4fcbc61e4202aac2b1b7bc22ed4f1b4d1a1fc8b155c682aa185ace1da062c163176939dbd0bae9510feedc6015ad185a5758de8d93355bc11e0f5f449a839ebbefb29e527bfb6174fcc62af15170b8f0f57e652840ba9ba1e4b06fb82d3a5750b2b70a8aa4d233b3f183b9177a05bc605a7d418e483d1ae6e6b3a43d1af3bef4f9de11bc528a2383ef013ddfc59865cc92ea562c73217d3dfbbc9310dfdc55005fd85ecfc20a7480d442bddcf5968c4bbd8db3ca5a9faeffe2146f1c3b538ada4a5848f02928ac00d9c6f40864e7e074488abbffeb71a65f37bfd8d6b97057e55d3df280ad1ac1963f8b01b43db0b3f4f5682c41b38269000cd79eebdc223633f7ea60fef8b89d4f3afdebf2e83932f98f29790ba717df83281fe756d9a7e364345843b28060b5659e6552c11b580fdf5d43bf8dc3800dec38fe0150200b8edd66c5f7cada7106fb8d63b3618a9cef52e377cf8477b9b8bf02520da107308b2e760fbcbe3bc00649f0b8a804460b0ec925601128fae38318558ed12d49b5de402f31556301678a903823e8f7dac9d6be5042c4c800ecaefb5c84da813311329d670c93fc630ca82d7716e2f30579432353b6ed6b728248fd290c657826840101f7e8c4db318d23c60b76316c4c5a50864c795b1779ecc69b6abe0068416579addfb8a12442693e100af295ad945ca5f4d2eecb612a4c57094c245dfed1cf7c5c12e69a0be25ff42d5442d8ae31e832edebf14d8b6d6f778a7595c58af84a38b77677ead37f59e0ca5a8bc53dc42030d4e0765813e903166601fabfa2938335b42dc6bceae69a9d9471439c6323b4e230b8020b359ef6878204ded86e25500895a3ee794067593b0137ef307d8450ddf366086a0d896b3ca34a6e65bd5cbdb142d211ba9a4415f0183dce9e144dbca8a924bf5b2375bbcbd393f1abbda239cc1afd9e0088dd9293b92616483a46f628134d029dbfabf46c41c28233a002454347aa715f44d2779a065ec8b0b60ba9d188b6874a18347d173de8b043dec680d0e6a01dfdab5c44d20986a90333801bb9cf1f2b3bf24aaa75bee29e89ec71c0a6930acbb69d1f9df7bb46e0f51f438afc832993ccc20b4fdb80027b9ec5dc00803285f7a8d77c2c8c8c0e4ca8c7585d9f38fca050d395a23df1db545610cc9e80e415270a46e5246e87c638999234a6e5d3e1e957602c0e5c48f7a628a0a313860cc3bf15639903bbeb528aa6393719eb0321b5a7e12f18de25f2754716aad2dfdedbf4c061505b0337ae5173cc7f2ce3fee4e219b73fb7e54b1229cc6e8f803d336bd832b5b882616cdc2e302a1a03ece752c789c38de46c5cba74c8853a31b8b962c3b221531886166c7e10dc7ec8c02813b09f65384841cc01a94683adff6fa8a04250514086df3dcc56b28f2af23ec8fdb1088ad119f343be5813dfdd3205ca9133b75ff69884e2818c49e59fd24ae1309fd64150f53e52e78870a125a6642125b38379a5e1ab0acc03ae31a29512c7c449ae9daf52e56e4e62e8c670cdec576cc26f1bb5940053beeeffdb5dc47ad432acf647fee95db2fb5fe24d525e318ff26f9c3f8adc572a8ed1644c84e5475dfec2af04d80e7409f8c77f0f0e0142c1d9c7e5eeb43e60036871a00519b02a6106f3860b54b4c84850941f5cf11bde8e41cc057893784d3958e9b7d669d9a50314e1cd472b7910f38d069bcd6f77c0f8a054b8014eceb11dc1c4d8b9d1ec55d8a24cd6668d26d80f967c9efcbead2bdde58b012cfc87b83c477c8d143789d88dba7805b9ffc6d1c9413cbdef76a5b360bc0d4f84f75f3be809f95148ab84a7986091b6de4cfa6ac62a04c9b958e4039a3a4a190d48d875dcd6309367234e1cc24107a55644f3c48678fdce39aa81a0a4c809d8e13bcf38274809b33b96b449993ff859c51fd17d17e899b53cfd2be056e0a1a9cdbabb140aec150faa09766c8787ff77ecb2f1acb31a8a71f7d06d40240016dc20f1683c40e5ee46fe0139f03d5ef8e6e3067ce8e77ba267a170e4d91ea9424c31324c92a0152b9e23c8f445cd829cc5baec388ab28232ecb818ce5a6acde415c8fe3f61694149964df8866dcc2fcd35ba543b70f16faf59630f540f0ab1acd5be54c31b06fe2043072b7c671c075f9cb782f930ca64f94ca3155b6fb1b84e3cdcca7f303f5d43b830b9f956854be893155d43907cd4c4a8f6ecfc77b0d77d65a8fffb028780d0757054220f3dcfd3cdb6660418e5d52cbd655c953f7f06560c9ee88b845e449a13a11eb7fda7951eb0087cd2642171013e3b88f765c850f996863f3399f474fe73233db81e0e9e633b07cabd770f4c86f664e409898ebc35a9445381618cfd3dff1fabb2b17fdd0b3c45591d19f7656ae80cc571779640a614abc307e571d67303c308aa9a97570937d1f11d650089d1f10bed02cf26cfcb4dc446080712c8a9e848df870afe3bd25530f90cf52eb6ac7977ebd1efd5d436976e531cba1174cb04ffc211a20d2750671643175fe7e05e639f3e3e8c3da9cc9569fffc32c2b93daac12fd8fcc0cbfdbcc23f120eada70271159dc08a0d59d8dd236b1341267bcd9fb60b0953ec948abc31f5ae3957acf5bff412e8c067a09f459f87cabe63ac0d3ed15c44198c120ce18f4b130396daf0efcf9f41ffdf0af2f90910f5470786eefbbef75ca3077e04efaf6c3c7ff61461598d3595f0c8fa06fcf18c9f5ae0eed88b8d196cc44045fc573b6c4684b101c88d79ec2fbeb5f2988afed366ff2000f351c78e82a013625f5ae02560176c236ab1031d06a8b117c5feb2802ae975f0311c5caf10ebedfdf5fd2edb75a0385894ea14847fe47c9e4176b82963bcbbf4634efbb36ca67720b6d69e5aca3ad8955f41ea4cdc9f55ac735bdebfc194113340835a47815b7086cda55b81950fdc7cd2807f433012ddf1b2affc80556c026f72a2b163a8f75be2954777c306b3fbbe01e39088a2d42c7cd95f97005bf9e9f06f55fc7eaa780ab905bf0ad641a9941447f25f6790b11f937260fceb1bcb3b73bffbd1ff88f73f486fceb0266580cba34325bf5df823bcfd343bc8f8ba72263877f66aa01d913eefdbdd4a699ea668969a3db4494e91ab9e345d42ced134575827a42701cdee1d64396d34322dafb5e6af94ec2e69335052aac4c43db2ec810dbf4d1c3fe2a83a0910f347ab767a7022a27ec127985572e71feb87141d6ed72ced6ad7454704c9423ae04034f16d7e2eeb44f006c63a85a0a03f5216b83407e5b349d995505b67787de5a95e51ac2732b0e220a469dc4e73490189d1ac76e660b648046c52207cbc47978926632108ef9affcaffe885a7f8e91b924a4aca1c1a5c2e2c8cff36b384fe914fbd6c1475baa7ac2a73a8f89998b98aeae421eadc4b97fe13c8a64c2e07cde18a408dc9d8c833637bbbef5b56693e5c2c7bd00e996946b12461f76197f77f85bc14f342281dfc2d4119ae8456ec156f34a76ae887fd5fa45983b67764737cd95eabdf425d384c02426eb4946e1ddd9bef2b5d2941b10ae0af14b05b06c2ea7759e44b4a4f6f924fbfc1834d11c1970950ab6877116cbeb025bc2bbfa1b6be9f3e47a09a3f777a2323bece2742c60986729668b86a4e4086366c1bbc0b3dd4492e4b06d6c39e0a0f269667bd3adaf74a9f92c43cd20d6b42fb17493adb8726bd19d126cb4b8a4a724e579da8fd189155b80df2582211977e55047b7ededdd7a3c7c0cf8dc091d696258cf18d717cb85c707c323ad76d1a31706d3301033f5e9fed13125503f0a3a40cb41b398290e1e51aa1d3d05ab20a6d824af65553daa15049e2ae85e8ceff864e4a4f47fc1e810d815ac21e55c15bb98be33d45f17a63f605145ce1bc63df199dc43b1f5a4d1f192650c43a0cfbd8568a0132cdfa6cfbd92edbb1d04c343b316f4b4e75ca3ce1ab5f257cd5016ac8df8f421ab12d82a4bce3cb62ca7f56b63a97ae11b99a8b3ef6fd3a4b59b72dbe10394eaec90732390c171e84cd4eb9931aeb8c3a4b28298c6c5fdfb1ea2f9a4c1b37769964ac9c2e80f9b539f6d4803875fec0d3cf27a353194458a924102ed2585fb8bf26a16e2792b3712c5e084d30b20e4b1f39495d15697d4c3073ebb18dbfa0038693a9522809dc5e7ed989d6b56822b355fcf81a01bc170128dc26e8cb0df69012e9363e77b4b86e0d347334219b5d615b4c408276051deed65f8f5f462cf4ae912b84c903908afe50f27284222b2e85576796e90979868a7d9238b003e1e4be5c5ba799e379b6caa820c2527631d61950158f6a32f83216d32fe1d8afb0c11890582f72f3bf6c25a8ecbf6ee3c519d461b961718f927558e28dbd7b34be1739afbfced3436410ccbf25bd385775d0d3bce07816614783b3bcc295a81c74892bb9f07bbd81a02f35725fdfc96c48b0daabfa28634f8ee86d9260a372021363ede15f116a7131f5de9599e76ee294e5b117a4494d556f910de7e27ce062206ccd18db5d096c113d9b26e6c2c570a7971c262a5db77c0dfe28b33aae86fb4edf16ad171f469df9987f771e10e95d72564c9c30964089d838c85232d501f42fe7bc5860dc0bebab898c1b76b618cb86ebb2d3502d08003090daeb719d3644f208ef4c6de169a98a40e4ab51b2f95d60ca56bd244c8ccb4be9e6566bb8717ab7331edd910499dd44e9be6a363bc6d1b5fdb30b967f1f78ae21ff10237d54234ed559fd4607c6cb3465e1ca9a6219968e5e63aa94ac85ce6244316a5fa1101481458fbb4abed89e2d64601537755b25ce9b29f9621a41a23bae9f7e179375e4fa2c559b2458b36d9c156b1f972a255fd1da952e26c0cd57ad249689ad4a93da5355c6514d9fef73d1b13e1929e57f26e01850d392b70ad5eedf0c2b20a2193bfeb88af184a11f1f76772cb0ad0c62d069f67f625572bb73e09da5fd882e6ee3a7981d1693511d283d4a6f6358b9938e40f43f80d82dfda5e48e3953b246b34359f0a2f75393c1e71d13b87d9368818b0271369b909592159b2ca02a255f279a852b00446b58e38ae0f3fed5012ba54b4aee689f76f14385962662842c2a75d6895b2e91841a79a7180f8b8501e9c82a2b6b71850c6dba13657e659fed6d61bc1d6d0d2ea58ca0e14c3ef5674d07daa0b2f97ae7663a34e9f3295dde23c843a6d3e01cb6191303a2e2cbf5bfc088917bf1bbde3c4f22ae63c2d5ae17ac2d13bf902e1c009a22ea9b25c149e5f08a54706316709705587280bb6661b915f5f2abf6b3d5c906d44390ad0dd55cc44f5d9b472467a320773aea28484efd1d3290f36e63d64582998c7fe6cb45d268fc688fb6470af7c04cc6ac9edd10f4f4d525f23c503f1de3eee5b2b8a1df5fe9ce82b4cf31e6da245a04d723b644c2a94d9ae121f310ae1724378740afb1644246001c1ba6f969d6aee9a116e73afee5c9c89bdc26c7c58a1c4707dd3b1d49082a6d38c76039d8a8e7f0287b835b4a0ea0d9b5ee1ce2a089203b998c3b944729285884b3dd2a3710840dd063e712cdf3d9c0cf873aaeff979d8aa5705cfcb8ae83a7cb31461af220a3c16056614d8e2b37650747bc37047e7a5b48f343752580dbca49a9d65244b5ecfe85565dd38f1cf7714925a42224e43d3138eb9155bf6b8f796e5c67f784e3c532a448a6bb46700d75cb4d043a4ca937719745d14f164d7a328259371319f7abda5388c3c0db27a9390ce265f97ae955d0974bbf9fc1e6f77afa86c9b70202f4df7968da023283c257c172b577a9cb8c1e4940aec90ae52700134ba850f80977044c8cb21afa8392b4df2efad0fd8ca3652871a660e45118e1e3b2dc1b1f38f98d524c95b4ce9f1ceda47c4d1c6f4d1289ae5874d0434d80496e126982b6f823f2d10eff64860e062ce80e9dd968f7d42298dca89667d70f1c593089aa5a025cc68a9dfa2a1c708c755651b65534b4c9215cedc9b61a674bf1a25b558982604077e1d1ffb168e33a1091b540360672ec390076577aa6d32c6633e9c622b5f911293b4397857c85d09863dfc84e66219c2c69231a971ae816ce4ba62a2897bee86e79072f0f278deea293233adc48fab3973dc13d5d5d5429a77edafde72e9f8b4112e40c6306f425090b390f68bc6af8732e0794a60b7dde618609471012bd4ac547276f59d250acfe5f6b9dc18eb3f9aea07874c785843ee4239aafb0c1848e11260818d21f573304f4283b3ec0eb0c6f1bbbc7c36748fb0454fe45ece976cb28e3fbeb86f5a048da1dcdf4c34fdd7089b099d388565cdaecd01551426ecc6a79946561def3bbd54dc926f5a94255c1c2967f52bff439ff151690ab2dc77b3c2ba048aee5be17cf36bfa15815ff1f92c3f53434668a4ca11ad32062d233f5d472dc901d076f5a8dd75f3e4f172e086e919589f088e350396adeb2004e636cd50ce40876a08338ad82a1b5f46bd88d47d404bea7900d070e37667503d5b64cfcc5ebc156008a1f4a7a1b7f2baa7977c4652ea2e6fefb17b55929e10835fbbfef829d6ad8dd3799528e02f2f2bcb73b13987a016e4aaac1de935d0e41a48ae7932cf9f640e5a1785f09f87e3de4c3c711457b773751e016c4ed761989017fe08c25bfcdb4e20b52e33127f4465c4568fea6fce0c3cd2623422b993cf4f88c62df10663262bf50e4eb123884b20eb674e77797484268e900f532b5584655da2a5d58b6104a36d14cda8614b4a1aa2ca6ab454ecae8e9face953eb68d4e39b199072da78706440757b5a11020f2a93138bbd4cc74b661ae7e86c723d902a6ae58214e8d0a26f2808a498dc8f0079b414e9fc6c56a1052c3a3573118d20d2158a639ba43684184c16ea233915ee28714fe79c583cfa5267ab3a519ff204958671ca4882c962993b94cb161eb4ab590a101340443df82c38904c001a03d7a9b41eb9afe7cd12aca65f1cfeea9e4c977a2f25912cddf9628c17e85531265b104138bda2ecec3475bb3dff5eeeca7a950789d8e1a16a5a863a539813b83ae4e45a9b029b5043a33552e6821132e5ddaff01abcd8b54ca6acb5c6ca30e0468e1c97f7e4b6df56ea88ec78197b67c514784375697d4fc8de89ff47effdba2258749660f4a9022eaeed1de4efb6722a207d9b0998df413f21425d4d9c0c81a2a3307b0b2e250765389a4c54e1dac938dd5f91ebc2581a6e8a28d5ea9f450a703980874eea1f3288fc800de8053caac9ebff468a1af3d7d301b18c91d60c4a3689e434df4f0bca4c968f79c3df5945d06b1da3f9701dfaea5f6c2271a2939bca61186d68714b1705f1c120ba8da6ee2320bebd5db600cabeb5a34cf0b55d397c6a8e05b1d8008529df6509c2a204f6f0b8da7609fe92028b545109b83ec12939ea173b7f100f465ccee59c0915a984b979f92ff8516688112a37aeca1c5d19465d8e4879855c6756a05ed5a3febe6b0e5bd3b819ee153033beb2ead23a561e0b919e468e6fd7e67c1ebdadde6cf93b13e4cf5cc8e84b9416cb8466e32a5d502fd83cd26bccb58eb56fbc021cbb56d450fe8ef542108a577070a341689d62de45e8bca2cc0fab7f0136addc6f5aefa78c481909409779e403d2d8d996a66a8006ccdf07d359c4957697884b3f190a6b290feb9a76cb540d48d276fde6f650f87b16d73053423e2f2647efe168f4e420cf61e18583ba9c0a720f2591c6fb821447296a93c2a779594b74b112dbaf82e322edf193f0b27f998cf868faec45d72254bc7fcfa0c6598ff766502caf79b418e3bdb843d1f3fbddf3492fb8d7f274b6ed83ab34ac71b74c0f1af702de787f0bca40a5e71e8cf38041246a608090136ca68cdfbb8706b8f40f9a7df596767cebc7edafefeffaecc0bb71d6bde6370b8cafd54ef81da9735b548e9ceba7175c007be55ea539909f16f03150d78c585de274613aaeabc5c9e172f341e4e3814265c5f249a68fe2d6ace216da519d1260b8f67b529260e0562240f498c5c4e59644934626468df22b46752b2b7ff8f59b05cdd83cac400c5c82814263ce68bc41e7809762b9da1ad87a1c188a150ddb475c1614c528556d2f93ff71b96f25095dd6293b0c7a13e5c4e5bfd790832b8cbe3d5c9efcbc651d2f5d14b781355634d8a1fc6b71b21f4ed00f92076c3846d13d4f52472dabdf3c48dfcd7b852ad53f428d8cb228da82e2fb3b82c555544e29c56441d153b97928d08acb71064f080997d0d3de0f6b157b1d22141194d905ab678d1e545c05919546d2ed28e047c50782c69999708f434e23eed2a66a814d15a0639a3415290c3e8b2a0c3cffb53da78d089192c10596f0dbe7bbd8ecad8809b4245f31903c1b68a310659cfc0c6f6f45047de7968b3a5b185d1aa3e082be32d547f44389456481fcbe316a411f3e1e8a4366bd6124558a0bf4869f450112c90dabe3865d5cb77fc6464a3a3d6f6873b32a297adbdc1f86888c3043b2948a140408706ed600a332a701367064640e10732f92eda85b23551e857401ca98a41dae472a3fbe8e51ce74e0b0a03f94a045f140923a410d9aefab41ed11f3cb6b9be848b4182b4abe8b1eb7ba380e6da12a0873c4da38f8cb32544259707b3d5c4b57ce94a52ece354e8d81065723819019fb01be178e634a892e781207cd7ba5f87f58861b1901c8a574c775dbad481d89424a38ac5bba189a0cf23ba6ad4f72b016bc2d0027580a9f351c93af51b8dab105813aa2e9f98fd552733fcf09bb23ec93cd63ca2d2b0b43c67e56c1ee24b81af6b7d10d291788170af0f28cadcc5f3659d9d970f334cb4df4e469ff6937f571b5525abf47687828f04ed8e21479c64d971cc9d08ea8d149f141fbc7b5de7a2563b71980173312037e229a4271091b4e38e1a78ba413c7a290abbbd1a9d0d3e8a592978de7b5ca15a78c2095859f30b3b8669be7ba461b588996eb594937f5d86e74be94e0079382bf11e51a48887b23a3b21a3f304a9f7010359b46ed3c75943ceb93ff448ab5451d65a27f2fdef1489eec23e9904a6167ae634568de3bfc66c315669f8fd04b42ff5c56b877cca2efa42d205e10c053f02d8d56bf3eedfe8aa53ccb5689c5f85b848e9727f3d73ddbe38938296f9f97fb3771017453e8b1bdb0223ac8bdb254fa6ac742fcdfb856dde86c6bdf2c7671fd154ea46db27a3cef2db91cb806c2589e82310719c07cef888e6af1af86f27cdc52b2e57ffc804062c82be2e93037adbc957b5ba7e5e649cdbd38c2cf54e7c6306b0748f9b6d0c04aef09380d19434ab726cd5748b6cfa07f4c358b28b33a5449796cd32f8255b5792fbce078eb202d931c1270ec7500c02fa7c91ea88987d0f76c781e371d451e934962c893ba23c7cc8d4ee9eb1ffb69a37b13d176b84bbd345038cc8a8c448f9de895d4b5255e2dd1df1feb1669a724353ba391dc3561dbac2a05ee62575e657e21b0ac57b7c396edf90d360d4e452004d53c72413912a6be18415e358227e0f2b05ba8dd2a727972a141869178f98cb8aabc8da819a044760684100bb703053e5b18ff5c5e5ac7d777ba5c3187a73000e0b77bc66de86a3b74df8f2bae5329c7e02dfbe7e16f4ef788a8f4a168c9d74d67ac76529233cff2ffe2050b093490ca268ef2133a4ebf4bed8eb4dfc814a295873d11cd72e3cb61cf124a9c41afe536b3be53581ee11c37bec1f1ce5f145f758e1a6f01e731593fb9841d7774cb2a6452246dc7e005a17fc54639d3d9eb02a1119ab38bf4a0f7209446430d3d370e4fb9ba176d5bf34feca9e4e50a5197fd2da467c2d7d60231e0984a1fe6e4f57dec80c1a505482abd8d2c40e77d52c056668414c721ff3916630927314a3e33125831f20e268f1038b5515732da82150a5d6c9b1aaa90893bb1e46004f67f599472e3bcf9ac2aa06b085314d52703db3e8c3c4c9aa2421df6864ed31b9ad902b3b4e79da872dc2c9b0baa55c3cca5c0f6c27fd306563e2f2e290f8d3c13e734341224e75b02cf0459738c4c9d4b3114c1ade2db167cbde48a70f7a7d6c734d7054826dcf20e876e5234d30bd78651363a7371644eca555771bbcd8bcbaf0ee8da00e5b7636665d3572a6947b63c5fe745ca32b65217673dca0efd1873e8c4384e4439dd9587851fe512b658c0e2d22100dc0ab82d26af10e3177a9c90808763f1e44301c57acd6a31d483c5686bf52346b598f6d41e5a06238a413cb84a84cb1744755926d06580a4078c3200de357a014d06e3d24d06ec5a11a27498b899a18a4250e446e37d0173b580f09b45a08884c5babd8f8e40650f8ef4c27f12d96ec33e7e11fac70e2129c407b7eb857c22d622d4210ad31157c0939e1a382af3aaf0ac27cb6bda79d908085a2ccb8da5e07782769b1add545e6a26075b8750a7f6e27692b344b4edca853e44340d6414581220e02303e398912ef1d06402d032731458d06e2c05bdf7cf70a0c5c4dbe063d54ec56f50e1fac7fb4d81f77f2f6f27038adfcdc8c101dde9d6d775de4386b4bb95b508e6de9196e70829369ee4ea095e14d297ab7ee98dd2f4affbf7967bc2257110608e2345ab8455513286421d7c357a18b6eb5611a9f89ac6d64842c676b7ec0e872a6748f6b4826dca52b6ea4093abbcd0b2cd6ca26f8cbe188d7bd829b4f7408202008ae58304b0f0fbdfe6e0b7bd6a14f62595ea0549a8f7125646afe178129f024d81079346689d12085b50c92dbdcf514556de89741cbc8cd42a68c8049e4c68668c2e8c340caf411cfbcc570335c649b0a6b0f3b789f3af1c878716561eecae0b62f6fa02ac8ae06bf463fc04dbe848dd7c41350b0111c6b734bcf804158d0c48fec64c99334f161bf68372a1b60508c739a8c7e2ffe884fb3e2150308b02a5d3ff2c042bedce85d9309a7a789ad8e9eb3ef48874842c9f0b1db991e2599607a52c75607ae60af20eb059c1f06f90b57a4a65357bd093fd52b34bd0712eca3c0b8d6af1713d4fd47644d5a43396bca37245aaee77cae158a8ce61c3d5f0f42130a584b802634b7e3a3262bbcc95cc98ddc8f123b35a1590f80fb8b5c17c79da2bbb5e7ea80c7bed4ee120d91bb8769679039e545b17931ba1a1ac6fcd85d6af728caa952147e9e0863bf92a8c889493cbaa9e18986e7867a70f22b86030038d7db25ef0c7b664f338845dcf1ea4325c526e62e97b2ee94ad32e87c056ae78bf05c83704ac43804ea3602653b19ae943564baffb620a83b65d532bfd62e539a54bae626df27d91e4c54465a3d45290213336b039e022764b60002c597bcb8acce049084ef7d340e2ca17583556a8c9bf6eb55e2ee516e73d3a7d3fb9f46db10206f4e92ab0f947a34d4b1749e50600552667ed1e88634450be8fb49851d401fa1254a245675195f239e58d0aadcb6dda106c8c97af6a4061d61d85af980e52c5994deb62208af22ac7e6cd9a2340b6a47abdb1b6ca1e788e1ebe03faf577614a224f420e1b3a212968fcd10fbba989ee7ac8d2edc39551ce5ae5253d08604599932bd662e39c4f9c23147794292ac4809f11a2b6c09c7ec43ed8aa868bccbc9049f0cd0d4b0aa55afa84a7def5ae4ad28d907492b337ce797a5bed40849ed85dccbd90af0ea7c181b0fc36d242caaad5c3eb8701e1dc33045b10961cb92f2a490d984f788283eff5d34f1e05f42b656a2a799c9a3804c7e5d849c43a1906296c50403044b4742bc9ec666847ec5bd759bc1ede9bd97b33a11973da03c2710deae80139ed84e1e9310ac13c7f143145eba24b138b38af419e873a2232bd0d6f2c9db35953f51fd3ba4622c82fa13367fb8c9ac0ee7f0ab78aa0e57e70b6104f2883a59d71c6356be6f80418bbbf83bcec5a1c45b89b065b7426fbcc27a616ee3c6004c448286fe4d0c689d8e0bb8df91a3c551db2e959ce3709a2ee55e684c4f999a79434907924218384fdbbffb780c339f948982bcdb863e47c74e39028eff45a5821afc829120daabf2d8c5d168545d5fc6d8dfc0ad4288d85180caf1f650a4e4cb2c1d20dc32c2f58ca2e51eb6371e82c0768a2455206c9dc26271d1ce3c2cc4335392490f4b6bf55c91c89e86b3d3a534e2515e76f1e1a41460de737398feae0177d040f69bef02729d2cd1fa7dc05bac588a84b6028093b9131cb446a84ca43014c357c270ca703082c97f4a06d1f5beac6b92f7d4c3d2a44258ed6a4cacf7aaa429d14511b3cbd120dceb5b6f8bc87f655f4ef5eadf8ab7b7038a3c18b1f4c316d83f6a080510b52310239a9712aa70d49595d142827c48b50013c7d7e876ab397d3e0ff548d1a27b79bf22d2f4b56ea900494566d3aa97e93547ff3c48393f058438b82a06c0729f1c89da9aa6b5768d0c052ac1bb424764b6358a6daa04d7b151fcc496c978a5b0a53c88a1d5caca0321a87004a658ad85cf79c014dc0bf4403a6e7da6950826098019101f95d1163dd6df427b07c3201e8544e0ec497ae6ee7836ea7f0c58f4e0e85640d1273508aecb3b8a75a2d3c63fc1712dfe54a2582669b0c28fd1d1511df10fb706fe7b9008ab58161969cd28ce697e83ef958bc7c780b5e2628b6e2545c075ffff62efd9847f85d22ac9d9f8f9012feb4fc25723c06a187ae6af47b135d099e0a7f97ba164a30b3fc914ed020f0f4f3eb6f6ce4a74ba332492234ef125dc8c175eda800044b56b67672debb8f6b72b148f99163007e44c96b2988fd9967c3e2c55426d79570e370e777a3589c65320004e1ecdc7c7702aee5a738177c9bbf0dcfcd0845955af15fde6dece6e68ae058d2afd383d99e16c319c266e31e152c48481a343ccfdd919237b8c0e018388712558ff7d53089b22dd73b69170d7c59c0538282c261f0877b84fe42b9d72466ae59ad6878d0c138affd462d196fec0372ab3bd1825287fed87ad1c55b8e8dbfcbebb18ccac8e633b1b0cb64de7d1b328911dbad40118974c051ea1d05b21deb611c1297b1c7a4c3488cb9d28d9ffb35fd83a64a4cb783a4aecdf836f1d057b67d5041f0f547e2a14eb063c7d38d9d96255713a3e49d46c85a42ccec7c273cb017555f21e410b8fd1bb602710fec26d66528eae7f900bb0de63f79518c22ceb0aedf817e12dff178217e4121526a3c432b3d1d24dbd5741269fe6eadc5893f71b3ce9134e413cc6f39d7da0994199ec67994b99bac72838a030faa2e8276fb283cfd8a058a0e57a4ac863456259b72c1a514081722639360d29c9747bfdd18454082255ef2b79f68bef124b3ece86ab2feb934b7777192e571b74451fbc34422983215fbde56752c2cc04597dd10fc4cfda86031185a661576148acc59e6cd33d3c7c3fa435c1360392d26798649504e993fa6dce627940274919645e05a26bb02c99662f8084ba8295561ec2bc3ab4cae550499b0a0cb80a13cb66fb4b470778af132ea2d21578ed610af7fd3863d1a21734b7736f32e2c7aa63d13217cf7b354269b7950b6375938b69e4dfeaa0de6d576fa9fd3bac8d601187ea76ef7ef20889260e9205118e87572db9fd6d4d92bbc454266492f073fcc1b9422f9ccb7059f8035c2003355de9b0909fce50e52959725510e76eed76844dc9d2d2fc36e1ee5ad9fe26e617cb32494e2f6c70fc331316040c9a1acb2d5dcb4f3a50bc2df08bb9abda09fa539bc98a8578940d91aa9abeb90488151a20b556c04b4da540c89dd45203f7dc5a92c0c857e25660a855c884c9528dd845130e2eb6774b8a85dc3e189ac3bd97c1bd3523d71a83ad3ee399cc04120634d8c09a1872a3008036d84016af791340208d2e401c7aed864b23ea10c0029a2c203d34d43bd674449d144242db141450c400518300777d70f2566270f0acc44487e25150fa7a18b65db73c7c0bdfc619dc9e76b514771590983fed24a955211835fdc3feff049d805e4e461730b63cf03f95e08dc1594bcc61561dc22bef1b8ec1ba9369e32ce64d78d141d6e029cbc5a5b2b24b4363bb357526d123aecadcc95307ab40e648b5aa60cabae0618e07b30371130789521aa17bf146077c5c589d09520e4e0f9879d62d86411de30a5e331696e2125e77af5e9333307e299523cc57e57d687062535dcd0b1822726f0cd93c41151daa22b9933471d1f75fcc0c2d99a1448d49a93f3f2a88bad539f928f2a79f04842d7f76407863c27543d80c09ffd83e19bb20629cec0aaf0a5ce1800276c3b0f76ec927094d49f0d32b567dde055698b7fcbd2f53542296bf7564181947182f1e8b84c49c48a8166325e8f4ff29b7b5e9e58f932b0545ca2a5de37a4bc0e8172ac79d74fa22037eb60b0b52eb6d98f27454ecbc22752060c1c4284e0dba6312d36569251d740a017f287c5600873c23425da6a575685a7c010d29fcb1bdc6e61f92a9f0c166172c759d2114839ba2a6e0176440341f30020fdf9fa1fa0c18cf953314268bf12a3db4f0451bc646bb3a96a187bd91980c7522f60281e01e921a43f13bea6c4d3194fa206a75a3e70fe7911c188aff91e2eb7ea1b7871143313afa003fec8124175aff87ebd67d0b856e712b03ed73d1fc8f6cd601d9fc8d28c6427530581d2c94c85c9fa0b06657e8eceb23f77917918bd00a7a4c7c9cff775cc9d623b18f051b004ba15a773f51fbbd9901242885c625bcf4581b30ddd92944a13af068ff240c0a8d48c5bbada410a1179ea25357a1de8f6a61d8e828bafc22d1a922903a9986bf71f4b6dad4c9c9900ac8eb892a285201b038a5fb04e6ee792119db1e133ff9b620264ac764eb563c3a8d632c0bbfa9c9a113d43b8444a0fc00ddddee9f6cef2929670af2410d3f1b8eec1b2a53ae6b553a3a49a2c4cb8ec7efb25a9b604fc2bdeb6654ff64ff482d7589d90c39cde43d8771932ac9cc746635b79066781a4133716e18137134311a1124e8ee604c1eb3b2785d93e2dd3a95ce84b0334422959266d0479b95cfe2dc972e06b2a88fe8bcba9603689ae18a0412526c2d365ed3c2291b8d9ca0dd86db2892ea001a075933319e7a03dee3438a2955333175cdc16ce67f210eac95e00f46e8373f756d12af248f993ac93935c9689fe42499e1445b53ee54c6cf5a30dba23c934d9d2305f47e123ab801377ae17fe1522ff9d0b50b976ab11b554e4ef8311b37bec1f16506aa801fbb4f71ac58d286684630133b994910005aa1000d28145d2b58c71ad66a9d2534a6611bd3900668aa00263181893b81c94ce289b1d9cbebcf49fafe2b6080b189e00deab301ceba87bec0544bce2248575f9e7bd738a6e8cd82eda003a81f7d4e54661ffaf2643a1ed1e9600ad890ec975921c6d11d63f353fc7007d38701a8c684c8c3e997a1abb695165a9b48bf0ca07e894984719bf40dd8e0e1346a1b8023fb6d265447ceb14d54f2e0acaf7e99111165c80f285f451ee1f6cb2c9d6838e02f08b231f96be856807ffdf5b0c3fdb3ac19f4e6042048d92f339eb0137ae19e9223acf7cbd0dcc009d965f04fdf7ab88512151b0b5ca9fedacbe85dbc02f73cd05ff073d21f14c424ff9454c5e6c0ba70e44c906392613792d9c35b668428959cf7bd9b45f724c223f2facb86678d2874585147a8f834483d4a6fdb2f83e4fc94913912a1e1324469bf2d89a2585953b7c38451f6cb5c9a0abc461884b64488913b4028570361dc95b92142d9ed1017b5acedacac4a2ccf3b4e18164cd94f6c719d0701f56522949075b023ee052d97738b8471b96888e783dd84b397d8a77297becc5e89f6bfdf92d94f03a7af08a35bf9fbfebc9194e5040dcc3bbd2601b1290ad4455f668985c69da4301aac3ddfed499e9d571df1fa32cbf605e975d2f0c339cfe5be8cbfce6656aad218a6588ee12d11ea8fcb0afaf357a60aeff2408e50b4c52534d292425f267a50cbe629ac06f12492f958422ba89a8a704ac488e3c5790504fc23a2f865051a60bf654e0fd3858af03538950b173f075da62a82207522fa27d3ba8f2edc12e628b2d7802ca0b35e3a70ca50508d7d2d0745d054e1d097d9671a134ebebb4258ffaf94ebef7488ece5e1e56568445c29e6fe53d6931d20183236c921c0f94730a3f059009115b478fc64555959f07afa9895bb9fc4478db8def46b006e2807eea26ea1a7382bc4e7acdca13a9f8155776885f966a5dc8290b00c4a4f44fed20a911a3c11d83cb5726c8fadffb290ca7af2b73b7dd55a31801d30aec9968faf7d130acf49796fd88ad6e3495b41e75420e156c84d44bc95f7ea1002895278118188ea5e428cfd4f48ec0f4c3addeb6ea48f08a20e02a65f49ab8c8b07d5a54169fb2d864f57c7cda35a37844998bb49756c318bd27bf45dc321a3693dfa68c1f7aaa4f084525c9db0cd4d620b14ce2a63d0731e26c5e81dfc0babb6ebf2b53501984de6d03c204375ee00b19702304076a900e051a98940604acd2854b82f860d155c5c0a4c88aa70019b513a083cfa1ad028f13585811aa76f108a094d63f1622f058cd0b8222df46dbc7aac093207b5c191564a15ea71e68b9aae2c30f82a137e8a94f3da1099aa1b4f1a70ee97a2f816f0610039c69c6190f6efc6529b092b3c0f44ae083f052c8e976d2b233acfa508e08a68e197a08f651a4b947494417779bffb05448c053d23e2b76caffde2e3671ff172dd19e5a4cda3f28f4de6840566be1b04f9c6a940cfff7e53b640a03b5e3398084ea589f06c7e859417508cad19a66740f168a80cfb25d322fb94fb114107266327c8e350d27466f272a1812e323588592b9049425180b4568bf61bad4875f91bfb12102f6b2c5fc5c73e0afe0640611ce5602b2a8ee391bf16f9ea5dc49e57f544ccf285657be3e39f836dcfe11fa1845b9ef4d3b77577396ce585d9a762533b10f228865c8db6609a1c7abcfe68163089cbeae5251b9989454eca5be2ec73aae743f8dca7556f5881f9051256af5f708017c5b298d51bc2f85cd15a8f3646ba71d8ef17a9d5adc0b2ccd51b36f8a96258a93558c5b0e4d51ba263eae3a9cce4e459c9fa80aa8ab9bd188325b1c3ea15d844c27a0ba28a905d020fc4a46818ce2928820fc368396160a0436189fe19e3d1a4da2b8ebf3da8df928063c42d8ac3f841cb073d61a7254628e6cf55a7d8c1f4748e662af0332e76028350c9fd67961a90c8aedb7bd6c3f2c8684de310f9c199441a4908d5d40fd024f9cc4aa4ed2cfba264a7b27977b25aea404741e61832b69ed40453dd19e1ded2acd3ac4be9582b19ad85e15bf1ed04726dd5ea8bdee05c5a95eeca4084b6571212949dc9017f271ed56d24af2ceac500d51982e3a22aebdd6038d91e2851d1904abbdbbea86c48b8075b015f7323e6f61bf058a5fd07d30c33272acc426720f54443675f0432ee646c6fb06a82e3ef63b1ce18124f62e112603d1c4160de7059e5824132ade1588811e35df58c206fb9c9f0a0b4c924ccacf53fd04242f71ce3e33b922af40cbd50037f2567e907cfbd004dc8dbb9dce22027e186689948eb92ba8e4a1df0fbae1f75f1b1114df14b7de44c27dd8af9d7511fe3a93b44e683ca61f454d8026369a90e3e1159ceaf47ad79e9d1d2b79b496cfd3ac46692c35a13bb3355d34fad3742642d4bf91b95eee6851735139901a06e058da2d1870c48f042d58d4c42e06681270967f1c49903a1e81b5160948d4cf20185f4a49f89ec82c0648aa4b82be9b1f781c8603433902c84a9817c631b25689011762bf8bfeff07920933fe68ad1b11615b784582a11bbf671a42cef153bf010fc94088aaa23445d80700722974de478a20aa280c0eafddf21f82340b11488091bd58dcc0da188c62aa7270398a500ce8cddee6f24afb7bf2f4e87d2d0a7eff2b501b761f49f81401587f10537a520a334a3032cada6996091ec4ad01230bb20cc5bb4f63090fc0ecbc7fc6ab2f34de07c7550c6d5e969a9005cd594584d180767e5313417e3940a63e6068039c14af7e0ccf8c4cdc6db017d1384b61a6e00e3240a46383d184475e0e42f267c6ca21228197438c9b2000018181823040c38c43f6e87f10505445c091db775d9dd35b8b917227e0d4ed22f4970921038faf06af7f76fa212e93212d82419bd8ab11ecd25475c248edb0b3debf4e43914946922a5c3fdf86c1f5409a565d12ec37bfa26814b828a6206997c9328867b3fb9ab1efb671a136561c58954131792cec1d2b12fa14d8a9e6fa691459a15813c3c019d81d5de479511e05b69e4fccb1517956c058cb72db3ac641222582711d3ba1ce33578d26ce19043b904f77f5828bb7d6e4dd24ac755e2b4e96434d1c4dda16d03d348facaf6926ae46a12a2cdfa6dd148e5ddae72da6c0b0e0ad77d6445239323a7930a398081ad743527197276dd5135e196cfec9387efd067a946d8b0db9caa719e8184e92ced38e6545e345d46aa87782464d8e938c9488c7592d9f03007128502ce17299fede9c8b63c40a4cffe2c1027518ef3106502f3df86c97528287991c8e38f189c67fc00286862c59d259ff4e545e8e6ee4c38b73f7257080f3709b7aaba290de944332e249cd75e17a35fd238b461497dce44e82b5547693a30cbc051e17c5a566133fe6b4d015f85d99c1bb2bfe78456302ac083180fda86224569cf3047f50f46461363dba6eee7b16f5f2a4775ab780f21cf1bec9bd1178ff0129d008b098eba8daad507b99467f5127275c68e4ff60e3398fdacadff15f11d04c4e04cb3cf3b28e6ff2350f250a10ebe89126fed1751305190e061865c48fa5a630c513860b463afba6828c7375c49751833c5bfaffedee78bb66d98945c2c3970601252bd4227e33968367e245557b14628c6254a3ae87adfc37ae17c3c9c3f2baa3f64e36a885f7272925b79c0f655ddae4b0bed8febe710a6fd0622a474df1c7bc830f2b4a5ff58bb5f6927ef85427682e7d7d559e3b7bc44cbc57c3a166b3e7be2320098e8f63511ba54a303c7f02cc9fcbb08f60154ea222cfb9bf16e88b95ee1748a435bcbc365a916b9b3168901c76a627c30a3967d9a94d4c79993186d97a7d71fd2aca8845ac91232cac00c6e92ba6b280a06ebde4d401d2d9da35df32a7d2e50a8d5973a2b57df2290e8d6db770c8e7fb3e03da965c2cac951b55cfd58c879e6e625481b2abcedccb01f2f6dabd76329e1ba17908749542c69a7f7450a43baca1159aa03405c11318c1e0c71cc99bc54858cb945362058de66e5fb7e00895f912c08a8c72020efc34fa7aac41986393632da2713ae35a8ab83588cd4dd1c2ec078b341b0df28ebdae7cc49651ec4a74a3e030de94ff89c2e1b20d64aa0160c9ddf6537b1ccc88894a00789dc3ff6c7d76f805711ab3b3891e0c77fa15ca58a7c498b26aac110b17ad515ba45511e1220db535bead87ada96f330f670d9c801712e1ea87fbbb73592b0747ee8f050e08cbfb012310ac3c39f060ac26ba89b5546d8020ac1bad4e3c25ccceb28c42941b4ac695b7fb93a4e7563d70ae786a7dd32ecc3d22cdfd8dd0c4b71caac75200d43eaea04a819cf0c26145fe35a79cc94dbc8fb75e94244466f2b588d5d69c5467a84f8e6590f3c3715d90b61ce83ce802f8c062c5e430c9648d39dc6177b504231424e01c7cccb8326f84d6890e1eb57b5a70265a7feae6fc20fc11f7b3db31591031238ff3b0c3213a85eaea863d800e3fd0f7e92db1bb5f2032e9b9ed897d295013058ca368cff1649eb395d0d070e547da3ab2ffc058a57e31fcd9fe7dac1b4c5737abb176b35c2ac681d470e714153d0511218144ed2a60765c0bfc726676eb803354aa0dce01affebf9dc19dca2b0a81c470b9a42d1b08d4409072f106dac5d3e92aa7d609b99b22a380779a231804a079acb1986f8566d201f9f7f7c598550a1ceea09dcab76fa505f42533a1a6cc9122159610ebbfbe96a9dee848957b473e6641ba65027657370036a695ed8ea5a710412dae00ddd365c1fefcfa0068c044afd6f3edc0fe28ba76215e0db4ed7f6dc50868e96827f1ad669c8a8836a7c0cefc7cc29644a512c03c2d4772d35e485eca8649fc5f734b16c95c994e4b65ed7aac5d7cbb46fb776780901cb79ce3f9cf60986ada99db2ea044f52ce6cecea31d40324b7901a6cf060693029ea01b00408ff331beaa2af9f47adeb578afce2c6fc025387a6dacca88cbca017055d61f7f0822ad1bcccdb652e8a6f6c4bc93596894cdfaf2328452b056b9a9f9defbbf0a12aae08b97fa84f767babd0f9de7a37b7a849001ad36c2073891a30816bd663119fb8cb0d60ad68a01963058a0ecc33af16fee97fcfe53ae94ac802ac0c2854935da759dba5ab68c0110a566d31e58a2a333a9b54e45213330190bf81d8b88b46e58c57761caeb82746b8c8b713c007c3f098a90febb00a8940bf2ca7c38b78a3375f1641b03da1d3412a2f503839a82544459c5d2a0fb9387b7975a4aba4a57c12445227b9b12496339e156adadd086e8b9999c951186a1caac625ced781bd43141a7e38104975e89f7ee9f9d87e2474be208393c3d593a11720d0312c6b17288ec2cff4b65616dd1750d25d5bae0c302ccfa02169ff9c40f3b716548d6758e9d4fbca9d5529480ca92141d5f6761883521ea696f2a525fe57687676b4f96e2cb16f9c3ff1173ff3218fa1d4bff540d65441fb5bdff22fee1b5b4a5d80ea3c10abcc774b7fc2085d75605c3c5af23a33f83f7be0fbf8c250226898defb907fa1da95e28447f9272c53c713b30acb08aee68c1e87a2c25842683b6d2df79d1213aafb2e1ff0321dc782e980599f50479c0d48caaf3ddd4ba6dec74e8920a01dd14212b0c82ddf3d7c59e3000c8864ec33c796d4157ffaedb94afbe1933f591981d14d45f3335cbd93b8c3f07b0115e8ec5e8b1bc2b5a93b32f5bf576f244dd00371b81a8d043d88476dbdc68a1dda50d48c7c64d5fa2f6d75d9b1b0d046face55811e801081e749ae0ea5e3041111ae32110d9b4e1bc174b44ea08740b365958a5cd20b610186310eb3b45f5753194adb48980ff995bc292a811ff385cba9ab2e5d6754e45bff2e93882c085bf3a00b76f269308f51fbcfc3fd09d4269415faa8b45e25d76e82c5833422f6800e1d1b19b205647d85827644d091ceaad82adaf1961e52e92684a71cfdda004ab9fd1a286207b167e865ef7c7ed3d5db44a2bac0542185822f1d9f141bc2744127c2021c631c46c97e5c45ad6c11bb1a6ea6d2430b204285c98c4ba0483a557995c44a9fa404ae52ede822c651b21cad155b35664fd53768ff629c3f30cd262a9c2bfddb402a3e8696afa7376dc3a4a241b2c754db237847f7874011b3893d535716648f221b2e6b0370365bbee82398639b82990074ffb1c7fd39b422a5a5fdcfcd617538e2e0e417681ddbb918fdc2b02d6de2fc2d08a6a2b9342fd4a5f43c4e9d3724a209d3f93c12320851f54800b53040f7070768ecd11d3d211e5656607f1957e576c0c167ac2dc68bf20746c8106647531161b3481ba4f866000238470938136cc7b7d7f248a3b6cd456b73af46454c5ea10acbc977a54394d3cf8993d51df3a648d8486ab4337b5c594018cad758b307b5cfe9254970e0532d669da204a72aa7a2c3a0730705606b4d23da2e6798330ce68b27315eb5b2618315b0e6e97170ecdae65df31cfed6b5983ee8ee8bf8ac899266446b164397cc30e734b890538d75ce49d988b4b437014767ea2375a8a62058a4cc07ca51895700410a1f78000f42485f3c1d143eb4270423ea60544652c1b23179e72186b277cc38ba7a67045345fe6590103e8ce09da7cc327a81f0a1fe9f2a26056a95252899c59a2eb40ae8588141e3c67cf0b13bc9de63b51eae809a5c05c2b898cb0e43d4720527904f20f047e22b2418259d6194398970569e6e724c338e35905adaaebe5384e5134b5cedb7c10760f9253e2d906db51cb015128d70d0f4074cd6531e8478d3dee4f29b7c6c067d61994c8e5ef517fb25f31f3bb0bd105fe081c550097b0ffbc659a87186917e94dee996d9a72e45c2b7ba0f4679dc118bb2bb13f9db8c666627bb2926d30e42c2c7057fe032c8121ac2fd59900f76502989ff898ee3d4620d6cca0a80d209a8b0d8e861405a3c95d61190daa0ab11908b5111335cf18e3bb991a25dc63a956771d18cc90717830411d27367cd853a0ffe0879c10d2b16363f6bdd5cc3a9f84f689c711041e0edf4f126a5c499afccee7cafd3479ac8d961ab807c5d4401637b11765d13834bbd2f9ce3ac8378d06e1eca67d3bd9b7261d7e883748285be8efb3e9b00fedd55777d4d744015b99b94c823ffd8b2e2d8ac54c832930cd462d3907577aae53828edd752add0458f5f98704703cd0f65fda62d11336371659def9cca431d847e60c241eec3fd9ee1e72d0dc1222ff28b9cfec789645b1ca1baf6352a2987b717f98ec8d93b4011925bdfb1269c5b15acffb1d4935e97ad24d23fd4eec44cf4f0b66e8f583d4b9126a60d56b7040dfc2f367db46220ac5488bc2a185dc439a6f4a60ad1df52785c898c7d2e4f064960d611111219cb9c54619cd6d0c400ae956874da2e9c123863dbd7f0775d219df08583b1c7e2c61656ebcfb07b73c4db756546ad126d890759dfaa9a0b1ef0c378f73554a3c81c083582f4652f01ccdcd1665691d6db78cd074cb26988d616111acaeec67cfbbebfe367b81170ccf8e8bbf4d92f89f71112eadebddd05dffee79744e9ce862abf162e1f3fab8ceb17be08b28c82321f5bc23fc698f365411259561b28edb150deaac299fdf4cc6a9ce994d0e8830359c29f11612149921d4495cca2a3c85a4bc63ce55f0896c812ba82d6132c615e25811897a742bf5f7e46aea609d1f2f2592262f79935e63f98ac445e0d42a37b8503ce4bbeae58da715849d01425624831808818d26ea031763b55dbc2ec68bec735c5b6951c1dcf5ac14ef200c43d09ee4d27412ed62e9bee17e1a1c4376d991d6e255a473d951153942564f0046746fa5149a1a91986e73019130c9def37f48deaceee539a2ebe6a25eb7145bdb1786c401a94c8d93a5ae5758ab2fb28d6a14ae0a7537ff482146589da62c7cb0fcbe34f726ea7610ca77128361faf0623832ed8a955244007d0459377811a2efdc499d8154d6c2be1c21954ecd7ede75c91811f4d8d1f002fbff7eeffb1f114a52a4251cae195c192fc94a639b1855aa25d9b44f4a17aca493b4b2c43e11aa623631db001820723207a8e2117686a611be4891160128ab917b724badae84a55955a1186c96b5239b30a1c570ff7e4321e1274f6fb00b5dc29cb5dc68090a341051507867cd60b83be3bb383c6c39b1bee8d0f817da52b60e30e8d8734b1c044561c52d90c4e942a895b32e32dcf8c52a1a0df29d48b9f132f930bbca599123161b77bc1031e8fab64fbc46b705085a372c9bfcbbb5e790e14fdd8448601745e049e40c503114f10705a9303688c37ac37cc106e14a8082820c739bc8c5d11b1ea41ce11cad091ec77209b1072449d99992926d148efd5877388f4c55640fa371111111149713a3185f1d849bd4374ae6f6666ed6e198412e713140f4c844221259e3899c941c60810324230e124f3dba65145b28d0807624266893b842c81832558e0ae4d6ffad2404b707179f1dd2f518025b25c19f6339f93ce464b04d1b25036e226df038a1e0770ce6b25fd7d2adb9cab54e082224aace1aa183857c1c00555121c8657922bcb527c088c2fb6b8628a27963862881fc6f75e7beba5775e79e385f75d6cafb5b65a6aa795365a689fc5f5565b6ba57556596385f5554c2fb5b4524a27953452481fc5f34e3beba4734e39e384f34d2cafb4b24a2aa794324a289fc4f1461b6ba47146196384f1450c2fb4b0420a27943042081fc4ef3efbeaa36f3ef9e283ef3d2fcf6b9122752ab2993e134af81812c44790045c09b80e705d437c0cf17180ebbaaecbb9ea05ce556c3857ade1022d465c385a76e8c142124de881730e07074a428d9e9e0bc7c7909e9e0b67fbbe745d3e7a845cdbf7a5203d489020f9a152c3054950e1806b8810426c49a2c7399c249024c183bb34924f4559a205e742a12164e181194ec875e4c805835c6038e7809880732707389721c0b90de5dc5ba2c6e938e765892c37599e736e892c37ce01b13d80650658b8d872226523edc2b60c0b75ce552470ae1a8173d519305780b1a31241082a10385799e15cf501e72a0f385795e15c4546c505e8ca7565872bdaf5b16b1369590812b9901cb99cabc670ae12c3b9aa034ac698c281c610c381c6b0c3396783f36100ce06dc011a3850078ce0406208e140626c0712e3090712e3030e24c60d1c488c3b1c680c1a071a23e44063f8009941c608079281e240324c38900cc981641ae040326038908c180e2493460d0100e2c3399b12c4c0d994e007cea60453703668c4381b346e703668dc381b34a6b3412389b341233b1b34ac0000089018381b203970364092e06c8038c1d900c982730e861f352019b86005678347e56cf0b071367808c0d9e0019d0d1e479c0d1e3ace060f28ce060f91b3c16373367834c0d9e0610167830719ce060f14cc38e79c93c10600d0508522389b2a48c1d954810bcec60a206763851c9c8d1586381b2b14e16cacc0336383116a703646f0c1d9182108676384e86c8cf0c43907240039808a0c71a022d7818a3471a0225a1ca84817072a9285734e060890187cc02003801f54389b35ac70366b60c0d9acc10167b3060a9ccd1a3070366bc0e16cd6f081b359a309ce660d2d381b36609c0d1b30381b367270366c08e16cd8a0ce860d1c67c3061567c34677366c949c0d1b5dac3aa868d1c3900c544d66c0c20426e14004c0c2396761e811d9302c6b81d58215906003658c5169002bf1cbcb96f2b92e148695b0f4f011f299d6fc756d9a490f1f278f42994c18d7ff2a692e4d0ca072512a1c43005c131c0f403b6678f161e424dda350a46cd3704c9aee72048c2aca17516600038ad26570501c284a0d03a0784004850482228232c46f3ee327cc004858c139f743bfaa00207146483b791446d299ce085670820d808e7882db7c0f1f27ac9f4ed8cf7552728411ee889b239cbb7086a4360e8e66c5b9008b6a09a02797735d9ce19c258413239c1399b8171c9c136632615c046a2285738eca55d3c486dc338c7b2ad83ff1643ef34e884ed8290b3101c085a3653ef35aaa08642c9cab9c174e9034efdc153a689834dd85eb4fe4845d711ca413a40609a09c2a9c73f11aa2973094e6ce39d09226382d0b492e4b9c5c38ce5511908073d5155a6481c51556541170aeaac23997851e112220254b28b9ce85349f5d1e8571ed3a91aa70cf45b445fb2e5bb4c722000732620e289a7405640417ae8a73ce0de7dcc9818c9001548414404504c11539632b02012eca22a6ec684aaa075410d80194848b93d7342f4af24149744217ce0f276c499279e124f181248f2c74c2489a0809cd1128b80ba79f485bb454e651a92a9a9203547fc276360ca3d2bb682a9a2ee5f82954808e3cd0919bea012f8ad5c4838ce8c05d3854a450a192af1f7ef8e10607327285112b8c6c464a2ef3a222174ef759114d34440432e2e4428204897395028cf4c0b182bb709cab4e385c403805c099b291ba1799b817ee0567080e0e209c18409809ce3921a292be2e9c2117cee83a91aeeea92061c5772c07a71c0847a972b330e5d22a55b00ddbfaea829db65c21ee51da95e9d20604934b350d08ae4b289f5d5aa5cac9e70a09d1e4da3a21cd35bde9feb191a69d6c5a464af95ec28298ae2850b49086a30de0ba4223d475c248a31e9f61ffb409097279ada4995ca19e28533d3ddea44f3da14dc34a98178f714e429d3ea947c890203d23cd7fcc7f8d74d223be85eb6cf35c7c8954e244b6910fa974699c84527244fb2cc875e928574f129e233d26edb38f11d952d885f95c1b76f2822db942444ea44b5fc1a6fc13e9dafa297585323fc4c915eae9a9728584684268286d0a725d214d47f1c1b66b4ba14a5ac88914e4ba423a4f52df9bf40ef7a82a4f301ead7bbfc373744ed80e96792d276ca77b272305880893078c343dc2763650a8090248091d01858a848280423e847c804235211ae750d825248820174e914b4810d73524880b07855d4382b8825c17ce10ed62420910911d8088b04048102dc229021af205114ad3b614e63551a944da22da926993017680c24a25cdab53496f27ddc57321f99834efbf06e35c35a593aad29602385791bc499f9caba278f17de4f382ea3b5779e7aa2a5bd59d733a3818f06a575ae45cd523d2a492124e4261be8aef5814cd7b269bafe24b5bfb0ddbb1b2856350b60c2b692df35c48272b99f6a59c0ccbb29ca59648072aa307072ac33a5019a732ae7020325ae04064d4e140647cc13987c30f34385761d9f4bf3c4f1441404123998a708d64d2c2057590b411ecdaa654c62f2d851261db8924ea5ca238d7c4e1887a8934e238ce554bd4545ab8dccca065219127651b480045f0a46ce326edb34dbb3c29db400230c3b92a892a0b0cb0800470d16086730e732020bc70ce69592872c1c101fd8045b54545012c4e18290157c929c19a68d84ee5e5c27caa9312201fb600f9c0840e91240ed483064e24eda32f6d4ba64d237ef2fb3aa5b2cb08cf95e4f2a24d7ed3527ae42583788003c44314d00e5370cef994737538e7749070201a9ad87112b9e0e08076d8c13937e3403ae051051d74806dd7900b67c8856386734e87098074f8e22e1c6cd4e51a02d281892d8581742802d2210777e16c7ad4e51a223a696ec9e09c3b8003e53085e67dbaefe9e957171c8070a8c339ada449498efcec3970d840381cf9296de1d8a675b27003d00d5b38e7f475556f806ee876dc306409900d77843a699f309216900d67f038e78470201b504e070ac806e7b9904035c820d43594f6231c2d0b657e43e9ae455e1c880633b42223eeb76bd3d9e535ed4ba8cb48f7df77100d34a01998009a810cd00c61781356c59fb01d9eca021c48e30c2326d2a5e92ea38dd431932665dbc72e14b65d9bf6e22b2b9ce6b79fd229d397e782ed27be633b4b743c29e3c9f8898483b34da92cc7554f800090022d0b65d8a633bf916a54e0c3193d8440af9f9fc539e7405ec001c60d64a4c039e77c0c80869e295276aa289510545c48905c598ac31c2124c8164ca4914242b40b014244d7102dc80010700d11fd6c9128a49d4845b693afd233cd35928e1226a1aefd0807a747899e9eeb63fc527285fc09d3d9483ad330ec77096d7a94eab2f91f2b99d6257469fcd2bae7a2b5ab9fb4c64a1bbb34dd456797cf89846d230da54fdab5b5462ae94d1b3224db1ae9da36af9146d726c48934e2a4cc9bfc08e54324d3b531d1d3a38446d27a869d9e5ca19286c2ae93922b7465a46cdb98e8d1485ae6a7f428f14923aefdf531bf89a40c40ba707050da8573615cf39c89ac2325678ba854f25d946042892ed79052d77ea489603e9ae742f239619876694aae90d64b9ef4f5132b527e96743fc587b404c378f4a675946cd84edfb01d6ca79fac00a1a7a782e25c858473d511ce554f9cab9c385735a9b273958e73558e73d592ca08e7aa229cab9238572171ae3ae25c65c4b90ac7b90a3b575de72aeb5c55abe95c259daba2731574ae7ace55459cab42ce55449cab86385711e15c3584739510e7aa20ceb9984a08e750a098202ef4733608a60b6ea46926baf649806094707ad3fd025940f8a1881ed1e67dfcd75532ff93792e18d7483a5960036449f7c34f46da9b17bfe37df494debb603b3a3c8ba6752c67f3553a490765ca9c9c3c14ad5452d29f28d19bd6f1a727be9332944947ebda3be10688620093cea6692853baf89d2d9936657ed358fca6b72a3e27d276d25c7cc953c9d934cc89ef58ce9529234d3b51b2691a4a9456309efee391e81893cc9f30922fa148190fc6d34b56349dcc4fe1a714763a29d1da80c211be7084df521b094b4e17bf138af2f239917acf3c2a14e58fdfb2fdecab4788902141827c8c886bf65c1ac96b58c98f2e8d9465d8bf7eb8a6f7c9a3b0ee77b09dccf74cca97b2a5a49c9e54c9fca98b940ddbf1396119962e18140ce3f1a2a3749f619b73555509e14a55faa6519ecae6ab6c1a0665d3523add77c1fa297341660b0cd802114f4a259de34547319136cd5ffddab09d13767914866d3b57a89f86e82a9aa6afd04fe984693d3d5aaa27d33ddaff98ef3af3a42557a8a72785259180eb4a92446f5ae71ad2b36b48952326d2a80a4a474172f90cdbaa78d4cf01aeebc24e3d3d3df912c0856d1acaa4bd78cd85b471edbbdeb42d855d1f0b691be994e2a102e5f4c473219594a0bc47a28acf89a4bd4e15beb8704e5db01312234d8f4e291c1c2af4a0e7da349643852a50272b990a4b9c739da4a7943c170f0585f1f098a6e0830b8789a665a12298868393615e0ace399c3bc4b8c3017734b9c308bde92e126d5e1389fac96b22aca73451f74e90b83e7929a4e1ae4d5f5efc09074724852ca4807217ceb569213f7e4b100713822868c1b90b448189730538913493ce34ca4a0949da8f46c4c4bd645e64e25eb4cc93b24c6f285801852f504041018bbb70b868c885a365432e1c52f799dfa279f49661515e8cb28ba6d29f78f1fda49f8085734e2b958ae4e19c734bf8411362f0c3094df0f1c29632a9e1aea04c245dcaf18252b2f92a4e7c152d554265a92a3fa9253e27522f614efcf6c44ba672f25cf33ada97727c4e240d2be574bfa13ce74a50a6ccc9c9a3a4e474f13b2853e6c4778f2572c1c19157e21513f762e2599610003bee703d57e64960871a3938381a70ce959c8d1d315a162a22f219c64599130da5331e1ebd699d91a69d68de474f2975af692821ed3a614374965272651893abb449dac96b97d6485b32ac4b172da59dbcd7b011bfb21496c415d2b4d4a6af54c732d435c410ba8b5f7285345411249d2b54823ab238ac0e22ce21810ee7423f7e0b11574f7fe2513f3c3f1e891ebf456b3d27ac27d3bec42f6df33e5d304dbb3694dfc23d97d2d642687eb45d43342c57d7f4e8228dfcbe7c4e244e3261278cfbcbe744fa29f1685748f31fc3b2293f1e89aea3fd7824b09d9d2204c139a7372c0be204e0dc0f4570e29c969534c79c4b7d400c2dac2002173304439048496fc08b21c4c0b92148a17d17021c2e3b91ae2e58e973920f06854810f0d8bca604d705206ce19ceb8273aec2c339f7507ad34ca46df35a912728540f4d133f988013651ec5499b374581a49136ad6d1acbb8365d467abc68d3cd75e412e2459b6e8a18204889e4f955e432408f75b2344c0b429adf7cc9f7273362084164064bc8e784655dbc09ab7285b49dd22eec749d74b664060b122ac53976fdeeb5d48c123dc00040a6cb6420660b2b5441481091460afdf82da21f60f27031565c4cb65070ce3da18606cacf4977cc39e704e75c1398e09c5b0212cce08111ce39dfb193eee277bee041cc8954ba92c60ecc082d5129717638e794e09c8b41c219d50e9a60430702dccf496bad7b7fc24add6ba42ba44f9a37e1ac28dc966dd3bd63a7cba77a7caafb531729be633b3d3ed34970ced581841618a18329aea4831d9c43c21239e88096855026ee459b4e4bc8018d9685461b29d3453414a6659ea4699a0f8f46d2fcc9377940144ddc20054ec332ef44d7be7461dbf549230dcb1c55dca0c7b9279b88a64cefe01c13ce668e296c29d3ee1897214984fb8e712230ce55cec5cc01c539d19b6306e7fd17619b480e2d38e7b412496fbe8bbcff72d4e11cf64f72d8c03977861c5838e7b41fbf45e4c5657e4b867511fd8fc9b1849743c76922398238cd460e9b38b4e07e4a28948e630971cc11470a9c737190e1e29880abd488630638bae09ceba20d2b693670d801870d2e6ceb7a89005c0cceb90b0e1d4de4732265457cca00be8bb8e72223870deac8fc462a9261dcb929dcf082730e083fe84195b2418ed3b2d04fb69d7c119436d580053e70ced5f4e0c8d549a66a8b0d0daca065a122924b119e695576a43ce1c9d9b17284288b9228a2d0156c4ae6b978522f615e2375d12edf65db4859a6491769c435e792f92a1717bd5172ee44aa3245679b975c4589288583c349993f791f112a777fb2c23d4af3b26d3838da136de46006569c739a96857abc13a492e884f568a45a1395b49685341a9ce19cf506146c1006148c5833b0dc68432483369ccbb02700b90139e1004b88b1630e3b66c8d1fa93386f851b2b2d71ce6203948428ceb935d4b0c670411d5f1c080974683f2725d1c4b36060239d489f05251296524949f71370ce5a41f7524a2525ce596968ce592a38a5be73560a3a29037ef31957e29c85025fc276ba3f91beef6268609ec05d1354f8a3b32fd0702eca1f9d654a34e7ac119c11513ae3a9c2a32519c24dbc62e25ee4952f3610022b032070ce9d9e64dbc94aa99462724a614c4a5b6fd84e2f614ebc13242f3a8a8e7396195b86a1b0ec64c544d2a51c8ff168de33c17632c6054a673cdea477bce492f63ad8ce168e41c176ba3f59f1a5adb19dde85f3d8ce16aeb72a5a76cefa80b326e00117657f429ab58c1fbfc5398b8c177f3c12d61862e8cc23516ad24ba4518ed5812dd328e72c0e7452962a4d71ceda40496facd4c4731276653ba5b6c947c9986c9af6503625534e7ac4e3332c4a7f42d240e6b7904e5814e7ac09e492e6a4d3887b9e9246f2f1504a9ac4493d7584d74e9e443a914c5dc94f96d2b4cf780af0b3c439eb0bb725c398fc2cd126ada590e827bf691e0b158c631cc3e29cc54518ce9952d967d848d3392712c637d212e72c309c73d6175ee4987896ee4f56ba77ceeac2e2c2ca00f64f4f4aa5d48e7316069cb32e606d81fdd313cd02ce5915c8ddf3480a581390401180b0033a6a40871b203a5ee09cd37ce69dc02c318bcc32b3d02c358bcd72b3e0e0685172c1c1895cb8bf9204fba72747b8bf92612792c99bf429094934d2f448d49fe0e0641e95d24cd8c9771376d234ad974858921ce1fe0ac9e79462724afdfe843fa9f06e999ef2d3b1255ba651fdc94fc796244912e59128ad6cda09cbb986dcd4911b61eaa67efc965953a4285349788e707f05075318c01205380006b7001c5c1514aa28543fa85850b5e0065e627e40c50d80f0d38f568940f3a18829e630a246478e355c656d617a418e1d6010c7cb62f8c20b2eb8a8c2b929dc145448c100066449361848518ad027d265245e415c275fbade85e487ebe44b1454833bb828a99454202b20c18208400084174b2e80c5942b45ec00a2818ff3a5bd49a7ae7d366bea0d18442e221c114a7b037b43bf3145c88533e4127d9f05e1e982e56837c5fd158d8452a29150dae754429948332040750237e6704d92b8d1c42539a2f98e9d64b08613693c9bafd2c6169c73a0369c88c1111c062a506dc0015218c0675c60702b0d90507ed3b690b4cd5f9dc7a3a4603b950f653ac3b2213d7af4e8e1e3a4975ca1cdff6c1929a5840d30bc5823082035ea0803a406772e8803987143b370418ce88b43c0015a90c5e94d5363e4060b6250f938a7ad8003ceb9fb6fd2d082735ed230c3392c0d970613aea74adc4b3f6959a8a68b3fc95849c0698921439024417209f1d24941b6efa1e050c9a46cdf43b9aeeb3a2d7180cb4b2789bc4ff7a22ac0e0054ea60451203942c475f22551141c9ca0082730c30477b892f6557c3645675e6799524a29a573ce39e79c734a29a594524a19638c31c618238410420821842fbef8e28b2fbef8e28b2fbe8831c618638cf1bdf7de7befbdd65a6badb5d6d65a6badb5d64a29a594524ae99c73ce39e79c524a29a59452c618638c31c60821841042f8de7befbdf71ec418638c31c6f8de7befbdf75e6badb5d65a6b6badb5d65a6ba594524a29a574ce39e79c734e29a594524a29638c31c618638410420821840fe26b2b9d32c228a6272e09901931e8cc1729c2330ddbf1249d5e4a6158ba6025bf24c73b81654c9cb3ac647eb46dd8e9d4f512e7ac4e05dbd1b873cedace59fa8491ac50f9d1507a2c51134e6b9de77ce568d98eb6a1529e8a3ea52e9f694fea5b6ba97d31e9fed445a3b44d23f9ccffe8d255d2644c71ce5ac2394b091019419238a5ae9316b2f5e989cf525bea67a96d5fa32d23ed2b74d2fadaba14ea467c48da869d2c2c57fc09db71ceb2e24d5815ab8a731615023091b53ca922d2c93a527276b2888a142a54b22843b1a223258a288b9228383827bf05e329a53a16e59afcf6c4072bf527fe44f239e51c0e441112c4555529abc8d8c0fdd9224dd32823b6933e914ca48c6ba47e9952276fd274970b73e273226d19b6955c217f651a58c339cd394b07e7ac1c70d0e9bea437cdc439eb061b9cd35ae7ddfb8c8949eb0ce34b276157b00df593f128bbb661256dc34a55664d81c102110aa5717044280d434a63a67d6105a7c40a96792d3f4b4e4ab214e7d84909890b49e74668a5a60b2fb8700e074784d2bef02105d445171c69df08455ae651253fba11a6ba8880941ce72c9b5296658e954a4ab80002880b9d0cc0c055f13991348d14450a500696c0c016ce63e009ce398d2af2b3c56001d132bf69292a978fd7aed1a65157a9a40407c7390b0620ce09208bd9010301f841660b992a9c73521ce802a32decb000aa0242a8343a81b92ad02bd09df3f21a40813a4e240c25a2001bce4d895c7070928c34ede4888ff6a34bbe77c17a09c3b8281b894ca993176dea58942909ace12470440b1b68410217654a0b235536565ad2b3df343f6139fd090e4e8e0640590471561058ace11c166560e100e7dc85e4c875e1f4f45c9ba6515cbabef803a2c0c25d81802b9058d1863563c95831ce3913cfc2a329e9dee4b72726bf3dd13612960858001401274a40556801540519be746925a02a50ceb9905645ec51a6207005e79c15078200182e946159e64b25df45d3d7902757e8e7d2fc1208d007a4c0c52b2725f08aa7d2c5ef50d1054785155418e17d7c52da35c46b7ab443870392289594708d14c57b26dacc054d5172cef97ff568a79488cb96932765447efc160b4333f488f86025cb72ceaa4053e8e4a1a5013a705d74264311861e9153172cdb234d8f400d38e372a0067000fba7273f25144a89d7f4680a8f8683830603662019e9116598a867a4914ea47f2dd1b290b6914c7838e72a2e389f1329dbaae4e0e070df311e652a89a6e99228f3282fda74c48b36794def2451a68e78d1269e928e420ba765a19286620a170a8584d87c492b792e3825cfc5974438ceb9299ec8c213758c343d1a697af4041ace6d1936d22e0cdb70bc96792e3eeb3e63a29dfc166cabb07005e7b41f3dc5fb2fd27e344ad374897f51c361fff424ca8f9ea2f924b09d0588b1000e2c000bd773e1545498825dc00e5a16ea46146086735a163a8932bf9144268fd28a70cf05a4002c400af0010163f891a69d244972a4a4b713e60429c346494438389e946d229426f2d14c7ad37d27ca9413474aa514136cc787b464b449d19bd6d1d92225ca942e894a18b6455a2989906b88564797219c733e891025d790fee408f757844499e20630890c60ea5c5eaa0d2314810843a88410840d09a06d6a297040a880e09c8e128d1465c3b0ae3d959f6c3be592eeda53d9b05215ef04a9cae909ca9439c9c92853e6c4b9ea07950f7ae09cc8578142070210043a8ad0001392f006193e38a2040d330ba831810f9009e4c8e25a8113d6a90a27d8810148484110323000ca057ec0028648812ed0408308156ea8c00d71d051868e0270c0f30024439871ce79418d8a0e90018c40c50084cda0d28173550eaa392a1c3857dd600ed0698b5377e26422c339f783f653aae070aeb2410d40a52e38232a235876f98ded64a1a45385520d15b6e8c039d7b51f624b96cd6b19540018e84deb800a60032255e19c0391a078cd474f018db270ae7a6306ae72c39d7c4825ed9d20695b0afbd1508ae85b3877c7971e4763a271312e0649e568c0a8ba0ca8a271325432355431543531c63a9809c4f44063d5d4c8c4c05495b3c10a39cb55048829a2723446649c0c3395abaa4a46665a3f2c5755158ce5a4aa682aabaa60669cb02aaba2b16aa0525533158db32a184230d6cc4c101f57156359315854315565f9a8ae60553d9c4c1563c1f8aa2a805555568d154b07abb26662acca095655cd5815012a1baa0ac6aa81810c0c4d0c550d55555516b668a881a9baa8ac6ac6aa2a0b465459313e7a4c0b4895a4a692b9814152d158560c84f161599510196a758018f88309cc14cbc538ab03550c4c901819ab82713214a88e5039cbd9d8d8b8ca5531955545a1aab186a82a4bc6b260aa4a5645aa9a0a886559d64c4e258465c558d58309fdc0a16600150c00c8c1b2402563e150c5543095b3a658978f2ac659a41977f5541180713fc0a07246c8c082a966aa189a0a860a660bcbaac181a92e4c6559319705a447904aa6aa685e0cf4e155968f991aabaaaa8aa6aa702acb0202cc4cd5c38a81e1520161a5aa0a8648d5e38755d5d0549611560f560f160f300ec6553254339655c11063031363e16059563553c5fcaac74df543c6aa64aa18ac0ed6139a1f3dac6ad700a1b12a025435550563553195938a070b5b3b583f2c1a4ba682a9accaaa702a1eac1f164d4c0523035355b682a982543d2a20555519a97ab07cc0d054353195555538553553833543156355323115b67e5430560f150c8c65c5583115b6ac2a07cb47d5a3aa89b1aaaac2a978b07cd0c0543135315555d9abba61889a233044c85430558f2ae686aa470f9c1f4ae8d043258098cab2662c1a5fd9d0f07e38a92aabb2aaaa22e2681cca69594075471251705712612c618e247ea8e30958f4114260c50845703c3ffcc05509e306be8a96c3510983055d50f901934280300a70c7143d8d8012460f5570a27778388c1b8a601dc307ac1160b8b13ff8a8aa112a2fd49e3cbca8d7175ca8078f1e88f490610d298218d890eb0d41041843a4e043cf05c487cb0600383002c084eb91c9c25d3151b84a065a169a91c2471035f842d383a6474c0c3595a6070c0f40789ed801a226c88c8f9a1b0344862a06c88c28a60b0c0c30a0981e4481812f333158343d6286c0c0c30dc1171f5780f49821313c614d1d64acc45433475ef00509141d5014568c8f182842b2f04509500c31c713950c0ec807239eb06272802182aa7e482243041d5f66667c9822050d322c61004c9327a6f882430f2c4066003283134c6840d5683eb0f0e5c8d6a3498f1636343d606090d9124345154fd4c4c430c34325837cc20e0df418620752d468c10231583f648c00d1e01824bc126740110099203e98f818c0cc123143d0602854104613283c70450d364f0a18389407c4e0cb8fd4cf4014304419aa2b3bc018a1c1a13ee18306cff8a88901c63e6902c3830f2658f8e283e6090c556a9ce89099f8e8e10448957e44055f6c8819527dcce0040086191f3f32104d88f1c5478d931e3604bec8c0d8c854330498f12163646688244b7ea47a0851e364c6070d0e30e8f4b889d9e961c30c3b0c20871a86a82102092a0378c2474d8846c220ed9329344062687290c181a93d80c408711941d383c6474c11192462ae11958c0e303fc8d4f07ad470189c8ddc50e3a3861ef6899c9d1fb32648cc4dcccd8c07be0c11438c8e0c11323df4b889d9410608c303145f42452a980f43240646e600403421011760271184608e35ce10810738f0800524c08bb6e57bded3c4125ab25cb152650a94239ce05c1964004108e08a91411b7948e10976149124082072c081060c386c30861804c845e0f04003901f333160411a2020630c0e6c200c30bab012448822a10c6080a74a1e5db0c2d6228528a821c2405a5c41fa498cf8a021230b2c6c0f1ff4a00c327070b561861f3e6a6876d001052758c277293b473c6192bdb0828a29005004da021184c0030bc072c5d61b6688b9c11c55b8920449ed4133338206a441020d5440021038c0175e787185949d2446840052e101c3054b0b31775c51b09610638765049922543fb07860eda0071d407460ddc092c3628135021811585b620a50dd543ed4f020b3030c3858365834543380022003000b54d9c4c460fd90f161f5a8a9b1686864ac980aa6aa661c0c32c0e800e3822f3111f81203656688aba2b9c21336627c9191014233801f3c1113068cb10108073e30f3802f31507ad4e063871ba2f8d22389182d303dfcd86680d430a9b9333e608cdce043a6065f6a52f06586259ee86161baa00210227c91c9e38b0c901c76f005c806840bbef4b821068bc6884c1199093880861f3858008a982abec8f0830c3fc0100115a9b9019407143244d45c9a233032c01ca9e1c0179828b0c88c8f1933bec0fc98c92166c80f0853c5008919e283890c113449cce430e363a60040660032438f1b7ad44093048c17a098c901e60c286466f0258802c4982e51103cc4e0009161061453c11081c9899902c486198b060b8d0e343b3234c450cdfc8091890102030363c1d0c0d4c0f4f0b1430c0c8d151a00c830c507886686a682a18999314562aa1a1c607478a2870f321ff81283194f80666274a8d181228608500021ba5c1e5fb0c3073db8c11c6fcc20e553250b2cf292229058ec2485281411c246861a1a25b448d9c9230e1de0c0872bde161630020344e0811c6ea88102118c512434800aa4b62bb4ec0a53b8230874e8a00d132c40014d2ca1258b949d264c7ce8c1861a58b082058820040a488088871db0930f3110610806307dc9e30b59c0c2124ad8500388076ec8800d35507082115c610515a22692c02265e7891c71c8008e166ce104083f90c38d36d47081181c800003a298c21d3ca0430d17b08004527cf1fd4906c1704712ea20c21b6dac200d34cac82202be8b9a5842092c4fb2111c212018e488e38d2e32908514be3771c41326d9084e0c30c4b824d421471c3490c10ad240630465686185144c1cf10489111c3ba1100080625c1e49a86308347843066dac208d1194a145165644408a23889858a28822a12ee0010509196210c20e585401812c589e062200811f2f20e89107cc172c2fc8e06171a1e603311eb0cab0c6a8a205615e15fa4104860898ab061fac1d2a1d687280c1a1ba21c686aa861e01000000606c62640012830d0c3900c1e1c70e3e403d686a6668ac99191919181f4de8603b91325411df314e3aa5689a20a309279ac8404d40e9b9825c27d2a5917e329de911bf741339345103a8891ae72e2447ae20488e5c4cf48009389cdb7e769ac8fb64def4202d526d21c3bff5e7536a082986d38642a6afab84a016f2ee5146c8e7b77ec23a0f506521f3ff2ba5b1fe7bfd7e1c6221776be9b3d4df8afb8fb66f52a9a4ff89f4865457c8924e69a3bfdcdfdded96328966f54465853ce9fdf8de2d39fc983e3bb250a4e9073525b70a99735823f7f1f7f8ded39b0a79f629ffa35dfa1bb9867364a1c9db2ed514729c75e378ed8651d7fbe71d59c387adedb1c31ef7a47f64b95452c8fd714a71b57efe6e6795a92851c872dfb775d55e43e9a58c230b2f1472f57f5f5ee7f70f73eae9c8c2cdfb489e9b9c1b274b74469a7632d2f4c8c94dcecd129dfa843c39a5155ebcbfa671f2a8b31c0ae9ccdf1d2d22ad72429ef6f6c82fd7ff372147b86da4ef411d31e67332217fef35e697f757398d162e21db0b63f45bd359678df4c1582b3bf2b53dcab7a99f5a4a0abf12b2966fdf3f39f4706e1fe1c842bd957ca7af4a42c6555748ffc5b3ca5ee31d5928c2b6083f8665532294d0ee68111d51d591abfffa62d877d72f5eacf568def034b91969da494542f613d6fa7195fc3dbaa11d59f8e20d4f139f93a6f2b58742e5ddaa23644cf78df1c2de35a5b0feca08d97fa929a49a43ed3bb437140a8542219da534c409a88a903dad1afb8be394555a3947b65e22e4bbdff51ed33f2be77bfe91853c506ebc604b42a1eebd605bda2dd510e87d57eb7d2d95efdddabbe71a55e5c72311b2700aa11282d5baefdd71bffc5b6b4716fa11d7399e94f19434c7a08442a950887b2e3f1e8991a69de4dc541ab12e3c7e8b2e2d59a2132514da5d74c303e5262ff1a48c27140a512ab30d05f34515843c69d5b0f71939adf6deeb04494b5153ea2437d30742ee2f62ebebd54fd76835ff418e5cff8eed977dd2afe3963ea9ed759850b9f141aebe6edfed8c70dffddf1d59d8618c04a87a9075853bf6fbb1fd9fcffb7990fdbb7cea1a7587bfefa9779071dcef695f6bd471ce77e9c85a4a7f6b7dd1721e2bb43ac8f7fe5eabeddd4b78a5a439c8f44d6be1afbe7edadf8c1007d9cb07ff7b7ac779bfc4f706d9d38931bf3f6abee7bf768e7cbbaed1566db7ec94de190a45288256caa09223cfbd6bed1e4a6c3feffd41b8822a8e1cffefbeef48affc1a6f6d3be94d3bd1f82b3872a7774359f57bf0c1fe2213950db2eef77e5efdc4f2dd89fdc8c2071b50d520bf27a986f0de5f779d734ba8828a069962bdfff60f73fd7abd3d05d51b99cfbbf7eff3e31969bf7f0659c33d2d7c72e3f8f993de8d7ceff47c7f88f7e4135768824a06d9fe3a3dec94fb593dbd7089aa8d4cef7e763f383b9454f237b23006197bfaf18e97421df7f5736421849501150cf27b31de37eff7b7525df9c8c217332d1482328eea0599f3fe3fffdce3febe9e7664618ca1908c33a8d8c83c5efe2bd49553f835c663546be45dbf8c924b8db58e5f532ea492eff686a789e4421f542377bee3e3b8430f61eccf8f2c14619bc85b68c233ee6811ed542ec8965ae9ab95d2d7fa31c6334a28140a8542307aa16a41de966ffaa1adf24eb9b715fd64db83323651b120cf7a63e49dbeaabdfef0572bc857ca68ffd53dcebf399d326f1a79fffe7de5d7475a75ac5f05b9c70f69ac35e2fe1f8df551b9c9b97904b89902e5c696502692c89750a94d545390adef525f4e7bbd94d6ce2f0af296b37219a79f3bdef81ffea23a41e6ef460b2dd65f6bb8e7ac0f7ea03241c6d5fea9a9afbf460cf91c59b8719b73130a8542596e726ea254b9c9316d5aaa005d89f74cba7f53a8d0c87abe176d9f93e3b9b5fe230b2ba490a72a41be93f2ed29ed78763a2f2441f61beb8829a4937fc92bb53607d508b2d7765fff64fcbdf38ae3c8c27ac3d3a45a78469e7d63b965e7dccafae51e59e84b9d243a61f6091441d6f2deb7a7c7d5ffbf3f1ed910e48e75f7db7afdead35bea91d5bce8283739372729373937fd4442e226e7e626e7e6c72371937393f991a69ddce4dcdcf040b9b917a54da2ee21a495062a10648d31edd7fedd3bbc0fd307ab6068a55466645c7dec5df7feb4c7fa7710541fa0b1def7bfdf2fe23dfdc8c2920e8560f55279206bacef7cb5c678e9ac8f8f2ca4373937393739a15028c449a1d0f5405546a6d6463d399c1d8e2cfcc936082dbc3b5a44465464641e5fdc74723dfb7bf2ea9185d5e4b727a1d00d4f931b25373c506e42a152499baa8442528a518d9177e5fb5d1a3db778da4d47168a443196b63e590985660c4125469ebd5609e9dcbfea0e751d5978b7a83a90e184daefe9f9a5bfce7d47166a184a7a5171404e2abb8770f30b67b4230bbbe8ac72a0da40b610c26929aeffc768b51f59e83354cc5d541ac8726eeea1bdded3276fd4230b4fd895120a695b306c140a59b8812a8c8c6595df47c93db79bcb8861cd5281d16fe5ffd789a7a597dafe8587f6690e3ff61b7b88b117d152cc37d4557aa8fbad5df0d9679f97bea9dfb3f173c1ebacdf5788e3de53f307a108d6a0cac08c385a0d2ba651defbe27bb08d0a031edfbd6197926e4fefc317d0964f8afbd5925a3e65df4e9e0b7cd08d6a0bfcfd7db3620867dd90ee0ccbb22c2f3c4165014aed85f4536af187b1622c829546185415e071d77fffc6b4ee59a30c85422113f78245704213f722cfa828f0b97dda52f960dcf3c75a25147a5004b9e7022186a39ac0c51ff3082bee37fabf75ce4dced5a29200c4fc4a2be3d6b146dbbf169f5ab9adbed04b2bb5e759d42925977ecb89f5d7f74fa172b3e426e746c9cd1428d38a0a0b6ce57b164e5bef8414532b67c8c4a5540ae53befee70fa1831efdf4a8ffad93acdb08ffd532854b512ca44a2a22aaa2bf2d4f2463b2fc4fc7e8de9c842d1e67d2cf64f4f36df24140a85789a844221fc20062a2bb2b415c7ef25c45052787b04f2c5afdaabbb8ebefffde7c842efb34d04a147fdf0c409e9a8aac89e477ea997183f88ad8740de7def8a7def74575ef17e40fedd6b3d298f126ebe29a52253dd219c57cbbb5fc4156e29a536bee16952d2a74c0aca44b2b05658a81c90f18f1f77e9e1b6f64edaa7c8f3c687e7dc164b0ee5e30dc83d3eefffc3f5735aefc70cc8d5f229eda4f2f2f9fd96230b7d4e242d4b719f89a0f7e9f986a7c9cdd71e4acecd959b9c1b246e726eb654945028f35b326dfa9e8aefd84e28140a61a5929307a3efd86952082d2e2a2972bcde6a4ca1af18cbeeeb4da7a99b9d9b2d53373c379ba66eaaddd122c2aa28f2d71b5f6c79c5f6d17a6709c3f6d5524191ffd4b5637ce5ef74cedf677d22471b6bc70ffed731d75e8f2cac51a66cf525474be58fd6c627f1bdf12f20dfdfdffeb7deb8e196bc2a2053de6184f5ca5f699532140a85b250baa345244a40aed0dfc821df4ff73da34540aedf6fbfa7a53ed26ee13c40d65273f92a7c7a8f2cc4b6254e642ee3adf6faaa3784bfcb918512d6263f79c60f9fad7cfadf2f9fdbcfc65b0a757a429578c95defc7adc472c2d969e45df2f777cf383d8d77e32b3597ecf185d87fffbdedf4578c9d44a96cbfb6f37e7aed7d18fa2d5b8c39b74f471db9a558cb7e5aaeafe418c319b1cdf2f77ddfda35fef8634dbf0132e5f7cf4ebf8775c3e85159ef8ebbe6b34a1c2f8e58def43e0ef5ad1cd21aa13f65f97eb4b85e08779cd69b72dcd553be3f8e104e6f4b795e0ce5bd50bf39b7ac5bb28db4dffa3094ef464a7b0172acde7a4ce3fcfcbfda4979deaeef9efa7ddaf5e5a31cdfa677daebb5b456fbe44fb77e9b425f77854fffdcad7efffacea5c75556ee73b7b762eba5de16ff6a7bbe5a5f3baf8fd4bf1f2bcf95bf0faded7d427e2bddf97f792fdebbf359238c3af74935fd32feedf19e70f764fee1c618e33febc6de8bf2a5d5477fab7edd53dc9bc86f77a8abdebd461c2f6622ef771faff0de0be17e72898cebf456cb7be7bb574625f2e6dec6d8a7d4314afab4962ca5f41357692d95d0fe24f2adb4e2adeba416477971964cfdd4f4e33731b5315e2cb9ee4fbdafb24eab7db5f74abe7f420b5fc4d04faebd952cadad5d733ee3b513579e3cab8d71472eafdc9c57c9d3d3c879ffb4ca8d23b55432ac735bfcefb71eeebd0990b7adafde48b795f4c659a7645f31a6f0db8be5fbf85129f9dbc8ebbe7cfafff9e63b59ced775dd3be2cddfdd51f2a4fa52abb5d55bcb88a1e4efe3fc7a7a89b79c342291ebc414bee93dc79d477844867f4a6f398cdbdaab9f64bc27b692bf0fb796f74d2719d27fbde7d77eac6ddf4df28f7ec37effedbb4aaa2593dc6ff5ff555f61e57fee9ce7f552ef2ee19e17439d4ce1eb58426de9bbf2c19893edacd1c7ad61947757be2453d8f99b774eed77dd1b2ac97e47b9f5d43be239633722e34df5c652fe693db6ba88bcb99c5656fc2ed5b3de24f9eebdb9ef9aebe7ada74832a6d247783584dbc63f8fe42bbd86fb4a59a1a7de48f6dddaf8f4ecbf4bcce11b5978f22511f75c44185291e8c21d2d222638596acbedfed16e0b5f95fb7f0c43c1597bdd3586386aaaa9e4fe66f95fd454c2abf7fdb8cb918522096b85dc737962b396bef3696ff7d23ef8ffc8c2cc9f4e24518475337d596bf6f3c25a39c578d7d97b1f59b865d7089a67d77847b825b40f57fb47168aec9db9da5ebd7ef755ad3de57d64e18556e6e8efbe73d22bb9fe56cf91855db0cc07c698f7fcdbe249e18c133f084716669b06b3fc5ef6cb9fe7fc79effdc8c2cdf4b195976de5fc7db925d4230bfb498bb00ea34da248b6faedfd69a7b3425eb51d5938d252285186fdaae426e786e78607ca0df757ba682a185abaa34504259465c7df575a61a75d632b4716667ac445cf6fa40c4b28b4997e28e4338c63d95226d1a33b5a44588864bc2fec577b8ab9bc51fe91bda91b26546e6e78a0dc884e241bb30d257d86f1b9a345846448e6503f49b5aef65bef2d1c5998f91311996a0eb7e412cadfbdbc7b64a1d6bdd7449bf7a1f086a789a66f5e4cdd789ea5b02a5442219109eb279d85f40d0f941bd1c43b5a449503861069a94c24ca4188176df2210814612591cf89e4e3839570104254691c620099de840802879b1c0430041039fcd0c385830f3bf41084072076d041871d7230f58043866d7a871b80b0e16f291e6af0e247a21d6898958719bc605db61e025069bc0070231445bf4597b6c8e7441a697a74812e1b111032c8178326040c71c330205dfb2cc88f213e36ef23440fa80d51131f8d48c88c10325100315014044c34615ce43391086ea934a2b8d7ac15a482a21f9148b479f1027039c0610309bea8bc499f626c20011d407e38378ea003253168c224ebe42c519204c9112338f8da4aa78cf01509111942c4104282083180206e80f8e1f2c1eac1e261075783034d31c581a65803c6013f9c1b44b081122705256af08673ae824014b238e773da023c506e503a0a4a9b62c0c8737fcfb1be3fd6fea894a1d0e63507c47c9177b40fbf0bf9e6c587a0dcf040b9f9f1482cd1d97df718e34586914b2ea5a69d72bdffef22cf1de1dbd6474a9ff6fd7391e783f06d692fbd13e2fd33909fbcdcc2db2ffe18c8fb43fff79ed577fbe7fd17c8745a89377c147ff961fd5be4f9b6fe72d3c9378e5c7e0be41d1f7e5d7abe79d518fe0ae40e35ef14432e71e4137e0ae4debd959ec23deb8d13fe09e40be1b5757228bfe4107e09642faddf1eca7ae585107e2d7287d24bacbbe4f5f6f9b3c815caff39c4f17588a5f758e47be97eb2c24bfbeccffb2bb2ad5bffc8efdd1afad9bd1559c2f7a7b79d5acda1c63e02d94afaa7b4907b5bb5bfbe8a7c2deed1f7372f04f2bbf6622bf1a41df2671f903d953a52befddff16b2ab29f95c6bafdd314d75a1d90b7af14f22f377d784a3a45decfc738b58ef55d5d6503b2a7fff9baa5bdfafdfe3c03f2fff259bf1f851dd3dea5c875cfaf7fb555472c7714b9c32dadfedd4faf3d85225b796d84d07b89e597fc89dc2f861bceaf37dd1def982ff9515939955e5269edd479646d5f8cf0ce6fb7effb0bf9ce47f77f9b5f4dabc55ec853c678b99f57426b7b17f2d7f2d3b929a47b467af1c811d2efe3f3156b79a7e542deb03f0b23f7b76f217f8d5fd75e53dab5902d86b46bb9b9877ccbd9b390658516dfde25dcd7bfd8b19021a6bb5b4ce7ffdd5fd8af9063e77d526e5ff4f7f9d7ad9027ac1447b9e9a752d6d7ab90b1ae5adbbbafc6bc564f857c25b6913e7f35d492fa2964acafde7a7e29397e91df91f58fb5c3dd279642ae76571aa5dd78cf2d6f14b29ef05ffefcedd13e6da190fdf4baee88ededf1e2fa844cbfd411da18afdcb352276408f59f76e3a75fe7b709394aeeffdbd85b2de9954cc80f476ca3877a570daf5c42eef5fa57b9bc73c23aa51df9fe5bebc4534aae842c2bffb776ad29e45e479e840c29bd9e4bdf2dc4b4425e87bffed75be98e8f2321eb39ffe735d677840cb784efeb28f9dfbc7623e4f7bbb438f2893f9f9f17214729af7d706ff9eaec9c0899da29f79c175edfe9c57b0859c2f9ebeeb643ebe3c35b0879f7a96de7dcbeff2cbc3b0879efc8bfa4bd72bc3baf1b08b9cb6ef1d51ffafeb1adfb07d96a2bfd86b6f728618ddb07b94bfaa7ef75ea08bb8cbb0799d3d725e773ef78dffb3cc8ff7dfdbf94d8c2f8a8df41fefc410ef596d2ea0d371d394e59bd9f3d768efdb73ac852623ef1c5f3c2baa7cd419ebec63b6bf59d3f1e2d0e728d58fbceed9cb2c368f50db2c44f563befbe1ffe58f51c593fb8a7f618e2befb955a8e5c2f87b64e2f67a594471d47fe576229f5afb362baa18623bf2af9d69b4a8965ad50db20c7a925c414cb5ffb9e4fd720e31afdc490565bafdf9f0619c3f930b6d8f27827fc6f64acfbdb55423d23d4d4cf20bf2eb7b51ddf4fe384de8dbc25d69fdabee7b49e622c833ca3c59ce21e6d1bf9420b2d8cf3f9edf99f31c8b04f2afdbeb3d2cbf5c430c81572bbfb965dfa0bafc42fc81bc7ef27ac5cdfca79c46ce489fffcaff6bde7fe37e23532add7773e79c79353fdd5c8bcdbd8ebc7db5f17e4cdf787174a8e31d7d4df16e4493df56fef1b7bf5765f1664f97caff4433e71ddd0de15e06d6bff53bf5d6f1ad95ffdfd7fefcf2aa7ad5705f945fff1db71be7aa79e3705d96e4d63b574cb67e5971705b9727d6384f176fcb796f70459d26eb5de5fdbd9fb95d70479c75965b7f163fde385178dbcfd7e70faeaa39e54be5b827cbd84f5eaf760c55e7f4b82fc398717e2b8e993107f3b822c2ff6b26fffedbfdd7e7b469e74ff2fed85f2625ebf1541861aeb677d7d95d3adbd0d41c63cce0a2397d66f8dbd0541e6f7cbbd2ded347a3dbd3523cfaa238d1f5e4bbbaedb7e206f7fb587ba6f7fdfbdda7a20db59397ddf3f5c46a65feebdfdbedf761f2d195973a9f59354f6baef1c23f36bb7dfb4befa6f84558cdcf5f6f26389b5c6b67720535f6f947b4b8faf87930339e2ba5fe75dc769f906f28b97de4b79941dbf2d359021adb45aca2585f05a1846e6dc577931bdf2bd3d9f0523f70a6197b862ed75d4fd8b8c3ded127a3aade5d06e2ff2add6530cfb957e52dd45def2d93aa1b414ca3b3517d9deaef5f7d35befabae19c85c525c637dfe3f6c3f0632f653fe289ff736427e814ce3a3f163fef6fbdbce2d32fef5733cf18394f2192d90e5e77ce36ebbe5935720db5a7bacdc72ae3dbe14c854df7e299cf2ea5d2dac13c8b25eebbb8e91fbb8f19740eef4eb4afdc5956ffabd16f9cbf7f59ed6f33d7dec59e458f9acf5bfeb61a4178b6c6ffcd1dae935debf5e91317e1d7f89a1bdf64b6d458e7053cc27b791cf276f04b2d75e46f8e3865d435e05aeb672b8ef8f96c240204b39f5d6963e2af7dd95c23c20c3ffbe84d6ff0ab5dd95c25091efe6f5e22aab849ddb49611c90ad8df6cf59e18c5bcf4961a6c89c3eddb18d71d20d69a4300dc80f6abfa9be716a293da4300cc8f14bff26feff6dafeda3305264dbad7e51dacbebf6de4f9828b27db8ef2761df3d56ed270c14f95df93485bf5a49e5f513e6894cb9c7b6d30aa7e5fef909f3257befe59b8fef89fbd37de691a7bdfbf6b865f7b2e33ebf90b77d5dcf2de9b312d63dbd90b586bbcea8f7b7f1db3bbb9035c6f35b6ae3be7cbe3bf1c8f7ebfe9e9cdc6a78b79d5cc812deffe9ddff5eeb7b9d5bc8f85aaadf83d2e229ab9c5ac813c2cd9f8d58468a7b9c59c86fd7b8ef96fbf367e99758c8fb7a0b6b8ffed22e5f9757c8fc631f2b9e74eb0f2b9756c854d24d21c71e4e7ab79655c89277bcff8d7ffb2dad9654c81d774fe5b495564df79553c8977eeb1fec5b623cf59577e408e1b7bc6379f9ddd14a2964bca7c410461ddff6baca28e4bdb586f7763975a55c4a28e4eb799dafc6d8299f3fca27e4f92f8df7f9a7e78f3b4a27e43bed8f13d2b92185f0c926e487a7c7ff4dfb9990217d77424a218fd67fbf840ca1a5d3da7ddfed9f773b32e7b5d6fba1fe3df2ca959029be377ae95ff51cd39d844ca9c6b57af8eaa47eee3a72e7b56efbf0c316f3b8919071f7de62f8b8d6f3627d841c3b871c47be5f9fb16a23e419fda79b6e3c35971f1721ef1b3bd7ddbf872f7d980819d2b761a5afc27d5fb443c8117f2abbaf7c5f6a7f1542de7c3f5a67b4bc468a6b10f2a6b1ee17e77bf86b5b81902da411dbf9e7f75a621a7f90a1bdd4c2e8ff877dca197d909fc6f2cfbb2fee1656197b90a397d6daef2996b3fa187990ed87efd6f77ce456db1877902fd69262aafdb4fac718e9c84fdebebfb510be79ebd741bef4f5682fb6754acd7d0ef2efd7dbe9e3a394f7ed71901fbef2cab7f97d97f27e838c7dbc18566f6594f7f539f2c43f6eaae79b7e63ade5c87273a8abc69ed37eb58e233f7f27effd7f5fbd9d1a8e0c35dcf85209b1ecf6621be4dfe7de353e0db9df15d7204bcf5fbc514ad92de79706f9d77b3f7e7cc73879bd6f64f9f99bbc43a9a7c7f5ce20770ba77ede53b869f716ba91219df8575cb1f47c6e0b6590dfc534f2fea6965d7f0adbc8934afee9ddf7db6a2b8531c83cd2f9fed3fbef3be38430c8b2576ea58d9a5fef3f842fc897736df58b15d3cefb67236f8eb58ef3592caded7f8dfc27acf3ceaba3deb37b35b2ff744e3bf1877ae2e95d90f9a3f1e17eadeffccbde821cbd971a468da59cf37316e4cb2daf9e3fffbaf67daf204f08ef94f8df9d46b6dd42aab7c7554fecaf0a32e71d7e5dbff7d27b7e5390a1ecfb615e65e7af4f8b820ce9b75bd68bff8634d613e48ff987f555da65fd939a20776ba99e585734f2fbaf3f0b6bddf5dd384b9029d41c57ffaaf4953f49825ce3fd78c37821865dc61164deb1e7f5ddfda6e59b0b932b16ea5867643f697f90c3fbede6bed37a658928c3bea8c47d0f856e5cc31241a64feb7f39df7b765aa90f41eeb86e0ee18418ee8f650441a670763e3197b3637ae73623fb7fa19c30d27fffabf57f20f7beafc4efe90925bdd27b204b79ffee0f771edf875496619591efb67cebce27fdcf737dc9c87dc65b63c47a62192fc6d80b6b8c6cb9bf50533ee7ab51f36f862546fe93ebff37e57eda7b01ab03d95a1badecbf5fdd3bc67d64e1b5d9e240b613d388e38cd1578b63b73690a7d71ec71867adb1e20747165ebca345b4004b0359df192bf756d60fb5b0c2c8f456cd5fa730427efdd760e4e9fb7d1263ed6b9c91e32f32c7bb7aba6585df4279ad1779ebdb3197dc3e6edfdb5d647c23ac9bd3b8b59e5cd29185dea44ff386a749032c2ef2af9a47eca18c7ebed77bcc809581bcfde6356e0c21a43dce58a1042c0c58d83da45e7fa9bdf5be974a3eb02e903df4bc4fdb3d875cdbf7936db402d616d9c6bfb7af7343a9f1f46f64a109cbfe346119935028c61d2d220b0acb02f8eeff5ebc7d76de21ed15e8bd4efdfbfd77d2b9f1c842d18d33b028906fe45346d82385fa45eb27906dacf6f617377fb4f24f47163e98852581cc2feed5db492df613d3f744e49bc807196069917fbf5a3f5f7585b0cfdeb3880f56d8f9eb9bcb91851af53cb4e58442393739373fd99528a1909550c8492894f9aefd48c370c21d2da21f28b0b0c87e42db71b415ff2fbdb4645857c090139615560472b417c62a617f3bfa7a2715ab8a0ea5b41acb2fe3e3f88f2cf4594ac34a3c142a95b4a877bd9174c6130a61282d3c2c08fc89a5f717773e65f73514ca175a0fc0fe72abfb9fd1d718fba7c257a965af554feefba4d70157da6fef8b3fce78ed9b537459e9c5b0bef83cbfe9367563228db410979b6d53379e9fb0373d3f493931a99ad58079f5fd7fd228fbadaf54d2fc6ea92827269400160368844fce882996f0d98a61acfccfe9f59bbfcbcd771f59582a693e4f4ce2d550d8119614d97afd3ad7b03fff317dd28a224f6eb195b7fa187be59a3ff8010b8a8ca79f77fafbf8f77f478845d076613d91bfdeafcb2a61f476c7eead2fb9623f39f5f851fca0c53b8f2c9f8dd67ebddfbf166efc852cfbe5be7a5babc6923eeb851ceb8737ea07eb7eef79d8857ca5eef1d63e29ec965f3cb27df7cfcf6b87f0613db99063fdd6d6f8dff4f4fff7b09c12a8d48f0ad6a918c43008194200e05ccd000000c312003048241a8c0583f1a068bef71100148002528c76b83a968984d1508ea22006421004a118040180010419628881558d8d0090d0b1e62d6d9dbcbd64125b50a83997a25205923db23f9412bf5ceb4926a6dc1dbbb90c924c81ecd7cecc8e9331466b870a3f06b2ecf4527cc62c4e57c5e379fc88469874ca88f72716524caae21e1559b2082d89441faa6aa44faace28ff95ad86cb2916e9e0d0d4e8a2095d4dcd4c857624dc707dc6ec0ee44daf1dd9ba863d8178fbbc62b74bba866ceff91df605f3ec6f00ab29235b4551b80461e1389079e8fa93de683b899b51f997a05e695f22d009525c227b4027a5d76b4e6657202d7a33a81f6a5c24b00f26599f49174922152d0be3e23f5092034c439a403fb5be397eacb7de42b2420587a24641935019957ebdebadf6ddc15bfbbbb37ba5fd42345b3a2034897474e86af434ebc6efcadfceee5ada38b4e839a69738e8d4a9d50fb98d7a27c55925e0f741a2d841d349ac42bf8786932e867941ab4fe937899491f753b95160522823a04f55a3a7497746579ff646d793f68cbe9fe636aa0aa303092b8ee3b5ae6776182e98b18f1df83bf53b1a7605f5e4ef667625737fefbadb3ef00be6d7df99d506be9e3a8e48bdd23b997b335b49bcbfb9ee771f360b2a7bb2b8b6854e3e679b0df74fb98d604e299bd09f541ba4397536577ff646d793f68cbe9fbe8dce9306199d3e8d1abd269d327a7f5a35ba4f5a6774fff436fa9d346774f0696a746822867a7bd70dee99fc71d99de50dde3bf51b8d7b8177f2f766b792777f6fddef3eee05edf7d3dce860d294d1d1a7abd593be1bbf2b7f3bbb6b79fb7bdf7edf7167f006fe4eec46f25eaf9d2cbd09ad44ba1f5a37bacf7af1fbf537b33b9037bd77d46f6abc5686bcecb4fbc4e64aec44f25aefa5d4dd075afe8b9e24b1039217f59ab21445c9960506a262adafad20392e0149109f7132f862248cb629e11b827d098bfc420cdf283ba3121b4a48963624c902f15c8e4416af72917b9ccb2b7ab94b03a6cb79feb5cb2057560e8cd46b30b0d6cbaa4db3f51359b1c015d86f8ddb5aa58c2504be8a96f31da304d762beff6361df9963b6d6b2d9b40c150043e530ded92c0a506e69ac342e778814408bcccd6657eae0dd07ee323f017951b51284e82da0fa35171641d9645310e4c6830eb33606ca057925905b61b5251bb82e76d7a15f80b8aba3121e09e192683da90cf3279bcd160e4ba37c843386c850efd4acb80a575c236622dbd8745a727379502e447e76f7805566aaa8a601a79cf24464aa69223935eb8203641e6f9b17e157ba1721ed8a49a8c71b3b10c0e902b531b08249a6bd0d9dc8de538fc5741bba9b8c562d8861126c07bea70e0607a7b49ea1980d58bd6801e5e90412dafe07a70b8aeecbdc4927cf2e345c5fcbc408a36b9296bce29e857fe286726afd0d939ee7f6aa82eb15b7ad5642db57dc01186897c98fe48a6133be51a40e1b8e4a487baa8fc39f016c1fc675070c755978bb960ebc84bc300030a51f8ac7833ed62ae3031eee665893c1278daa023d35359461c7a4518b3ddf5859158195525d961021599dfade8247cc3578c25dce16af4f5cf1dd4b3518dd893e3efb916d59dad435c9cc3e4e337aea2aa13cf75386ed83e3f8c88a23c732dcf5b7a024ff8acb6de8fbe321bbc98cd6f3634649fe200e5861de1a079439e5a9c204e3a5d8f395f6bafe78798f9836fe2797e6c8d5339637ca9f2aaa073f77c8cd2146941d3bc5d118eb2c2707ebea3c94bce65ddcb200029612cc219d4ef1f68e498d3cbe30d48a49e0e2de94d82e4fb96be300414885f088d6f3b1939906b8e7204c3c802e6691ce7de1d0f5442af91652dc7c6ec9af6fc622cc36873be94cbd3a259252f2dd8e7d5ad969997e58d46f6cd9568171b522c8a525620c860dfc0d2f233c6d1eec126bd9699b9babcf76cc42554e7b43105cb56313d4731b09abfe91dc5e835f88b8ca620b3bc54a3ffe24b5f4b9e80cd32b60bdb9b9287d365da43faa1d8923ff4644eb3bcd3134f43436512033fc073033fcc73353bc8ffc2f571f97b2d055ddc09911c8e021cacf5015777d5de626057aff70dd0aa1af38e8c531ee161c681c02f577e94cbe5c98ba4519fc5ed617bdf797f80148576901a272a32a8e5c410fa01ec6fe981dcb8be703d3e1d69fd35b34ef03efb6de75d31f57d7cf800977e1303cb1c79286b5068485379b01716b4ee2900eeb9b0df06133a3152075ec7202300bf02aa1c41105169db6938df3d74851e2585fd1225100228338d22fc7553b927ec5ebf06b6072b724c9121cfbde8a2a06b45619977ecf462db054f25818dbc51bbdad464f30c84a7d87d781fc1508731b71cb0b8836ba4b798d00c87f7403e21e4853b0dc71ba26f0ee5166e5d5ed762174de7fb9676896032ef91c81fbe9d31043e4bafd2556c19e482456ba746b34ef49d0af3e0a8a25906482ed73b47d115ef6ef8cb9b0f0295b5bb5ed434ea8e31457845edef03be76bc19bca915486ededcd28505b02c65a0c0a45037b39cf2a420589c28e6336e1068927405fffd007027a726cd3f0df62576e124ef0a349fd32bf4c2c10d07eb20f6161dfcd6a49d0cdafee33e21195a85ff1698a2afd11d1db2106f46f36b29ffc115709b45fba70576f38f4c118f909ce639091e45bb86edadbc62849af689836ecd87dd921198e2876dc3efcfc2fe03bfefecf88c64fdcc356201fc92e6dab9b36329c8c1f0cbbecdd4f55054dbd1a517e399872fa9955ed92c3e478a6289148c823351bfda3d86197055db1e6ff30f65d4a397d209479e4a07a59c0cc2ada7ce7485a61368326c6e4a2bbcb288c762beaddbb65d4201221ebef5e9dad759d887bb908bda2487b8f88f5369154ee093004489e2a7222bf8a74f915536c9ba44678ee1f443c86ab859ea8d60c7abe2ff08d2ad0bc4225a9c6da37c5428d9bcbec04327e9e52a085b4804b2cf90ae0afa368890638d18e0a7adb28f513dbc4adb684b200c7e743d197dff80cf5f43f17bbbb0f955f48ccea8b22df409b103164a8c8dbef88ab6b059010c040546d8580819ed56347c6cb3e9b10943aa4d1cb9178d6d506e7b4b311190744a759384f9814b71604bcfe36828da1215cfc3fbbf01e9307e70ecdcecc0dc6a4ae3ae5bc34df177ccb315f6ddb0a99f8907765c382033efee015cf597dc53a29670dd6414f50ee3c9c4f47dba04a30b6f0870011f8816ad4c1ae9df4f004241e2b08d964955a6b70154f3114fc88fc53b82c542632d041b42e74354000dfd0fa3b52a52648a5edb4f4ed6f071d75654fc3f34e7f574df278e468e1b83d1317b5736e8556d8d24df639349e5a8d5a7f65bada9e72e3f4de71a4b0fe0593f337fab0aac880c80e42e494f584e959d7a552017a25eea5ce99ba4f4474b3b06569dc98dec406a98d523fc1fb42348dd2eedd0f1ca9e8d70dd7bfabfc7ca1e0e1c75e770022422b588e69d754417e4dd52bb2fc9477bd17ffc0883c16c863b24d1f30769221753916b2776b8786c1188809000102b3758cfe50e6093405dafc67dd6c179d65a07a72c782fd742566c62b09822aeac343c5d14b95cdeba044d27cda08700e4bb4bd0aa5a09a2ac023a0ec63fb0f94f322eeab43264cb816fc7cf8714d74ad4d190e2028b5c4fb61646f333331615eab4234c15c0eb8605b76c953246a28785a3cd99e89942287478b4b15a0aec11f23869c6b7b854cac2c5ff6aed3553d768f17fbb02bfa2b0682348a5ad4db8f22f7e1b4501158c13757b56bcbb5275d92b9ac5e2d0d22a5ad505f6d809a46b658896f3363660469755b417a57782e27569238a235fafb3e4ff35f0b8e5b5888fb5e3ddecfed233ede638bc930da9c5cdfcc77be959182653dfb100949a40bdff561be8c218982a562f879c6029ffb7583ddf5a052622262dd2230c61f74c72e93468f56071695c5ce5f2873c7f797974995890ddcf3dd842a27fa7d58ea836c40c572411d320b361e0688267bbba896e376e4116c079d2620b0611a8542755301d4bf51c62a576c23645cdb67938c53bd8c147d3881797a005881b975f003ca72cbc0d8b73f69d1e087328a408e43b33bd283f93c30098df503320e10e749e508b088bed2b0a56bf5177c33a663e062e97824451e06bc0c3843cd3acebc3d54fd2b87cd8969bd6550a8d3016a5366b104c4aed26dcec9c046ebfea97c83c282accdc449eb73da8dffaff0a549e99b5e032fef8f47a14c2ca32b0ba96908be818d901780893cc133e9fb3899c5e34657a637ee7166feb39b9cfea984ee9b7f9d30d22d96d0880d7a4079bc8963dc05080f5418c3d2ae7001b65719c6a1c1bf337275b141c3138b82acda3074468223eae8557a581ace4c84d5636118e5228573eda4220cbf8ac5feda658e84cf7813e48586ebcad31b0026a85486609e02a0ac3b8814bbdf677b103f0c76861948149a0411a780ba27c292b4cd44b25200cd13788106508619641542d3860618bed95e171dee5218e39e5847446aea0d7c1b0a4909d90bcdd428ea2a4b487023ca488c21aad1a492a52981223b21b78ef7b8c1a90d702e288a540227c79d41f988c85ef96206f86d43faa99f0c143d2c00a054922f4ab948b184f755791a8c1bd8dfd4720342058bfebb72b9844f7693c835951370eb8e5f7c830de2eb691b70f5e7fc1fe6e83565a03795fb57a6bf215a49cec9e3bae822d31842c725116bc284c245a02b114890bed6b12e0be40f5930fcadbc3002eeccf9a50e00b9bb4e6f267b1390c5bcdf89da81bdcde949edebb95049959d5343cbbb0b902dc72d1b754d89a2187c9e8cfd78d6a87c5c83a7b18ac4a45121e2af9e0762b5be4d719592c2ed9397ec37c727f64f96c9fb0153e8b1655842e52dafd62dc9d1d9ea09408344771338f061ba103c28114fc33255eefb16c256f82af1bc07e5f0288d3c4ff0e1e7fe4ee3882fdd89c87f13129cf44d7736abdaef9cc13cf038953b9279bdf864ef1e7905e6eef1badc2ef3fbe2b7ef79e020b893cf11cb97ccd38b6f7bab917730d73eef2c5f89bfd0cd1d0fc84d291e9dbb6a3e6dbc41bdfab757bce6b68bf735f96579963978f3d47134f415dcc9e3bbdc4ae2fdd5b5bdfbc037b85f9f33cb0399d39b471da7c6ebb2f4f327cd8627b5fa9d64952c42e5e3b2a3f2f6d2e777fba9291715d46b075de618c058c8b3fe6fa93a1d4077d934f6d80555132a57f0a8bc16b76b6ee9846e2d54f4638eed70e1a48dcebbe6fb3f0902f9db8e0f6a7d29890c7ba1d62bc1da0e2cf07f9fa7d6155fd14c34d602814e128eea92db34d5e51eb5f8366d532f94d9b90a342a78defab2b0b9a1eb79ed0265a9488cfde3fcc8b800a058681cb09e2b16e7b0a8bc852d17e148ad0bb9a4f7dcaa8ea876fcf90e92c246663632b269babfdf4db5dca2b5215f40e29ae36225bcfd04c234ef5d39c616dae1ca0286aa2dae08830c4361b792fc13408bfcba3881ee0c87c689647edd3d81465361ddc558b00163fe58ef9a6d68e2c2976a757a0403f9a500853ec8e1a4c24c581fc23eaeff90b0ef7114873504a341c864c4ed3036548b31323dc11a0de8256f2a246ecf3e80ed2b59d0cab4d4d24950e3612d6281df3faf40393b9652f074ede67eb7e7e632c38b20ee340789d6dcd02b361de7ab368ccbb36b74e6c91e04716b38de27114f399020d22b76ab52f279e625e4c6e59a2cd1c9989db018033f274de698d3d6cd60b43203209672f54e3072992fef85c21c7ccdce333323d9cc3e2ce17c96de0623cbb021b26a8be4439b1c96138102e8908658d6601f037ad04049a3f7ed369beee98e875b75befcd1f8cedfcbd4a58383fb1f97138b9e47ee7d5ecd2e383cdef8b938b5fc64ec6ec605056e9fc3eec8ab8a3276bfa72cf0a96aff8f908eae38653d155a9410acd83cd884ebacf3083a889ea0e687e42ced8df9c19ec90a0e974b4d4d6df94c8ebc81c2fdc802d01339c91aeca6bcf5f6cc1fa6ddfb394865fc57c4ed166d940bd5f3f135bfdd3eaf54dc5c0973ce9bcfe627d1ea04ec7d42e1fd8fffffaef1c33c974e5049f271d8160e36f4478f11a88fd8d47973b09baf2f91d39064b00c20b0b1b5e89194b42599c93e65490f34a2b410540d106010f90d06c55e52cadf588eedc0d3654eb8212b5bace72432f698bb18320db929d214d16381c4ff8787ec9d09320420a8573204f188ebe8c73ede72a5fe1407e1ade41822068ec16bb2444e9fec5b9915bd9289cce93e18ab8946dae74bc3303bb834aa1fcb18b8a12b39d9f6497cfd2058882e65a8f95e4b43c1c5e447afca1258e578026641b145e492a5dcfb261192c96f3b5a4c409a909114d82427101b54bf5e0dcc67d55758a54fcf96844a484434ef21860c2ebd2585589dcf3cffc6893f49c94f615031fa0278b2ead645efde4c505d5c998bc9ea4a11fd6c4fa9f1dfcc7b8563b27bc1f2c264ef16821faa6e89d6f25a52b52eccb2e7ad365a7d19f1a97831984445c8d5cbcc19be3bd602faa0ff831b264f0fd496c37265d6b7e061fbd2b73ee1fadafdab45c428822b4ac3535f50f244d501ded7534aacd10b01a2aa2af64b6cc7c1756c2da42f333389985c6476fe65f98d59198de3958b1de1ca11495d30791f9069b88f96f3b25a62a1eb20fc30b4126bf9f869b5d91d47af4dfec6fe1eff35d06600e030cd9f11139385d6522e6c270d3394c4db70fd31b59d77f54c6672324ba7d8cdc25c41329ad3a8201f3e9e156b2382ccc387b746429abd3c3353bc6b44168d2ba0b58c56b56a199c0d6b93175b654aa1bfb52053e5fb66be8baf3d2453363dbf8e8cb6f279c1e52bf66200180c7ce52c82a0a4b06ff06f4d4707a535d963202a636bc075545a4500a5e83222b753b8376a51b6dc1ba9a77fcccc2621c74bc5e5543f83519f064d01a3b6429bf8f1e50c825293a91eb07ca14ff1e9c576aad63fe6ab2c9e710a40382a50ab6f2bc6828dbc64c6161b1a8b33144a2112326f299426b8d2dc79afbc3c850e30a4a9f07a02a2fdc43b7b96f712aa432bb94923a05c35ebd7e2a115136508f57daf416237c443675ea529ec6480694949902302b6720b536edbc6c8964c2ae8a809b2ececc72f66685acf60f02e641954622975a5c169e697479d02cbb0cb7a9c89814d9fb4105a714fa8282d779d60f162d2ccfb6d4bad123005cfb31a1e91b701b63b73a2c5eeda02d8e848ec80ffed55217cc36f7059addf47edab2cbacfbc5f2161875e5e962cc86793538a088e9ffcdfbb6d47b6f826ac196ad485cfd0fe98e168b867c15862b7b263c5a0876ecbd9c859e21fc08785367f8efdc363691c8bfd5c23d3b1d03686bdbbfc4e5169664bf3df926f2439734532ae14d445ed9f7611058a475cbe9f7f848e0f628e49b8cb1c7724f385b5f392e491d96541575045f872118bf80fb372a2ec74b066a9e49bf3cb7b856ba574cfa8f034a47acb82f1ca9e8bf641d193c44817771d13386bd95b1201386ddead503f36211d82385b267b004ccc27f081aee812e8bb7be4c28e687f991d2df22f255495f25844cbaefc1d4d0a69ce126121c94edd57b3303cd4ed81fdfc529c37003c3e7b8f715450071bb45efc984f5275fa122f8072a37133b8274873ec0be779b28a62ad30282e99069d38cf6d6058e99bf8f0e3c2c8b91df3fedb2b6f46474d1bc4cb3ab1cb881f0a07c45d0e1a44f41b0cd0ce81c33cd20e4b92f64b1638e43d4199e3835ec6c07bf467d071738f5e6aaeb840c8de988a29c085ed5ef14ac93d1762356f5b046cffceeac19494fc510cf3866c4947ee470a50c8ec7883cd474acb1831fb0a4e0d8edf1b519f287a385e06ea2c63badbb3ed383c8e0a77e9ae3cdad783d7583a0968affe893447cdd2463d6a3b8cfdeba47604f78031fd7cf4f8e27b0c9c903860e00a9f48c2da4ed32c2f9c6cdcf54d70667d679751f5e10a8dba69ebcc4ebc5bcbf844a9e4ac2df5daac593796d69d1f5538b998a5f1ff4182f9125951ef85c313ebb204d86159858387514d37276e801f74fa0bb98d1ba546d6aa724c5b726a3a14259d27821cb69d193efef6963b5ef8538b9737dea407e0c36061c9c37d643911cdd38ac1573bfaa0c76c8a577ccf8044410384d203257d5adf3464ff4c91b7dafa01d6965e2c1be487a818ffa74a71db5599101b3e44b50fb87b126d0f259d378e02ef00e1d9a53b06d4f69be7cccdc64efc68063869268f17f5264f90f29a873b6edc092f929da871548ee77ccc22fe1c4b827f31ad743aafa11e7186cda1877801b22484580ce85087068de0b2cd3dbaec97f82b99f81015ece7166a183af66e41d27b6ca420ad064345b4ba2f289482c8ea5b4e9e036cf7e0b7f4696d85146e9f0415e75865836d389cd2df259506adc3e5a3d42a590067665166e749243ee1c9395e390415367b009401b1488ecbcf621160c719c0b92aca2c094ea5f0dde18439da7f3bed186b1aa57dd514258c3701256506f9cac1d766434bc9ffd02c03e872a02dde52b0faf83dfb52f5e1ad1e52b0b150410501dbe4f1e8728aa81b29444fc55e5c1489e6dc63c9c226ae0d6b6cb1f981e05968bec693fb804ddea6ebf0d1bfc35654defe7cad380ec05b1e1294e779b3c496819dd3485f38b8cd0d23fe4f15e70eb3d5cf274d69b5731e3a2062d39311a60166380c00367cee689f0da34af4753d0ce1e6c63477f50d71fc694fca2d636d236dcb95505c0afff9d55d8ec6afbfc28b21d2b9f772659486ff5c37db88f069f61ac4239557ae9da711bdc3397ff3f6263f4ed8cbd183ff3c92ff14f6f1a6f48772842fd226304d3747e639b56f6b313cef47b010a8fafe20ce2c623f2cc223d70bd19ecdd18ba7c582026f9324f727fb98780a234bf7ec0f690dbdaaab02b24619c83476042f9f88aa20d093e9ffb68d6abf18bddff18a6d3fae823cf43697a5f187472ebb488c69639078be26eddb9513c0c985c0b007d9e4f37df94f816a17b1b7db64df6c802da0e70a5b0ce66579be298ab3f1f2ffaa5ba4bdbb4dd196b98c6bd6b50e4e7a6852cc6cd77e797291e066f218bbc03ea2f5bb38ab5dbca1d98853d19ac1cff29737ed68d92565fbbec2cbc0ceb41145c0bc25c4771dd87250b3b3b3523a8d5c9a415fecc7e5c29b2900f8eb36ed7bb538c56b7da954f81053c32ba56694d513798bb853082b4ed8fbf25e050bd8b1dbd7ffffd57e64f6f3fa5bfc9c2f2c0757ff97bfc9d7ede2f27d7138b81a9ffc7dbe6e1f87eb8be17b06eefa787be3fc290f3e5fd78797abcbd7c5f1f86a70f0f9f8baff9c2daea617cfefc7c9e3d5fee6f6327a5a1c9c7f3c3f56ff936bcbd1ede3f13ff1b9b8babfdc1d8e6e0387ff8fcfc5d779e56e78f57d789e3f5e16afee37b387d5d1a01b9fcb5c2d7bc42d6d5b07b42565eb07b67cd7fab396ba5a7fa9c511d3eda29650d2101413afe274f1a3c18dcf8ba9cb27c736bf6e27163e0fdc7cbc9a5f7276b0f5777172f9c1e0c6d7fbcc658743bb1f97e70b1e066efddfcc5d383adaf8793fb1f060e8fee7dde4a2d381cdfbd32b2426111040153d093bed34fa31af2c4c19304eaaaa4342ba0e0e9e10fe7494f374207f2c5eb8e84e753ad39dd3481ad15821aea2b05718700d072773b8721ec9c015ced6b5267e9559de333beb507af0134fcdcfaa66dc98d1a39d62cd77aee1d125d78a91b1dfaf0de0b74c10a4852f4ed586b6dfcd359b4ec820ff5aed598ad10d12d752c454739072c4f022efac79dec8dd5e5e2222acd3408639edf9ab57401d43c112bb5255a191897d784c3a7cf97e9405d2539cf441d5b1da33f0e4079985187a59b2ebbfdc0786188b97321a36fd4daf9d21b1e58507a2c00e572e43bb2124557279b04743276a3be0c363b48bf10fcec9f1941c8b068240aadf95b223d5d30cbec58754f2b8d66f14923321edac1eb9373b9c24f0f8bd0814f8ad2c828c3844212112e29ee2b6365e64d0010805bc1ab872010f3634ec2762e2db5b5b64bbc9a9e0f899acd51724313fac0c24a62b35bff1d0d9ff677ecd457d4717f2308429ab86cf3fa65c4540c4b0c0b00a3d5564471417a12cd3fc921d7ac51bc826641cc72c49c6babea2c46de4aecb125c1b8314209e603573fdaa9eced18d6d93478f87864912dd234337920cda3cadc9701c3fc2aabf3d4b69919cc0c60b3183db912e21d12a7553e15b31da829ccd0b00a893863a46c7a4bfe1ebc8c42058f64c1c653e2d4ec7f66f1e3cdf1a4bf5f0d95768bd414faff7c671b28459ba0cb2631d68ba87973633d7112fc8eb8d269ac7b2f7e1c21420a6f1d8acca6c1adc99a1f28d443bce3a8dcb36503e40a45ea8feea9726390e8c246b8d4f1925272411136880635bcc8804cdbb9d1245f4393bfac9034ecc869a7a3ecea7f549245cc80430c2ce3ec2f91e273f29ea639844871edce7933df1270c3ccca2c1733d12d2f4bb59d9234a333f4eb31194dacc61ac5038718e36a1ae9ab1d6f4a5663226950e1158f2183be6a0d25115f1f121904e6f9e5332e230377e82a436c40f24655e381221463dd5b49548a8a3fd1d34ab3d9171d134034c4b8a72a95d08d432c4020bd16fb4f62223ec8e2398c666e5c5fc91b311ea94d418a774d4e2f92b1375b71145b40b75dc090b42b3e10ba3e3f1cd326e0a2559e4a09ece94b6e21f234e20815810b0ac06b008645a935f6a3847db85963a7bdc11c64a274bba0f43387840966e6fa002ab30cd7accdb7701adb12e7b3a25a090893ade906779755fdaf9af3f7d407cf343726a7a3f060bff11c8958083c2e572f2c25f32a2bd7412177efa2367f1a8afa7da21dbf460d57cc6f8508b1d19db2477a2db181ea06d8312c03f1af90357a7e5c1b97d9bded01a31edf749c0bbda9fb96b0f28c345727ac14be5f74b52ff6e787abf0f553ee3d05241d0293e70f12feb935ef1663b20bca338715441902c736e780d1b447823703133e92c2b175e98d57aa334fe2c957d7fc4452490b3f2961732cdc24f7be3fbbec4395f260f9f1f01f1f3a777d73c7d1e511017e8b824f0239eda4d68c582147e70d14989bc27f14a27794312ab9a50948f7a9d5c540f482f53f4286329632f2d8f9719d7b9db941c9866de8abce3e30efd05037cf048594cfa8ff5c2dff35ec9a5a9ea2932d1ed9ce51d130918c5f0eb160dc248c380cec8a0ca8a91ae491bd271554277833ec575f81cd41b777882e40f89bdfab7b9905789c608f95bd1dfaa7c81b72ddcbc8cd5e5a5136fe15531ec98eb941862cf2247a92c6c4c52d7b648f1aa1a0171d2f24640a9ec8dd1d9368c2938b38326fe7a25429f677ec740e3a107da578dea02de55301dcadbd843e2442d1074c953b3247ba2e119a8f95eb59c04f6d48226df94b0e6cb2fe94b35c269c3a92dd7e4e73c6a99914ce1529a975b6ab1ad904235a32389a5bc931b2d3d931a087fa1d994a4e466345481e67824696ad82caaf1dae93ba9670d08d4c0efa138de5fa72b3cd2976309fa1ebbb0515ba7d8a4ad1bb46b87e7f5e474456c06384990c59b0735a401016e6ab78df6161e93aca7025f73b5d05aca0ef4c31292765c1b1b6ce5505de6e3b984b33d7c6b2217ac0229347604dce7d260d52d8569b794ca74dd32fb9c3d226bf8f9783547f66ba404b85be7f44fc9fc060f46359af1a41bef58f9a74ab75be8b7d152384812b0b15d161fc7705ddf0e465ef05341a1dbf5aaaf1fbe434239c1954852d9760aa5ee25c7e0811bcc60a0523eb904d0bdc5eea0bf4bbe29c76ed663902dfd80c2314035256546036162a17df2782e6975a7c02eae238aafea3398de189eb4ea43431bc1261b1c0a7a816f48aae539749ccdae3f89e8a616b8ada59cecd941b3b79472f863ba0c9b148eea9c812a0c9f7124968f48e182d2e3e363a87091929b2c4de144fa43523ae275fe03eccba02e7f9729bf69aa7d14fa50e6f9dbba307d87b4127facb3e3e6e2bd38da8f717584283553ab9b201421130edf424abfbc019d47b36c0a2d2f7cfb013a87c70c1beb83e901bcbfd3d66c85a39e75f00ef6250ec0d75fd4559e87a20d8bcf68c13d1e285e388ab0090daaaa3ebde4be18c241b39c5874d0e3dc2f337a0621189371704c7fac505b2b9d47bc6c858f7b757313630e5c83bf2c6bec86db1c94894275ac4262e0e3a02d944ab7318b25f52a12f34361a5bf618ce37c5e483592132852f08e8dbb55296eda602569f472434986a4f02e5ac4257cb3f4fef40f735c67d79fb6a895873112d5e06adcb97688ae2ef4d41ae8fc1206967be228988132daf665b16e03bea201ee04bb690a04dbc2163be3c96703d6e965865a95a18d159e62991800a9d90db035f7030a5eb19c1edcc16c96257f192664c33f03d445c67b5325e3ac14c4038974b6cbe0eb87a2fe082e3f3f0a547cc170e6bba70295375b9255476cf8ed07e59e396ec4fcefab6e1b60c7fc3bd6e7fc277dc502492564f000841b1f8b32e32dbdfebf3625d6bc031c9b576b3ee01a353daf428495cdf76e29d62f2b52fc48621d572a66480b37912b1da5e1086c335fb1bf2ec30a1aee85429892d37abc54481500ed0d5434028f58287dbcff6fbebaf8dddb4100885dc7630034844f5cb7a125e9bc41002305e3f486507f5fb0bf23536ea1b4121eca6c47978154040f34040efc806b638d505b7aebdb91c4681bb38ea19958c96868fbc689d07c1fcaba7b337b114f4d1119bb0f281f1c325ff9ce6c142ff54de09f678830128e8e914240d5ec2468e07092e39ba038f2372cd2a0470314f033d60415d019fc77e43a9ba90dbcbd5899b16101b64097b02f98d6c4c421530df014a97d8b32e730b1b41e7c732489610753548f37959b1218807854237fa708111d457ddaff13a7fb55faffc0f1df76b874839d0a152a294916e8b9428a9b5fc3dfd0ad25700cba4b8abf4d215122f5bf425198dd14b495f7e1606538363c469cd92e5c5fa0dc47b45278e0feae30a9809e4b4caaffca67ddc6c85e75bd9fcbedad4b82470ad1ed611677096aee6631f1953b40ec535d36cc0f34dd9e9865e9791218466571af2a51ac1f11d10abcd8a19832b80c4e3e5e5c5cb50ba607a1a936122e3592304a329cf1484ab1896dc866c2fa4225a537eaf5e9f0e3bde95a4e9ac4ed1068728e2d475b7700f732e68ebc660f42e782f02180c916b4f62183897e05ff700b910b27f5c9f0ff5e18f27d6860d2b95706a67ad2bc97fc91f9f02783f89ff181c9266e0c6b4723ea59f2896e4b1a11b91e8ce8f6b08bcdced8a65de5bf3325df01f5321bb96e15b30ffceab08ad39112b5ef3edd743092b6ce00a15befc4d97f76c5e5a32f7e73743cc19ae94c26b3094eadc319eb7524dd945f46df8615cd6512f7d366ebb4de99f335f0d1705b12dd1f799db37f050697bdc3b907e2b0854a4a111be070e9a17f5b247e2619f2143a1afbcbee220633efabde87f2b63fcb2aa4e626c24b33957767c201d0e42569bc2bfa4849c69fea3582479b63022821e85a6c5b32ccfcdc34439abdbad73996b8bf9495f7784d3352499ca8e23755381e4d7d5025e353cb34cea8068d2dccc5822bcc69349001fb6909b0957dbf989f44396105ca110b55ccfd34e43e92a7dd25577f6105fbc2069031b6e99484c296504944cc1f8dbdbfe3e3e33256234079fd823037c24a3a7fad574f48b762dd80c0ef3282cddf4d81bdea6549e95351bad995d5c38d08ebd3958f769ca3b934b99003fb8520e1d8d70432c6c19f15ad19e4d7869caf02ecfcc2141b40fcf1ed9d2135e1bf0e538f457e0c0e859e7778a95e8178f2e3af26370122477c0253a6e580d8b7e639e5c0d764393ed7977b996732e02080790203e7c909673a43cbcdb37195dd71b59a3d81fdc9348bb1890be7491d7712d5fcb12209416be67d0e946781656a67a93a82b698c2d5890851e7e4b38debd756810a542d06ba4f20c17b5d727bb0e1aeb034dc0b737d6b1b4e0c18c75fba779698f0f246eb3df3e866376206a130ba35ff3dd7a40395b011b607059ced13a78c036ed5c2b60abf50af191be351f4f2b33a3e33faa9a0bf55fa89d1c19243f9ebe5cda270c99e88a22a7d3f78cba62be620808537d738aaf0022b0baf49516f7f6233dfa3a7d0a96eb0f7619ddd2fe31f16151f067e06c4aa027631881034b668bb5549b3abf63436097af62435db02dbf96a87b18ddf182f96c71cfe65727f58d12bd19053d02e002630b8a903817ffe2bb4817f593d76a714d17a82655ea9eecf17b0b90a9661fc13d2339f1f88be53db87872d0bddc60e27358a8fa696b9e8a5eea23d2ce93178c5bbe14481c946c665e2d7108f714d56844a7a9739749d0eb96cca6250a816693aef21faa39dbf77c459965bc0cc633e53856615f18fcca9e19b703d2da2695d3e8f111531b51c1d05a3a4a2988c2b16f658d9ebd8242a0491fb36051ef340f9ec462e2da0c18e6fe1db4bfaf9e5155d68a8486e01c3b05ba7d416ff09a746534785495ae2b19f8acfe504103dfaedec4c459d7f5879733ed5d8d45c373284c812f56eecc1927c6189bc6370d9aa5bccff7711b41dd991eb0a3bf9817b670abb08adfe98ca4423f16b53ac39c1ca0f0cf92c1f3d321c035fd81ccdf4183aabefc937e5496e0fc8a8665d72e4fd299b437d38c979516e9a396dc1ffdd83878b45bb8a0dfb23d2806774bed369053c5c2c51af9d0ff2e7c962d63dbd8f467d46e319938e5b6dfbd5a7a3df9a4e43eb315c6c161259d77ae4d88b03c6dafb410bd4cdd70d92cb2d9e4faf1c6ebea5f2c865170ebc1632b835c96733bfbea8568f28c2efbc3f2d011137c47eac12964fc6b31849f19e89ea220c5430f27c445fe9896b7cda096b2873c13b114401e0ec97e1797a1a899d8b2372ceacf32e868330b57c0facec6f42fca9fc30ab863cdfb8ef96a48c8368f45e62974e7bf2c1afb77cffc0af5e4e7c3ea802b7cf374c90a7badbb5dc39af86d3e13c6faa0ff491abfb47dca7e6594f32be877a21c01be7d5c0c597cd34953bcfda0414380fcb3f04eb4fd43f59ddd1103f3601c4b8d7398bff1d48e842c55278b9dde4433ea6d2f52c234081d276b78eb317ca9cd78338c4d4c0d3bd1b7e39a7fea9e876ab208d2daa9e49b61a557b8839fba19a07463d0f574309f1063f31c6411bba902bd2f9c4ba760e237d262c2483cc3de200c2fbc4f225cfc4fdf151a9560ee8f583c3e91367112ea9ae30a47b09808b0db9b96ac469f00f0fcabc0b14e26494ddca120d7a0afdb21c67c72e822322065f1a4aafa3b50aaed1d8920e9ca8929103f2e334335ca3ad5c2d9e607a4bf1123bf060111bd2d0e66f43dd6f8700c3b8d09ca2cdf5caeb9f5ba2d9a4f683b29ec1388fd19792161fe009ae8defd329deffa9bef7350d3e826f84d9d1330dc9decc6d31968fcf92e81c3690ecd74ff467e390d8b4da7b7a5b0482fcb40ebc81748f1b2e1e68e078d0c72c1c953f693652932f49515ee83b26478b9bdaaad46974f9614f5f909bcc3adbddde2a62f281338465c71e630bd13f29fc4a1231a258f1f4394ce35b919025c910b7f2d16e8fa78f0c14d8fa8b66c6057737448e6978cef145e2c036250789123f616796eed5f9238d1b7abb7de3020d15d6d679dd307e34623d317ab8cdcd35ea5c88c9abb0ad4b620e95c610b707b2508c58140f8c32e8855a9f1ce18d3d74aa98b873aa527ff291fc7fe32c7392db09808cac485a1e285a26c8d4896ba6a3108925fbc1081430cf8b7a9da3e8e0de9a8fbf7c94f33769f337920e86582ed3f1bc094588d5fe82b01ebd1d1d8ce0b97d1318fc709eb60b2e88a03d68c208943f7ceddefffb54eacee51043b39c003c7fc1a50fa77031bc267427f7b0e5d87bca8750ebc225bf9224724151850b24be2dbe3660305a91e6a7fc36256df564635e5632a131f30db9c1dc4b009d113998d0502df262f4d34e3265e07d4f7256b80eb543bb69ded6c8993d60770ab7f9851a46c4a2906ba2902c9216c7a4839d0591ce8e57dc8b0a5e5c697679345dbebe5ff47f20c83e9287d39e137faf338ed74dc23c0d0cdf0fb4abd39244e7e241a95b2c0691d02c799fd88a63e15b6c3be6e226042f8ab86f2fcc85336299b25d6ec32e719f8fc8c76bf13fd4f888dc1d3fff41cd487b7f63a1ac0853574bd052093ac4554eedb0026d2bf8e004770d67b882a06b7092c486b97949df0e61cf318e965fb1fc4a0777587a988d2e79ebe78c754c4c8359ceb00518e619b782541f1cbb8f65675d171d392429c7a9de48e6c1f9361a0afb5b6f1859e3feb789aae50ef3dbfead7f2769cebd870ce61e081c4e55074ccc41fe09dd8b7a8147671287e9d24de41bd7f3927ae080dbf76f703de02fe12b9ead4372409d631f551c2992d82bd8fcb16ef04fc4bb0e29911c934bc659e46b953cb1099504c2254a5d3094c920079e1e349b2bb49f8d0b7f208e3723ef53f9ca0a62549c84a8950725ca69406b619d5a67c05451c4b469ae5192d190bc3ab06212746656a1f46a049e1be142a98af1d523ea28f418b2858111e0428a46aa440ff071b6a41a7f52924b4ca5182c33648e7ee6a44b1035c7097194e564255f2afc52c984e21250698ce099960ea24de5c8d208dabed3191e354c2bdca7e23d62318c07df2e18100f78b1b32109d3012f9440485c3814b5a80b1bab71f5b45b06b606c34c892d1248b6fdf09e87307e1cf8dcb63375e7313bc4fad355e9259862c7240505081925b4b11bccacbd070b9d4cc49c04fe8059f8098e27efb9d8ea79d148cd67418eaadab5cb925eb082027eb5521d7a27fdc47f9355865815d657c1494b774b7b0c66b6b2c164694a4a51ba71bdf3bb287e213962168a13e65051bdac2a516a14457f8e0e3856cef41db449c059eb849278480dc0d5587093458197c9a200ce12ed87685758e0d6f3913b8f853e7683c46e5db14cb7bec08062d6e7ad208fd98b12a8ec8f92ac4b2f640adc146389323f92859d7c8b4b6730faeebd6cd57390670eb87d0a2fcfc440608dc07ba04ca3599ccadd4e505ad49529ed1eb2b20e1f92830ddaa409b6763e6c1b754bfda2ddd840a9d3774a94d8703bf4959f7f45c9fa5bb3abe3e54509f5055c204edcffac8f7b8635f61e2e476d9bfc225e6281d1975d972761666f39a2a0a8db085366fed94c4c7419404579f3cb6f0edec849876d84c4e70db90d073da51f09869b2c950c0981c5898008443deddde26604282385c1cb95d7af5e5b9f6482a313cb66d7896755ec96dac69ca1deeaded1923a8644fb3e4565b4851738836f5a411325a82aa8848aace8f45868db490d8e5887ce278319cc86a9d3583183d7a3c4ad1d2f2b5d2f680c3ca8e2dd643619e22260f4c029c683359a575a2f1aaf6957400fd4e9bea4c4acae0f0d03d5dd6796d535deeb95497fb5d422404fdd3496935d1c75176143e19ba9b2eda8aa96326973a00fd32d43596a8b20947b233f2b48741a733322bbccc9493a2e1e8423ca415c48787cd7c293c9905f35573de427b418c9db6c61429d4ed3d76cd505673e98a866221c68f26a9012e465f9a1d15c43756a39bcac875ea14712885852a54a48066324f4b13970795d295b8ff09969a73bc96d2a52fa50a96709fb008afdaec301af925b295daa82ae28838269e98f8bffb01fce9a1798732af07517b6349c05c37efc197e8c0ac73a0b2666bf6fc744b71033f95eb44bdc7bd0dd538971155292fdb25dcdad09b202e4bb43ad7be0df87347140ce56cc4c8d594cac0ff420c19116eb02641a538918b1301a33682666cc3d428cdbf0f563980fa767a7f68554b7a0fe2b776be813ed734a7f108171986c367ef2c6db60f88b725002e8103cf2510d50aa4c03617effcc43d8f44344fd7faee7234f9421fdd9a57cc2d4a241156d8e46360b3eaa6190c793fe130a54db09649709718f53e076ffd99d6be5c5bbcdb1df67909c1d3c6258f7510871b6e745ad3de05a08a828a8b0352cad41801457ddf9cf85529b086d68938b8be99f1c6239baede51e7693ea3ab4d40000bda183779b56559518e96246b9f09fa6ce465a425182c1f67ae289b00080d2287cebe33651473c0dc6033609179c58185d17e56483451f52b1e7d95e4c7bcd74f822f1163dfd6cdf3f11179dfe8cc394fce5a3c7cddb27d36b82fab3a33622fe7f0f17df7368319f64610990d21ef9dd2deac2fec294974fc473dc97b386a5d411c1620aa1cb49526bd3d83d5a28895bf2c204b43ba642f1dc73fe21f8d1e4ee78a1ed41f2fb981b1502e725ac3e50c3ebc4290fd19f5cd57b71223cd526607f8079124eff1549515407eca39c02d8310299ab721847e6ca48caa73a7ac82817be006334e85d7550a8a4f194187f1e13f09cbea3e781a016d49ae54534b6f7bc7b3decd80937eb703dbbfe8f82b0544304f98770c548446c1caf256369ee02c2de262ca8615c557d6d8367cf85c919c032e172310e739d76c1f03a2c566406bb17b6ea5dda3e0274d13387fc6786cf0126bad1044a7fffb678fa89b76e97c0e6b83d076605a913bad60798cc48b315abc04ec7fe2d1f5d1c4d4afe10389fbb5c3f7b8a1e1f62c7101968aee4d09dc3d95005401582b327dcf8861700d644aae30171809c98e80a14ad0b01539c02a30b2e859585bc02c6dc62529a2ed7d882bbb75f17e7d278e8ab2ef0ce2fc2d43bfa1964c8bf8ca7551e848c51503d705b1e64b94dd5332bdc36d242bf7a81c5e0a29654a11b98f1668cdf05d459118f1dfc84c90fa4a3b2f5347d1f2e9b3a9b0fbabf4f7db8b05997cf93f31b643cecc147b50ba8dab699529e1efc9e0f746984f01f66f072edd97154305971f4e1b9b002b7c8f1e9b77a399407fd8f99d8b74cd93c1feef5874d0cd91d8e70c34e01169b4c930f3bd2b8b03433eddd0bc42cbdc6ab80794fd7ca7372747de977f0e412813a1fc53d5dcba7f60590cf8f115c22db492b4b6c82ca917797ac13ec664faa31970205ed8d6a26f7b31ae99aaccb6ee7aaf5adab6ca3a44f59d9bcd3f0bc2eaad869b3f53955e427d26754cb494f8e7eee2a0f57d9204579eefc49eb91332af61f649f1dde4aba457c0f6ea24469732de826ffa456bd21560e8957f6aa2f490635b2283a1698da31bb091f8dc9199b8ce94d94b893bef5c3f2f159b2b7e161eceeeaabcb1379e03da8b8e0ba9db145a23591c4733fbb4d3b4819458e3b1ae79842e5074626455665b3e861cfc373982df15a3c96ec9cd7736c34684e0bf43d9f2cc536a0f858d67128186727cd2f2cb1606c466a64cd69c83d70904163764ae643b846e5e4a51f263e8608c3c67bf5ab6697f1725a3827030abee03d9149fa4ed1529c7d56a6a0080f70ed480bb210e9d71784e38918bdc926888e11a60819b92b9006c1b3bc0d6ba08d360f0ff370cb3c46fbcc4aabd08620a8fbb215379bf90c55fed190820314ca75885704a1c1e839e6ba972b098644317b53097036d7c438c9b2bce759fd97560dc864887853f7e2cc2ea9c5661312de8aae5263660cbb2bfbc6c596c4ea57e454c8c704ddb0e6fb033b90a0e15f53277168009b7edeb20606244e2c56b4eefd588f3c8523efeb87abe22bdd381c58bc5d3569d4730fddafdc7528d91ec2c9e375ec0c5bed976e5c9ace44b65ee0744684de02ebba6241070ee187203bc6eee7a1f642679b7e608459d64bfd02050a0be234d4d0edaa9840ec4950d6697a85a45292743f53219979facfd39e275c829b8bee5fcd2fa77267b76c07aed70430161364faaab2cc4cc783caba208c620a2a6adea32a80e00cdd71e224062670dd38551023b482da2bbd100de0e0209804ae9c35f8c80569007e5e91f3143449c33fe2df6af42b0d324f651108fdfce5f1f80f1e22409c43c423095dc6ca4b7bebc55c5350186aeac7d7667f2149dc6447039c73ef26385e6d21933b53307fadb53880439bee794a252acacb1d870050b58056a10afa54096487e530de312d883c9d9c110f0d3f129f3b5487cf895101285232f05e2219c42847aa3e40b05bab8539e74dbafa2c617bf83fc130f9c539e23f5fad571909194c13a252bfa5ede7504da5a940eaddf5a049cca511bf5a4302f9ded97cf0881d9f72e6326a42d3b5c36a6e83dbf0d9a98f1bd1d120fd3ad19a9c74e2c18e3d44cc411c312068b2dbbb48198b76ebaad9c681c00163acbb3ba88145d822a716cf915bcc2f0e8e0e74620884dd5142d67f2c08c9883120f31f2bcda9e490b99f56e015791582d700b107169f80f0136be878acc6fcfad0d00a146b15b3521a63c37da868a71682650255b7b59f3004f0e295fb791cee2b682bb6c0f6582a6233ba5fcb6908869c75ea420a39842a50bd4d5769caeb346210862d240b1e6f45709005b5f427e9cdef201d4d0202cfdc640528beb1def837bf9bf01edc14af35d3f32954b7cc1aa330cf50ec7aa87d5a4b801fbd58ca4b646209ed0fc39956ba7c7969885098bad321632690dfbe454c0b825fac3358d5c8e513ce02726f81d372b952d5cc8dba384000482b7d6c29c6552076a230be14c526384a0443e18ca1c04ed82c7e8fc039aa3102de2b844a7453eafeed3ae4781bbe364460276f6309a90e3f73f422a42309fa94dc57a6da7e0463cb59f63c44de48e385709805bda32e19285b18409711d900f23a75172d00034da9f55a3e3bf620bd5af0b7c399f94218d4247a0db6a1796744003887b10882437ee922cf1d5f08d2e27cee8c7d1a439dc2f8df725ae8b1b398dd21175c227098cb36b489ab8e411524f13adc37659ab8917edd4f43b7a42c7db98f38ef56615e6b8274f3eed8d95ab18d6cd4c8525e0baada36f8393e70b84e135cdaa9c2a3b77ecdf476d8acfffa71d67e1bf0aabedf0fb718def51b5cdcd282f33a5c7a5193269a9a6ee7fd44f44f345555af0e013e49c64e058ee9d941e32d166c2de69cc075318cfa295481b4f3cbdd05bbb12abc25b3b79c1c4914e5424c3e7f915d92b2b134373285d55aa8cd6c9c7189bf39169b8bb6dd5537ddcecc0c9f4a5f8e21386ec63ebae489d7bf4de675e9808a181276f3bf09923e47c2fd86ca8c08eb1f0f419be0cb714982f05bf67df1fd7b20595809981068276ea95bead39a8a273ac1075b1212746223770e957247f50afddd46357d60de8b2996c4f5c4608e80eed6cc914e55d5ceb99ca66bbf71367d902281074a3c2a6cae2e771088c71f6e3d06ffab51491f46f1848b71b7a9ef1bb010848792c9459a406c529d64071e7b9eed333a4c2479e32949ee5b1d568e0fbc00f60eb3231f49cc657eb70b4aa7d3b7322adb32e2e4b5c15324c47f876e0924fcbac6b5f8b88eea76eed285cdd439a9804209eae89bf272b9f26f2ba28a0fb63d385f81030057de520622bc615c02f40e9fa501147f01fb5b605d50bb6ad17fb0d0ad8683a7c8d8213138e1d5d4ec8b9a9645e61e09afc520b88430341a46b518460b48f2377e7f071e8bf5409a75f34165bab2f25cc83c0f5a96181175f3c8c3ad51139bea0ffa805c6b45a9b2b4fe23375b0d8089c5cf9204c2f45421a4c51c59466ce1b1f159f28bd93e0ce17901357a05b042b217083a49dee456949c21c0c7538c63fdab73141ae43a3380d363b9a0cd07bb240d8dc5e147b602f76255bc761c75bd1ba78211d1d443801dd5c3736b9b2029078bb40ea5dd5ba5a2b6f8ce89ba138fe8f8ed4fe297137127186ce0b47703b256232b3a508a00f978bb61767d46d66eca434bcf2c68462e7140749957582919611f69a0971bc59fcd2423352ca31919e691bb40dbe6a06f225c3b26ce56897594edb060af80f50baf973399e00a2ce75fc92ff18c650133385446b2460a347a1842c16c73db9046c8dd7085cc5c154168804d1587a7de787154486ce6070fef498b731f730b66f58c3cd54f043e616776eaa43d0de488fc008cf339c8a96420dd01d5a971357f7900c246890c091d8392c16fa2ca55e06ce4f8be927d12a73ccc7a243a0fcc7b94c2e8023a73ace0656e10a3e2c9a25789344c2a7e5014ab6b04aee714755e755ee9e6d62b9cd18601fcc31998ddc2919a7ac8fbdcd623a974004be77b07e75552b66874daca2612b7ae0cb61523d8f05ad4e555a80dce337e987d513c4ac0372f0caa7805b34d65b5dff5094623c8a2d81c45a8400844f08996cbbcb0f80ce03abcaf2dd3fe920027767fbf8118970eadda849803b09bfda67d404bcb8a54264d0b53a138da0b1a0ac07a4a0c56e754f874d946143c8a17feabebaa65e760779c4d825053bbfe01f23f158594223cb5d5b0500e0f033655f11a974539c369dd2cade86ba0625ea13cac1468ada1ca2af09cdd0bdb5e254bcf6181a2bf1030edd2838a154faeadf8403f60c2600849b8e7e213c28b1e84f483d95608fb1b5afde3679779ad82bc3610fe53bc52b3696ebb77f1be1741d016468d31849583a0385c4c82029018b406f0552724f6caddf5b0cd2a6867ca52677389fbff22608ed8e42027b59ce20fe184fcaab1c9ead71dee79cfedfdf6dca08d124b727f70f127ba59fbb6940b22bd27c61c95334aee52be58a463462435564daf99a1c4b03efcffbcfbcc16b38ced9392dc3d45de699d392ec59c01b4ab41c4df0fbbea455ba7d4c682f7e32cb1893cafb7c1a9151638391a83975adc5fc686f86588b849cdbdce80d456db25a61e86bd46a2ac3bd27cedce9838c3ad0f69fea49768d15de11d520dab17c88401680973f6acf8efb44f32209d40d654656a1843bb2ef322933ec2b2d388e51a977123bd666de43525adcc07521b91fdd8a27a247cee7b96b61415f92c5a51670f89108c8589f0a42caeb46f87f442db79bc3e4765e58b264e4d44b867f3770af39ce6e8d4a71d9f8c40b5ffe5d94383a9c4e964ce2719b15bf9ced949a6e600f1d2b8b65d69ad49565b13289991dde27350d6aec2e82dd4a203591e3e599d5463f2e392a794c51bdf1996ed4f0c8ddcbbc6ae81957655e8f872b149a3be0e3903179206b4d32cb93f0999f1adfe5df24fb6c16b89f250bfc1e1f791233489f021847bd5bb431e1ccc560f4403f4bcf0230b699bd203d4524399129502aa7cc4384778bcd866f13cb7e91fe548a7eb1890c24495b1eb984d4e83da1f2f81bba5b14c0e426c9a432303e9f45e582be452389c77c8a59cb41a099be213ece84f7d8c53384ec4c36d51d77f1ecad44819be49c6df2900e870685f5b99971a4523b80a3c6b31a3513511cda8154b4000d0aa174a181068651f463d87bbb845059d25a16654e8e4c1fbe3a11af3154d3cbd33d57d27c39562e71265726e723dd4e35866317e28d31d4efefaa0b3fc607189f20040fd0da13f20f840c11b6fa97bacae0baa833dd1fcaeac2f9d30792e30e050f7831c039494a1e405e825f460dc9410ace01a654fad17d96fe19394edccf27cabbb4d5e0474e4b7208f18fe7da700ef8238ee7bd9b9168ac49de307b5d0d5f0bd2ad8ce84f3a9940c4270e1842340c478d97a9ce93ce9c2f6067e4e686136a512878904cf4ee848054370fec213bd9834a743c75d69f985261908aad7cffdcacbbd20b22d8078a66b5cf7e60ef867fa4140853f13bb79d66d3e1f60af1352d6b651e29201c58c507aca72d88a9b00d3e278b082f61d2ac28bbd9e2dbd8d87ec7667a5637fcf4df2f0c7cd3e002a83d3b958ea307fc3c07aa29d15c8e9c17a65ed178953a9d0271799f811990d611b748b00a8e9b07f9ae3e669c5d71838542a7ead9a239c884cead8a711098ada29eef3eca719d3df012d9dea59055215ed964f8a4993174efcc3234f2a5d69cf860283d0718418c906f060a006bf3b01c288216bd05dd3570de67aef0f01a5056d4c321a08e9e895c1ffc170dc65eda06949c94f4d6fb59d5e463673a73eb1b2f550f53b1e730ed9dcc1a2b217f20362ad463e982046beb336cd9be409fe747a0ddad3d0cf4c213fa1b3b218e86133633f09019f079ae34ebb7806ea13bdc487772033378c58f2a5e0d71557e67b888053d6e7ded0ef85f30b1a68f1ee378c9ddf08c909dfeabc91ce0a8d67927a0b3d5774ab9907b33b9dec372eb00cd4d004c24159158eac61f48946dedb1e0a56c56a20d4a07e47e056333a46aaa4dfdfd44d4ecf1333c12fcb8d95596ddf7d2b29c0d37091eeae41f88c1f011926601f43c0f30112b4163e6383785a244367315cd7623a3553f40f05db764e0466b7c8ba461d058c9bda079d42ff5f611a5c169975206a0f1feec336dc7f08d0629c9929c12b063bb76590583bbf2dad227cdc5341488d739290c7329c55ccce2877472fffb4a000efc82e9133a60b7c987d50b8b8d2aa2506fb1c7931082ef06e14f9684d3e3d08b28b19b0ebad5507c4ee72a54069c4fbbfa64bf7ddb7b657ca7fc831693576a2210c477e482b2bfe6ee246d6080fb09ea89cd4eaa24cb78326e43b59f7f72373d0d498194fdf1785f8188eba8f5fcb7e5a2f30f88a6cf578137630fdeb7f33841f759ec1515fe4cce6875e609c8cf939195cc9507ad9e5a166704141bd3a09a7886fc6ccfde7c6ec35f5c0302e5e2c67f7da3ae3043a5b1cfbe8cdbde5a56cf29af356b190508080e3dc77bef9591bb604062da1a7189894c11b748d7e74aff26ceffa988df480c3143dfa34cd51a94baa1e703552f3fae5437ef8a7b4f922a259b4e54318d04e77f40bc4cbe16a0f264069ae63f3adf88ffe8c5c2ba7604f8f0581d511b7b3163027711cfad9fdfa596418ad4b46978b6f71cc870dcc6c234b9a0c2a3b7e58e82ef5a686d7ae7a4ddab50a789aec9cfd510149db96e636dcd3766a66a0a9f5f939381ef86c9b3fc1b9a036bfd9167f3a745ef5539e6ce930dfde2ce3f8d8c2191427ecf6a23b834051b92b5fb3aec4cfe317871c837ee43d7b0bed101b85a10e60e4ef13d35cd316acf2f93631c0dfd368fb52ec9d8507d80989da0465264e10de57d402bac3a41fa5100f931774968c8a8542e92f75fc523bb43c2971a3d09f3aa012990b302cd1611b092392035ca0699c9e8bf7448f0cddaf17fba233b020a5ce81e30f486f581c98a98d7ad79b37a1bd2acac478c50d4f5be2aab895cfba6189f70c5419ce567dc396bd761ff5293dedafdff4ea7e9a54696897d64aedb5c90693f77ce1f7d4b6c3fc880d00d287b24f0da246556e176abf3b0c5d7b5c843abc8f1e2fdeaa0cec35ed3a69aa8bde22df50980c48f39329ad4f3c3dd24bdc1ca37845955a1f9ed7f05b248ea7c5deb3c1061471b7068abeef76cc6e75ea3c8a6bb93fdba7e2cfe5c1bfc900bc00fae2f21403ee62269ad1fc9f592322d0f348479dd234f0de7c73d0e47bbcf31eec5a9282706643719b9ebc21506d665ce7e476ebdf7faa3dce63fdf179687bc1f09df1eb9b177b18f9fd7776bb37d4cd73325795f821cb353885887c7d4c7d54cfffd3e9932226720cb09193c73d321bc615379425d3fb8bf2d2a7af841391320909be7ccd7ce6ee16d2d7dc1c03dac3f146755d82aaa4ff03f96f403f07e85546cc81b13202c27d4c78550f3635102c367142539ed1aca89154155f6bb3154a1a6a0aecd18fdd65b3f4f248fac7ca17e306d1f0a160f6070f87148a60c8477428ae09f66c1ad3204886d9f9b071fbbbb18ac3f02f7ccd7bfa2fb62bf2d1941fbf054c8f7e479d083a6f3a802af87459918ec76460d8007676f6573ab60acd769926115f0bbf21ca29175c06b871f772fdf6428aad0301458e44cda086ff5d13493a217eab582e8fcc15b3d6c99a23a45a1ab7372593d52d26f87e93b6fa1bcb17005f4c954de047cf1c6a8cdb02aee584bd0c3840b0a6d0013c0c3c0c3c0c3c0cbcc6f0f7e66e6d664990292529b44281f6da4521524a322599228ffebfbb3fa971a066df7b333333f3e702110db60c610c8c6d84c40b72b393c5e5cc0f2a4252c7a4d3b89592da1d9600899098548e7f75b921246634f5652a2815748685905c72475debaa78bc340849d9c12c6ad54048aa1883ec69c8d9d44a8022357e901c634ea2845b955669b40c206070e0042224a8e183a4536e3a9498a9749fd383c789c047901e18f0408d1e24c9ee1c97f50e425dea34063578606aec2079474ce8dad7bb7cf2cd1a3a48f235293a16e3a5b09c31188104f9412317e9892b19b562be1515c345a6b47a8dac89970dfea0718b04bd9bda72e76dcdcb3068d822e1720aca34ffd98bb64f5d20246407185f8484f4f0c1234831550b63c457af9fd24dae3a81062d924a578de80539774d398d592485f220d40979958430454e89a058101e3d78f42043e451192c8695182f8679203e7a0434649198bbbff3d9d5fbf5c62231fee9d0d36add60515824899249369ce9e8d1c157249b6d3275ea72ecaf8a2b12e483e9963c19ed845a911466e173901e7249cc8a2499a478182d9e55247a65d84d23f2e28436925565ca9489816180862a925ffc63b2d8d629e98f83300544ea81f86835d04845d2e714bdb45166b919631c3881c80968a022392b9636d3cc7649a53708193f8290d181532446512a7ec2447dcf6d8a2411ea9455e753a7325c8a840b9684d2ee9ddd635402344891a4e4081d74e8a692293e8aa450d7a63ba623df3aa248506d8f29c6b8263d9eb040231489772e57797fe993ea419198f4638356550e67fa44828ef77a3966345d5af64482e5714be2dbcc84b07ca00a343a91b0d9aebe9537292b8d1134389164c9e23b5b2c63bc3592654a17416313891b732ae754264e4975246b07185fd0d044d2df26cfa1838e398bf6f881462612b49fd2333196a3f234927530916c22aefbf1a7b53f7a89440f69295dbcd992a6444b24c6949392fb508d197e2512458fccb731e98fee77d2a044b29eca95ad317fb8abc0e8ff11829010379348ce9ce2d668cfab568c0334249194dbca64b6aa4c3a68bc078f54de83470542421848a5814624bc7c5131d282ce8af8f0aa010d48249daa2577d758b32fba028d4774a934cd67ffbc9e63590e68382279dff2c65cc8341779b143043bbcd88181201c460542427a7c90201c460a0919834623926ef4936fd6eeff51a1c18804e5229bc75b93df86454a11416311094ad306a5da4593b52a5276071a8a48eae8a75da971563d5d2552a7c62865341291f479465e90329a80b936d04044a2c8304f51ae4be9d349c2206308340e917ce1ac94a68aa16cf48648ac72bdb94ff7324a2f4452da86a8f831fdbdc6099198b3ede75197457b458348ceeb1fade152506124880421744dc9f220c4ce8148105175e122d633368048dcbcb15673edd9c6fc21a963c8f5cbf352625b3f246dce5ebbe2fa41a56c1f12f7375e56533153b1f22141be4ceb8c0eedd0f79094824c279ac553faf9e82129f9b75f58c6f5aa9c3c24a5dc6d53a71e5f32e221396db0cbec1bbc4382f79d50f146a998f1ec9030d63fb369a63a24694bcf59ffd321395e2c0fe32f4a33ab3924b9b77fb424f3efd7450e491eab5bf4764ca15e8e43725e2dcd5f1be11664a9031a70484cc2b2bdb98e90fdf39041e30dc99bb3a8ac9a4e9e3c6824cbea070321414888fe80861b92c34ac618c65c4b6c8a5281461b12af3c6887ccb4997ba740830d89154b9a485111abb15f43628ac65f6d4fdd1cd46a48ae8f55dfb18b0934d29094ec3353ca6257f2a08186c4eaf26c7a6e53c5ec120a34ce90244d77d7d58350d3263324fb5ed686688a6936bd49a05186640db6974b99c560da4486c4d31afb520a61337f1531d0184382e5b90dfa723a15f3c672041a62488c6feeb25abab25235028d301cf38a88ce099dcb100c89265b2f6ebb649c8f687c21f1830a224d85d1af89d133d0a6e18504f9543add8795d7549f18d0e8427250ab24a47c69266122e382d0e042c28bdfc82d8b3176f4912c332034b690602554f6b424bd6353c4e8120009f2838616927f75cf449ba69c0fd7da018605b0078d2c2457b0a0b12d9befd83d928560a0818544f7ec2988cb4e418e19648c03625fa07185c44a79a6dc5489537993c70ac92bde7ba1f92b9b088d6459488879814615922ef362feb499938cb1053d78e8186850212964f4f0b15cde532e85c01ca63185e4d4317aba9cb665515573011a52a01185e4ca78f94eb2b9f2fa23799003271021010d28a431780c2a5e99c9a299f8cee99abbd9cf0909b14318d07842923821e7da93ac9d60f03048c2601e417e881112921c388108a2e1840439ef738b41df63f447b27af8684262fcca5bd919b35aef48d61863fcf001a44a8c9e41a1c184a4d3416672fb94e5d943630989a7a76aeb79e7e94b34949018b2dc6b2ea98f8fcb09349290b457364a955cfd950e0989a3c37bad74d29bcf1d2159a39510772a1f2e968c907055a9d325d1e2f276119244e6b2cb413667ae8608891def3c67b52b75318790ecba5ff196a1ec542a84a418a383900de61e2c280849417adc2c1697b2e1b2031a40488a1a4b97ccbebb341545028d1f20fbb2738f8c9f22630c9136853d7c84e14548c8f7f011462f0d1fa4dab35596d579f0790001a39840a30709fb2146aa974653aaf22041e9594de979ecae723b483e71d1ef6389522ac568e82041263dfaf35fcfe63f0c8478f410d95c24899bd58a41294d95c9ebc10c5c24bc06bd495cb26e131aba4562559c8edea5204d9423592ff81f43a4c78f0411315b248832915b3a562711d54896bf0cbe87d5310fcca84572cdc6eb7caaa26946235922407c88c880816460062d9293ed5ef27e3f25adc23ab3481af9399710759d4e889f071030ae01336491984929abb3b11323d7c41fc6de60462c92e4cde67c497d4aed2e2c923ce4c56a10a2b3638e64f90822323206193f8e04335e91185f4a37d77b3ece3b92f5eea347b9222965de247b513be8b776806101201438ad4852e1af665ad1a38e3a9215a4cf4a252b92eab4e79b4eb9f87b70183f44aa76806181a28319ab48eed839a34b7ea427c8b74077806181e701040c4c552469e55c9017837e115b59901fc38060462a1247a82474ca7b49a8309e60062acca12f8f107dd22f788ae4d0f1fd141aab64368da4b96086296c46292a448c19a4486fa538fa337310fb08668cc2e0674afc739e0d7b24ab46f0c52935cc10457228df14f463a7146421214398118ad2799d4abbb5152e88053340912044d65b294f69c49f333e91b0e2397c885598994d48c8954815ab50ccf044a2ffe54cda72f7ec74c6108381b00768c0430c1e417e742024e44ae4aa8c2766742249598d0919d34ce569e73083134931955fad89f3b1d0e5306313c925ffbcf37efaaa086922399c4a17c3b78687fa0d3332916015f36513b71b757d4c248579d17984a65367a54b24ea7eec20cebdf3aa6489c4de7b791d214ec69c21c38c4a24c870573232f5097d7e0530702891fc566184b492953f9826911475eb7a2d9aca202349249d989d9ecf5477f64622412c5ce4ac5c235947023320912076475fa9d9bc68db239233c9ef68fa5579fd32c3118959543ce9b9a4728e79b1a3746087173b0a077678b1a36c6087173bca173bbcd85134b0c3035fecb8c38c46249dbcb95c8a9bd56e23591fa4071b18331891ec1deec1dc73cc1f7480987d60c62292428e0c329a1e4b396432527e31431149398afe0e7516f457d048d6d1c08c442405cddb41680e8f6495ca4c662022d19256b0307e29d486cc9414cc3844828eac4ea9271e5364f03daa5ac03d78038a986188c4d3b82975760d19269f5382985188e4191d43d559dee0d92711efc122c6768061811e1d104107c0f862c704cae89010c342cc2044e2978b259934d3bd5e3b85198348301372740a97e5c20c4124f9ad7ebc509be7821f88c4534963a6cf35204466fc21295890e139a69449cbc20c3f2486ee3d7dc1c432a9d43e61461f927c33a613b10dbd4ce93961061f923fc766a62443c8ee3b92b51e10c307900a1c33ccd84372a96c62f4ad752ea6c0f8624748488fc1430c0cecf0c2c230430f09d2e3b6da561ecd23a261461e9232e8b85ad9d126e6e3213153648e7c669b85ee907861e6470925541a8fdb21e94c8d16cf9369dbd37548f2a4d34795da36cd3974484ef2f6daea744c59710e49f97276977e5ccfd1cc9043b2297115c3f68dcca6d285197148d2e9bd945c8f61647d3824e8a9d95a5f5e91691e03c48c3724688b5262f2532b3ec4c20c3724ea8a52a24ae44bc7ce5261461b924d8bccfc96de6a4fcc8604fb4c7f317cca554f19a38cd7c01a92e46ec3ade63f8cf6d590a43e321f4e0999941ab50833d290246f94ccbba62c557ed09020aa846ca95ac538f5191254a75073f7309a959b21c9a39628153a7db2d2962129068fa34f5efea0a26448926ec9ccf28cb4b0d931246aae5b8eb6e3e2171543620a6366b96b66ea1d1f417a60200cc997541e6d6f3a5e3697469801860425744fada55d0a23fe201808c28c2f24c8e7f26c2776ac3e29f2417cf4a8dae1c58e1d607ce1c58e927c183fc800638707bed8714998e185c2347a4a1633654fe229357a9d0c6acecf4a54bc30a30b49a53ca559d059b2cbe642626797986b0afb6ada2d245e58ca09a546c3fcc30710ffe1030805424242c6f8e123997ed02c2362d7d9c21f77bb1aac2d26dcd082167aa427a12ca432fd6aca167c335e58b062ddfdef46cd43bf8295f2a60aa67209af5821b9345bd060d2b2679e55d074a6bb2ca28249367b8ec8a6155d9a4292ca9e2a2f3b4d85fa9270430a869c1e71d95042158504d3e2193a23e57f6346b244ca001224b170030ae52d1fcd495e07dd982724c8f6b839bb79a8cb8f1392a2784cf993aea45b2e56a53f580c33851b4dd8de746352abb2ce23262c1664b76d5b6e198c1b4b505458ccc9734309099f938e672acfcc2e58060301c2782309c929b6b7e7c6bd2ca123213945e5b4eaf44e3a898e90a44a99e8d3a2ba59352354dd284292989271be2c5fba341221f1b5d346f9af67edcc48d648101e32b8acbdc08d212427394f9b726ce7cc538ad125404b3784806e04215170030807e4c60f2a6405377c90a442e78da1163cf885aa0b377a90f0e21ec4d98d6c0c7f07185fec08093923c30d1e248b9e0a594a933e21961d246b0a23be6ac2ebcc3320dcd041b2574e9fca53b3e64c23f941f88134e622f1c3c5ebd229a924636724eb4242709124a6f363ba3fc5d3e916c99ac37fcef311a35db74582bc5342dcc7e5ec8a59f3828d5a2409bdb2b32236d4a9102dda2453867b5a39999ac516e5b6738e3ca52a2a8ba4cf236a47e6a5d4a4138ba4f5bbb8199934330a8be4d738a377ca4366cabc22f153aea07e65336ac55c5121ada8105624a633e5aaa3728a6929ab48ec394da7573daa48da18f453d9e7aaf23f15c926e4cc6e4cfd6ea5b4818a64dbcf59fbf23692e561f848364e7166d6ec1463b6ccb162d4549bf6b27a389595fac16298326c9822d95c4fe752bc8a491868c1732024440c1e21213eb0518a4411d6c9a4bc26d5199322d133c7d369ee6c5ab3a348107552b5be738c11b72812dbc2e6895c768baa791e40c0b820364291ecea15b694963cbd3f289264e8bc58ed299d8e15e5c009447ad8f844527e92bddab9bc735a3d91dc595f39ae2921efd323599d48be135f72bdb7b7c189449f758d7675a24aae9b48d257b9dea14a98b25f1349b262094fb5318f2cf90012648cf7b44c24c6f89abc847c88f36b063cd26222513e8f78939996224697484a2163503adef59fd0129a1c254d764c53de984a24b8abe790f9bd6ebd532229c7051375da0bc387487ac0c6240a7da6b541f9eb41586459604312097a93e524cc2c83e5a3078f0ed88804c2644f9f862071069dd45df08eb9472407cf27efafd20613cf880d47a45b7e426816cbf946687e6af52c632fc56a1b8c48744ddbdc31ac83d6f0221234bfe457f87253a96d810d45249a5ef6b99dd2aef14424c5e5d4186a54cda22ab08188240bfaed771daa73c987484effbeb9779f35a7aa9421126b3e9aece8a3f39b2f44c25cc7678fd992a14684484c41ad3c07b9141dbb4124e9d16ceb7d62533e6575824858f39456752ac693398148906e3f66b9f7413f0444c2a50aafb441cfc7de621cb0f1878437d5418f148d97f63292857e480c99e715b4c97d13571f92bcb2b60971a24c490b1f123c6f349ddf8e65eada437270ff9843ae336fe7f490743a66c694b7bc42ab79484cb9dc8bd925b78187a48eb766d1620fc487c8f7e011460f1e77011b77484c4a3c4713222e2e2c56a60236ec901823d46ea64e7d4df948961736ea90e4419bda2615379ad4a81836e8907c3ac8f3ae2f21c45ce69064b23ffa73fc536a1b671f619c0dd89043c269efb76db1ade29098cfdd2dc8e67f66a50536e090a03d2d7c5c4ff134657018646cb5a0078f172c046cbc217d276b9fbecd42f541c6d8510110ec3012d870437298cea11be3ece7ee0c36dae06c182d93da67293624e69a29a1634a3b89b56c59437278a79d917e3a7a5b3524badf07edda4e222f2af223fd830c9117f8f01146da077678b1756260230d899ad9631f9f71b3271a9262d09dd736c5b7b23a43f297fe1c357b6d38df0c495a9bb9c7cc55551b6548fc718b51e5b12ea53692cf030818e7de60830c09ee29f6ae9669eb2c27b03106ed6bcf6212d798e71443213228cb7b9e431b86f38534532ada49c5c68a0736c050d06a167383a84ab13a5a5b031b5f48acd774212f4fbd64a66c7821793d099d726f5dd4cc2e24cbc98df9d216a72ac50617126fb36ce9f898ce63b585e4707dbaf94e8ea5ac4bb0a1852499773ac656947a6a4b0936b29014a27baf93ecca361316125563b4858b61a48cf80ac9c13ecc5efe55c918b242e2f748b10d5aedc4860c0936aa9034f695d2de3559b7a554486ccdeb96264ee956d21412444757ecf629f19f9142c2c94badeb5ab275298a041b5148f24e329b4c6fbe117b901edf5048ce2ab2f296e68f31eb4896a930c2e08180bc07b214066c3cc1cd20e4a4c6cfdef17442e2061de7e1d6df373d4d480addd92d0715322151f4497bab10bb5f731032c4580223f3f1f2c7a76b94909c2b69acadd5fea426213959afe82c21c1c6119257d645f9ce8c894a396eb061844411762ac7074d1fa217709063838d229864c98f8e3511ec149e997a74aa6908c8067167e722c47e4808091a841035ed1eb59eafc146103cb3112ad6af97e81f08a760c95a54f783c48fa35b4b8ece9b231f54bbb1fba33decdc10d8e841629a30a19fc94f3e4c3d783010b732ab32be541d6cf0e0d3a1f46fd66c0cbfeea094e39b12fd985db191ac32fe05226aa78e60430786758ce9a9a38785598c32d71eacc7c54f842c601ad8e1c58ed2c087817eb018a580f808c26b125123178927b6e6274486e6f32a10357091d431064d229ef6e7fd328080d1011078183cc810a35855a1c62d92bf72366d6b909634b6456225abac8c9ddac3362ad4a845629f8fdcec37edb92ea3871ab4482a11dfd2f7f0adf144aae850631649396df8a6bd4a267b9545d265dd670e5bb2fa3cb1481c113a07a91753e868609160b1572b86bbeb06957d428d5724083d7a4c2be9fd950c8f50c31509eea32ea64b3a660e6a2b12573e998c1b73dedbb567841aac48329d327474925ee2d25524c636737991e13eb6a78a641d4d623a3e5bd1636a958ae4743988a76c2a2d5d8d8aa4f6d9f8cfdd394582b06066da264bf7c53ba648cc7c6acae2522428598b974c2919e4c64991ec9f719573681b359e51246f4ef5516df3a9e9fc406e07181608091145d2fdc93ccf9f33c9bc090909d2fc438caa110a1f3cbcf0c2013540f1891a9e60408d4e88f0f8a1801a9ce0f16302df3d7c20a0c626125043136394f12f58408d4cf0f8310112a4d48105d4c0c4075ad00206c301352e61091105d4a884016a5042e400352621801a9228408d480ca00624baa8f10802d47084088f1f05a8d1882465327458dd70fea5c48804b9eaf9974d49d8fe8b48fafa4ea64faedeceaf880419366d5242572ca1f64424af6f858b6af9f62b474472521eecd3957588a48cd1f1eb748c714e6488c4b3db18bfbb35c8720b919c332b659f0f7d1a5542242529e23bdb06d3b07410499a72a953d2730cff5310893e427ad2ea9999e21388a460b7ba6939f6ad090191a4d5921a9959fc437287cc5b2921b3aaab7e48529f7f337fb13e249f5035b649d387aad4fea0061f12e4b52dc868f239a56f8350630f09424e6ba7cf5b41c60e0022d4d043b26db610f641de96def390a0f953d4c99c6478100f093ac713d3767d6f31171272831a774816b1ab29c4e791f61e911e3eae7250c30e09a7d2655346abc8d3d721497356b5fbac3e8b4e87e4b2d5b0fad3a0b635f5ee8303a735e6907c95f3fdb5c2e9adcff790810f111f41b04a4da0861c12a3e8bf185ec167f33824b968b27d0def2e4b8243c2a7758cf64e23c4d86f48daee8fa36df2964dc80d89e795bf3b6b69a65393032710e951a30dc93baa9f9d7a3e1edfaec186843db1a44fca26bd9e5f43827ebe4511edf23b223524e7a8a9d5c5453d2f4e43926fac4b39859051fda221d1e2523ce59be2bfa7c61912c4f266ee11232b5c585950c30c89172e9d980eba630ef2322429d51c7ef92da97c3619124fb7c58a53a3ec3d3c86e4e01de484cb2853ba1892c4c72cd6f5a9d3a9270cc97d49cbdd7b5526250443720effc9557f4b66eebe909439b9c6aa52cf156baee185c4381d6bab43e9a0e43d92251246189c2223417ebc772129c37ed28a9b82bd8fb890389fd6828e1653b84eb79018f3e49df0505f691f1e2d24b5bd5e65cda6e216cf4252dc593ed7a04ba3cc5848d85c5994d6b9d026ef1592532773fb7c29364fb542e2a54c5e69f73b1ac42a24a5b2117753faa2a9478524e5da7e49e50a32a7ca4896196a4c21a9c7b4fcc9cf1eb21e3c38c803390fa82185e491ad1f6bae1ec42b5535a290e4167b3a754e8242628a711d845bb691233fe14f3a6a3de49af804e9c1cd23d019d4704282f0d4c92da8bbd3d28f6401f151caac0c20417a3cfe60315650a30989a794a5b0a6a534cba50613923f2fe8d8ee0c5bc1b484e4a0639fd0e5d92b76af84e4534a5427f1d3a1a5242429532d174ff5b7e71a098975955d2da71b3f797b821a47482eedd895c3cf5401a65b851c69485a953591172673988aa1420e34245cf2ca321f1dec3b6924ebcea0e7303243522a7da1ebbe9350ea3492a5aec851866453aff15492cd564d1ac92ae3410e32248765caa743852ef5f748d6ea20c71892add35c1406e2d164f803c920fd3fea1639c490585deabff28c6b528721c13bc5d7056fc1909cd2e3474f7f423c8511c8f185c4d81a7428e16365e9e485e4d5243bf532bb44ec5d48fa6cb2f141831e2d522e24993a39d11f64c55ce116925664785afb550c931612740e9d34e69425646410c89185e4ad4d7963346c542d61215964a837d9312d3d9d574890e99d452ea5c58f9e1512af4cb6897a93bea385b138c851853ac5cefac898448564554d714df83f85a4d4b9ce8d5a5135a5482131635abbcc791f5ce528249c566c514a68583f2d14925327992ec9518e2724e88c2db2f36cab7be8044d555f6ec6bfa99b9064e1ce56d332ce2bc78444cfa49b52f7a9d07c09c951b48b363f8fb9ac282159f3a5973e71a31da349a81c4848d01a36773d7f466a90e3087cca99ae43cf4479398c9068313b96839a8c2dab8c1c4548fc557f93e96b537cf7c72042f2e83ab1915d239ed12124665b5d14f1362fed84909c253a97f694993fc32024e9d8e9ad1c2c5fa86d811c404892d9adac4285479bef0709d6b349ec272bedcd7c901442964e53f7239bef41d29676e8ff14de415c3c4832e1d1334fe6b71b15327ee4d8c13198e64a29cea183c4cffd499be6cd9ad29d8ba435719b93fd95562eb8481c9d3dec3a6a5cd2b985a1f94da839d1202f6a8be40e93c9ca446f30b76b9118d4339f4a576b1783688105b9da9e527eec92b3e852c7f646bfc232461689235a438f559a6c6b6391344aa4ee5f500b264b5824e5cb41fdc447e9e8e7155f94dbeaeaca4fe27445b29fec9e6ee65077c156248e1aed2f0dd3e1634562d2cb703a9ff0df4cada2f7b3fd8abd295f061caa48705fad1c44a94cfde04856008680231549298ed262a5c542444445927e6a1afbed9c37bc91ac0f03b105a008384e911c638cd5b4105a429fa6483ebffddc202b695b8ac4dd139671ba9dbf4b3bc0b0001a1de020c599d4e9caa817d91c11e01845a2b9585a988da7768061819090adc2218a24ab14ccdeb468244be46310860fd5314e097084224967d19a94b8f6ff1a47b2d2a90d8484888c8181901011830314095f41d72e36598c1b707c2249997766b8ce9cf2d7894bc0e189c4b0d3ec29be0a4188157622496ba73815bd79a9d42241be05579c480a0f6afd73fefcd7bcb131e0d84482d29445959a36d70e6a2259cf4aa9bccfb4a8489a8501472692f7fb5754f8ac559b13030e4c2475d06e6e6b616774fa1249371742451b0b31d2b544e27ece5164f49af6ce542241ef970621a636f2513510c04189842d4f97a6cea468b3708f0eecf06207184fc0318964eff1b471bd9d4c69b4804312c941ccac5aceaf1770442249c55d0bcb3dad7191dc020e4824fc99ac242e466cccb308fe3c2231c6c5b5cb7372f46f228580c0e1084da4ab65ed2f95a3091c8de04f258dab1daa741861ca5ac963766bd658d929658eb182342164e72f816311096e419cf4cdcde11d3bd3071c8a485217436a4a95cfe0bd87954859cd0147229283f8ce1ceae4767b4744920e3fdf5e3aa63caf0f917433227e44dd07cfaf2192d4968cdd15cf72985988e49163f2ae725217db1022e9ccd5528c6aa675b1412479f4cc9fd3e3650b2a82480e5effad9ef3942a53209232091994beb69caf392092a3e910f1cb128dd7250f70fc2131d86f8e95b6533d7a38fc90e09b95fbd4898c37a71370f421b1cd634a3327f35c92f3214907d51d73a4bf0891ef213973e62a5d2a45871ae921498fbcbfd3aee62129e572f02d8d1d62291e92827bacdbdc1eedf4bc43e2e5283d567a31d566ec90789622d46b4c9795ea90f077a7646ed0d16b373a24a9cc3d7b3a3c87e4b4529b46c620347d72484a6a646c7736dd2f8b4362c85bca3a76b716c321e93be47f8acad19c534c80e30d49bdb3494be791da96bb2131d3f589d4caacec741b12c4a57ebcbfcb912d6243821217717ff1b68fa23524c9fceda8fa9fb18dd59078bd9593a7ae4a3aad6948ee202d4c749b6fb58986e49453bc42d564742ecf902457eb6bfee6314dc70cc9b9c472eedba08459a70cc99ee72e95672ccd3f922179ddc2a728ef8f3908c790b8ddedf9a1528379288624213fe87f9d66ccf88521497785d9aeffef6c1f1892929f9b8efc5d30e97d2141becf540caa76d93b2f24f89608d5ecae0bc9653122646898ccce85e40edf13da3a6f52425b480ad95d69cbf54d5e460b891f744af9c22e8b3a2d0bc9a183c6b3770b21f4c242b2df5cba4f1b5f9fbc42e2c8d2df393765662c5648baf89de6633cbcae2a64e599528ca5ae61965cd3c63e447e10151247873fcfcef9b92482534894cf4bad49452e63de0538a490f477af1f84d614435846b244ae7af4c080990c18c80670442171a3faa9e7fc6a992a2824a6e6a48210175b5e33333f580c0ee07842e2cc9bfc35dfb6933d90ab321930902f703821290539f5ed30b52e65004713122ecbd85b18d59eaafd6031cc72e0042218c0c18444916eb276ee7e2b630846c6e00be40c702c214908d3ef3c559629be60c8804110122203061212b24a48120fe1d729e7cc593309497a2bed4cdec8694b0d07122ae4348e23249e25910bb3f3da9a1b21a9da625bf747660c6d111275357483bedc39f211a40706bc308703271049388890549be4e6d1a4773a734e80630809261a572b78a78efae01042f2a5ca25eb67722a8f2308c9d9a2be77ad95ca19120307100ec70f326959533ccd183fc628e7387c90a43676fb77344b62318e1e2466fb86af0a4f4ae62063031c3c4816e936a67a2d85dd7f0709cab552f220da422815870e12439ad75bea9c93396838b8918b0459b94586678bd14208843d50b8485ebdac163bdf22b1f37bae4c7a6fb46b6c91545feab285a7d422715486d02a37d5e0062d92548a1d2bb5091d4ee833b8318b244f4906a5cc837ed1bc2c92c4aebb63e6c510a58e458252d394b3fce6742d8245529272efa16df9db41af480a42fff3679cd331c4ae48de3eaf1c365ffa7e694552c7642b772363cc9a614592d5c7adebbc8f99de5524495325337605b5d7ab2a1294f09751d26408f5742a127b3d64579b9789911a1bdc4045627746cb70ba9256cb9d2271337c0ae26e4d6ad2291adc304592b8e554579e5224b55fc86cdb5abfa646128104f9718314895945688ee3adf13d78831ba348d269a2e2e9d8bfd9362b841ba2482c1d6b83f829156e7bbb118aa42094f2ace7b51973b5841ba0487eb994ba66f56410cb07373e91686154b35f8bd6cd494f24be5ac7bc6935e8796a07373a9134426bfa132a887c19970737389114bdc5feb5fad247b489e47fcd931b8fb21a339a48181d63c572455131a5360737329170e2de3a68b470fa4e984832153d54325131f14c07372ed1ca480da525e6668ec20d4b241bbe2ad975da1db51249626a49f7749212892ba7c9c47a0ca6e721e1c62492338c08adfe2979b52b8964939151b643091de44824fdf95dfcab3c159b8444a25854ad542a5bdef02392f7d3a607ed1947247f8ab1838d2869166345b8d18884d3a7b9bd2763bf75c47083118929866e2ff91b5b42691149b1f2aa660a1d26543a2424cd0e37149164af59b444462bdd26222966a60b42e3967a8c22223998ded22ceb26d37d8844ed8d1b77a1628c350d91a0396bd975aea7b1538804954a5eb0d5ba18442444b2a93416d2c2b506e1209274bb626e4d29d4524e10096b6da5357237e35d54dc784788aede1c5d032259bdfb62ca39fa43b227d910133a6d90a623811b7e48f0a454ca8eaa4da3ae3e24bcec27213a671b933d1f922b8bdab6975e92a9ef21412e7c3c956af3cbb31e92537b8ee7a26298ea5ca42c0f09e65935366d655dab7848309946665d2fef907c19fabc63d4a0b7736cb86187c45169779a2b78a30ec9da79d7ea549a8fabb9418744311fe9a7eefe72e86ecc21c964ab6ca78a9ebabe1b72a890382476c73ca767a9de429a75030e4971352693f5a314dc7843d2958bc7ec940cc10d37249dd685af986a2b4237da9014ac64e74f53ef9a3f41dc6043d269c7d497ad1fbb38176eac2139e754a173a8fe4f4bc9c20d352408a1c7936ef8ac9df50fdc484382507531bb8ae1944eba8186a45c6a67df9489794cb97186e43a9de21eb3a955c4871b18dc304352f6f69957dc2b51c48717fab85186c4ed963ded702bb120911b64b8bdcbc462a50b426763483af1b92a050f1fb2733124988d0a3fd74ae2540b43b2ca8d75fcd370f1e260480eaddf41674fa3d4d35f48caa093c7fce29ebda7171294a6cbe6a3b52e24061513a54c531ea1642e248602ef3ebac78b18a18b392466c8ce9c746632d556177248aa2bd92093fecf59e538581770480e8fedae4a1f673c3992d5c51b123da5d57091ad144ac4eac20d8915af9545894b1b1244ca9c9297a52eb46e62605db02171d73e448acc03a18b35248ba6924f976c66453e923546d60c9290902ed4902035fe5caaae4c79f63424dd8fa5df9831a672070dc9d94544ff3d9fa6e9ce19122fc62e170f955dd1396574618624ada0974e79cea263da451912f3c79c7e4c945ccd9a13a40b3224e6a83d9992f4944797c6902453c586ec3da12dba1892b3df8efcae9cea2f1c8624b3a453c5285a42e9160c899db3f937c27f64ca7e21d9935e65788cd153a45e48901ab65be3c5133a48bb901437a7e62f5d722139e6b0b999eddf7f3a5b48582f551d7e8b41175a484aba63acd6bdc5bb594852af1bd2567e538c495848cc9e2a5f57adc5defd0a8917a22d798e253ae4b642b296e9f805dddd64e12a2499eecdb030af64314b8524b1943d6fbb4b6c904e2131e8f06aabff73394429248fca9e5d95ddd1c28b42a26a7918b541e6ec2f14927a7466cab895e9e209493aee9e9e1e5d75f1d285139264fefef611ca4dec32f0e14548880c7c0001d284a424c23749bb774db93d5f74c184e40ad65e2a4e8349bf4e2de1f6cee1d692cadabfe07f8caa30ba5042e205539ade738b2cbb81bcf38f88bcfbe851db451292577469cedfa973ac34922583ef61d214035d2021e9664bdbfe8593c19246b20a025d1c2139e592f13e68cdfeac19c922a30b2324a620d73d6f0cb97a3a2359223d78b4e09118fc4082848003271081411745484c7983a9e818beb49d225d102139558e0fa1d7f4ecff212459eac9de2a993fd1114252dce86bd7753ab8c8ba0842a27e58cd68e1233eec12e009ba0042f2493b5d9742f5538ef941d2e5524a65a88a1871e9c207c96ff2e3972a4bcb64e9a2074553177b4a97c59772b3d0050facf2055deca018b27c37fe6b8b6ca60b1de4efb1635c3173a0231747072e74dc22b14ffbe4bd270f2174d822314bd99dd023ffb3e6bf02212128021db5484adee92ca5b6ffb5132d122c08afa87b9d366c388be424e3efc76db9a0548c2cf45c96949ae8582c12e574ecefd16d27a30816497ea68476a5b47e697d45c25b0aaa728a0e5724a77ce930dd9e417a8a8e5624c968f5fa25211674b02231fe6696e57ec655d12a12b5448dca583ac6eb549194526f4595e6a5bf4a2a12454344aabfa78e9747457250baa3c49b1a7d192f41c72992540eea74f66831398d2965aaa0c31409a2554ac7f056237b1f818e5224c79266974506bd2494a44850aa938ddc380e3a46915c39a5a0c173ad9254e1a043148939dc0713ea3e67145d1b748422b96490695d84921f13e90045e26a06d5395e6d979ef713c9757ef962962c0f9d7b22e1525f060f9e36c98ceba0a313896f7145cf534ca6999c48143d636a363fa2e2b38924b36ca5c407937136c4811d5eec40830e4d246517bddc6d79f3b54d061d994852e3b1e476b68d9e375b3a30911c2f26a56475b2921df95850e8b844b28f8a12adf5133a2c916cd2acf3ff275522e14ec5919b57af61e49448f6921a4c7b3d89a4329584d4d049c3bc2c89e4ccb5a7564b756e869148f87f53e79a1b84764e0724925477a82875bf5569d3f18864bbf5ae4db955645e743822f9f565838c7d1a91dc75f74997c5fc9cbad4c188a4682d1a64c8edb0aa8d64d9eb5844b28bc785b3ab342a6a56639cf29195021d8a482e5d97645f1adf4e8b13742422313d9cccfcd47c622f22127fafc2c75b4be76263d07188a4f9f8ceb93337274324b6c82525174d866bae0b3a0a91684a9576b1fd60169474102225dd2beb2ff0e163240ce761f6071d8348d2497c9f89e96f0cbda0431009df715ad697b9eff9828e40248605b7904b963b66bc1809c283043bbcd8b1c38b1d3bbcd8b1038c2f762457ea1110897bfac443e72f468390d1811d607cb103043bbcd8f1c518403e063c28903a905ce9f84362d2e1c24b7d63fa3ef921495f86b49f73dd4d531f92332bb42c47caf6890fc9da1f5ac3d58706d3ef2129df5b8948d3985e7a3d24bbf65c983eaf53dae721b1bde72b4611a7eff2784850b974c7e6deef9014de66764237c8b4bb1d92b3752c611736bc8dbc0e49da4d9b52b94336874e87a434df2c1a2e2f88cae79018d57c3409195aafd37248fc34e5379741e53c761c9282d82466367bff770d87e4243fb705b30cb55cbf21f14f7328d177f3a76937247ab97dce416a2971e936247fe6d3ffda795264101b12d6c27693e5dc993faf21398e30d172d99aa266352499d015ef97db73b9a2230d497964bed4a4378f8c711d6848b8914d279ebd225a3e43b256a89463a8c7ce8dcd90a0eddd54bbd2d4c5b80cc91be3c443856aef7cc9909ce665b9948753f1760c099ed4b5e7e7d24b9b15435267d131e7db14c33d0d4362b07cf174727f353fc1903c226364cfaae80aca2f24e668bf06af1a8d37bd90e81fc33c76a60b49e7f13736af3d1e4b2e24e6888866921dd3a6e41612d4a66c9ea7a76cb716125e635ec50b1e2fe69385a4b978317b2ba686f06021e9f6a39afcb3fa92af90e495216683b8184fad9058256edcd3d48f995885c43a5df5bbbf263b8954489afb51a3edadb192a690dc6fa9613e9d77c82785a4bc3b5f8df9fb1abd2824c6d039bb27afcea986427207a53bde89e74e217b42f2a8d41eb53e1f5b3427249a4a96b564503a67a909093a3a7b8c65b9b22613123feac5d4d432f79b2594a14309092363baf98bd7d9639290a44b5edfc854b12e564848b6981e47d95fda0e1d41871112ed6bd365a5da19152179c49b908d6e191c4685c13d7cf030f5011d4448cadb253b8e8943f0830c7f0afc20c3dfc5a06308c9a2554bd7e6dfcbc723694aa14308093a433b7d6e111d3b5e4888ff0e2f7604e9206d0a1d4148be14c7af567f4c3ea4030889d629b89fde68e9990af2638c7128d0f18304fb8be7a7a376b637c9f8b1a6c3074915e7215b2366935075f4c053f2b9be2f854bd348567a20b5071d3c488a335727358355ac5fc70e12735232fec5fda669a80c204176053a7490f8c92d58501a4af9a78c647df38801905c24750a9652bbbe6ad011052a072e1273c624baaf76fc53900b396eb156aed04ad96ab135a62067236f2a3c4614c1e6918cc8618be44d53e59a7abcf246b548cc9eee3a8e184f39645a247ab8a56717afce599d457296d3aefb9aaef594458234d728eb71e94d68b148cc263c6fc358923b162d3fc8018be4ca3aa23da2629a4ffa5724e9e7fde5e84929bbfa05ede30b27e47045e2c7f808df981a73b472b422a9e39bce9fe3cd54122521072b9272dc7426b743bcbf5524c846cfb51c35a717ab22314fa5c5fe98de9f371589eb1d2da51c3cb57614154942e36c2cf7341f913945e2c8cd940d2a8a74399922314be994a6cafa75c3a5485a1d65c16c346d8a85149863147f50a1b27dc68a29410e512478f231a931d77a0eda1ca148ac8e2956e5a00145f266d656e578d9f737ccf189e4a4bf4e84fe30d58e19c912e121624c18727822a9ac2be5ec885131f6912cb3428e4e2427f5725ed1cc324e249a7696d6b096caa2bd7fc8b1896435ebdfea64f2430e4d249cdc0715bd4cddb5948964ef1825b2a29dd8bf9848f8bd103d2d4297a8cc1e725c2231f33254b0d05a2231dedf99bc980b9332ca5189e45359349a7db64f6f8f1c725022497eca99d16247240e39269138a7a2e51221662d77237923392491e4714527b932554a5b53c81189e4d36a1715acad526c235941de02212187c80189c4d1e761635f6a4ba38f484cc1edad4328139b9b23924d7fe8b56cc2354cd68824f1981bdb1c5294ef012de4604462c53a25fa832655fd2828722ce25eb35c4a7ec5d19f912c1191b31c8a282695da96b54b3d2241c6f031a29588e4954d91399cf9694d8f645529277220223188d065ba5b75fdf64324268be3733a7ed84e6a43249c5aef2e152fadec4c4622472192626bdc8ced1ed359ea0c2207219293a7f40d3ae59852e78348b8919a333befc77b67049120c582d062ed9b37465ec811880425335b959d8048ca24be3d67f21f12f3a8f198d3942955213f24966daddc27ddee9fed438258d6a41632c6d1951c7c48debc929951a6a5c5b22de4d843526c5ecaa173df8553a320871e124b6f44a58cb6af1b8e428e3c24b56eccd1e94345baab50c88187e4ccb41511115dabf348d6f6c87107cb6187e4d4b145834ced00c302e6811c754812573d961674e7d11920ffc3478691830e4966a7764d5775368704df1c9fb2222a7de72172b0053cc688410e3924d8a7cce88a2f1d2a71484ed9fa37e6a2c8972bc790030e89b35bbbed3bbb154b31e478437259ea8d798672d3dc0d49f7c97452a9b35a14711b92aee269da644aa75ff7851c6c4890d7bb1bb339c631a5488e3524de5cf855cfe88e20871a122c95cc7fa553de2e8e78a86470052351200e07028140000c088347f6b30133130000000c1a92c6c2b1704c2e90f3001400054b3e2a4c3c30202820140b45e2d048140a8602e190200c08844101503010868238ce94bc0753133af96b65cdbe75685d26d89c53490a10150b5d581f0b31b1fc9823149b65357f8358ea401517f01cc0502415df7e8bfe9592c60838d69b2eb969d8363a3a7c76010441d4ad1548c4eeffdae40e84da30e97196b4e27b59398779cb17b5e42c09361a1e812687c13b88aff449fc29c8805ed61bb16d8442c3a50db33d757064ce4d325443029e17b04a4120857c8416071478b8048ef13446c5ba2744d852383e8e39e7ab2692ccafdca85f0c9d9ddb6098c12a7203a44af32ac444bcdcad1c5498bdd8a93421a020c81035085008b78839917a65c64508429eb9085f76387b39c18a15713b203e09f3093485bbc22801b1b05e189e01efb6c8c5989d8096cafd8d8a937a61b4c1c3034307b824a82e02310b4971954286a16bd0089afd1610146563e7b72a2fffb47a58bf67c6018aaee8b6fd5c84f84eff10f958abb84867b1ede487fbadfa7fc399fe3ae6aa71d87ace4718d0bbaaaf6941852fb62eb34ff86f107ccdedfb6eb919b9c26feeba26c94ebd2c54d435f963dc8d799d011bc08b159a235afb90faf698b70f6be7e14fd118fac2f8352da363b1940e7d8113db2bd084185275304abba52d7072c20b967037959f7f76cc86e0e31699007467135b0ace682de438281b4ea1f0796a096dde64844daa828ac60154cc37315b245d9ab1d3bff43059c5b9f7f1fb3e78ba3a5a76edb72526d20d9f7ed746cf155f887ced0279cfeec6f3cec94bb34ce24202dffb54f74a38410933fff45898ae544634619a4f88fc1a3139709e27bc68a06c54aba60a49b7a9c2ede235af05f3c9062f9ac1e63f93820e594da0e0d943fdaf662b56f61ed99398d491b21ff082a816f48a6eaba9690b489256181c5bf2c8025eb2200ac0ba53dc90ae2ebbd96c043ec43c54d228128c9cc8b91cdb31fc3a667b5f88dc0365e7ceecdaa6a4cf91524f692a6250c773dcdd19f7a167bc8c0e03f28ad6f9251ab844803e1fa47ba40d67662930bfb2271299b369ba1d50f90081e20d012c7be0214f6237d45c606ce2f7a4d2b2f1c02473dbe0322810f2d7996d1553fcb8cf3a77ac2fc2604a153adc8a9fa85a53ad287ad13b27ce71fd8abe4895a6d991e478db46246e234ebf5fd6158416c6ebe9a2fd2839b80ac626ae8ed9a25f53484203d205488f1e749108b3119915ab2c2e6193c4bd3503d1f4eede9c6bd50e0a7e9604e746407d691dec8d0e69a1271320a370cfc14cc889b5e56425a1fe4fd06e643b7b4ea66c677d554b7bc31859801838150a64099c95fc13ddab81a6a9111da1222d2152080ae012fb44629f85aebcaf83fd00050007a3e0ed1eed050c28a7697bc435d11893c91b36d8d33430538b34411ead1d46de29151d6d17f607eb46956d2c82ba9c3f0f736e3e91fb15d3162ce4a28726144313417fce3a0f2b31ef1b51e5ee1903dcecc42333c017e5565f59163ae39571f99d1e98f2e2701bedfd30f0ac4125fe3923ff780bcef96ac6240de61794ed60d6c6a44524c56769f5ab8f0b063688184a1606f0ac63563d5e3f584acaa74c882bfdc47185c239c17858a02451e499900b3a1272dce60d37e821cb96ed8998f2dda2dae5d4fd763e2da3c282804434e6634bfed79a353a65d708fb45c9fd811060f6f30d035f32644c5e3ba1326578dbcbef56a40fdc83904241c72ea0da0d161e974f6130890fe56be6b8984f318821594639bf7adc8e857d295f3c3ea788f3c9e7f5099cef3ebf4fdcf193df1fbe04a2aa9821896475c63cd7cebc37de77e54ff8621c57feb3f5cb1cb7f9795820931fe7cf0180d1e7e5276080184ce3cbe2b10603f171f10883497c503c361f565e325c109c2c49ae4ad1a7e7d89309244084f4d71607663d83b2e1b6cdf1701857b133cf6aba2a19f41d4bc7aea48236ce0b97e5db37f9398dcdfa5cddb6206e63a52e552e5775e77ded6e4ac68bd00c95a8998f213ea7d297b4f0651db38e73a63dcb5795bbc314cf91734a85dc7a7434779d004153527d188b3d1f8264c64bea4d9f912479320263531493c2250bb46aa02858786095f99630a7d125e1c99cd327b413f84692616a4e5b9851c9d6a077c48e94e14925c9e1d577b81911c6a1ae7a1cc93c57ef353ee37cd215eadfbed4a4caa3808cfcc81b7001e213be0c84b7454d579bf496ea0a1aa87fd81c46d3096dacc14c2ceb6456e590e6fe6c2d048e31949033ffa9ca08f125a866125c663ecfc6c025d158888965c10bf7d7736fbd01d79b31c67c471aadf31b754a1eb48fd2a87cb1e83a0e097e5c4b1c0bc2097e909c0661cfaac87dc9e4142e78110773254d1466146ec4fb3478dae043594d4f58baf7212ba061e2f96c029f55e97dc1a3bb105b3d0becda941fa2d378b990bafbca67e447923672d872b06cffe390772731d03550e9a4ca54d0a38c457ccde6218519bee5de2c80b7eb1050d00e7bd706a1896828aa6a68dd180e4658787bc12a47c8e855ba9216e0dc7e5e83db421dd4424382c6448034c4cf7e2f8be54b950326e00857ac92518e38d1278e32bcd2dc62f55a5f3449917cf8537dd97cf116f919de4d6af6d7c61447ce63fbebeadca609bb947254194375a8ae8c0ee34d3eefce92aa00f5b74096208b23fcc6c84b26d7f177a8de1a22b91346c8418677c11d3abac0bdee5e99ed5125d8893833eb61cd6db62a66737da6f79275640061dda8d464fdd26eb46fa756defc7a228e6bb4879eb829fdc3896957f0dd73f03d48c2bf98d09e2e10b3cef2099c395595dc10e3502b0e6efd2515483fe75c30440786343f9a5b3c2a21e6735aacf08980819fa848f9511df23f2548e28a76856d4506e5e463a456c0da959f76be9fbf83ad8cc01fa44bdd0c798ba47c864ad029b32072625c7d9aa01a2ad050697166819f243defc8c1dbd67d2a194a87a36e9595d6d5c7948b3969ba33e8df9cf2ffd8e90cd4a9bf7462c600306ed8c9691215e4b45115554df3d4c789e85e2a994f2c9225ca39b519112250526869bdac0894f40b78a76901f2472ef4c916511801c7f6b881659b8bb1c80e47b5c3c1e914fa9a1675a114c66b41f25c86ef363c9c2e1ee37fc53e9cb287ca89f48c60cd6e911a7ce36dba7bada43291ebd15276b4d824aefb4d6b802f4209a9e1cef81919bdbc5f3540adf69d20cdf5fe4a7b22592c37abc036e0a46355cc4985304a19d98934974b9f454a1189f2081f146f82a189eeb07f489227b40929e240905262800823af401c4626b702af3cd1538e228b5d6a0d6d2909382096f402407ea24311550015308d16008044a970f310815805e947552039909851c30aa7051ec08d374da139a3017f730acb561db57824b187fc97e5ef6378af13dfe82b35cf518f192f560f765cac71b8d69f296503965b91aa6c6030d063309bef07b40857b999433b495c282c5b02ad268c0f74616553dd1210cd26d0b8d89b102e437d5b6828f8d2c23d2afd1fbc036ee05e3d00f0d62d1cc8d47eb229f8611e8da1314f8daa30410c521e696e809936e98462b109b6df5560f46b74d70b6723b02cc0473e94c1b568d169bb12a2880a85f5393385b8da0112b29bd60ca8b986ec2e67119c996f717e5cfe400dbe455142c03c4eb24f426b251a2a3b0475a161f0d4d174fd00b367c1d30d15806c1d510807395d7d1f286770f2930478678b846f7ba11d6756d8d3e81a08974675a25054b09f4a9b8ffa66115bf33add57219541290bd9d87dbdf86fc217abdf61ca7be82b0a2b1bcb06845bab07e2764a7bd482d53f6830d3263e06670981663bd29e77a37fda2ffd8c7526ffb670a1acfd7e4967f6460218d6013506d0009652762dfb8993c805a1b8b0e50c310394c1891da31f25d5b08ab08861045fa6f39263bebcccff4eb463cc2ae23f49c88076e98ff4d80128114908cf494dce855eb83e012b29bf5aa7a0dabd53057c1685123953d4a84039241d4d2010921356c121e51688c8fa760bf85c6ff1409069a9b4c5125c75a0a8e4589a00d19c6920440243293252ab48c7981c23236a4480d204dc11ff0cab6b66393f30feb58f467d0bcf5367d526889c698675ee4f1d2bd3d60a506fb30e8513c29a6918910beb2ecf009825c8798017ae0d3610f390cc48197fb5c61a92f04e49bbff327ea554bbea0c36815874a66da62600ce43ff4c529677c7a190f955bba7ac1eff86345b2a7a56feadb8554546d8c9c88687c3dcbd6529d021028a2a6d627da754bee5ca6f00f8b26c5101115dca14e2503c55cb47cb46de332cb4785da140c156a0b2d7614f82dde3169132df25a7d5da2651f04444135fc2db4ba5420282491b748b8df155946b04a3c0daca52b67f102f0da280c060e0b1b88e4502da5d6da5c53c6f3c2784b3ca39318147703ba1479623084625418a3eb7e0acb2b33974cbd900b74522b96b5fafea4d373a0cc8254cdce2e9f2d3af3edac88bf05a376dd5874c753da98b690c5a78e80c9837c605a3a3bf645da3cf9a57253a087d9829cd1abdae7cbcd619941e7cd19d22be608c5d265b37020708386c9f5f70f136aa1e02d8aaa32a9f99cc24eb24a86a471abb925bb3ecd84e55a846c31c552cc1a68787aa2a0d90db9d641c51beca4ee504a0fbed3a927affb23f3ffd4bedd315bca94ba819a8c6f6cddf77a2a8230af1b1b54c5f354654883ce5ff331204f488d3b8a9fe337200a8510304bb47e0543f82d642a8b7bbd99952154d7d7f8f68fe80980dce85340856593cc426d9df41007cc1bbf75e6587747d5d3e011091264d695ae23d367cb2f321b21fddfcab4622301bd641a9ca2379c9c287b186838663e2d50581b6c549353507841b07dfd7412208dafd2151da28637eebb827d2ae5d245a862adee8180253d9be7903c99b291bdbedeb72305eb2d6adc89cdfd0fa28589aaca3a4f7e17ac771cd79f5495856b669fa649afda0c834b203f1a6935d76be5d88224985b269f2a558bf8cbcdf8f02c13131e5b0f2c5ea35fdf1626bf312065466406e7952bafb96bfe76ef72088fcf3e35f464ae6104ac13d6dc2420208ddd27fd1fee54cabdff8667dfb46e420d62fde12ef894b14134928e6bd6eec823602f2058abb4c340a9678b773df899645b95d08f86638d4b311704086ffa2857284ce93313ae4d6ddd7c925dc0ae6a204deda41e4a05cbbf77e810fe8cd49a203e6c28f26875278d60d3f7c7ca481fe224fb415da141147bba34d8958da2d6d8288a25dd0668828da2d6d42c4d377af5864339bf0472c05be7d37794821c2370b384c5a916e81ae687e1e38b92e04f4db3b4e3aca1a075720b6a4ae05a428e3cf0b91225282f280d1861458cc007c7307310fbc99252a7e00215460aedd4c0260215796f332cfe062fe58352f01497e93ba81e1c9e39b0bc9c4a8d618e308ebcd172d75741b410e4c063492031470434504ba65190f179e91967433f5d95d40043e936d0359de7d7b1f902b3702b8263624100154597e961fa6a4d3fc68889edc2443f4780a33212a7cc4315928cf8908d9dfc1fc6d984d79796f3f2a2a3c4cd6c76f17ad68bb8ea33841af0080e225f6636c208be7b1e1a8d569236b10eea9edfcf4dd95e140a20a669573a028a169542bc8ca967396984bda8cce828fd672ac73e11c2d0d103640f394790a42197322cc0a412903777c1de1961990407ce8fb8ee2c87a9fc0e0e39b9ef1d9732838630c683655bfb8f92169cb1a4197686313ce8c90180144e1310650e4f6acf5f90bbf5d0264c76b9544b61a80aab2f50a353ef49560eaf6a843d75493e604040041325121c3ac18f40615f655e23333311655c22b2d7ac16715bbccdbd4d40128ca628030d85aa507802300e6d102802a61e59dcae462836a23004b5bba8e39b7f2195c1e800f8b162ff016f05c3dccb716bcc4f7ed7107fd84c98b0920c9ac33a6fad5b8320f58e01c1f7973b7f8a757098d18367e83779c4c6aa48a1ca1f7cd7eb87840fe80393daa37be6ef0d552c2360b37315fd7c4ffee1a44ee23463a955b4377b2b7d46610111c61d77241e00eae7489adc684315ca7848be2b082550db8a7cda4156e3bd9d76134051a5d4153c428fcba77d03d92a6d573abdad79666e47423e1682d4cb9d2757d0b35c179493720c87fd233c17128da9812104033dd4ce990a36423e48f1ddce8ea1589ceaf8664881b88d424bb8e6b33a82ee5dd1208a00997859698ee5f7adb23c5274d21b43cdb18da0ee99c5c54e26ad8a618be18f11e262cc15a714082d3b3d9b31aa2ea9364a9251833c4e07603ac2e44bd142787140aab9fa26430f2a72ac9b96adee9e7ae5fbc1674215e977f772de305f1dcadef874e081404b35ce34c2214eb20d4535bc8592f7466d22b407be62c9f5565afd280db34b24645cb69a449522ade193f8a5d35dd200f0e4de6b521222d5b61e4762de42b3fc78dcbde3cabb1c7908e4a719425639be54db0c4531d101cad51d3532a3389b9c90ccdc5a1e07766e77d3e090ff0ca6ce734ea6ec85ed78c55522e639449d8669281b3f47fa8243621b3e166405c86029fe2693b9526d89dce055dc25e78f6d44b4dbb192116dda68a42dd660fe00ee1e41ce8c95a27ddbd4c43033c46cd8d17f790b01377257049569141da6d39234e93026df8d975ac862382d1034495541a609999363719258cdd3d041a0c81102fb5392591f9857a5540493bd134e21cf6a3041c440f6e6e46ca42dd70039b4cfcbc77da179041c4538468b54d9359e1896c3a3ba116214ee3618a2826ad6cd2b9a6b1c34a9f893d15b4ea22a1bf412e2b20fbab37f55817173c732f780ba3084f092ea2c03e022a99d7192eb6c6b04bf3440916e1a20ad06720038de820506c3bc8550da5214a492fb6743063b8fb57ba54af56208914b7e9971faa57e4b1e0c85ec63070e3108954ffa8b6096b893a8d8545d5b4b31eb9b78b7748060fc4cb3db4dd892d473bd27df49927850095b62092f5d4aa570e0fa9020b20c6eba2d1fd8505a60e6608347ad3c49825b1a0c8f26edf7ce475cd2c7f4a9989437db87aa7e7a445c4c3b81c476700e7a2d22b8b0ee3b5c90e25b6ccc73686591540fe11533d5d38d9b5f3301af8923693d6c7ccdae74240d2360451f27e0b715375ff4674d64444ed9cb46f91610ef36ef3f62d5985ad894a880675166af266bad3bd36bff9e6a4a3833359579ceeb7dc912e2ffccce7d9430d59a913ebc1293ae168e9e5a2323ba909686e6366849dd42fd0488681ebf8b8a0396c2612d5a884d037dae3f9572b0715f732b64c63736073ee077f6ae3b5cfc6ae09b23d4c00f4f6098455183d2d2b1ab5c9e752dd6370c1ef0b10de44d1a40ac07980d7fc3215510be792a78cd7e0d5128dfd00a92d0ca9af5418e20518872bb63d7ae8cbf94fcd8b59bd76ac185d73e7cdc4be8e3f8211c4f5d2c8c16ac6fa76a071fc82db1b97b91e8d2e315967ec199193cc88d95fd92aac8ed1d09325cb83240be60f6a5575e2750aedad66c419e436c290d014bf1939e3c56873e198e433cdf728fb5afa96d1a03f332064d7fef90bce5a7ec9c134031ae2081c733423aabee3b68cf8e942cd58ffe36aff9e4f68e6c47fe073f31fd00d89ba25e11e197848957bd8b77ed20d2a88c43f60d56fb031b95ab9dc7c6d6239b8537f6c298451bf668176d7d355b28c8f554740215d97d06b65c849d10689de6f1a00951702c4b4b7689fdce6c2fc0b20a66e5881d87f98f6a9297b6544fd8df7a7b03caa786b5c715ec2c1662022f0551375c1bd3cb59269456c024c73291130937df7c4828abc4c4314164803ce005babe649b29796a6c4d4b6fcefae511d96adb7b35d88ac68488dcb704c563e0a567ba8273867c64763643af63ec2db794f78c0f15b64a8146d7298631e5a8836ec23a296058928dbb0402941a48f975ae4a7419af5b8b472fedab1969192a53a22ba8cf10d3fd4e0a816cdc0e74de1417844327dac233a8eb948e34e7c32c2d61f4ac361bb8354a478be34418e4a5b4f71531b4902f452c16d724954480049df18c1eda0a7286a9832392f7f58b320a22a1a951ba6750819925a92dbbc93b1ec0f5f548162f00ef811fd75b1e493336fb73c55b704e911c1102916060bcff42e61ef405a751904bbb93e2e956400c9bcfafda572c8b8488d48fd29b851ec4aebe0a09137ecd73bd7a4f773315dd50e1d3f6660dbb57b5c4f3632311b9f86c483963f1d84f7afca41f2046bc0405dace3ae01d0a0342f400d3b5291e837196d7e8aa9ac50ff398303f009ca603610d5fb5df59b48712a16062f24716dc23466beb2592c2ee1aeff909dcef0831173e3b8b76188d99c00cb6a1e5314a3fa6fd9d0e6c96500489ab0f21280871fa4bdd604cbf9373d39e43488c6e1c2243382425016a6340879b69b04706ecf909cf2ec1559370609139f21e84928d412417e5b7c4e456ac0e24e2d199182a2f282b2485e93382125d881c6e4fe7dd69501c6f38a58126f97957d3040530278ff544714400052424bed371c2440d9b87400fecdcc2e1ec9bbb4b9015c001d58b092839ba64a23036df69ab64f60d0e5b6c9ce1d7ffb721b75e38a06063cc8f3a6494a3d3c38813897b138bc3a34b84935d39c332fd16ff1d31418d78f54e65b71d496b74380fb7025b693e583d03af4865ec05d07fd77d7af186d92a3bf485268aaf12410da780e7522f2fe3f1a3d31a387569ae39eddc292e190b0e305cefc84416e9b6c3c3981115b4aaed692f9ec92af68a9c1a670e2a31dd7a96e51c44f3c9d9a9d96179b746c0d13f56a00ef00cfcd86b4d3fa6c288f7994622bbf09e606e33d655829bf6310019eab1a9508edc0789dafd9e91c50480f3a0b9e6db86a64945cc0808cd14f46a06fd88c4a34aa0786715f6b4087b29cb18fa74f7d304e43f11a43ac981546bca57afb1207d4a6cd21612deac65ad0d935bc21b56ccdb20006f3dd44dc711381eb3691fb6aabca4441679148d2fbd174c0ade3878561b2945696f4001c4d60e04f4ff9e7c28bca14abf89381a1f71b492746c6b775e9255c01a3c864d173ff361a93f6b999f16806726d43c31e7cfc9e1c0ae3d392f4c531f92885a76b4c99323437661594a057cf9f94687e84128385fd42714fd7696ca87b45c9ec4fdbc255373a596fa43db89dd60e1d19001b7f09876a864b5d27da6ce6b20a9454f9d73d0dba7befcffb7887254d3c40d0b87c3da8f09ec67c0c251cf717111ae5de3a714d13a46750e654ce499079feae2c91f0e3e71a3960d0c3e7e70301c806e8014ef083bac1c83f9705d02a15e9d83f0240b822286105c928821951a008ea43803f04ce8ac2c16977a10ee4ec5a75b8bc9fe46e242f167763afbfc89ea48e502860f1317fb04780fa0e9746c02710995142fca6fc09a1563c5c844830d66ef72b4259cbb28ec2891834a4987490f7831ff480d70b2b2b23c2e7465690cd6c39cb0b5b10959239cb37b511dca9166ede484c6a6c594dfb3d02db4c5ee910478d2341391209f471a5849bac0ba2ebf2d966a670434fb4881c419f0c6e1a8e1de0c988a45415e21869469a66c2de813038848294444ffdec93a384d410c927f4c64246691160c6a6c80259c480b4eead3571f4d845bb0e9e3e817eeaa114eddc63a3a03d8c356e38afe01f66283176dd9b2941284135cbc541e340abed771f5c7609821cee592f3c0561e4d13f19de1afc6fd49067044a8b5c84611240094bc19177d978f4d3fec9ae828d89f5140b23eca08888c896ae72ba459bf427b9e4dbeea71e25838d18950afd82d285de43bf99e812a65ea4ef6824d41d0a218a828a44718b8263694599d19683d1b481326c2e6f502694615ff6dd78e843f65b23266654a8e99552b530a1fd8802da2a0980c5c03e24cf63faed9e069d1ef83819a9a18fdceac458d4c06721981c8a64422a3d8cdfcc2e696103d070dc00b79182975011b1d037a5916630449768c189584a1a55d4acdf3e236aae465c4ea772f819ffebc3af40a415170069fa4a1dc0d783bc0178ab26d2ad421c890a53866436b380ce5c9f1f333fde5c98563e90015bf2743aa2f13660bd20e4fe0289dcc18767767f453ac817fa874e926611e6913a8fa2f68c026c9a815e2e82caae7359611e6d00703e787ee19962f301ce07a89805b4a259ee43c6d04e5416c46515911d83386ffb111dd1468b9aed3d4cc282f88e1ece5f26d5ad506b1ce3d9e70f2c046ae710973126c986fd7156fb5ff9b20a47cd9baa4d349b66b6e9de867e9b12e566069e5ecf37883e62ea50c1727aade2d25e68964ef99dc2c144a2ddfdd893e7678213f10029c856ce89fb82ed0d65871a4cfeb243a783c0a7142eb25732de2abaf6baac90fc8ddf16baa4a404bc455204a48fbfbf5cbee83db2715ed5dc2cd263dd90a23ffb0e39e71f7f698191e6df806b0875bb58904409047d7acf907a12a19b5a1cd58964a9a2d1be1a6026b44722312c218fafa2c3805de62c278ff7b997dd2c00230c5bdb27b76009bb19111524bf6605692dec7f549ebec0e8aa6a4c11fcb9275e44f96382260a11ce1f9c6938e5df4a6676f9e2d2c6ea8c6f8b563cf31c2653ce419355eeb0528314b81e63d9e2515dad96e5772a7938dff13afa51cf2e44cc9afecd2dd534b67afb14984dd3c6b578686c94460189ad1e36c487cbeded3745866f8a27d359ea904965de5cbf9985a4786bccc58d12cefedfdbfc4d7188976a8087a0c3130ed9703f98a4c00ee50b89ca230d10c10b84631470f59a344ae314a743e3d8930c368400b805af325a265fdcd25d405b99882cf3d1a15d4dd058a81a43a9aefbae8db06ab717b275389d779418549f08a45904a1e60345ebc4fc3c11a89326e320c61e7aa02e8a98b91f6c9c08b52441143b684cadbf4c87f7ee07f8ad09e398a87e4fdd26aea18e2f15355be14df2e23bb4d0b471405962b9db2ee9857270dd36415fbe1ffae8f1d157a14a054f9af1b2c5501bd652a768b7a377e821affb7178f315775890480a113c64a00b8ea7ba06563d0880a5f00a8083f3ce851d919dfdeffc32f85936839a581b1fdac6d1783320e223489f20242a5bc929bf32a0e7308e218bd9b960a1fb8fde029e018d53eb3e1cc2edefddb1e6cc918d3143dc331f595c4afcc2a4bfb5bbb9c1300616f1dd3daa43462ef8472b62c8b97e24a9962d95d78c4383a2e6a9e437a639331740308d47b1dad27207168a9793962bb7d9dda2bd0359b3cdd11784eae306858f8d0bdb0ea02cb15e2b00a296131cb3e0cd9dfb5fda9c1c20b6b88cb22c28008f86541d5819f4f722d565979af75bf576768f17a8b386c83112d985923ed0138d6092e4dc7fe1a992e157dfe4bac849d55d79ed0a458f733ddcd2fa3fee265ea1edd188e59fe31d757ab9164cf0784f928bd9d21eb037962c961acde62d33fefe00c6617119213956aa308839ba2b3e773faefcf0844935a3ece98ceb2a0bf660228305b128189546b92fdfcf4222aab3ffe5c11fbd6f659846ddae7ff1e4b6e1909b08bb7d4e845ec6c474811a678efbc8aae75b7df5f9619dc3c04477e24241d75ad12568332ed365f70d9bfba8d0cfcc2830658227e0ba3d7951636f16e38d42ffd9ddb9e1a03710950f4bda77dda6a341fe95086f604bea004904be88a69de977d5a9456045d52f2018d1716579bb78ba3c7b7ce81f422d54e6101a10a4e7dd831b1f1ed0a687de03326fa1e26874c0e5695ddfe18a10586fbd030e67aa4c0d1e98e60d6ee94d68fcaf84b06fe97eafba0120d4343b5cae0b7c7c5ea0dc526f3a5b9d415a6c7e0255bcf06100b14ebbae4b6c6c8434db69d01446407be4e04667e59a707bffe050920bc556e884cf163e6d3ac663cf38705c1de4c44f8e660b23cc9ff6219a8c614af200cfc019870169bb1183092de94303773a0bdd099985b7d47042b9e1f11f83535d5e8480d59393601443f98b7fe740356409e74d853283f00e996060496a412639a768f804fbfa91ac85c2261b700fa72369eb0d7b6078dda892fce533379948cb7c5f9871139d4d5f5b12040f83999280a323a395e1c3c25e19c2281e9e1f3e67c15df0d3e6c13373660794a7fb9024832438835ca73f7a9f11a8be096f4919898b4bf4e00c8c70be46cdf4fd5c00b826373156982f8e30a59442c4a9231659085ee291ce8ac256d35e6b74b7acca88220bdb6b895534eb4e2cbe581a6c30c95966df3e2238f6b71d9803d9b56a41608673ec2114336cb69074b34bc9b5d3472567a9d3589b16960ddf21ef0c38ae381cb0e2bca16c6f7bf52a0083624ab6547ea0085a0718d7ab0f65a80a09314e5c3c586d7051ca6222113bb5a33b7402dd1285c6d8bfe3a21aee5c666f14176d75f63e500e85bd24dec7da19d00cea8319cae5170188a38f896699a0de23fe8bcac0de91636f24fde643814568dfa56abcfb4e69438ae38bdbe8d43dd08a78dfe5d74d3d58c46651989a81870db02dae8d8052c34745ea4a87d65725c4c5be7036c5767a85ab8618ef00128f7a48f952a658d93f1abb1e2c9e7f088de10004891f73b91bf081997511e250a155105ed3c05de23f92dbce85585086f08db94022b6c314d93f2230d57d0d4b0507b23acae81db99812069ead8bf9ed62172f1f01ee787aa648afa9515045814f6ea277cd029925444109e1099d28b2bcbb97838ee0c54648d09fe55a7a44be2236c9e0d4e61ef7cad666b7d3452ffb982edc6771075fca3ae390a0824c091124841f38d92fcdda838e0e070b648e49164ed5a2f66d26dedbee2e8a60a9461af275459e8877dab759253ea070a760264541c2a432ce69a2b1d0e253e73c46221ca5f027365f490c1f9b68986e2b8898fc8f287e34c1f4c19255d45a38512e03a60703342f09ec423f642f94a9d03c17b38b0621a8b05475ff2c42b0eefa228305d097ea287aef86862807dc7656a8711714add1dab7f72d4c8362735689812cba4d02b154893f3509c3f497d2afe86a383915ebfd8cd3adb99a922ab056981a8e7e2e9e053cc9683708c71495e5de97ad6e26c5feb30f47294e86c009fb77540cb32a99a31034fb0de30d5f14fc6f8650e772bf331fa09afe5783739d6bce40933740662aaeeaddf9683435450af8ae9136ecc1e3649f0190a813b12b61a3ee582cf3a71481d2055d934a6576421086bcd551d81342e7b71a4adaa3a364f7857daf8167bb83840e434efc4f21574ab4f0d63193126882508238a8683d4877314b13db6c1281dcddc263efc52ff79378009cec626857ec69b3fb308798f6c95c4e99410cf746f8339612e6dce8fb8d452975804dc93e3160abf506ae482fbd948c1086f4b822a9cd2968094900304f08bcac64bae8299278247ebe4fd40f9d4d98ef88e93c81960829661644e5ddac4b7409a459490d0699d9eecc4353bdda1d77289763c6515a57ac8bf8746c94163c0c9e18a196a258ce3bdb2a02e7c4110ff275d23ba3ffa93e922f60164e485d456131ee2b49f075b2d2d88ac775239fe87572531e116aec0ae5207705a5fd381e33511b8390e635805b35c66d6154003c7c6578e1ac563ad48b42edf36baaf4006cef9a3ca68774b565232209d13eee3a698b1df02386078675f477d7549ed697d69a7195d17618143aaa3c9673548c324a2708f02dec2aa4ed8357e998ae264549e1dbda9f330a19338a5fda164322e3c3d6448f58fcb58038277295e602c3afbc3dbd2becc085c53a673e9346f614cc21454ce4938a65793a31171bc843c4e5223f677d39525d913540c32292b040cfcd9a9cc6d36dce45ff27bddce668fcebd9c33a80928b321b01652a6571b2b99d69fc42f82d41190683b4cc523107228789a7a7b340bd0321ee70e04a0725ae72e2816a6501a9f28a9a0f14b336deff20846af3910b4db9b2e6404f43dfa036f96846a98e984d187fc853e00050ce3254f068a52556d52c75f32d29eb2f1eaffa874fcb1fc7a36a38ad60ec0a12181b35b8a8038b964bc1a3b506b85581fa3398ad9a5410567db88aae411367a70eb848230f250d30453bb4f3acedc62bc134a721823483acc18d68bb8476543d9bed589702bb0d1443802f02ca084c1c81a69e04d1d08cb7c95b4f792e1a9fd0664786573a90fb0a0ea5c86eb274134149d0f5d366851577344e94863b578dc08d98688b548fe82258a97b3de92a662b324bc66e22fff9e61d671190b3f568dd383486da8195e40bf83e4be8802ad3f15130f28f931e38ed6c4238cf019b9c1336ef7f77aa2b7265f8b37f22adf27ec63e4b51a4253d629821a125af3661188dc77b31f82f89cd624a2c86f82e0036645f8d13eb410c95edbc06c7b87d57ec8987dc9e74dcc6d8e5235b48cfecbcd87fe3d8bc38cbe21fc88c979f68056fbb9ec2cf0e2737f32dd54835fd96a654bb304129dce6d1053a081a6c6e61d662a9ad03f1de8c95051d37b01b818e87dac9929b7882f8dc0768e952b8360313ee28968a360c35a367ea4c69cdc67f06ec21035e9145460e3750b2a4d001c33f3f3f3f3f3f3f3f8b326f5bb0cd82501264929b5c9e3196621029a594524a4991c385e615000000c2d61a218406086c806f0e6f0e280e279d34290945394e3c39ef327ae6f6a028eea75297fdf393313ef089c28679b5beb7eed6ebc3136579974ff75ea544883a51ce7533fdb2313dc79513c512cb04cf92476fced8c7260a7bf5e993567c0ea2c4c68726ca3997248ece9b667ed41f99b853939cf25c9e846f860f4c9444d37f2dbe2f539697286865069d5fe2c478a325ec70d2b869fda31245fb205256f7465ed3bb0f4a14369bfece30f6c9f49328968c4ddbd364396a97443106d1d17a6289b143c64814d583d64d361a270912c5586a2367dac50425e81125f549465a283d39d805850f4794bb4383ce56265fd5a61165fd32c15485c888a2894d26c5fd8be9b0b10a1f8b287b28f5d366aa1d73e8b0f0a18862e7b75da56ab452d2771f89288b569351e9e5bf79a4850f44143ba6883897b9f8d21da294f51ab39327cd8f4186287c98cc31dd5c88626fc80f25e676c95e4208b3f13188abb3091e273d7ef721886249a76ed4556c67ac578128c7ccd09f32ac79875237e20310e5d4b53e2686e80f0575193af726f1aa72c7407cf8a1a4a67eb496e6bc1d94fef0d1071d38f8e04341835a8d92379fdc31cf71c380c06af1b18762fcb4b249b40b99b3a387b249534a4b6e69c931f3918782eedd73ed6061deee071e4ad97a52dc09e699e98bc0c71d0a5bfda693c80c372dd9a1ec99aafe3e37c7aeac43d1cc6a2c446e08d91c1dcae76232c933f949966a0e65f710a7956262e43a45f8904349bdfb880855f52ea638942cae94be7d1d99230487d26c34b1f1e98f373862dcf4264d5d1e3edc508ca146d78cda508e96b14b4eda6d639e8cb035273ed8508c267569ebf9688f9f11b68f359475e5de5f63c6240335945a4e281966cf5c436f8a8f34944c4535c6a41bae43a2f8404369f374cc49b346dfa31f67286aeda70b13b775758463c71837aa047830f8304349764c27091aea11b632d20d84430c2bf33214b344880932a3e81df8204339bba8d3f76da7ada3bc818f31146397a94ef6b104bd0eae18ca625aeb37893ff80843d1cf64cb4d92a01136b382f60186f2a69c8c0d7a4ae61233c2868bf8f842e104af4fe2464feb952193038c2fd0176020e2c30b052d535debfa27cab6d7868f2e144f63bc0ca5c3c4b4fec6e1830bd98b72d1499fce16caf5a934bec9d2ade1430b65cb986b74290d621afac842b17673d07c53da93e07d60a1e45697ed73f19df1a6018e32c6f80ae418c1183f328232c6f80a7c5ca15c625badcab66c6afd0c1f5628dc499dd362842e498c3970889c033eaa503851726687a8934f528e80035f20e1830ae5933e7ea5495257f898425945b47de7787af336981f52280972842ca95e64ba308942296c4f491335a8ccf21838c630bb0f2894c43cbbf9f0ea91b283715bf8784271732a6c13c1ebc18713d2b0d574cb2dd5d5cdf2d8ffb5e51b4eb6e3861837c2e8c0176098e08b1170e00bc4356b42b9cb4e30d968ea32899950fe0d266ccf83e7fda0c8cae16309056542c6fd135b379cf9a184c2fbe935cbd1246e64cad871c30f1f49289874994f95fe9da9890d1b65ecb85167870f2414644c4e5d79b1497d3ec2c7118a1bde2ddb94a4fbfe21c287118a2797f6f675d5a04ede081f452898ba385dcdb973d57492f82042b9c4ac12c406f1025f8051be00e38b0a80d149f818424196de32514ccc87104a222ad7666fa2759ed8183e82505c0d3a4952ec7dfcb481501437492c41aebe964a4590e1173e7e50f2ea357db5ae4badca38222f42860e0a50e1c307e5d13ae9233e9eb251dee0a3070531b5c14aa6da67f0c183529ba68efbbec9693f1ebb28bc6a34c1345b9d8c1f91319288183a0c0d444470ec400a78e8a2789de47b9d4d7284ef61e8f01c13384bc62843477ae422fd9ade5fcd24513f63f01548be04767ec30317e552f245cca7fdecd1bc45c14e7c4cd273f0d8b0d9a29cc413e5243984ba894f692dd88316e7310b0f5978c4a2ec9e2f4da6a85935496051de7cbbe1e464f2497af38ac286ac12ebbe0f196e57944d32e1a53f3cf4b6dd8a927c26778e6cc8308d595150df3e62f6649ed1c155944bd0784ae76e4eeba22a8a9ea34b5abd978a72a8add5c69c4275ce5051926e4cace9bec7f74f519073dbb9e939d74b4c51dc18f6329bf0f1284539e81379921c0d2a8a8ce8900119653a9c142519997c3c3cc3f53d8a82cba60a5dedee131351944b5cc3da29e9e49335ee118a92778a0899cc0345696c35733f7f282d493e517e531d26e47c4ce93c513e59e2654cf2373fa866622427f8828047278a3958e82a21632ef2dc297870a224680d4a75a6313361e7133c3651ccf0ae0f6bf25a237868a29cb5835ed3a2353f7864a2bcfae14d94ee7df5b407268a3d7b275ca78c268ddc9ef0b8445946498d3ba2f322c496288c2c519d6bac4cb6fa62041cf8e2121e95280926493f2b2a6358e7609461c278364a7850a224a6f0eaa0664ffc26a1769ef5f72e89926776e60fad62a3088e1d5e8647244aa553dfccefe718330e897250fa7d63b269306b1f51ce244b45c9a653ff84da114793294b28c15c3efc30d8ab824723ca5e17b3e14dfb9572471819510e32ea63c33c47dd7a1125497e14919de1354295c343113ef04844da3e4296589a933c9729d6ad7920a22427e7aedcf42f1bac5c41781ca2d83996a4b1448da345f73044a9e24e12cc733cd1340c860b6ee838bc8347210ae2f4493a28933ad90977c183100559bf5bfef9d49c8d6cb816c26310850d42e37c060d1bb5ece0218882d63d2d1d760343cd2310c5925c9375db26b5c1a40d1e8028d89a2955919f4ad4555483c71f0a9a476e4e3b39a3cd08803478f8a1d849f7959da90e0c1e7d289efc90ff27fe050f3e144fd07df7501e19377fde73bb9f877622f0d043a9744eb11332345b4f234c82313e70e69887b27ec9f626fc26dfe081878216f7547dfd41a5db6bf0b843b12d949b5af318111a3378d8818dbf1bb4097d76d7a1ecdf2b1f4f5072f256cbe0418772dad693257a92a40e9a391484126ad288891db5cb430e25dda524419cf0563de25046adfa1333e6620f3814433d977f2e79ee64bc285a183cde501eb54189a6abf2d4adc3c30dc595d13d6382521b4afa3cda504cb139bbf597ec8ee24863dc501d9f2413583333b3326f5e450fa44044003ff06043a9e40c2f79e44bc94fe2b106b3d11e6a301b1e694043c3799ca1bcb175da334b8ed3791d593ccc50f8a86f1bb23da68e65048f3294bbd2762f460f32147c64926492c6bd74d08d701861186381911d374c209270f01843f964ffa9fe2cd24a2849d344c68487180aa2eefaa3cef3973918031e6128c68ff51e6a7326f1cc11fe04041cf8020c1d608061c346e900aae0018652586b7a9813c4ff37236c4e028f2f144ebe19939e412f860c741c19e848107878a130ae72571a3f65ce9811b6f38047178ab9a79a5463b6b69b3770ece0423929cf50536ba7fd1c651cf0d84271664793ca97b2e0a185d2a8e791d3962abafb2c14ef3487d7f324160a3aabc9878e5bc1e30ae5f7bc97399d18aaffb6029bc4b0a1e3c9f13c6678f0a84259355d7ac8cc34d9ea2d7850a1702749191feffa94d6d8e03185829027cbb5dd4e9dcd27f09042497f3e935f4b4b63d47cc0230ae53d49deb90e1a37c1030ae574ca63ec3ffcc99bd34cf07842513368b78ea91fd4c61e4e28aaa739afd1f0d4b91a616b177834a1187e7307bbfc701b4e1e4c28ad758df853a5edd459038f259c8712ca1dcd42c3e63749eea411b6bb197824a1dcfde39e333e6bdc3ac276db020f24943f7f3c891f214598f4089b8e239444ddf82b2a7dcbe4c2f03042515d83f24ed73ce1b2177814a19cd4373506a5438482e734c24c700b4f7e0fa1b8a5e306ad5bdb314908e518c6fb44bfc4f4ff06a178e6fe39a737fd4d2b100a2689d8dc72cda44af007e6c6ae589bee7a96b787fb66d41a8db0a11fe367f0aa040f1f94da649a0bddf9194d0f0a7e6fa6215d93dcb14319402f9217003678f0a0781945bf83decf8e3278b18b6236d3c1a45a074f4a70e8b061c3021bf8028c2f30a08b5249b993b9b33d6db7b9288f72cfb02649ca5364b828690d93637ef1fef85755c18b5b144b4acdbc99dea348cb0b5b1443fb8530d98454f0a216458d5f2d3f3189fd7a68512a333b8df16544ffb3289912f95227285582d53703111ab88e2878218b926c3ea935ddc8d071a343873fc18b58943cc68e3f4a0e1fef2358945443eb8e8f9d3e3f794549f7de4b4c99651d78e18ac2cf78c93ef33615422f5a5110cd767d55e79aa515810d5614748c8f26dab48453df2aca396f9b28f26434bd51534561939279ccf32a4f6ce741f02215c59f13cdc1e3c3e79860c75f00158591495daeba79a7eed8032910495e9c02cbbff89c466db6a628fedb659f9c6f94099b52945bc3f4abd4264539e91c3e9e7a27bbd07ec08b51f8e15eed9679a59bb32b195e88a2b822ba53998c89ce3e1405a53976f375a9a80b81a2e06f4a888c97e8bbc9274a3b734a4fac0e9eabf1c21325cb937f9561739257752f3a513a91a66592b0a31773a224d63f477f924b8949df4441e612f67d4cebdbc65e68a298f394d614196f4ffc3351be160fd23ae7c62c260af3b13a931c83e9522f61bbeec5c824752c51bc3dc993bfcb785f5d09d380179428f597f0fe101d839cf016c18b499435467349c2da5f9b8e24caa731c53c9f68d28d23514e5782d7e6fcdd5d5efdc00b48947efb3e368f1c3926fd88824e92e9acf69284c7124714a4aa6f125dd2aba6a6118519d313f5e1e74b4819518cad8e49099f2ea254a34930a13cdb4435155112aa64850cd3a9b7bff622110559993fc9dd3f39f8271151d8fbdfbfd574926fce218a1dbbf54356e3a98d31447963c692358649f1d2b31085ef536ac4e67cb3f48428a6531dac84914178ce0ca224c2b64bcca65353aae885204a3ac926ede9dcb52b76208afb49729d2de90429234094ce74e4e3ddf76df4ff508e19d3fd896692ccb2fba1a026d5c9ecf8d94e6ffa50dcf22f6136c72c57b23cf0820fc5b4cfd3d9d11a79a236f0620f65dd51722a4fd923add643d1749db68ca325aa6116311a789187724cddd541f3a86ff4f01ce0051e0aa6e92c547a7c755ed18b3b144374bfe9f550e161dba1ec613bbbc7972b6da201eb96945603c1f95cadd64f9d79d1a43b6d5ef5e40d67fca020367f9fc828c22cccf04131e6d26219e3a6ec241686193d28a7f5f59f19dd31d7f32fcce041499a133aa61f6ed5ba85eca2a4dbba45966c85105d14e63e93ce1adb949b2c17e5f02749ed1ee4934c135c94e4a6ed8c96eddc41798b827a7acb60524d36eb6c514e82ae127ceb5a9463f698ed37d4a812d3a2f04912cbc4c7a87d627816e5f825c868e97528312b8be6ae2c456ead4d2d2ef4fcf2da4b92c22d9421b128e8d2f458529e70629a7414426051327df322d747e6f4be0221af28763e31094a69f9664dbba258b12acae6939eec1e0521ad28a7d1d1047f2f39a68db3a2185a4c1254934e2757ada27babfab2cf33f14e9f3d610a5145c1c7facd4c4ed259e684a4a2b83ed237a96b21a8301b21a728e7cf5efb4965424c513e31e62f57d1bd39a814857ffb8f49c9cc601b2245c193f84932de2849929051a4b96b6fb959a623e2e55da7dbb60d1145e17dc7e41053da4a4476d4e0c74831c4c8c0de23424251d06ae36b92c94240515a8d79574da5a87a0e06120e1c39406018f2897b459458aec86884433c5196d689cbe69c89ebdce8ba6dd23106f35c0b423a51b219e57baa4c18c8378470a2dcaf5a523dc9e9846e36512c33b1eee49cc3cb89347123241325bf5813f3553f6fa2104c144643d5e2d2c4448d219728cf49ba26499973eebb0e422c51104d1f84a718cd9d3acb4448258a638278afb1b0fb450c8310428992a4d4b4456a725d13343f624470b8a07d103289620c7b9f4da17fd2278962e7bc66ed415c37121289b2a8965c1b4dbbc47443a224e6297d9a4447dbe67a4449509218aa3b8497160881e6d841c60a421c51d2af9e6a73a61b51526fdd22a662942799ccb1838c104614d3e4d4f9a574b39c6911c5ccb99465f87ccfc15744695caf94264149aba924112559cbc5c453f7245809224aa146c7ded1f9373ae710854b0ba9495e3dadcc3144c194be519bcd14a2645521af74949c41a80951d853928717f5d6717b100521d647962cf193905941949326f78fa5637e983710a5123c9738fd98499a1410e5922c735cd6f66ea47f28c506794d52ee87828e2293bafeab4733fb5036494ee2b628419e60261f0adb1b165efa1e4abaf3d641e8d6d11feaa128e77d637f9937495d481e0a3ae33b8849131e760bc143397b697d2d9d94e99185dca1983a083db169946ad209b103a3e15e3277155287e2e57f89db36dab6dc11b60e84d0a1349a930ec2c4ef924a2c640ec53842fb293109254ace47d86cd8d8f12e10f9020c1b36c258be42881c4a2fe399c9a3ebe6c67128adb8fec6e9a7d58ae0500ce7f135b59c9b1853216f28c87f4f6d8207a95b9585b8a1202b22ae42681276fc36145dbde37594509274a7103614d784e93941b3968529640de5be5b3f613bcca8ed216a28babb5be839e9cbb70e49435ab5b3b566591577a15ab2a3a44f22002e84a0a1b827850cfb249e9fbecf50ecccb7beba3d5fb22b84103394b2c3497276f2b2d774078494a1b4a5468526f1c49f94092143a9df7d4e9bfc4f91766620640cc5dea03dd646697197c5501a4db2cb46e95866128682857e4f4f2b0d1b4d3094ca44886f9ef17bbdbe5018a1439f5ce2886fef2c0d215e287b7ffaf0ba7c1b1f8574a1a0e6ee372c935c2809935e649c20378850821783902d94aad32e4eeddd7e7a3107215a282941f474fece1df39e8592f8edf6993b394a2861a11cfdebcead47ffb9778582b291c964cfabd7fc6fc0c0d10ac5f5d8fcb69b37a9c66783902a94a4f178628f3293e4893aa8508af3526eb1da65ea9e42b9ff642a71b14aa1707b2509f7b1edeb41564648144aa6dae4ff9af99235f106215028c728a3c3fde78535087942e937c96b57dac47de5236c7638429c50f6e46a429cd6336d274d28c74c2789d0269e984d5e4f470813caf3774a6b8cd9a01d2fa1347f65a1f408256895503455d725a7125cf77631429250f0d46b1d3ec87ff5d805482885982731152d49accebe20e40825494927674febc031c206831023948448d3fbb876fa353b0cba1c214528b99a6ef236530f42885032e94b06216c3b8d49860c81d570d395cbe8e9b742bcf77a297f10228462bb8dc7ccb28504a1202e4f9fe823b449a1130284f2ba285d427b0e32ff26e407051d274dd84cf3dd9914e28392a074d071a64e910be94141f565d56a34e1fcb4213c2875897ffa7e4f1ae2efa27c9f04933d289374e7b82e8a9b2136fadb7710ff72511c932bc47c9e9a99182ecaa6549fdb9d584a52826e51f290a51db736105b202bbbab7b792d97731e1f359478ce06406a511e194e09dea3aada3c5500a145a93d7e2f4ec974239352009945d14e5cd9f6a5691a25b22885c5ba77a9ec099f82c4a27073add725f7f3d50a0bcf5ede3ef4332f2ce3b353a7da24ac268da9027945494d92d40893245936c8d300e28ad2ae6806bf93c3e405d28ad2c81cd47a959cda5db242b7eacc530f1bd32bab13ffbd4d8ef9415651ec3ad32ddf415514dba3e7b7b1b593775f01482ad0a1a7e7edc43f6154e8e6259bdb98ac21e6290a9fb39cbcb9733bdb3545f984eb09911f2a45e932864e629aa8f8be0a428a93781b3f956cd8236cb94c8618377014e5284a189dbb339c0c7fdfa8c16320c7d30007074e14851511baa6e44bf02b91c0860d1c39de0663e018c3860d3164300648288a73f2e14aed28414051f68cb1366914f577be7fa2f4b249e918ecc42f39c78f2439cc8b20c70e1198718e1d3ad013053d11ba3d852c86c8181f061b1938127d904e14d3624bbe1355256a50c100e144f97b464ffc3c9b0dfa9300c8264a42963c3f1e3569e7c79a28fc86490f9f4d3494fc9302209928dcb9670777139d3916714c14abe2fcb6440717378df161889c5600e412e57d8d31d6882ebbce2088258ae649752725c739cc485289e2f8dc4739ade5d8a18312e5647d6a269c656a8c8db0888e1b673e8992bd276531ab56e9d111462226870bd4cef873e04834002289d29624aaafa69ad48cedd01189d2283317ddbcfe69930a89e2a68e39a952274ece503ea21c635e91b521a486924447144e6acc5f4aaa30f199d346943d988c19bce48f59351d8c28aebce7a43967f411a211361411d95b44a944bbcf2fd9a3f46d32d00688224aa2e5a4b869fb4e263d0b8024a2245e8737cbbc0dbbe9089b8e1c662411c181d234c70e1d8888d24791a5f2e4c7da8f0e51d618554ec3492294b48218a2a06435b14cfa6993cea41025615c4e12e4de8428c73e8d49b5e874b179130ca2d423664df06cb2092f19610bc3e470c11b32cec4c881c302de208240c7984249626a84adcf6420b2438cd4170009c46a97793d16c99581c8ebc861c848f3000820d27fcf693dc9538272fc186364a0fe50fc306a546aa6ca0f4537b14279dce0df482a02b3de2146420780f4a194194d923de6b8481a1fca3947535fa163e5e3e7c880c0860d1d39de05207b2867953a612234b41c7a289e30bf9b377de7b33e01570fa440e4042079d84e787451b1b13120782885c70eb549748d96a25b0340ee60def849eaab1d597e00c40ec5f44174fb093bb6e11e61d3d1752877c637f57832c9be21103a1444f7ac79072526e141236caa0090399442b68350dab1ff24510eb798c5272587a76a129038947fb466974b93a25a32c4b88107040ee576eba033ff7b83f4bca158b91d279932ebaf1ac40dc5f190416932b962d296dc18c380c0860d1c698c1b2208d2864df03bfbd1ccb0a1d45943951a0fad553268bb86a27b9afedcbd19b43e1580a8a11ced457dfaa4935c8dd9b01146189f7820052228004943694e7934694dd0d113f31813b061a38c310c7a20052205040da5ddb82c694afc94221b61d31d62a404809c016d1488190a3a7fd69914bee1455f0394011b391048195611adef969935f7d4c16abc73ccc98d3074a0bf41c6df2003476281107c61397690f105103294b773a4679051a2a8100340c6501c6da7e66356257b327d08d60532388f74871809c900114331fbe4b673af1d159a24826387085a0640c2508e1dbeaf7458e7feec081b0240c050902b999626c37fb8ef0b85338dd99c4936897ba1349f9bce74ccbbe048d553a77f63d24408878700840b879beb4d351fbdde081bc2b1053487acc949d6acf307211c5aa8a48713637763e8940840b2502ec9c574cb49622a990c316e88a0cf614674348360613d59ed6a4ee61dfd4800728592cecd59353f46031c6184614674b02d88158e39e84fa643ef3c8a430c1c39c8b01b0148150a235d4fcecc1df24565054285e2a5e87cd5994d8d9d238c6307da14ca2e1f42be12496eec303b749c1988148aa644873811f9f3d116d971230c3274340574fc8e328e7a200522071285e326396b16cfa0de21031c65983040a0605c7dac7a8be67abe7e204ff8007142e954ee6806b58fb0952d00a409254dda631c993427e90d4098508e31b94fecfc7ffb907183065906c812ca99c2dcd44a549fef34f8313e8761144094509619b1af6a93a3cc1a61034942d16438256a6c3ccb04102414bd42afbb66fb64758fb01da124e67bd2f7fa9e212314d6bae72f4f8c9b925d0248114a3fcab3eb866b3b9d264249a5a8d54eab956eee1d12408650bc12ef4918ef7508a1e47f1a55d6724626519d114082503eb792d7d4e797743a2f0208100a6bb2c8bc76f7e84c7f508e417ac9d93ec767f6407c50f67827b87d12a3e7ba46d8708c2172e71e48818883f4a0b899194d4ef6a0648e7100c28362107ae27e869aedfcd9453109aba1f6d4ae8bb299fa245b59ddb79be4a2e461b9316cfb3bdb36c2f6818b92e867621c51a5915b14e4ec4c89af94d3c1a32381f0618be26cfe67dfb8ba8cd1518b727a3415193a3a6e84f13b6e8cd04064c7bb80167d7ad25e42277f16452b53d2b695300f551625fda0397e431e8b829d989f4ea4094de23bc2763ef880457143d668f268e77b370f3e5e5118f7b857e24aae28cb874ecaf5940e0fa35614fe44ff603aaf47b70f565c9f8f5594932efd233f7ccc7af7a18ae26d99ce172f35b3652a8a37772684081d4476ee03152549ab6c86d165724efa384539779b3e4c51d0c9acf48eb2cd9cf3088be4d84146e1c8b1fa518afe20459a8f517c88229eb65010d1a74e9284b92d79d742c14f1e75160a32debdd87db00e15eba006160a3a9c85778d7c034709444c8c1a572859669254b7fd6f49a2dc831a5628d998b811ab6692146d3f078ee40735aa50de384a6e3ddc6586870a25c9a4d3ab7232d7f53e85722a49d8958b580a88d5aeaac8677abeb89578e613c5ed43ec4e5128c89537f1c4e3579d7e078e304460c3c60e1c61e868ab0185c2debd7a85fe84d2f8698f613b492243e784820eafab41a8fea0476c82235fb5ef6efa1ef256af9959dec48f9ea833a170159f9ec30825e57ee61a4b28ba98c7faac2342ac5342416df3ac9ac90dfb66124aca73f018eb514bd58f843b3dbfc653d34a2cbd6d732f6c36b329f5274728791821bba4d9d8b3aa110a3ba7bde24dd99da0ac518452aea992e4441353ab05a106118aa146798d76935bf16dd80040156a0ca17cef7aa6e4a819df19dc405801ef334f0fd4104241eee8d3ff2cb1ee7f108a7962eef1568d633e42410d2014df6d6ce399347dd3ffa0184e88bb13e3094acc6a0d1f682bb2b3752e175a775dd9bdb994e6dd89cfd6e841c994d02fa62f3426c1a4060f4a5fb2ff9af45a9e2503060b68eca224a322c2be47c6f9f808eba2bcb39b53d39324c7da9d0c1ab928b69ac9d7e94c755d828b62278bf74ebef672b25b94dbf4849356b6e994a02d8a69e2aff2614c1ea14b18d0a8454166131bd9b817a667cb005f408316c5b99db34ed2be65500a03078e13068d5994f6b3f79834418cc91e0d5994d3e98c49277372dc3916c5b01a348babdb6893a5018b62869251a3aedb86bb1b7845f1effbe41873092664940387c818393e036c39be3d40c31525c9bee6dbc46cee986f45e9e39ac56cdc74ad39ac2889d669ecb7daa3d59bbe024f461923685e4541ae6fcd668c26c49ba8a2dc6994b9bcf7e831e15414eec45fdd095ba2838adee2acec35f4ee64cf336dd53445a5978c0f086e8441860872ecd0e1344e51b8ba4c51999338ed2153145f43e734bf96a1a4be1425d5ff25523c86344851dc9262aa55a29a8c2668a0318a8269f9d8df24b3e4f4a228d588df33cd2723ca1ad9614060c3c6c80e43231425b1d125474f3fc2f64806617c0e32b86980a2249aa041d5a7cfe6d0c80e03821cd961c8c832765cd2f844c14c937d8b1608c11745c313c5105a279f30a723d0e8444967173331eca8a67822641831180334385110b641a49c48cbd88156468e10746fa2a0dccbb3072534c2a6e3469b8e306eec90c1036868a2b4417fb6740c7521c399280913724ed3953430510efead226d2ce487fb12e5ddac639df38ebc3cb1842283d0be41e95a89d28e3831bec814b3fd2951dcd5243eb39f744bcf244a79a1e9426cc8d2de25511a29ba4ae8aa9128a7f549ad9b4a94c910248a269f9d678dfe495fe611a54e9aa749ccdab14347c311597ba99d8bb8e8d9ba7927f7cee193a46435a1469466bd93cbafc7def46144617c93e6523663a7371a8b28cbecdfad9c140d4594735042a7d3164af62e1a89289ef694276bd2d81713224a5d92984ad0992773598728b89d6e0d6d82b0f9942196d30b91fbdaaadaacf23ecfa2f394d526691582b1fc34fdab9d454c871a21dcb872b34e2d1b0b79d7d84edfa14c78767610c55862ba09516f9aa42b887288999dd7ca0bd5a648de8e316ee000c19a89d00844f9ac43e720d7a233e72c0d4014ae9454654a9557a0f187a286be96ce27742cd0f043c1437950db70bf40a30fe52f51454b9be4b164990f45ffb8e973f093443ac68d1191b7c10d1d9e01b48762ccd31274525288b4901e4afa93c5adc91ce4a6390fa54de29e584d224bf28b061e0ada297d4785675129dfa1fcf32394c72c19b2363b94ff2441de089de4b6447528dd4932497f2df14c52d3a1245afd9e1cce947d8e73289ed0a5e6457e1431b91c0a2608f5d03e3fd2528f83b9239a35eb6979babb6d32ba70288549e2685255ba4b8cbea198f5d36f69ee9c439a9881861b8a4155de5f937462ce1e2bd068433144092977192ca3c186c29a68e26fca87c61a4ae27b96a677457307d550d2b5fb1899ae948c8f461a4a9f719338f2b73fdf4d030d25a5c2e4d251d5ea9447e30ca77826115a6543c30c05693a06cf1c74a4a7b20cc52429cf9f971a19ca23537da8f75af939c75038594dedcd9577ec4a0cdbb7a9eebddbe97ee8977471778d691a612896a061622789278ba734c0509cb75653721aed111f8d2f94d23f3bc638217227f68256f9b661dbb6b955fba1930997996f7a4b34ba50eebe12b3cc8d413f8606178a416df57c1056afa7a4b18592e79c63bf9b5a9a2443430bc52a3997e441294fdfa72c94357dfe67139f0d1bd391430660d0c0021f5ae2f2f6aee55e22d280c615ca258912ccd24fa9f9f8b50e6858a124f6cb7790fa23a3897240a30a25cf4c3ac7424b2ca1d1a042717e355ec77bfe041a5328095193413c49a399275da02185923c62de93a74cc2e4570834a2504e0fb13f4af611fde124d08042e97395a8dbf424c6cd4f28c98b0f25dee6a4458986138afda744d3d5ce892a8f46130a523749d5e29e64bc8bc88492246a9930b78de3a0b18492faa9d8884fa2a184f26e3a59623a2175c35915a091843f98e423379c90500ab770fd24bb4a099dc6114a555f9292269eed5e2702348c50ec203eedecc9d07227348a501294783d4d42f6324c8850320b25989293cceb1ad318c2165be561eead2faa6f9bcfe4f823abe64d34845074539feb41de88fa9046108aa3a48f956d124be425420308c58fbf6772fca8a75f0ed0f84141ad7c7a1343cd5d4614a0e18362096ae7d673b48c15d1e841413ce4896994181a3c2849198f3fd1e419bb286c6a083db9cd04bd715d945ea47e08f5269acee7a2bad09313cdedaaeb94516ed52709611f74847051ac17256f44a7c898c3336e51f43d9b6d511cd9617d2e4d27e5a15a14f7bdc48f694d9e5cb2b4288e8c5ba6d1e133ba9c45e14ece33c7c8a21cc2367c099ba765632c4af69762bbd9469a68b028cf89a54ffadb5252865f5190276b67d12e173ac4ae28bba68d0e324b5092aa15657acecde6c95ca9b68c8c95fbb5b9f5861505a1a58312be4a366c5061c62a8a1faf3b9764a7d35daa288992214d90b9c4c9e94a055f7225a721d6b11df756ee338327f954a828972062e642afc78de3294a32889af809514aafc914853dd3d998272a4549fadbe6f8274f8a725272887bcff13dcf1e45316fade68e511645491232f3a60962d63b170a5ff575cde34dad3ef557f37acee281a2203d93c9137dbb7ee527ca62566227f5b1b93cf6443975ac1b5d42942a49d909bde2edb5cbd6664b85bc66fa1239991345cfa8279b18a5831eab073336510cda35b5dba9512af43bcc0c6ee4204344c4032910b1314313253987659a293337c10f23a9066664a27463e2e4db5c80230c9c8189c2d7e8135e726ad5b91136c6c1814b686f66df1d973a761d1fe61ec3c6b8b9c005383840060e0fd8b0e1021c61608e1d64ccb044b1947f29ef701f73469851897208ff1073ad0a59f23acc080858c4ca984189625c9793c2af3cf68d236c61c8400c1c0107beb061c3868df6400a4472cc9844b92acb9467cd399dec0c4994c2f4b604b97b6bca1489827aea86dea693159a1990288971e77ab4df7b6efd1185f19a8f7a3a88cce174444928d3a554d9a98d288b7e39d55527a6513e27cc6044e99418c446d36c8f1847662ca27099367eba124f124e3a4311a510914ff59a444dbb2314f04414935e68ea1cd488fd201d677b8858f3ee36ddeb2de65abbdfc47c82125ca3c3868e19872809530b0b315e21943682198628268f6632fda65937b910255f8f6225e6e437b22744f935e8965cbdf1c409cf184439642a55a63b8228e651d5f873a6198128483549c5dfce6a2c9319802889cd9de6c9f4c418cd197f30dbb6bbe56bc6ecc35bb5244155a7af11569d1f8a2384f5bea9a7273933c6c300c70ed371438cec4341d664f83ca73794326330830fe573f78dfb49b50681197b28ee5fe7cc9c348833d1433945bf7dbbec7a943b0fc54beb9359ba83669933f0508cd1621b73a4a6fcdc51987187d2c6bccb24e97dd1e9d6a1c38401861466d8a1287b1e459fa7a30c9384197528977825c6b2fe736539830e7d57cbb7ad5797ef6739d527cdc6d767cca160926c7529499ceb7228eca937514de7a77e4f1c0aea4e9dd0b1a3702867faccd060c2b8ceff8682eedef948ede4d1366e289624266192ec9441c9771b8a27c99cd63f099dc498c486929843998c41491f4c50b206bd744f3ce32a2b4ee684ce655a94eca24d33d450bed550e11a4ec7cc6d461a0a6fbf3b9b9352f39d040da5127556fb71b6e47e86827033a504dfec5b159e3da6eb3c9920cc2843316d65ce24a753f3277e0e10cc2043b1fb4daa53b2c4e9aa9b30630c0569efa13a7ca893b37e314c0e038227a38c11dc156688a134a3325f85b2350c852b4ff2a9d1294d9ebd0b33c0502a7dc2ba5ea8236c64d88e1c384050460e1b367c30e30be518353db6194d46d1d34a00c60c2f14f3e4b09d265fa26146178a9a4a6eab2c69c4076770a128ee99b93dfe6671d1164a4a6cebf67ef213b6b419d8b09136034c2d94c3d7c93449bf6f382533b2509ecddd246494787e262c943c6cd6923ad3952466c6154a4aaa6f19e1693cc7a030fe86056cd8b8f5c20c2b14db2431c6bd8ea6d32a1b366cd8286347193b4e0c33aa502a41ce6c6611e223752a9447f676c678625b7a69c614ca1e35a9fa2094895fea19522806fbad309de37fe734230a45d15f32a6d3ba0d6ea51b6640a19c5e4f3ed964d0bc570e339e500c9ede66afb14ac78d0e339c50103fd1b67ff2f3b4c7c38c2694ae24dd59d2c6a463989950743d1535f9194b287a8bb412a6844e25bd3394508cd53af9d4b7c74c910b6146128a63e26ae917ff9acbcc404239dffd5a77d53a661ca1a47feea478fc869a6618a11c45458c18ef0c6afe34cc284239e899cd9837b7cabf4428b569505a4d7c1b3ddd104a7632e25273cfe8ab6608e1b1f02cfed95714cc0842c96e469798b0287bda108f1ef7b3fc576063329bf016b9a25c55a2c53fc9373ad48ad24893e37326692a25ac289d86ce37e9319f4eb28a72127349d283125514beaac432bd67224d45f14cf24e13a496e70e2a4a621c25d4ef5dc4748a9290a14a33f535d5c614c58e61837e6ad2f1538a924a71bff41f211b5214839263ed97d267a38fa21cac043f31cd248a92091ee7a774a1287bd41825e62741890e1405fde1a4ccf0ddf758fa44f9df4cfd4c30b9664b9e28979716bd49de5852963a511693af24399512577b4e9453eca3994955a2279b2898f79e28ea1f279568a21472f3bfdb9fcedcc944498f6dccfe2ab2b68389e2c6cd922ba749b87e89621459a7cb4bfab0b1250a4ace79e368eb521757a21c45a7e7a049cc268952a22064ba66a798b0ab4ea2fc9f648f1d5ab3367d49143d98b8fcaeb00bef235150d2a62c49e9d5f2d443a224c778b86c9349eaa44794fc575c47937097be23ca2b0d35a2b4593c6b6bae919ec3886292c4dd860d4a4f7d165132254a0ee2454594744e42c4f632cdd58928899365aaf9d7e5494494f4427da76692ebc14394d3f548d7fa5192b4210ea23149635d21cabd795428cf224294a4ff2ed973b6ca68a14114935ce254e992204a9f53578c8cf9ac3c8128d9898ea1d5014479c37ad8be0b1952f387f2da8bfeb4d7b8931f8a7baffa3978c934bd0fe560325737f6aba8f9509ed12156657e3bed3d14467c6ceec87a285ee72f4963f2502c733d7963dc27c9c543517409574a74391dd73b9452d684bb139460b2daa15cd6a361f427fba8d6a12035a950fa94ecfd291d4a26ed4dbe8eb9c3a67328c8e8bb1bd38feea71cca733752fd4445451987b2c6cc247c1e371d4b3894ccb46709d1a12b63f2866256cd2f3fbd9e24b9c40dc597fb929d64491b0a6e1d47c7f6d6632c614331e75462c62a75315bb286c206d192736cfecb54a286f226b983a7ec2739494a4349941d93664e95ce263420d683b65f093a43e1bd6c2d359f60d28919cae6d7395896f2503a6528a60cf6a2171f83c790a1a0eec19414f2338672c84e93db6ebb49fc88a15c1b4e0a13e361289624d2640a4d993f05437937484bd1d993dcfc4251e4f9893a99d5217aa1e81a53a88d3fcf77174aef26bcff3478588f0ba5cd2735cca7b773eb6ca19ce4e43642e9f6a494b4501e938f63a24be65016caa5744e63528f8592ced1b46444572876c8a456bde239e958a198c474996dea2a146f34e89eaa351331158adb260999f57bd4be532828d12b69732a613469a450a957a62e4d140aa3b367cf2cf2a73c0385929b8c4f334fadf97f42a9355544ba4e282713ce45e7b609c5d19339ec772694f74e923ab32651ed5e42b1e664efe910b2474a28e7206d473f34e89984921246a7eec76e002414fb938e9ece2e3446dd0047287a7abdbfea5b09a21bc00825d135e2a9e4f4a2e4dc004528de9cf0d43a7682dedc00442887e87ca2dae8ca1873030ca11cf2ef5c6b7321144bb47cd3a82686681e8462676735499780501e93a493e48df1bd04fda0b472a269e4952447890f0adabc2feb4fc6ec9b1e94ee76bc84d00dc08372ce49addecfbb286da58e1cb941775417a5d9d938537332599b8bd2c9a83d7ea684a971518c213a5cf7247d96dea2682d6a26638c6610daa25423df9f732afb935a94c64c4e623ce95346af6951ce9a5235496faac659946c6328eb68a2b242b2286c52951ffba64d2716c5dc1b3f1d16c99bd192e42c79454912472649c8c715254d82afe674e399f556944ddea6ed68a14189ac28b6664ca6364d56935b457945bf573fa78af2d97b6810ea647b2d15a53cd96bff0c1505257b8941d74cd966a72889274f2343f4de5b6c8a9224bc7cdf2c2e45498c36b625a62db97d52ac27a6f2478a4651f053a28cb4b25282125194840899ec3a4928ca96b22577fd89301d5094ef73b4b97ff5fdce270a2733e92c3997bcc73d512a0f1e3dc37a3ba83b5132396613ca7f3d35cd8962ccaf4910bd375192574c4fe45c29d36aa224eb34c9bd25e6bacd44496e505249b362a224877acdcfa27c747a898249ad4ced413f8f698992aca74ee913f3d2042b513ccf20336692a544b1d294a861fae4fcb69328264def26f8b692288937d57c62fdc64e8a44c984c96f2fa9e3dd43a26882522748d3719432794449f8139330233e679738a218c2d232a376d56e1a51bc92ba834c9ec457c388c22641750ad55e52348b28a7339367cc047d32ae88e226316679cf5f4a9613510af56ca1d664dbc88828650c9b6d5d279b141fa2dceefa1a64a852256b8872509ff35c2a64b85b88825222df74cc11a29c74c79c4e94f8fd980ea2e4a9635ccdc3ff6a2a88d2e69d8d2bff512fd340143f94cc3193a58028f5a769d73229642bfd43c9fb4778d0941e44c90f4593e4a4db348792d5d487d28a658c72b1f736e1c349ccd92483feeca1247fc3bdf39cf8baeba11c3679125eb26426c94331c7278d26f7444e1a0fc51cd55a334cd264f51dcad6f7679da9c327613b9474d824e5e23a94cafaf446e8b28f6dd2a19ce4f5ccb9640e25f931c73cf76f992a8792925784953051c4198792895194defd9b8f251c4adbeff97b931ce7bfa1d8dd49dfc2e25ae48672cadc9c3d8913426f4379636a320d1b4aa7c78672dcf7cc145b2bb3ada19cdad7fdb3bfe6ad520de5642e9fba3587330d05254c4efaf3848652bc89d33aff0cc55a9357547f3394a44e624b3c3779e449194a6362333e98307192a1b07e32eb7335867259c78cbe510cc592f36d7c9f6dd68d6128e528d3e4299329d322184aa2a9fdd126ff85d288f153ad4e7259e685623065b2cdd7db4f855d2899d4ac9a31f8eca6900be51e31dbad915a25690b252508dd313dc6cb3569a164da6676d5a794260b056542ffc328792e3f160aaa45c70fea5fa138fa69627fb6aa0c59a1f4eda13d66922b40150ada4e28117b236b4fae0054285d9d6538b9f3c4247305984239b78832f1b09e74bf0248a1b81a93123d65652fbf0244a16027ba5a8913b14c5f01a0905ec9245949f13da1e85d7f6adf24d7789e134a3a6aca333daf09c59cb64a56371335c6634259cc049d4fec364185b784f2c7de6efd3ba9de3a251493ccbd7c9ce95aeb92503aa93d3b2aa2f74c48285f89dfdde613dbf4472899a84d4a091ba124092b42680ef38c7d114aa333287ff536b9132214d673d0e727b4b41b4271e63a85121a64de8450f6145dcdd0ef679920944c885127e37c7213209424cfaf93cc949bd87f50b43cbff5cfde986b1f9476e402f4a0b8562574cc76da4f05e041797398d25e7287fdbb8b62f6f829dbac2e4a62ff89a163336412cd4531e73135fba0e1a2246bef257c778b8279c80891f7b3add9a2dcbf2a9e5e92595c568b925071fd7299a63389164513467767e5da691625e1aa41c860d2cbf8b228c7539b6f327ed2612c0a6e6e1a6b323d3e048b62998ed64daa641925af288f3c5793a41b199bbba25c7ae4ea285372e8b815a5934564ae0e266fb9ac286aa653133c5d4549c63bb72c49668eb1aaa18a925dc82813b333d6aa1aa928ab5fa60c2667bb91a91136df400d54946aa47e123f13ebede414a52ce146478f8927b6c9354c519077ebadeeb34629ca76fac39f74294296578314c53d1326ddc9d91aa32898e611d5a5d54b0ede8d1c3b5214e57e519f557227a16e620b4531096b734aa8ab031405ab5397edff189d4f94e594feda3aa13e28afce13258d9b6f6d7ed489b2896b12312a270a6b9b971a9b28e8923f2625b5a78982c71276931244978a3b13e5b5133a268aebdba14b7e32eda7bd444128d51276347b26936389e2f2daa44c763a753976908195383b36b7e2acc6dd5cad41897296eec925a394dd1506196264a00c0ae8d0614030021b36ca38366c98166a4ca2fcead9e2f356e5e9ba919248062c60011d8606366c885c0d4914937cf3fdf66b844d8c8d44b9dec4d6a61df38db1940e89c27e12f4fb86529d46461f51f26a0dd1e056ba230aa37474f4a0d11136c7408d4694c4d374d99e4aae12736a30a2bc25d32b2f4f4e927ce24594f23bc92063776da855a4063868b0a335504311c5d178426b4ed3afe11c615bbd449464f7edb9fe16edf119612b634488810387880b72888810a0c6218a2d4277d0a937a92f060e1c78801a864063dca0c118329851a310491f3b9b4e47182f9203870819460c3325846396b5ea629daab6dd1b65ad45adc3acef102365a0c6208a3946ab87114d08c208e3c6066cd81044d9a39de8ceabd6d05c076a04a29cd3c6ec6126987e3849fb400d4014c6046d2527d398bae23f9453cbab8eac8dd63947871fca9ecd624766f09373f7a158b2cd9ed2694b27a5c487d2a63ef1cc644de29624bd8762ba2aa12a2a3d943b5697144af478aae2e6a1b4e9527f74cbf9aac8821a7828bbc734e91b4e34cf1eb52b418d3b143c8f89f3b74750c30ec50f26d7dcf8a69347568752895f7d4bb9f3d4d2a17cbb29a3ab5a6627a21a7328c921831272a633c2e6722889227b326ae79c4b693a44c6c871386e8890a1a3461c0abe6dd2c7d8253894649d3c3afe83d2f1d4371466b3bfc91c952d6ad6704349fe20433d53abd1867209629292cd2cb5545f830d4517fd51f179d28a4a0c1c399255a0c61a0a3295f4a084ca516252eba8a1867209a693789eca2f29ed964186a0461a0a563229ab3aef0f2ba1a16c371fbebedf44c6f0198a2fd2cbc6b435435d997a5ea9ddaa65363ff63988a79a6b94a19847b7de598963dc1011590e4c80021fe0c005f6c9c091e8c0b7400d32943ed6dfd4cfb4e86a58c4740735c650f20e212795929310a2835e0cc513be36bbb558a81a3b0ca5f7523229939352cf493ec7e7e0410d3094434df473cfa284bf518d2f145c53e3e49d385d7ee28582ca665ca6cf5d2867197d622a15dfae5e0d2e14444bf633d3acda028efba8d4ee05e3c1581c0c0783e1601810089d6e570133130000000c1e11c5a2c17040a4ecfa1e14800455362248323222201e141a1c0dc502514010068381a1302008060542c1001010870d91ceeb0183b60f0da958c7cc9b7b236f7fb41d86af67b11a15c9ce2acfcded169c3431d8149e4397ad503dd69762f8125c89f9235084b8041eca8f95537b701e1da7ee103f8e9f95612552d2ab403d0886358cbfd9ebe5d0f84fe5d12067c6200f3cfafcddcacf713389ca5cf8e1d9345864bbe7bfb0231a5504059ccbc69f146cadc0f59373f219319ee6457b971be71467bfb12cda55ff7466eedd1437ee36bf8d1f91fb7a2b3c76b76c73081b536bd6d39d24257aa553da6b51727fdac785048b15f2961e81b7755ee4073304abb4b64a10591cbcaf386d2fe5e1b0f6e5b29da81d35ac4a856e0c44f1c12ee23c0b8dd2792efb2835940683cfd54d34b113d6abb60d6c704c154ba6482caf1c80a2c29e3102ed83bf27116f9d5986283e542ada9d31c5a371d8a6d20cce36c81e873e0fa53ae9e337c38a6f5dcc537800cf14f454e9c340a4d4edb1850ff33357622c72ddcd6e34717d5a2439b52fa6a2b3668a16a712be3da9e3b90f7739d611256ecfa3e35ee7229d471c9cddeb1fd610f0b13d7f256637508405da00ba0a1a8b94bd8bdf81abc5d6ea4fe4598e3eb937f2f671f0eee71cb673ed8ac02b7b06937d3cf299dbaea5c7f05ee7456aacb951260856e5a391934c615dfd1eccebe2ceddef37f24372436f85c7ee96dfcc0f5bda47aae9ff54b44f6442e61099fde6170447a4616d7588de87d67a0386b59fbcac66634277c4cf8e2fc26af4594083ed6f41744339adcfe72ced612eb7a120b6f83297387ebbd4da0dabb8aa6e16909d3293f58b4087fdd3de7a2c9f745b15a83852c4a0a0619fecd68b271a4ba1a676049aca287866b633515f4f6f09c3219fd7224deb5c4edd91b0298d13d4860764fc0da86119b3c1cde7ece5921c257ad10b4d85419be9991613f775e9ed85136445ffae8013f98162adc597b9c2e64bdaefc5a72843b7afa024ad6359f1b2607291ceae0ab876c138a502cf6e7ed475f51e2e78b87ad346650dd25db0db1bf2dce5d67b28efc4ed9d53bce7230bb62977863513472f06911aa23ae6e281054e004d6e197249264e631908d91a4e45d00a4d53991217362be109025abe4ba30c56d435df0b3faa2388d6da098a4f73a5b62f0a9b9921243a36d5fd489141ccb4e48dee490d2693860a73da8617a18182cb5c98a6b69179921c66d4cdf017b4b233152735c1bd5eeecf80a7b475ed14d5c674db354500fa9956b02f7ac5a7609e539dad86f24e06d65cc78456fdf3e3fd54db738970abd66da5cba27a2721dcac0b821319ea453b48876edf06785c1602e13335ebf63ac526627fc051fe039c367b929f1eefb688cea6340ba560104d4b9070b5d6752990f50009d3dbd228c983f3e828ec1223838e96dbe00c88ceda473061b248a203a9cdb5974358c370ac128a6102809e73ecbb4e559a921f0a9742cf95f491df2da1d0c914a61e6f1385cca9c1e441581c238432a14c40e02e5f6b6d07c1b403381b6f42c9959bf30f15d716d3c027903df69f33542e1a03fc01ffdff5c7e117e1af4e173b13038bd79cab973f106de1bad9ac19ebfa31d72c3b5884d5dd508884cfe0e5aab6117ad0b769a94af74e854f173f0e9ec1087eef239aa70bd3bef3d6155bbef8f8375865f5e8dca7083f87ed3f010b4524fbcb6c0b0e6c533e10793d73f62059a4e0e2103cd37ef99ac5f6af5a4650712e0bdf0ea33b3aed5b604089195f81b04af924bd70ab568c1fcb2befa5464f6c318606afafa22e06b4f2034fd3b16f24fc1c3df70f4fbfac7846986a68e6ce3f272dbab9c649480ddb9d41cc7db5b9eb4a73321790d5422aa980592fd0c56a6ed61fd451a1a73edeaace5d1207fe2d134e245db7604b8202ec820b83b4beff4fbc685a6d78957a840a2e22c1e8cca5860dccb6e21c3de875e1d6d8c721eeae675bd0435d6d9b5707c37e09bbf3a0072cf4489c8f70eef4d86b1e7ce038cbf7deeac1d8dc47d60365020f77fb425f2b49d79814589590936460eaf5971eaaca9e5b05d827d9408212c46b7201d631a0c9460d8ebba024a588dd61234bf909f304543f8bc2614185fe536090e7dfb9560c1f2abe64ab456e3347c7248e7f5fa61f0a56cf004563444f9235f63361b24af4fb9c329381b950507f048f9578c3598d65284cc19720945917c3e31fd4024587db8b1216dc8d51347ba650ab6b9276fa3f819f38c8349a54c238a8574cd045c7331b477fa2fae19e4041af06932dbd7ce1d0a2827e321cc4d1c78c95befb4eb064112b788daea272f8956f64a424b8f91c70292af048952877da2130161495d7c881ee174f29d870c02665baadf285e6a51028b07002309cd4560f56cf5b6c1b143f686b91493480de7d33f951b2a821589303bd4ef0c006d3757c2517914ad17a2a2804f9c592dcf2a48a058163b11b6549f599ac0993fae16c5528017539f790cabbd2c5481a0a740450e2e908602f0dc55388e36a6ece7a3a2197a0118884633c85c6a1cdd5373c97620403f41c1ae4b082dfe4fd897a6e71233506f448e3de2d1a4213cdc41f8f58cbf5f84f84ff9781addad76424645f97494ead5229df7255b3b439eebe10803e8f826a5892687920c22d2ee43c1b50ec74a91a9ca3b038a5ccc9550da52d17912acaeb224db812e12d7a95859f02a74e82482730d5e87f6453b2ab0f993e5b6a877960e207a1550a91cdcc9f77d8fd89f07231591c3acd2af735028580017200c33f262fe42e1fdf3a7631759610e7c4c93272a70c5aac6ecea9cd4044e73e4e128fa56f37d61d8d090c3d0ddb3856c3c5c826455cdb5fa33dcca5fc6f66d3a184ba656923e908a52e49eae62fa3179c8f6a331d5d72a17d58e378f2f636a6e4e0c586281d4e2cf4a7259a875006db6c6f0b9b08ebac1e4f18f4ee012d3924bb2ec31037c9e18bbb1b215890b20ea09b90c0ef9def978797c022d6e4a89420384283314484fae2db5a1002311eebae7581580c3aaccdd9e12a54e8201c6064b36faa4d174638e488894d1016b16ab949252f4dc66e3fa963f874f16c85884a455a7f11ae2b610d92f13718e6e714c9ae3943c12a00974956711b6ee88433a4011f7597871c2594b27933e3cfce290e992ead8aab9451c91a5eec2f333ba2bda912c2695147ae33ddf74d8a77eab3e2a8920549e2cdda69b366a34a6252862365a664228b636261447a810a3694b41b9640ec1715632b45202f082e4ec39922178b5249e9fa1a37f3e7b4003a2c4640f7f2d10950543a033e74ab870438b5ab4f5981485d1a6764ab81c0bb359baed382c693fe86f7fc9911d6e005f6d665b3c1e76a266f97f05ff9fa8187d3ac029e90632e06fbc30b09e302a5381f7ace808473de87d112dacd10da3cfe5b447bc53f0a348b2889239c2c113673b509f4364a6049e1fb0e0829adaa988d3435f1ce4355a030369eb9a4e0d6649377e1a46025be4d1925efc3e1f915a27d5af68d43a80f6a875161f5a197c6f19ca4cc7a76e6035c69dab18105b8a971b1346d38e863dd9bff2a7e237e7ee7dd8f432bf73889d5bf035c7bc7bf1be224ad4886674e9270b351b7be11eb3dfaf85713f297a11e8bea9af56266e6fde48e15ddba6874f33604cd5d56c7ed0485c9ca9818567e6a8e2142f54d17b7504fd6a76cb2c2988aaf3472ca9efaae11c67455b2a09fe699bcbf4cb58ae6a5b966022a000a87a635372be89e95bbdf20a9ad069c10b1f70353556405e94c316e876173b80fcc515d59e82e983092e2b4c9a852415ecee3c1fd611096ea7de54863d5a7cfe4c09188fc9c9c228871df099ed4fdb4073cf770d64eee42ee283683b30146db01ed48853c057c6d7ec718cd57201146a987d89d4b257c8ceacd60674b357986d0fc9339fda2e29f9e1b711a7c43f10335a3347fea7bb97395e825f42055e7e37130902e26e7000614a1e10ee26622011a036928c846a327a8b73840d7ea85ad199f3240716c9e1fb7609fec2ac16fc9efbdb7fc58de6f90f01db01788f72d771a560dea06554fa455fe962b1efb6c45f5d2327407d488b8bfc97e525f3777a5d2ca168ef0c597ec99019c6532632a90c0b5d70254744f63c2587740f2989f8231db67114a28e5fd6a8f2d5837bf35a4a3d09c127ee88b166dd6c63d19f96ad9091694242b2f2f557726bd8164e3f022077d6a6d8a7b9311517d77fad7740a1d1382e6df06f2eea2368c93299b0e575c43f6a34c7f094ad88385ac44786e3466058e8254cc3ca89e34397247d04154bedb72c5165334164a7073a1a328e941ac8deafd4820f370b0f57af92eff006fdb2d96c74ea40ca9beed0be624543ebed37b97e55ee6a2cdc460c0f0fdb570a2b70bb444b34336fe029c7afad3e451c4e0013678a11fa4a89dd290e34ea3775e49835cc3f45a21023ce829e352221202825869faa308420ef18430bc380d5dc10b81768d4b2ded48273232f3e78007df2ce722399cc5b96932a7f86e9277f19f664358c9e8b98d99c03301f4372af6e0841aaf7f38fbf9e3b7e5181a88a33049e88462ad7e161b5052bc01c2b5454c84298b05fb38d31aef12e2a25a4b06528d4cbacbfb0debe977288f068e31142091375d3b0ba5e7195b4562cde2a6f8510c367014db927586ebd25efafac5f57568163d976a330bd8511a73e13457f76542aaa3065c8eddbb34bff60cf72f57625a63e344d8d2e98e34629e15e77647b99f06e0d2481d7a15e242805fa4a0be46c25b66d8bf89a0da9044b8ec8c7a55ceddec8de86c047c4e5de35e0c555b08a268a23e146dd96f8da2d9ff7feb9ca87ee0b6499c46db27ca2651f57bc4024fb17168baa26099bac638ab275c73341649b819467836239174a33e0816af18104561eabc71f0cb91ae52d38c3ef880c4cf260ac895b646a7daf334bbac335a730a4ea2827b3320380555e09a32c71162a1f103220b4a85cc094993cac0390c204281d9f05bb6be0311304438dea0e65fd12e9459c7ee75469ec3247277f2db79ace6e16e44000303b2db1dc8d8443536b0a293daad189ddf60817b0d4f83dd1fe408d7caef166e2e70c6448a7a70f6937001620fe29714df9209bfd96ddc66a0056a2845fff1ef317a012ff787530a3749fa91a1eb58603335f8f7c884fb3e8bcc4d6b809b08d589d2fa6d9ae50195ce3c411084f6525d36d4d91be052de736d41f412bb97b921247e179c6fd766f2a435ea1df5277707f2d8df4574646a3e655ec16d8d53f9e98402e95c99a9ada5ff3729e41b5e0a71c216d08104ff8870e6319816aad50e28ea48722eb5bd53f02afc0e37f4f707d9012945958abcae9939344a3669150947e5eee0a6cb7d5de2fc2f0b90149beaf54a43269b97f4a74f463af67126916e5a8d2065f490cf6d68f5a014c7d4ace97e1eeca7a88457d7329f83ed4e4768782c862fe01befd002c5e2170ea9e845ac2ea57d618d7d7c883c898f000c10dd168c24551a7af9fc896ca3d8e91c44bd0e755178aa00df711604ef7b4607152086e5d033248a813401d879bdfe4063a66f458535a93079f3b91fcef560df9e209b0bb6cd15f0217c747374201d453040b843121c5ae3281cf55df69b43ab3962ce78ddf6311c829a03fb1713fc335993a50bcf6a7f0e8ecd67727551b5757942e8dfca9ba9342aab44d7a95bbe790f9010aeae9a00d081ad8f65cac164abc3e28bec5554beb9cdf30ed811312e87c87a83bc3e347481a9ab5a9b58d79e635f6be43c2b1dad488bc2e7398dd3a585956e77d1011113cf3e14ede83ec7f90948cbe2eacfc7485b8d1675e4038aaa119265e50d539865857ceaa1374c0099c1f693380ea949434fa8efe98fcd868e2a79391b59621eeec353d5bef10323e36732896c5c53c3175aa0adbd54348cbb12a418f95472d840165cbe9208ca1c1185932e94fb236df8938f9a466f8476e4db9486b455b9cf9b8747cbe95892db51b756677d05e3113e6e35e134d6bc91717bca4023169e38c61e72b03fde1f20f0e7194984fa795427c9d6067a44f92b1782628af16cc23b3078ee151827dcb993167c33dae2700de2d2482a3382e691845a83c03d1d26b61887182302699cd7507e08e02d7546d037029d5242846df9189470e1b27ecb452ac9995bc6cd47ca8b7551b181aeef2028e7246ac824ae885b3328ad0c6b0e736d193bb31f84efacf94ee204b2c131187095e0386db81e2795d35375addda35154f1d325901b1423696d4a8d520cb1cf9aa15e3d71736103d4f51d52ec18cf2f201ad1fb744e95ee62100e1a275e475fc7fb2c4bec5a118624495a04da7840d20b21eba06f82b664ab5a3719f948ca42ab54b504d47fd6e444ac56042295f04e7adeb6c8efa111f834b9d2841b01f987db3cf33097d781248a1d41db338b36a6c3b7c53d0ef2145bcf971067babfb1e87c66a507111c50ec10dc18e02542334b5d37482eae1e60faf1777ff362ff9f360e71bb0609d689608d4269fded4a9570f9e0bd47c0313b9f50a61cef3320bef4041a86a4e5328efae1dc01908fee9577b31476049e3d64c911ac1cc6585a6a004b43fe55220c220a7f1817b3c45b25e1047e15f5f172aa25c6e8a5eda317d081dc46aebab6879197cb0d17de455f0e3825d241355d8a3203cef71da1794d7d1ba9d9e7f01a07684e912d4531ad25f1fd3b3282fd83780bfc8582219d49a192868b7b039bea393930261c05201bf5a108c0eeb040260749f7f48564abe8f25c4d1c1d1d074063d3aa6d802ef25554103f762791a058f8378d7304426f67fd163245c461149e342a75005cd74888322ff95f65d86524048bcf0ab2279f139ee1b60e04070a0e980eb4b2026a497cdb56761e12304ec3c54c596443fa09154f93336cae3243c86828ffead6fac55740fa969a3537b331e366ca6ce61842ca01e9c1398d89f1357ee3698c9e26bf527ee180eb63e47066e9536b927c5476449716e81cfc0a0ef40c9749255e04351b40ca444abcf898b00b47234b374b03f20be28730c1528b4da9132ed4dce67f1086c97c37b721de2cae48a9b7ad6bdef97f4ca1da82ba75e8b3ef670c29ab280d7212dca3a7ba71024fa860af0b63849b193957d8b474348020ae5e170c8086d2f01e60d0258bfd8df896782587bcf037997ad13d838022fa0e2924bbbfd8f107bb0470086b9b3e0387ab339bd0eca6ede9501714496d542988a8944971d1ef40f26205faa25d4c8a41a52716748018380106bf3820e9dcb9bb6b81fc76e20db5a14f5f5ab5f3a93f4386e04ecee166acf2e2e64bc8d698dd0c6251c6dbe4081c3e6eeeee2ed3dbcf8d17d81b850c69130aa6b075bd5ebc6663c07b587d22fc637e7421573040e553003ab4521a37f340aa1bb379643cd9ace3cef498139eb4240fca4a80cb06d063935d72c43e2f85ea9fa750cf30981c0d9f2c0957bb8b28de3af8b85b64ac2470142c8da8b56ee2a3c7d4eec8d8edb09a83a3fe49c7fd5c94ae98f9d3e7b19bc49865add822d4181173c54d5d61a3822f617f56166eb40bff8bea1880f10c0a23f6acdffcb8fc8f4d4a364a540277ae9cf9c7e050e27ece8cebdacfeee3635be653f08f05de718d526c3c4dac7339da992653fe70dc9307ebaef45a811f2692917f14a71efe2f0171192a551fdfe5af7e52be1059635e2864172577475d93a3c7b0a93607454dd164adbe0c5e4b56bfaace26c3aaea9b4f4dcb6eb076a6d94c52aba6722e963631e02292473699e6e2936a0f50aac52e85e4056dbac5848317cfe10438c83ad3bc931de55086bac504317ae96ca4230df4953ac21ec1043282ec8651e86fd04fcc286b16d6a529c7cd07520fdbf82da92148de0374b45971beb3f4ae5f686578b5a1238356492ecee406f0f07f287270ff4c96d61365d701daf4bdc6d55c92c5f67435682406cb141873c4fa53754f538c3f7ada1cff1913388aba730a85a092dface7b822d0aaf66263e4cdc785a239f45ddb9670823f68f783a40ae316b2bf481abd78ad029884cd2956d8609b823813d4773004753110d2b06d6e184f7fa84c33ce2bed0d8bc2aef528357eb7894ac74409fda5dbce8bc645060e6d46d1edd1963ed0226d99bb2d636f8c806b160ad43d81477effc531753aa7ad188f33d0737038e8280e909e60c347284e1bc8cb22acf9720ea77692d0c1e32486424bb319dce771370da5400d0992dea6b4eeb3a0be500b218bd77b2d029cfb6f3f98cb5637c90e6706311869cad19e39699808498ceb28b4e3d073604d2a9b7f2f779e40e45d1cb802953f7ad3f91c10428c99867f761a9848ae9b058187b0363e0342b8690e1049aa0b1fc7930faaa6c339a2892cd85744d8ef856211bf888223f9f588d4e3a1539b62f86386e31514587522876e89b78b361a3d740461408030b5daa5046f4f25e9422c1177ffebb2cc8c1793d327dab6baa7f56acd2d4989b339aab691df0c03c8e4efeba22a989a4306b618e4a05ab6d9f4fc01b9939b28d6a9de40c7b66d403ced2f938a1e6fdd29d7b3e65a4562534d6af59cde64e2c197f86351f395fe222c5d2eb14dea6d97e34c00b414345a80f0c7874f750c50590ad92216ba021ac6c3bb16b207b4e79b7c8d8610713b3414d4dc3736b59071b769d5985488be9a474c36a0ba37b44f669e31639412a8f623b394197a381b27fb82b0b351cfd6a4f9c78ebdbc666faa7cbbc0d9de8d79bd6fd8425dc42863cd790b7c1af9c1af89949f3af6bd3e05e110848191be6bf147984819fa2b0e8b5ca2d5237be214e106817d70b49831b317f938db06a486cae8bf6f3227fdb4fe1ec01c1bd45aa82246c0a556a84859ae624b33ec3fe6d02526b80da74768c31ca12813dcfe00d659177f595dbdfdf2007a40c691c4bd5de418d737af0c429022ec554463d91736796bd45f771378e2aca120473872092819620a4ae067e8324181f84b2c7f8586c37e8c8399927372656e0bcfebf6da332ca437090f8ce21ea1121e385a88a78638aefea3f5b454446271b7744e95d2ba90b0341f69f5edd9b678332e2504a7e8c83990f23bdd3af6f78a8beb51c2cbed1f523d4f2e893e14c206bd24e0cac562c98358d82162d40fcd4311475458f81b3db6d37dd39863286a6b60e58749257a609131ce984493a62ae8e4b73a8418ca819a1237e79b0ca79a63fdf90695613c2c6209ce8dc9083ac7f3928d7833c66a3e2accdc95dc978ce05c004fce9ff040e649e145b1bd240d94e9f0b9f237de5e177d4381427a16af99803001b54fc68e3cec67806e85e21e29072624143a638a7f97f7d938021553ed4d7294e1eb0d46b74762cb0cb6e22616c4d1847ac84930c7dcc96d2036bf3413d1b2d10cece8aa5933ef6b6399ad423e30dbbc11ea23316d1a6c564de25f23e5bd33f478e6cd45832ad001ca4390c25b272cf69b33c4bdec4428526c8091f41e9c67c8b8f39156a8feb44770bc4db29814d35d01f8106f3b039c7e96603bf78d5f569f33da3fc3b36ede1bbd590aec489c798ac17bd5e92d95c7315e68eb2047b5b0e0e2c622610b1d95db2128af85d3f131c6016218df72f65cb1414759be95635bb51dc0f52a87cc7767c2b2c66b39e9617ea234799ca48398e404739cfe5f5923136ac781e4d80395f2335ec5e211be47fa8acf0a683e2cc4c09f2494f13582289794b8f288c77704f2a22aa8f62b616d4ef90713cff64085f0a4f99f1c4d4fbb48891a880c3e9a71ad1203523cba1417b74a7064b5e5f32eb674358a86f2b19d1e04e500ecc29c790d6d2f1f986ead5801585a046241a7825a18e59a6afd9aa7218502075cab3f6f40e32e4251c4d8e15633ace6ea6275e9cb6d951a95e80d13992caf2cf47e16fc8a843680ffcd8ffa83cc3549d9e67d6572ba16895490b39ff0d7a0cff72d257d2f57d6d8b50822f81d8f7f62cd9605114f6c8213e744dc3b263d5222cc4858748377d7e5de63bcbde0aa514ae1c404de514879e4baa97f137f27fcb900417d649814e793b7a25b7ddcd195d8acf755c7a1c34f8f37d6b808a80771403099aee89b900947700831e3e2612aaa568425b60a2de9705666a40c5f6645b6f517094e4265e38ee14a406e12c05366f673f5b830c637c9d85215d466637290fff2f26790e67e4ad78cf9fb8ee7c4c1a47d2f7646b7a12a56881e5e8c02340a24365466545f11100454f01e8c1e700afbe369b6f858271a88faed938995183cc9b9e7adf912ff558e70ab51b25f2d7f2291bf2660fdcb22a2094eb5fee28442d172b0895b5135e968779ddfe1f8ee96db756bc8be0002c4d6cb241e830075cc4486e910a8250e1c2969ae5ad8dd26e9a716806ae75d4044fd11726915524852968515e655b3fde19becb6c61ba7e765f75a6fb2660053ee8a9b1f0154bb4c80b853812968c3193f435599f72144d3c154a7c8e391853abfdfb23e0754ac9bad1152583ad60554e411da75709c6f5aa31a889b29def752a3b0e53a4ba87d05b6d2656910ccc3f1e318d0317a947e996c6fb9fb3c110b3db3fe96c392b74014ae229a38c84e3c474829a11b5dfca18e440300ccc54225cd7892b6780aa6797e6053904f7f956a47810a09eb95176b6a221b62649ab8f2f9c36943804505b6c950ee54fc53df370348270d2450c8ada752813cc9865c5b1bd298fc573cb5414c4d42464dc9ffe16d0359b0d8421fc1c3dbbdc9d4b4f023700a8bd90a11d75c63522d451c221fe997026f866ff204669459486fd59711be360686684bd53210ae26f19c7795a2c1db60978bb807733d54e72e751d2993078e4a621da4ae87bd74840afbd687627c3ef06694ed426bfc4728f6e3632b1e1828dea82b8d71ad6731d007553425040736be681878d930a0e23072ec3004a45d04463b45447c14c2ed5a67868095acc0e30e81a0eab2dc5d3a4b9844189c75ac13e31f8b62ba193f7c55183080dd02aec938e246b7382ba323cedf84cb09c3d6846c19b04f4282817d92b19137130138073f00f54114589aca2590660aab639272ad26c2238a53d088a62a3689228374e27edea72863845dfc4f07d2d66c6f0ec2bfae2ac56b421e10f01ba7237eb3f7558566809f01d0d2ada6fd15a53e5dff57d0596ca2b1c8ff5b79070e203327d728ed6a4c39cd23f8937a0c5c275ee33f1464e39c8bb217b5017207f8a4cc064dcf113467d7009422f8c65343969d00364a86f3a43907deceb3215706cca585d136dc9e96436a58cf62bb68a03b36930caea219b99f2d17bdd8b3c7578348dfdb845b8582f72559b002c07183387cd1d5c6ff9ac044091544d62af22924cc6925b7400a39e26496baaf94fefe35c5ab05ed1c15bd10a0351b382730256066b53a69485a3f9f4fe3df691392a41a6428658d920d977fd414b16acdea9daf44a442269849ed7bf465a812ae7fcd30497bbf11e111451df6d5669e3b227880ba73492793186bc0dc1498de62c3a92d58fe747c743112d8ef4749688c01257e0e6cd7aeef76e0935a12493b6fcb31a5ae10912a1ef5243382372646766822ecbc88a09017106c02acf21f2be76168b93cae111fd75c2e1af037778d033352ff49ddba3450057c1679c2a152af1d5761efd1e2100ffb9f92194097ed62212756bb05b946a44abca29ce7023cc8b9ab098340667ee13a3d74871cea33d3ce4bdd8bd6d3b08ec103b8259e3c7f6c9f3a1e533dfdf228195ea6e6648dd97d06a5fe3c5b19a55573825e1e62fafe4ff06841c7491025591ddea985d2a070c97218876d176225cd90e64ff626c76a5b9da2ace489ea0c63d43c9ce66f1a546619183ea9b68b95f5c0dabba0df0c883a642e1d80fbe746f1870d74d4197428ca3105c4417fae4934739c670ccc717095ad728ac32c1b5b2cf56f48d87a9d7d22a2f31b22d74940a22a444d799ea0e369ea3a783341354dc0741a7c10cc2c0ae964917b50475426b22be8fb50b5b8243669dfd8a7647b4d0f5efc423f729cec2c3a9a40faa361025d8943a03f7a12f01d4ab47546594e38ec118f15f52a25ca300bf40ec1cbf356f3c0f237d85cb74129ea2743798ed0b89802dcfb6faeab7d94f34894808a63cd938267c62d3ed08359bcabadea0c7187accdee73d6325f1a21001a974eb97fea3de0b5428109e2f388f66e371154977da3a97b21427d6965e9a5b5781b498df31ef7d1d7e0ce1b5edfb0ef7739b9fb5e329138eeb7c71f7c91485c3ac5d29b3a4d89f4a3ee6eba52871949a72a770768f90b3705e2b576c84be8f58b71256bbec8c36765e3bef8721342001827ff6274db9c2962d1e3f0d903d4d30bac2877fcb382368b0dbd8641a5a608657e24c7c563fc879640ed9eb2d72490692cdce6e16c1772d02060356b70d83890ca9adcce344ba1fcc4cd894d92b3702ac9069abcba3975bf72b550e75654aa1a20d230e8e9d0cc5303dac986f37edbb87f084ada1f5a71d9b319c4856d37f7c1e0dc2e3d0d9410e46a1d5bae34640b987954e3b78abe945add6af8620855d3257a9a432eb3acf7fcb0986c37cba21e0ce11904a53c9f0a48f22cf13862eed84bdc656582979fb999800bfc16b871c075510f570211a61cd1f7497324acb3912ad4d6ba8a4511d2907c10aff561aca221ee3d3bfeaba2c6973340253c53936c127cb82dd3b5aa3dbbb2e1efcaf8df6260fdbd1f47031779a332950285d7403c00eb9df637b9751c741350b5197258152f799496db21625da72da9f65fbcca64608c385ce27d8d3cde0935841d5e91f9e8322eb68525c97705c506e0e43ae58d85bef9fe274495d0b1ef7e8094f262c070b63da8499d335b2954b715811e0dc01a6dbaedc38e4bcecacc4184e50958367fd2cb02ca0e3781297f29fb2f2312ae90ea32d078982af88501fe9884c3c651e24e128224016cf090cfbc010e5057409859d1ab78aa66215cefa34a44797283bb91aa2641aa96d9a4a67c849555517d0bdc201ff583e40047217b2037d8232ef8cc51075dc9c68067c3eb74044d797fe249fb81bbf9a51d320dd7170e78bd6ba395635bcc5c9eaf3e52760ea22e108634d506c01ce53aaec990341b2c64d05277cfb9ca2343bb8d997f6732e223df46aacc6ca89811c8c297d99f4daa2252ee270afde22ea4eaf3d09afe84b52f680fdfffa89fc0bc6ae22fcf0a490164e8a2466328eac54bc66145265c5ce73e87d885f502813889d21670a40316d762a7c44b754a585ced616f6b4d94773bf6b4fb13c040655121a8588a1956291e086cc5a2e58c16480e6cd59c3ffdde6be514186ed38a2b2152cc225b16feaa18f9dd7b3ad0ffd18a6842e1e55a432dd8c1e285e21d523ece81f28fa7bffb802ebc2508622060d4ee03eee3793ab057e7dd8aa30ea840026b5bcf2fd9ba42234f09df387948c0b3a65522b69fffea30eb4db4c52b321f1bb810c3fa47105f2c29982db9327744cb73bd6b1bf3df921a75152412472ad7fbd5ac0346fad24a97c44e9ad12f0e61c77e2461b8a00caab08fac139821b10d2e7dd1988371191d2f3a1c40fadff601764bdea66005ae7e70ab06d1949d3493631923e1a660a2d8a9ce4c4bea16e0882d46f768a06d43f7f01701bdf66bfd180a500925f17678aeb6ec65b7b04d6301621a856ed4009ee351234076c8eecad9035983caeeb72e1057d19c5cc06300ab4522c2461f74a053bf8bb7bfe34d78a91f59f051763d0c31b748d9aa4f1b7ee1deb6368eeb4404693f3dace8ea7b219df9fcd025f8394d29b9ae2b0eaae27e6924ab9692e2b460bd73faccd5a90ee1f06576da9457ffede068034b8d97a22b1f0f417ad3d162c8569e0e15d4bb2118a2ceaa70e479c30704058587563d23f2c1fcd657683b799bd4bdc8b71d5ddeae85eea229ff9f8f43aec8b52595893fb845d8151f01d89cb9aafe70454aecdf1625e6518e2e411da9f83e416e452cd3395e7ed5c272529230652de883317f9ca9d0b40dbb376070d9e64a07d696593c709c10a631a685abab79c11c6af3e98d4b69555a574634dd93d2ffac17af48cddb6a93ae3b78b826c091654e527a3aa420046f7f0f782c5b8932bacc7c83d4910871d3eb1f7b6722546e457212de5c1d4b0215fa976012a4d15dd5d526e25c12e62c2365174670a58d69e862c217809b37909384400a1e04883fa9654e98940ba021a0d89da81ae7a691a9ab0ef1a0fcac6b0cf2ba2588a7cd0dc5407d0906b31049f0101992d5301c270b4a4edf4bd5fc1a53accca840d6c844c756c0f5e06296db9efa2793eca992d08573e223bfc3da28c48342daadfc26bcfdb51c189dbc0cd0e9805db1e8d9e86b29cf318b10092ee0c28691e1d33779d8de998c70a51913ecbe7d28a73ceb90bfe0f52353cea5c2a27c2be85e5e95390f3e6c0e414ab06f0a0173ae293e1343508e567e82333c2b06abc42208172fc933d449825d1ff3c78a60cc50fba0b77ed02b20eda58fed9d8f9bdc2b3e92d944d3baea3ac6f944ec72338a5179ce3a062f57b6911a43fa7a2cdf037293bafe979cd37926e0cb50796b3b93239d8e0a559307ea2967dd5fd51cbf27f9a41ec8b2b7c13273e1a513bca3bcdd54d202290026f73a8563bdaf862d1197e7636fc4d20a1c944ddb5e45c9735d8485e9c9bd34db5b7111e6e7fe6fa5ab00b01b6bbb913d33696abc470709a1d5fed05c30ef0a64b02b90b04cafc567aa78cbfa8e4293b7228c13eacb2fab0d42ef20400fedc2ba925cd75917dd9166345c8bb55a9b1a550f632005d16ca4566385bc1474022c9ecb72cfa98cf2f5a6ff212e9860a214384c4f2a571e32c7a0ce70e00eb70cfc987850c6beb738b346a7861860daf0e8de2af0f502278d18a053277ae927ab3ab0c27f8c905358bb67e934de5dcf600250ce71440db666fff9027f8a99dca8c377d28e176309e830bd73f9b5ce21d03d3b16153c43d23fa2deb16ca0493b52ca1bc3c29c4c901be20f8166a400fc3c67a4adf4621fd0e6cc0a9a24561019f2d86fb2398c82d1b611434c7256a91b2a2e7859d62f9aca4530d628657b4b537fe658beb139ff48a8a0487b0c204ad32caf9b0021d70e35ceccf0033e5a12702e401bfe72690d8f2cc88656ab564acdf316350e6517e28575baecca0fe06a194db92959ba8b3608495381a374281ce639165b0c3367316c1483f83dda3c91cfce49e077d7a73643162a01a7c180213705771d2042116b44fbc9224f273d2ea965e11d4e9222a9c0383dcaf9a65f6c8e4d20e27913a26ed3f24d104570e06cd8505338d816600606117714b3d302f201410c1cb07c72ca6628f5d5bde581b81362c16006609e2108ae5550ad41fa845f1ea440d107b86287ea034a200bd582e673abaad7792d8a33c67b272497034496a610ac572b545e2fce420418bc313cad9d371801e6d3302fe2b960a4b50bc6248030705c6cc10e61957e2658b33a05fa427a53920d329020f80c8485c2a222bbe262d60bd8572eeeeff4d08c8d24d941b4abe07acb7ad0d4b589019aac2e6e3340b2a4d001ffffffffffffffffbf676d6bbfb5c6fcd6ec96524af30328429494524a29a5a4b8a6b15d60df4b08e14038edb684c506a906ba06b9c2285bfdf6c7f8d647304aa783797b953c514fbb234702a3d421c429398d473749fa8ba2a6d34ef2a29f9be5872f8a225e44baaf66fbccbd28b88777a41e38122f4a23dfe3e5bab929d9d945d1a477926af23f8c34a10f5d147c4b09c2e3bf7f52ca454965f8941f446e3e59db7ce0a26442d4b445e3e4697a8bb257a6923ea8ff1fb628c854319ea4a5343e6a51eed6f4f4f77a1b21438b6226335dafa53ca9d2d8e0631645134dc9fee9a3a3cbc2b153adf9dad192354f4df1f4c1b23f459618ed2a7cc4a23c7235492ea27450d2e40316053d429a94e1bdca947ec68c193366cc28247cbca2b496e15409d70aedb72bca5f16c233efff95f0d5604b3b528d1d98fde1a31565c70d5593f5e3c60a2b3e631e8f7f23d76063d35514ff3a4f4e95932a8aef993a8968effedff53e52717d8c9c6c08cd2427a651519053ff2a6efb3dcafc3845d95de63635d40f539474b98ff877de125b2c8533fb629eeb5633afb9a74d7bfcbaf6831425b3136d5aab641485dd2ed3535d97c924114549b4da983cbf9bd021f3118a62a9d9bf1294a474ecf80728fc16b15dcbbb0ed330f524e4e9096a461f9f286812a2f3e77cf244b1bf4ec6f73a4143559d286ce91f9d4a2e5d721471a2603adab98cd22f513e9b28a66de6db8e93515654187c68a2f0b1b3ab8e3cc944314c5092ba270f5713260a9a844debe1b34fde98bdc2c7258aa94c8e266752927c4d6289b269160d23b223e30452f8a8443937b3353dd6c85a1947ba6127820f4a94ed547df82c41763cd90d3e2651107eea843e9d69524c3d6cd0e8018edf9103d1246166ab979785e7d6ed5bdc759566ff7692f3231245d1102522336692fe46ebc183841ef8800473fa99775afa5561b1a2cd949520ff7844413c078fd3b1f9704449332839f9a54965938d289dcecb1a554af8dd981145d724d7e2715d4431bcd342f5e6fca4cd1d3d747c28a2a434f4e453a77d24a258fed1b2dc73473ce80311c5e0494c8e38253150b9f130384c7c1ca220fab3cea63cb13a35ce8e4f3c689c01e3c31025e944efd2d8c956c6d2a1838c42947492848c9e9f43e30e0e1f8428b7c90cbd3109da736910c5188366d3bc719eb3e94310259156194adce0a3b9f411887298e69029179bbb7740943d99c72ca6c92b2307bd9ff8f843d9e2b387183d6b3aab7e289676924b49e2892b13d6602b230734d26050828bc4471fca9b53b6f96f98a952f2a12093983be98b103d8a8192e6f8d8433978d9c6691ef9d9a60f3d14bb6f35ef468f38d1b0cbc1471e8a5b5b628796f7dedbf1503a51e5eaf5e324e9b11d9b7cdca1f0722a633d3b943fc8cf2a418535d87a24e9068d1b9f7af0501303870daf43c963bfa89da82c39e8d0a1a4a59bcab5ce56e33d878299ba97176b2b9d5f39947df53453dbe8d3d61026c71c4acbf8018762b5ff86b7ffea92794349f0506f3283549f4d224307e9c9d041f97043490c9373f4a9d3db500ee2351f9a4fee095216381bcab6d1949acd9fc24cad8f3594ba7274a88d496c7ca8a1a4258557dda7e7127bf4c1471aca25c727a93a764eaaab207ca0a1204fd09ad5a492f1dd46010d68d4e0e30cc5b86e62752ec9447dd38dff3043f94cf4cc75fca0a7c4f9838f32945a4b927683f0126f43217c9001031f632888cdfee0a3745b5589184a97a2664f34f5dc563fc2503aa979358c3c494cfe0043f1fc6d3fe5e78fa6bb2f944f297555ffa164da89170a32cf976ac925bededa8572c8db5cdc7a69f4f2830b05793b76a176429a10e3f0b185e2a6b59feca673ec92a385528552d1374da29f3012e1230be55c5d6252a61493931c19e807168a31b74f7bea4f557732c6c7154a27c88a8c2777d2f56e8546755dedbac3735c3b44e793ec6b94b4f0518572d686af7536f94d4c3fa850de98df7932c5c87b2b7d4ca178f2f4689a29c9d4a9353ea450902607fded908af11105ad3ef3e445764d3537fcd6dd91c41023c78dfb8042c13f6e34f4ab9bd89a84c386d9197c3cc1b87b97aff754cb523be9a75ebe26fa704249c77f38a52789b492e94713cae1a47be63bfdaf226f010f323e98907c1aeb7361327e624bd04ade75dd18c7871212ff4d574f549e52c74712743dddf8fcae2a5777cfcedf7d1ffe49b012eac183860e1e1f4828ef9ea0b3795bf4e7d1083e8e5010dd4a13d9242394becc4e75ec984d2e2a4231bfd563495bebd0fe42f04184f2971e6df2c7e057fa6ac0300aee6562143bf144f718619445e8dacbd69c441d7d300a173adcc837c1bc94d80060942429d46daf6e6ad2dd0c1af08ba28e3e79b25726fee4f8a2b827c52749bb777c4d1bd08bf2e8fd93dae4b79373ac01bc582d6b334c3caeeaf333734598e9fe1373299306eca214fa62b736663c79a28b52da271171a55c14e366c97a155ad6260eedda995088154ae249dca42a4e79ce56a1980419ec547ead8f4985620cd7e104ff9229943fb7bf7feea55018b5239324ecede9528a4271d4866d274f8242397d99d46d9d6be64d4f2868cca759c38fbdffc809c511cd2144f54d2858596651b2e68eab32a1dcdda273960a9126869650dc5452dc09fb3b561e251463e7d462b2e9afcf24a1a46386c7b4b64c3a8e84a296c9b313f77b4f7d8472e5d6fa29bd1a93a03142d14fce21b49614a11cc4980665ca0f21c231ac3dd5677f1805a93986efe0bf30caa3bbdc84575991e10f4641497f3771e70746f174467bf65c3da1fe2f0a326c85f8dd3e1994f8a2205488537556a7b2d48ba27d2849f224ebbc286e5a0fd37974103efa2ecade3a3a26952b61a3eba2a417ef2bd27cf6a43c17c55c25eb55981a17c528f77226ce8e0c427d8b929ca4667436d56b9eb645d9c6c420948a96ddbd6b51d2e14eba926e5a94fc94dc3dfa711f9f45d164dd16cdf3a52f9545e9b37ce4280d5b76752cca49c6d438ade923235814832e49e88a50e6b7bfa238da49f0b40e1f347445d1d3d63b95bcad512b4aa3f1442b39c61356634539febccee8c9a46bf12a8aebe3f9a16d2f56524561fed24b297d9a64371505935483a912b47da61615450da24d4acf1c5d824e51989141cf9fe95dd54d51927133c2bdcea3b5a528b748d7dcdf0ced9414a5933ac6da24a9a32889397edb682d8a82da68724eafb539e75094ee7cb543a810225c509446762d6376ada8313f51105599270adadaa6dd359b64d289e2789411235b3649aae444e944ed5dce0425952a3751122bdf2eb9836a33d144310939193a429889627cffb6f9ae92d5454c14cd3326cfa6045da2d4a9cee346bbddeca125ca32aa6dfc04f1159eab44493fd6347f49fbf18f12255d15915a822ecff44da2fcd957737fd7ac7d27895249c2638a0899adae8b44694d67506ef2bdad8941a2b82932c727ed50b2c71e51929d4ecc51b24e95da1c518e91db357659238a33a2574337855a88118591cd1cc4c4f4dcce220a575b3a77a632697445145456decf62b4483711e8e64cb2e9d822a2249ace73986d2e3187289d748289cbffd0b71aa274ca74ee734dae79218ada3eded93b42944cb787d1a22a9041943c6aeae4d6ff1ad31e898d1a3c9c878e1c34ea0220822865f2f4246f763570fc0d15249403059d500e1c892081287d123e42c7656a1c208a1b4dc507f7f394132b00f2874ccd323c5d545453f3e52e34c9bc25fbf463207e286ade8e92e6b17b4b4c1989053366949176781f8ed95fabbe6390992f081fcaf95f3f84da063da002133c00042c78809a2540f6606b5cbdbdaabd65eeb499aff3bc7e7a2826d3713c65d3790c4220792896f4156b257bd09e673580e0a1a066ae7734669e152908408023993103e40ee5ccd438aa5b546f1a08c7dff8433b944e92494d486bcb74d048c3015287c2690899369a4d4e4e09840ea519e1795fece4f89dfd0dc301c81ccad9e773741d3974a0019143e16bec35a7ceb04926c93ca90c07894371cc734611aba6771de3e08e1480c0a1a0a2bbc14fd8a0e920dd4930007943393feb5e4d5e491af27043399be5dbfabe85f83841da50d8f8be9b9320744c2aeb618346590e10361474a691ada6cf835e13b501b28692a444b3d07680a8a15c9d47a756c90d4a68a8f500494341bbe952a14d6ab829470f3f366eb400053366a459ba618c0d1c206828897718afcbd57c60082067282969d67de66dbc776486d276d0501de30e528692c99cf93e86f412d78090a1b0e9d78476cd87137359001943397aea753c51e32bae188a25b3f989d558e27a1e06d346b7b24aad663f5cbc4a8f89bd47f3ac0f0c05cf18a1aa335c9ca41e01e40bc598ea751e4eed9d20eaf042a6dc3d3e931c02e942b9f4ff6a07d1d61b0f840ba5506f62cb42473488b650ce2f49e34a3309524b5a28964e82d68e5b92856287b1d0bff324af4c58b8d6ec6d37d5e2e6f6527b4cc39ecc1fb6e1158a654a7ce710a72471fb1540ac507c2f33254527dfb70ba40a851393244f880f4aa7b3bc004285f27f9eb80c4ae6f9924f374c07c8148a59fd1240a450f454a2adae9efc99491c40a2501af1dc34375db31d058142395b771c99e66f3e7f78803ca1ac6665769f9a7b33c709c51c2d2b3dde07d28482a65172625545ef958030a1a4f3bfaa48cb7bed7f096acee5eed689a5ae89cd24a68d8d1d0f4409e578636a3c7992de24bb2e47826304e8868d1a1e700f8024a118d4067931dab5fe2b24b0ae95da6ad622f75dd9259a98b2b23fc711dd11caa94cb457840cc4087c57a6bd797b6a6ab56c5b87cf272045289bc9a7734c1b63b037af418850fa249b395fad9afa6818e5cb9c4e3c1739390c95788ac4a11c42c71d11728243d974cf8eb8b8fd28bfa1d851af452631e38662124e4f8e714c10259c226d28e6ead2fce95e0a88b0a15cda2f34ff26e92d3a77226b28bce854dd9e7e3594a3c6ee8d2549ff4f929c481a4a82f789cf583ac49ea4c5218286e2892f7562c73aa14a0e0d3b1d889ca12c3e4a739b14e64992732266287bf415a5f4866871d828c18994a16ca1b724b9c5743327c1132143b135d63f97cc95247b2d328692dc74e265f41fc5101143f1ce4a9eff791ba14a56240ca54e429ed0d1b446db2c188a9f6d4749721657d344be50d22f7a9a3447ce4ab604112f1447dd64171d435310e9425135bf9e74ea996dd3225c2889d5afcffcbf4641640b6944b450bef0fc29ef1fafe566a124648fc83c61c54239e84e3257aeb7217285d2e8ccb81ae47a43c40a25d94feccefaf337b679e01ce5205285d29b48b7dc782176e223830815ca7125c3b7475553427922532828b924a51a355b83ad3720228562062de7d93da5821c8844a1a4749f8ed26f52830d25d4c7c35e200285825649bfc813ca4950daedcd3d64ec459c5092e59bd973ca9a5034f1e543993e2965461461424189c13b93d09a293b581d105942b94c6e3e065d931e5a112514b7a4d92457cde43553240925ff31f33842864b0a224830b493d5cfdb2f72846267b8df24889493b34bc3cc448c609039089df9e2756a912294ecac46c74d4c7268488408c5199519167265ba738651ce27dd86503372365e88304a21939924d741f9878351da247d897f3a304ab7bf354afcc8bf409a8ce96caef64d5a5f142f2b749023ba8409632f8e5115fb921355b3907331492a31c798dc395e143696a4b4cb67c8b7c80921bb28ed2869f46a0961b62eca75b3a1cc931c8f4fe7a2a0c5c3986e9111391b2eca2546d7932b5321b7282739f4c8168513a5794f794c32979c5a944a63d025fe65b428ca865182ba5621b3c03ae45cac3ad33a53df37d375c67812a38a264416e5ea53394914b76e3963512c3165bacd0caa4f0b8145c1a3a9d0313b663adbd460a38170fc18ea819057a02b8a6a92526ad49ee7e7f234a415c5b8fc9d93a4149b2fd96123310d84b0a2f0ffda193762d05845262a23f7a57bad999f9e712737ef8f581525315ff67b7f520d361ac881905414d5f4df6acd29e95bfd0d0f4145b9ff36e87e4dc829cad95b5d2bb20f3145316e120d19d275f63ba52849a286c7d53f53f2cb1a6cbd23f5b0911c428a923a4df7b51ddc4a68434651b258cfb9cd474474ce9d28ca25565fe5e88d519d0f4539c9e56133752e0414a5cb7bb33e9f433e51d08ca9646c9a78a2545ab28cf8add0dc3929a4134593ed6afc0439841345ddd4d6d142067711a518219b08d104629b904c58b729835027acdf2198b84431e7948fde179e5cb6b644e99486b819cd55e24228c19e7b57e8d7ca87d686783b65a1e6f49049944b8e902f3f1e3c4994444549324d3c35f8302412051132d74ae66a9df59028491ec3c631993fa2f09ba5edc64d830eb1234aa1c39c586ab28d28c786b82af9f33b46984b72b3924f7a2e59849a470993d3e89946459467a3331a561d76ae73a91d26ff632e084944b174aadf48d973139f8620823d4f157db5bc4f394b7b37e1b334c764b2065bc82132106288a3785ef1981a5488e2d7896592b462929224430851d8ec27be7efa0ca258769eb1447bbc6d1e082182289dde98c450750a094441b3c3a7ce9ae47c9b0744e9da474b89fa49f411ea2384fca1fc26fe6f778985f8a118c45fe7d735a93e74217d28e7e8ce194d123a2884f021a167df9ac48dce84eca1a02657daec98089b5d0f05f5ade39b25bca44c9287a2899827b953c6aa1fd306217858364c296d6af477280659bba2346d12534d2176286e1071d53162ee93ae0e2569933c1717da103aa09b75566776276fdead73669d3983d94523640ee5d6ac4194cd6948ed42e4504efd79e4a4eb2cd193308f903894bd24f118062170287f1c9d3a6cee5557c43d087943d9e7c48d1232bc9e3ceb08714331456ce8242875481bca3a9e74bc75d7990c2219216c2858c9bf934930d9c47c6719216b280833f324c6a942d450acb0f7581ebe1d84a4e1f7a467264919c41884a0e10d9d3c7327394331875eddbd4d27a98c198a256592cff39a20d24bca50325d4aac7dad92ad4d6428c750aa2f63e888a7c7501c15637272538fcb8e180a6ad9b3623a8dcec784a124a3d4cf85e7db932e184ae2ad539bacaad6a75f287edc93b5cbac53eef48295a62532367aa1d52aa6f764d69c83ce28e20d42ba50be8fed3177f27fc91b17ca258a6d9c18fb46ea15b28562362d3a482d795c9412dc11a285b263f83f395dcc298464a124a7f451b39f84fe1843b060a7154f7a993a1e5808b942492cb967371b12c09a80d904eeea1c100107f4e0468f1a62d8c031819ac13bc320707af02063470102d00333010500a0070f325840800024319e0c3170fc0d040880c78e74c8403976e848c00b001000000000000130c10248c0c3868e5740009200001e3ccc0c0208e07b3c9a5180007c8f473976cc380000060092801c3a68e4e07c0f1e34682c00000160c001d0468f1b35783c0d1a091881848e311e5132ed1b747458e8fc7f0dee3332cec6483b68946103b9f5c0616305238e401b3d508e311a81367a9461039141834602461871809145f440c751448fc4638c34860146125112e4f89bd0d612f66f4414e4641acbf054b2653e4431ef5fbae8f4e9b54cc64863f08e18a2a849aad43729534b796ab0f540c718690ce481c3468f1de9860d1d63e4383a5208a481801142a08d1e3b6af0b8418346024606512e29bd4e8da85293b38228f5ab962407b9a324114702511825ede430d1f2499a00519229940aed7d1a6a74fe50123d314926abe9eaf946fc50d03767a9d1dd847b37d2876338294dcc6efb081f8ae65993a0c5c7e45b690ce4913d14e49f90b52f62826dc8e0611b18d1c3ed2faaad7b92ced9d160240fe5564fbf73e90746f0502e3d1b84dcdf1017af061b5b60e40ea5506d8206b527c639590f8cd8a17827e61495a22a65849c30528763df34e9cf081d7c3032879383cd88c3c1e1dec06eb89136b8655a17b632e7f16126dd2e767de39a72f02ec831c286c2a6fa31cfa5e464ccd750f4af4ffad5dd268ca8a13c26aaead3f59134947cf327159a56c65e1f4143d16a9367108f513bdfc819b0cdb36b7171d9f00db59bf21133144f2c41873b1d2e43e9b3fa95a919791146c850cf98786b67ce511e4333bb175afa79b5f2ba7e99ce4c0e1595bb8d88a1b8233de8afa7f7a8a230144ebca6e79c66040c257137951c845ccdf38e7ca1687f19ca94ea2da164bd508c398f7f123fc7f29276a118c366cf59f388cb51d618e14261b5cd549c676a0ce6d9160a7aa3e4bc2e9df9311ed142e17efdf343892359287c9239cf0635a5badf5e61040bc51df926e72631e6a0c4235740ac3a475332f52356c0912ae0d960840a254159f8499e444fb26da660bbd75d9d58665d67be2352288ff660f24a73bf673c4838740462ec4827c0db917ad8a8c14814ca654a9d4ccf26bb4d1214ca274e9c4c9b3e6e4c1e1c79822373f9ea56b6abe5e5315255198c38a130a3b1e546e79b5012e5832a4949b2e464c58492609e4d7413bf6450e21a6c601859c28e28a1a4b92dc3684c528dc68c24814f6fabb5f9acb9b692cb9232c8ca95984f743a28ae638c338284d2959cbac4203f9328ee61c3c8116c068e112314753f4c701591196e1d2982cd182182cdd8619c306e46304480514c422993aa4ffd8bd2676feebb9027ade97c6133b6178abc287a76189dbfdefc2422bbb019bab0193610c945d983a634a1f28390b78ae0c28f93cb5993d54ff3ff759af46588dca270a5e966723493e925628be2ce97542adfb45c9f6a51f4a4ea3f8a8745685174ebfc918f5b641665b919519edd4d5613169145355f9ba174bcb1288dc99abc517422b028658e5b626ace54d29bbca2f4da69e2446fffdcef483d6c9c12445c51d64c824c1de2f46d3289b4a2fc293a3dd34ec96b6222ac2899981394707d22b28ab29e4c566a62f6def8445451fafcc93fc8de88a4a2a4edb4093295dda5e64450512e4928315c271532945ae41425319d50e28acc260f6a115394bfd37e8e9521c4542d45395d577452cb92278522a428e86726e11fe5e48de9bb5194334b1e4f134d1235eb9d288a7726e7fdb72b14c5243a67b0d0a163893e28ca7953f4268dc146ccbafb4431e6fcf5ebd498b5e69d274aa349fc46f9d1ad7572d789a29dd2fefbff99d5624e94cf3dc73cf3b392de290a68406305229bb0193210d14439e9a4c5947c4f9b6ec6cb44399cd220437630f9437c9828c9fe1dd366127567b27789828c8d3d1a42cc986ad012c5511af21adbc7ab84cd384a944b5092d4a9e31a6c3470e4c04183870dbd4914b38f7bfca0dd63e27a9228281927a792396476d25c24ca3137b2793f4c4ef2c78344b9f3ce6ac584ffac87f708e55af3ea5b643736ff8352cbd4605332441c51f04da3d5655e379fd89513441a513c69cbc33f7e8a8d8606114694c489e14789793da9128328b288a2da27b59b3b2ba2984b49628ab4f9336df0e8229288a25588efa7c827f14ed20e1d8724104184c8218a394f1294be89214aa64c9989bbcf97160b514ad98e1025a9ccec649ac952c23e88626ccba01a9a512b2c114114e427af13e5a96af70f446194091b741c91aadd02a2e025b98b1211b9d7e61f8a63372ea2e3cbe37e227e285c5e9d9c275dc74f52227dc0f5e2cd536f2d4f4c4a5c6c68df5b35d87a470f1d227c28ca47bb3be9e13da0881eca4928a9259f7836d9312279287fc698ee8c8ef80dc24339ab7310378f267445913bec56da6e7a695f1eaaab881d0a9bebfe99de3a14c3a40ad37b92e9564a87d2bd5d56092683e67ccea1245c54dd862939ad04c9a154caeeec875ba813976928484118044110c5400cc9dbd201431348201038208dc562c1804416c77d1340c1ca02017130128b83a170388ca32006621884411086611084811806a2b84eaaec73266f78310c5fbd5d81bdc87dac036277280db1d774996154c501b64d80fd6512405fd04d932a9826a84957b09469eba9a4d4b322d5abd7fc338c4793fbcc5c4b3bb67cedc72549b3161d0bc178ceb566fb75e1daa0adcc437446ba1ddf070a10e4d5a5abf2f96e552870a10c0b9d2a7af8774603f48321d52b4971c63836188a692acda0312f3ae9781dfd814e61b4d0b7419c519a6c4e8be426b6c2ed4b96d1ce3a2420ae1354fd9954be8180d4f3d2659381ed5015e42886875788f44532a0681614334dc4b509cf09acb86adf79efe1a72db44091e3c6bc4f7906980cbbc746021309af950c9dc20849732a971a2eade5f34e6d0c70ddd8977262d8fecee277efec034452da1eaeaa782255e2ca0ec038bbc1ee45b87aa1837557170a45fd8c55ad0411ae42e14500f216c510884c59df5a95942aa1a7badc567e0170a8a7013cbd2b0dc72108434a19862a0b3eef19b350e690771c5fb600d7d60c6d80b3785dc300964ad32665911f4b9234e792ce980c5e8088631ad2acfa3e480c81355fabbe97dfb1db0e8ce8ae7881e3f9a70f334c9ce0c41a88b0918f6914731a0adfe7b479d6c415b1a4c0583b3d7f5c77c3c8b3695af39e40a8d22286d80f7c8d5a379d803211b203a14d736f2da58b4dc1bf7c317210c47d73be59b9a2d9a84dbe0a1f6004c06d551948275612527bbe057b59619a918b2934b25d7a777031f6042b3723dc280b19ab4bf53aa061c2c1007195a530818dc1f97be7279137c421301a87c784c8ed6a53422be5d713168dcf3bea9fb86647bd98ed00454c8ef0c0c7c821c53fee176e1894dde5c9b2686572e3a6cc175de75e1acec4183799d9bf75a82875b1a4c4b72177ba2ec43c966fbff9628a5891813c7f33fbf664424030c4b93081256556b765fd60c4cf24f630faa394d846fe7f40c9eafbc1df4635ab0cae3e6a59b947c4b58515b89d3fe022f35513d7314a3480093a1195d09a3aad8ad093a9f96110dea2d185ba70f461ac2b9ee1ef8cf51704b0b488417bd659ba9053d2b3f92860510f949392908827cd8dc8afe4b1b266c05b99a6bb019e1ddeedca955012937e6e6e150c92ee76d2df713cc1efa43b3b77bb6c101c298156ee6708da9f934ffe39cce8b9de50552eb7eb0ddd4337f239700662a80c1117215ebbf9c39cb36696df6ed386a6af1e3133856fb7ecc1955acfe3fcb3f645d6cbdb6d5a6e61e4dd5778b2ad7bf69409b0e586208cc44fb4d8c94e73bd060ddb88a11a02e6c6fa67cee7922126b2acd23f268fc068af60fa640738702104235927523e2d6901a4c14126df8c86fbdacf4e87fc89c6d68fe8bcfc78aa0e861b540dcb8d53b30d5e789c3184988fa3ddf0f625a9c8c2bfab27130fa9ac39567c38e4045411595cef808b85c10abfb5af3b7e5462835021e3bb3c207a75fb51989c8597e863a944851af1c4045e00007402a0198c78d8397158beaa9f130786cc5b4383d7c93758101b3f298424118d6a594397d6ec4b0931a7c14cceb0a9239dc57da6e2f6cafa8583c64c5ca08e17cd6206cfe5f226b8bbdd028058617fb117080c6820e9165beb9f9270e1579c48651081e7e275ebc20a1540a3aa38055415ce84b054941f970c5047cded88af63f68572a1b60e380f608dbdeec12ef894c8c3ad602980a0d7103875f180daf5128b135b418c80bfada839c805f88f4b5bd26ec59a1212fb3a6d722f79bb0fc39ec302d07d8410f0f944f40a3f57b59fcccbc13996c1183bbe7fa0231b6d66753d4274e0f6040a86d0f6546c90cbe95f43d3061115d314a67068ada8a9fbb229788dc99a3a8cbee0011e24cd235513ef1d6e092eaf75cce84daf498b7491617b9146cff1edec3e43ed8ca76587699f291b02fdda9147032914250ab746dde6bbfb626564ea6c95aa696b810890b817baf36dd0916e749c75ce4fd2d067d00d6cf2e24182c3a6827fb034881e7880adc267e778c2c0eabf800474517bfe0bde8ec726e8f461344c75abbc979ba9bcae5cfe21c49340214a6658d225a9a7cdca4e0173169ef62b319bbbd2e07030a781d15f01ef44e96885b61efac5c3ae96398d850adb3480f9f557346670da49e6d2ab39d10315d9a1c14b9b0a4f2488ebbc0a003d4c033acc6f0c726e0d7188a27d57d13c4e80b2f9a189bff1d4f2e4e3f01226ca74c25f7583ba63a85e5d032c2b764ae433eab17abf71ab675a83de7b95decc76c5293245a5e74018419b0a8a9d6610c423ff89e408eb066860470e833af1fe0b8ac77d268b6fbcfff8d5b3e15ca037ead189ab3700d8462e703282d15f91020bc591b909fc283d4ba21ca1947e49de9aa667917445c10e7ec8496be5395ea0275b670decf98d62a8381f8fd931b6bd24f9f2a86924f4eb10b08a933469ea5ec9800d2ffab1374026634a09aa2df3f7b3843b631bad03593f3ccec284a70edeb92b33266e158eac075220460cdf305bc286992d6d6d6451a2309311f40ac51a6e794f3b0fc02ae269bfb310fdaea34300ce72f1d6c92d7b140d0a4d8448934a18de5f04ee050cc7c2e17165a8c529c0732e649922dd87eaff37adf2d9cc043a6089349dcb06311a69914160570985c064524f04c415ce65bd628b3c33e7fa29978db69c8aa9e4c601fd6fa5e02de74dc0043564ad3075a4a76c8d7ac5df5c9a0056304844277135642774e1877d21ab2bddf0fb2856621ee9a2c92c80669b9be9d004bcaaac18f800e8e53425f201860ecbd19731b05461d15fa6d3298c84ab1fd4b9ddc334155b84261270ff57668970b82f16aa204ea804e56eb20106587562b744d1adc0bfaf88c1e2a060e94c8c9a7042443782476a56495a59d7e255be24bbe48a7245e344c0c0bf8cccd64590ff08b47f8d2543f0024d1b8b6c7d882c96f213ff236a0858dc9265683ab320946c749ebec3f4ec3525e092505c97b612f3392218d8ce9595c8317920375471304131be1c880bb597c3f5581c67e4d254f746628dc5ad6e38546abea86ca0f938792c2bad564bd9d84aa2c7a943ecf9f710a443df1c442cfd8437aeb2de974521113d47a783aadcbeb85c03c43628f4501ceda86a2b87ec6b7e03959f06a80da4de8488dc4c1dc52689dd14b3e189202f9ee5f937b7af2cd2a5350c264830b81ac914f55d667b18077e304c84c72f0a714d72aa30fe1bcc7255aeecb5f173728a7363e29cd442e7b7751181384787b52656e321d56af4a456e012a8f777d3fc720b3125041e64e146c9d293972c2c6816c1ad821c627eb694db3ebf37af0758fed56f9d340f9eb1e95cf83387936ae0796b1d910096673e4f7e001bd940f29cb40b016b10ed6d9773eb0d58d5ad3aeaa3940069aa57ca7e152af02ed67339a7c3af6be4511e8187d7d7ace4c4a6827b9b0b329b098a3bb9f8131e3a9ae49807e6f8401a7a2aa8f7da5b92212bb5d765e1add4e6f948cf0885c3c2371990019ac2c20714ff6e33a5db48207ad99bbd96a726cd368bbe316970eac904c4808bc556c60bdcdd0f72a8723b619ca715fabf25daa325277b8689d2c44b4c63b7ef3e4a60ba015c45c851d3200ffbc437830dc6ac51e7e5d6242f5c373b0bc18fa91cfc2d1bf026dff1a2be6366a40afcf04207a8c40f7a28e605e3638c36d7d7666a7512083555de6aeadbdb4610a6a7dc04e7bdff285b07e52049324824536e6087085b44d1315eec65f9ee841082e446813770d733be121071452cbf27522967b5b2501aaf9d2c78dd5cba1ea07254ccdf5372513c560f0027631abeb3f6a6456adc9f0d720620677be34aec6727246f28ef6da50a50c0e1662bd0922dff37c393a62ae9eae87623c1dd2d535a7e295c392fea1bb23a209ea3a393a48bdaa8baddb4ab3da19206571a1ffc5ea976008bd250db0846ae4968f530b5deea4d032df16e5efe0897d93c27185880bd729566e857df30064e8c7f9c9877c172e22f4b083833b60c114cdf97a09fe5d9b2fab500a45341e4c2de472ee8446e4f89ef2523146a0c28490e9756a6090f6f283bac3f88a60713596b01af0ca05e98615c0e2ba2e05a21064b4a74cc9f33a02ae67682e8830118c72566df725ce882d7e2d35935e7bbf4c7c34e7c6f3e609904787a77bceffc2659da245c016c0fddb35746ee0d03d7600100bb3298c354b1b16d7301726564ddd94565c93a58472bbcb5995985c9b982eb43cc66da5827636d8f172c5eaa23eedd791af8d964f915ca1bdbb754159d3de750c2936684064148a4bed4a2c711bc5cf2d1807089f9fcc6d9ed9fc7377a3b268582b361e8d6508bb194b164d3864a814de73c553012bac14551d53e1c2beca153e8327778e821ffb5714ef3ba82767931458519dfb02245a88c45550d4e16d656dfc5f16899866cda21f151873b40c690245642b8135f0f9b6952e69578e37e4e110f9be961b2f70cd6be5b44f23a01cc2511d207094e07619c9e281fdf1cb60ffbd24bfc28120d46c4411f7efe2c5598e8d121dd66d22512eaf9214da8796a93ad413d59cfaff6d5ec6acbd6546f5093b6fc7a5fbdaedea84e19aeebb10b511fdc583aff7d499d173b1a64f62cc8309c47b4b5603aa12279ac4ec122c1150cbd18a909952c57117294ecd122a245876814f92227fa89429acc9c1515306675f5f87aaedebbda071c27605fced4c9b537084f65a0feeaa5fc142c84b255919b908a50808b8160cdb776227f663c45def5887080f92bfbc4c582f93056f12033226b8e0f6c957c6cbf53f243699b0fe15003761a8a3197de5ab5189b24d2deb058409c09d5e77ba2545a2bbf14a0e0c60fe24b6821d7d28c2b233262311897f799c95e809504b17fd5f32deee1e386c756d1e9e5919770113b99dfc0b26e21c84ecbbc698fac15c3c4f36cc73181c1f06b9e47548c766026a966d29eeb464798c4e1a8c8e3ea762ccf0b2dbfab155c9cc54173a10a0da09dd9f5daae1421eb855b2103489984bc88d6f00b188e250f361443671b766b79848c4c39582a8fd4d1905a6b0d38343c03d2d38ec9c56c2ebd2ae427fd45e322de5d5922a465e2bb44700579e173db34a6c6888e9c59810c367e6d67d428013ebf951783bce0a9649f9aeeb103a7d891edcb664e0f0930e28ece1a03412ac1cd74be60549cbacd46657a198586d1ed6d0738cc7264e325acb05960f0c40720b20bdfedf16bd5ba4cfde5376363b694cc1174dc4f8321cbb18708ea2b192e24f0d95246f213e6fdd0868067d61f6090e72e0bc896e299b9bfd5799ec715e79436914502a9e2408d5ac32b80c3eddc2f0da61c6b80d80b607f0fb70d4811ed880bce6bf2a313d5dbaf9fe33997e66a73b2d770b77e08f212dfa07775f77bf661d1b9240461b93ac3a133141e253426ac5baf10e6ed319ef50bf5c3cd77581ff8f42fbb4330a6e852ce218e1869f55f7c69d4f3048958ebbefc155a9395823a26510916ee42e3ac710a3f28688f2b2b7040b80d5732e586e63918eebaefe48256ef4b96a2501a22c51759a8be1bc98e0362703cff2fcf82600e91a4492d852c2171f58ace8455f9ee411e0f3f1678febc19824e73599f80d1bdecb7e812348394ca0db7deb892d0219bbeaeb1f3d7e095f477163d8cbbef087b5c5eb9e56be6b0e7636aa1ac9bb0772a299a8437e8923c1602af0c907c2e3086ccb3d470cf567651744c32d71443cb78a15936c1524ae13e15e2d12e347e17c441e2915bb12cf52c9238ebb0243a4d734275d96d277a10cd93465c6e783ba1f9f51a778a472f4c72e7e217d7b66cd1e27d2f7fab714a055dbec843175e829d53135c79cc211b8c3366517984f7cfdaf20d5133ca081b3ba5321502a9123deeb24070c32734c6430dc09279bb6902948ab96e773d9e28b687201c10de90f4ee48e3421e90526300288b1e5bc1f9c38e0bd4fc3984b87691ae16c8a08fd36599edbefa41b0d0575c6263daf6307cce43cd5f58408a023f84622f8b5d20246417ac7e7ca94da71b6744b99f440deaa75f6fa5aabded6baa59f0708a8996a35509f30e66d1bfa8d8fa198877292849c5645466ae0c4e2ec5a523e677a6496c72a286084b50150f6fd133a057f9c5acd10a629916f4fb83f735b4d006fed8241b65f0780263c9c1fefefb2b88a5f605d0f6cbfe44edac2376c7096cc1b5b6f2c923b9112beabd9c4e6a522f108969ef0a53ed514d08410961e89c866da5cc8e44bf3a633c0791829b3e9ff574e55fee2dbc957b11cfd6814302b042dc588fdcf09a439a6def5b5bc9084211e7b8c3f7dc46af3f034db1bb5b41b1246a932316a42b030d5d63491988f6522a2524c75fb18aa8574e2896b5f225f54342a0fe6f2f70359b2a907e1e9a2ca952761f00529380628771432c3d3c7f010e94c909827a2395f4a4ddbe7535c4fb35ab2765ea9175d027ac27a027fd021e2f1ae1b491fef9881d6196cee81441c932c92c637950d02e24b0e1fcec841844be8a257081da6ba72f8f02d4abad26aef5692892ce40c8338b220aefe23c138d6b3b52584b2a2106e80281346e8c4742502592bfc383bfe333915180c02ab7fcab6bf31d9dc10b644f300ed162e8a477c1cd5ebaea2fd443d14ed4ffa32981c3a01e6db92571237b0d209f34d92c832e5d6d997128aaae0392a19f4d51d08edb182c9c431c660df852a7ff824d45290335812aeb3b3a9e10f01d09e1f7576acc3cc51ebec48656fa23cb9a9f763fa32872bb7288570e4ba459978492187a9af410db95301cfa55221f6caec49d36889c82d834ce8637cd0c8eba00dab1c843557142fe4534e23559dd3923af6a82175314135dc748c312c5b5786d4fa3948f16d7f534dea567779c55ccb2f03c8f875213186408508754c9ff13092cb6bf254911b957958b58b5618b527f7ad1eb0c7f1ca739a0f58a5dcf7b4bb3cc1439564155062bbd57182fa41c0d6608af19a8981f65c16e2cdc4d17ae8b61245a1d4a49200ba29fd581ce959cb26d948832e76ec0853f4f5804132b7da96492cc06580b1e6186d9c40c6ef692b5585122b0bf030a5fddc144e9a5410380126070d87d739ea55b97cc243137312c108f1fa18f9d0573797a8188e5d2df267cb3b78cb28371fe0f0bcb79e92921ac7fb53264f3777364419c5e063089e6e363126b10383c2236a36616011a50c07c75de9165b7b7ff1ad5843bd4934647823e15365b1870dd9120068d66fa06e74dd9723c5168c28bc0130815d9673323dc545c70f830777c213527924ca5ecb107a478bf4b014eb53143224f3570d35204acac54a2c8ca52b3285495115d547899200e2d2e6f705139666e3664dec1ff72cf91eb77cd49de22b00999239f940276ba8adb54f036ad4ec2daf239c0e04d414bbf25166360946d4f2213de84a5d3aeb9ed90558f53c56086a5b8cdcb6dfbda16fe4f8200878baf65485ed54601141ee09f441fe10da693d25e2c1b46496f0375dfe127a012950889bbd689569264df770e91b5edfe8f916a307402baa7a3618dcf324d10055c27024d7bfbff2e58cc6e8972c0d9732d83bec60be11d76b6ee4885487be287c2ebde1a13ab49869101b84c6e26e93964737971f85f996c388fd023ecf2b1149537b8e05c03f86ee39cfe9bb949d5cb99c173b27e77bd6253f587219ae81ebca20666a14a439be59d32e44da90f1751a9441505e140c17d0434c4153ce35abd5e921a1b9f9907b49114ca212f0f9b4efef8e95087b3be10", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd00585cf7044e24461913521058e928e9f067e98eb48fc7d6e6b3e882522660f48debd62239d1e5d9526d1f6bf05cebc3fb7976636c99b8f5f4e957d7f6d9bcb9d2f74e65c61ce9c74947b8a92c36484efcdf486b84104236d97b6fb9655b14de113b138756e0156b1d995608cbbeca0ce4c222f90417cf5b111c0dc6c67afbf36c65f703b9d8f8d9d146c1db66d8f806d3a9f958d90ce472038d1363e5af8d8560ec85476672d859e79546c193c2c036c35e48350eb6165c9800ce4886c7f460e763775140d688d85dced21f948db17290be4f365abfdcce09e640ec11c505d6056914fc69bee7af9ea76d119115072d09416e10aa71a89b329c3003148f91c203b3cac26350c063784c0d380d22b252692ad80c9be131d819589cc1631e982b55f8c4a16c3e7673bef927df7b4f7642c039b9b811b1e8a7fcbc45abf5ccd2acf396245e9ea733d9c546cd5b8f1b110b5adb9158b5d8a8597996891b91bee46c4e60f4639487fd77f8d8c9ca6fd8efee1fe9bf1a1b052bafe07b3688ef8a85b45194725ca3b6df20daef0cd96f4e6723fdb569cdc6dff0cee9c442acc7c90373200e369e725db8f84badc69d78e04e0f30673b69f59eec3d65277bb230e7d2ab5e6ac35878ca476dadfad304f77e394c8c31f214a8c6e1602af2d28288838def4af6221bb0a784f30b52c63234331c0033b9786172995cb44c2d785859e7117d631ecda3c9e56501b36572d1cce0b8b2812bb7c0c5f3c0ee7eb023db8f5d5f9385bf0f3bb23172e162dcb1830c0ecb819dbf261d2b2b06c60cf77e31301818ec8897308612d8118e2b966158c5074f9071290debf3199796c0b10e5430859d978f52b39c8df764638ce7e91fcdbecb19bbab59f9e4ec8480efc5c7deb9341ba30cb8c8756a5e79faab8ba71b12ebf356bc7cb683d218698c3eb2728d7a51e0de2fe56c4e1a9f81c5195844cdfa7029789133d6e04684528ba99c1dd79d600e7cc699a5f166e4bd2fbb962da57cfdf7295fbfca7323d235561b1a86db88f433f98028fbbdd8d18b8c6de062eff4397ec6c3bfcb6eca78f8d9ed28838b672b9f41ed6d49e06517ad8c975b0e6c63951b92d7482050dbbe1030be2746fe9c8dfcebe44976f7f63d36aae9e56457ae13821f779a97f2b477aecb7a39d99db2e0e42f676d643d5d9d103734348484ca489efac85b7f8fdd0e3238795ae3b31d3bcae0e4d9c65b1b91283f3707acac7cf6b4d83dcb9beced88ac5aa3e0addadb8402f73e3b66943ccbca4156febdb723d1ca0a7923c2d944a068e57b43a28037de78c34af9beac44441badd05bcd9650645c0347edc4cc3ceb576e91545cbf320aec5796c0c6cb252e8b58c87cacf74772e942ca639c95bfeac9ca930f2b6fd5ebc35e4e16d92b8f8258f8de8a587656ec0b0381d7aee0deaf3cba180fb27e928b8d7f1b92878330704025171b3133966158d107b950e21fb151d0483fd68bb2f13c4efcdebb3676ce67b3bb717697daf80c3e668eb0bbfb6363e73be346c9f346443e935d26f9358c246620fd6b23c48b5dd74e0838ebd3186afccebdc330079e9fcd2ee3adeb5dd9beb57eb91d8639f4f7b2f1cc42e4e31fef7030073ed69bc5eeba828b4662a5dc3ce49c4bed3cad9732a79851b764e7ad7a4b166e45a49515c540e0e70db8f78b9a5d95672fcac2f3868436ea7d764a3e1e9ec64ecd7a9f7dcfde4644f69603db597f6c6c7c6f486a88a20c27c82e5ade62c539d2b14eb1b1b151dca8c747b20b4457ce50e95f6a213c8487107eb1104218f907d40008aa78a7fa7d54a76eb4ddff01022b3b50d531b4bd3c6c9ffb54744a471c1f7d600acb4748b4612fcaf66bb07c84c491e58d08c7d31ca7758adff2969fc98e2dec9ecdb806eed90935d9cdbf8d089ce7cd012b3bb3b71d919ff5cacb67bd1de1ac3c6fb151f159d460f76c06b5d9c9bf8d1b756dec7b96f136eb5dd979d85d2a0f6177a39de7e90c769701163ee3cdaad7086b1d76978f2cbcec2e37ca082a519ef460e12f37ea2ab1f057e660e179a0ecd85a9d10f08d37de3863e5617771b0f1d9d360172f3bb6bc25b12c9c9d109695f53e0bab10ef8d37de78c3de95858f1d37ead5d8a8771dcb30ace68b20c8b8260858c639a52e1c1f21c1c5d24ef111125b2c5feb9da7e29f3ac54743672c9f87e5f30fe6c9f806ee9dcf579671a7f8d9777e56e24e71ec549f9fbd2c6adc29b6975a6693113155348a2d8c87efc38d48577e262362b26814db77d871ac6f23421b05cf5b0ebc11e9f3f4f341c6b6fbafbbf2ea3d0764efaf2b1971474363ec8db64fdf2965b8c39d7339fb7e391bdf03023ed80f9ea71f8410c277085ff7a9ed8a83a41fdfefc87bd7db87d5e70f4cc63fee6d3f631bb88c6be0f8f0bc11e1bfad88114343434858aedca84b6d3f6b8d3bf5de296e549fa761171bd5a781bb9ced7e76ea14db7ef634ae537d9b4ec1f74f9d7ab6cf1b11789ee6e9d811e1c30eb1a2f69dda577190bcc7bfc70af42cacbc1179f53efbfea3abcf2dc3b082ef012163cb3f2e67fb19edd4ddb1830ceefd6ab67fe133d8c9c0bd2779f78195368acf8dbad1f2793a7b1db4738c254223654f7b5db41a0ba9f2cc58212c4b048d7def6f2ca4ca1bb24228c012a1d9f73e89855479435608055822a67def9758489537648550807deff376240e0dd9779ece5a6316f27ee1b9517cdaa9fb2c3c3f831d6d14df001c3c9f3723b1517c5869a3f83c9db5f6bab61a0ba9f28e2c11d3bef7371652e50d59211460dffb6f4bc20dd977ad536cfbbc1d7943f69da7799aa7799a3b6e149f7f74f5e12cc3b0ead74cc8b8b377eed4e5bfca8de2f357efe1c8f868288b652be314f7cee76b8715cf0924b081ed4862870d76bc6007d18e26762cb143043bacdc607123e6b4849396d3166ebc9caa3871e106891b2e272f9cdc38bd71323ac5e0e6033730b889e204c5a909a7304e699c8a70dae29483931827259c907033c68d18a72f9cc49c6070cae2668b1b199c64706374bae294849315272d4e29384d71c272da72c2e2f4821397d30a4e46b849c18d143747b8b1c1cd0a4e2d385171bac1e98c9b2b6eacb849e346093748b8c1c10d18a72e6e6e700a7393831b2ca73127346eb2b839baa9e2268c1319375fe8b0818e2e74b040070a7448a1230a1d58745cd121021d56724c21c70f72f820870e723c91438a1c53e430418e15e44022c7951c2cc8a125870872309163891c45394e90a304394290830439887280204712393e90c38a1a266aaea8d992a30539a0c831829a17e4a0a2a607353ca841a3264ccd979a1dd418a1a6083567d444a1464c4d126a745043468d979a316ac4a809a3e6a826073538a8b9410d18355fd4d8a0c68b9a2e3550a82953f3841a27d4a85143a6a609354ca85942cd989a346a945063460d116a865023841a30355ad418d5c4a0864b0d0c6ab0a8c952b3821a2a6a5850a3a566a806099a27d05881860ccd156882400386e68826063423a06982a6c8e405531a2625989260129343095319a621988460fa81a908261f988c603a328561fac204860907262f4c39303161b2625ac274c534025313a6221314a6274c48706e988668b8e0dee0b67033e096e0ace0aee0ca70643822705a3833b82db8257043e0bae068c07dc1d580ebc2bd807301a704970417031a2f252d94b0509a42898dd20f4a65947c50ea418907a5304a312861517a42298b12124a3028e1a05483120d4a5c945e5012532a53b2a25445c905253325284a2d285151ca526241490525294a29284551c2527a22c71a39a49023082432a42890a020c1b86981bc414b2185208330b77091995c90605e0a4820d0947858c834ac28e218ef05d40bec8c6d08db147678710263133365900dddec407b43e3828e14e87081098c8908a623481ee48001e90425296c5694a2b0514152e30941cbc2037331a16dd15e8065416b436641c382a56563827585a665930286054d0bb20d8905ad0b1207528cad0b1b173418685994b850da028d0c342fe8a0622333b398d4d88a484d905728898084055217485c2831417aa3648252094a574a564a232891a0d404c90b252448674a4a90ac281191b2504aa2b404e90ba51090dc206d215d41d242aa82b485d210490ba50f948ab62f6c6f6c5ec0cec82e110b9a313824e830c125462301d7028e0a2e0bc7026e059c0ab8293829b8147051705838147050704f704e7027e04cc09580bbc291801b01d7046765fb624282fc9265617b02cd1539aea8996283426cc2d6846d09252d6ab2b84470b540da407e41aac23341a4822483e2e01282cc813ca24f5836b0bc985f985eb08e60696115c1e26219c19a811503cbc8ca81c585d5e55db9c06c417825b096b0426061a9816273c216856d8d130aa41b3456686e44367264217d604be202c26b43d640d240db81e9035710b42f190ae812b4c804021a02698576665251000294b86c65302d4432da15b42dc4274c16c432a51cc8323228a4971c2ea0e1010d0ba40f220ce211221a918c588337021a324848481d9c8440f3c635841a159c88207bb08560e3c13c7319c134c68d9653960b09a6135c689c68d044f207a72e27179c707085b988707a6203739a028d12d7112e334e5ee40e6eb6dcf4401b02978593179712e4183749387d7115e13ae34ae30ac1e9cc9584e7c48d0ba6164c37c8518546849b2f37594e4edc8cd994a0e9818e2c330b345fa891e22aba51415b795b785a78675e17bae871a197786ebc2f70629e173a0a09048c079819580fa20d4c6ec42f3427b414684fbc275e14528bc4426e79287858de092817a635280d62112212a2111e1498179818980da80d30286052c0ca6c576c469b969a12d47ce02de18dc9d6c8a4f086906dc95e9069c9b0c8aec88cb22c1e99a7c66bc273c263c22bf39ef08840c30553156a96a0d9028d174c44d20b19c6a606c5723aa2516c44263126166417346ed074c1e404cd0c1e094a6be8009921865217f207d9b3fc3229ae863d4340b980132a507aa23871923d08c4941e274eb09213a4e9841f9c04818129477e7e825800d00f3d3f3f412ca000538d28401998d2f343867b7a30e02408202740513220a5a7889cd9041ee2470a14a01e209cf4f460600093091c0406a64871c2812a3d1b10c289142a16684a8f06380045c9e712b8e78729414c7102c589142ab6e7872941400068ca0682f8e107db638e0122881f7a80f031d3e02138d0e3e364882138d083644a10528618a267876e2a818b9042c556e9f1a912440492743309dc03040508293f508870d2b3819e0d2c6102444f063200854901a6181ec2e7879e283f208187009ad253a527ca14299f479822050338130dfe41ca1053a4540132a2c709077ea85081e2a44a0f103f5236a0f2f921881f158f198635e0040a101420a000f53cc0348dd001293f50a40049992205c72c02fbfc10c4cf059cf4006de0871e237a68e6195c25880568d30c1ea2470a90942a414401da00949a49049e12841420285536008413a0207e867022858a855265031607bf9e9f0b40019ab2010c3801faa1a78a1420a64871e2e4e6249d6099d98198352caf323e1a1ab26f056fa6048204c2a3f2ac88923812070747a2de91ee86dd1d734ce6397bf69c314743eed9b3bb27430821cfc90c19ce397b3237cf08992169428e1d61dcde9bf23dfade63d28c0d69e4394b724e4a699c909b21ec1821a531b69cb05b36b4625b1884d3a20d79ee808f61f784b1fba2b129166928256dd122417891ba9b27730e3c4f7342ca11ce3927ed86d1489c3c35d80c59ca09639cb39b526eee860c3b36e59e936384b048c3192343d81d3936ec8eddccb479ce48294f9e10ca375f7c12c639218c33468a350c1677f7cd6c86cc1d69dc48346234d4b22c0869f784118b3c39ca388940d8dd9372c38e7332604e1f944208217d4f2e40657df8e091a539a79c73000a480094a528e99c1b9c1300b22d1863c4228c11f2cc30e6f81ed3664a4971bb8131d28e50765318692643d8734ec88d31c72e6103d010d00db9fbcd3609a071389d5a46192964861036ecee9963486dd6b85b6be68ea6863ce764c834326390a1359b2d0819c2ab27cfc973b62c45481b8370cec9b1e54629c5688c0c29e58ecc32766bdd0280010880061ff39c9342eed72c0446ee788020da0ebc98999bad668e23737ccd29c81a37b786a3e164d81036842fc61f74ce3921a5944ee6f998bb5fbfe6d8b1bb6733b3d6ddcddcec7ac78e7edd3b1af67b94369c0df975c3d8527664c92c21378d11c39829a594421ae3b6c56d8bb131ac1b424a69a411420a61a4146b18e86c0899b70dc36ee6ec6e8d764b08219f206dcab01b2b71cbeeee0c72cf39fbcdf9bab5eefe0ddd0d4bb31bf28c5b376f36c026f160e6e6594384104a4a298d108b588c3132c7d90d9b69f76c8d069e0c1b3673bfd7ddaf23ece66686b09967f79cccccb079ca66d8b02184f0c1ee9611d22863ebd0a143070d0dec66669e936173ed1c0d9b1b360e1c9ac675942384102bcda0c3cd1d238410461863bf6e085f776cd8b0bbdbea2827ecc9eff50e2b76688134dc1ca81284067a34306500a2a74a0f1055827092ba81861e2955800830801b00ecf0f901ca057e7e8220800176f400408f9b1a0be80728434c815205c80990140d682008944dc5314de9a14205cae319340000eee9a982012755820082f243103f3f507af00c1a9002346503552a8701a00df4e889e204688a942a549cfc3084140df0b021d5c388208a000240ea061a6a82d03083131a7a7ca0fc5cc04906a6488932049428ef21a2e7c789115034e00307cf9081207e9c64608a940c6420889f1bd339237a809822c5c9142950a2fc80010c04516bf8f991e2a303648801c4c03400051104aa003c03949e2a363d3e4e808ce89912830d504f0606709e6108a021a418d1430002300d4648c1404f152a3aa62a507a7e7e70d29301285582001ac209103f52a2fce004e867035030d003448e0554050ad01003a001861c9ea107084a959e293d19a832440032a601889e2186e8a942450341fce0a44a0f1141fcd053c509942180f8a1c7c90c3ea91b68a0f243cf103b57941f80a05cc0499421a44c9182011411537a200f9ec1c99420a40c51a58708271cc080942a3d443839c00c37dc4003103d4e8200a2c2812a3f380132a2070622a6f440026c62f4ea09f14a4848086e4f566ff54a4f566fb512128a500ad1d51412e228b45acd95d06a459fac1e26242424b45a594f56b09f08bd9590905014824f564f484868159fac9ed04a28e395503f5909bdd57b22f48456504868d5d71316c256123e117a4242fd64f584de8a3e6121a17ec242efc9eaaddeca7ac24242ab557c22c4abf964f578259f303f59bdd52a3ee1d56a059ff06ad54f566ff59ef0ea3d69403cc263e6a78121a0708d05111398c802460dae64f9284b18b109eeb27c94a54b190eb37c9425065e705844127096e5a32c2e804c803e60620b32381e968f9818021926d8e823703a92c882c331451177dac20a67c30378020e87e523112401be400456a0e24bb47c94a58dc844185844512d1f3521848e82cec9e2fa072a864edd9f1f9636eab51738cef291095860efe1131c8de5231334615b0bdc66f9c80443f6a833ffb1c3f2d1125c284191bdd7812678325a6c79769dd4ac14430759acb4328c24d4b0f23c7a878f86868642a092ff81823bac8a955e58706ca9eabdc71acb475874b19be5232c60c0f512322e6dc171184970b126cb61108d41edc95ecdf28d218865f6f22c43940d3c9d8ae75b61b877eefdc4a353f787bd56fdf9614f8d7a368dba42828882a3c90213c022b98512cd9d6c4e58ba44aec17bd65fa558b240863bef53dbb9276b1da1600c6b3d5a5159b7390b616bd5fbf3a35e6ab918706c2fa742411998c356727027aa1e4f0986600e5b6a6d2c3cbad2848527cb75346a709de5a326ac5869f9e84a91fdf1acbe9cd0ec45e90c0d0d81600817a8e1022f90f8428b211d1d1964424460238c218821638422605154c0c5901a4c3063884c14f69e8444fb3e3434f40115147a600519bcc0a88c2b584145ed3b077756336802044e30610844c86204aaf75bdede4b41c6bdf386868686865457c7b2ea06e12f42da06810232446950a1093ed0a2e2739db22c1fc5d33b51c5e72519c31dd8e7736fc8b308e8c212c0248068688baabbf8852a6bad3b1c267d785883104074a4eacac19cf7952ae3ee7eef41c817e9ae2ccb6004318654ddb14aa8dffb0074c2b22c24f1f446e2695d59483b093f571602b59595862743afe47b6874bf779e6e8d3ee3adc8b3b4e2e4c096de085b5a7784c1517b9f154b0fbfb256f7acf58e9790a7ad95951d10b4b1cf0357f2bd30598c314b8c53c48825462762bc12637d567a3ec6a6b45efaebea900ef9d8491d770e56b58ef99a66b17ae32fdd4106476b76598f96f269736f48e8c4e8bbfa58168d334609392b4a79b2325add8d9a8d562c122fa768d62756fa5672deba489d0ecc81b326d1813b605801c3eaa46559e99475cbb2ac58e75714e39f15596fb41c63dc215d07ee90eaa3accf60c0c1df07d523d0ced859898f973c50c6ac4946989f5dbae8d285349dca739ca9ded7459757c664e2a28b2ea62eba70d1459757a60bd2bc3a96ded745d661bf3ab69cd5c1d59465c42fd04b1f51302c17b4be2eaf8bbddbadd3dba7f5be2e347ff566379d8fd1d0775a6f104bdf69ead5b1b474ca5ddce97558af1affde4d3f9a35c57a75ac75d2b1bb3dec3d5a53f5c9aa299b5afd6dacdef8ba78434c26ab54efaafabc575f174f86d9c5522a356c3e4aa99435764230f60c6a345dcd67477a967d76d969ba9a5bdd65d19ca7b38c7e7674d23927bd655996c55a8aaea2394fc3cd083de970237255da31ed9cf9acbb9cd5cdaea63b46ea68aeec57171b957136a336c39e65e73852edd4a8f7c31d1e9df36c1a454fbb74d1a58b52d370991ddbf74aefcdf728e9a49a8454efca924ebb49e7a49fa593ba52bd2bfb2813a18fce47a65393cef71e139dda4c9fef19363b29cfc436a0995ee3d959cb58c976d647a651f23b7690c1917e1f9909d49654a7e4be6134bfd94be7e00ec7edd47cdbea8db6ebd5ec56ef8fc67d3b4dc79cb355c870a7a6c26e07191c567f348b69955fea7690c16515085aec7ab45ec2aacf55b133e9fc12e9a57a9f1569b7ea433a76ebbd21c1aceda46dcef9b4f346243b4fd3cfcb6ecadb8bb292d2396dec94dde4adc8fc75da4db1b13ef3d733a861dd75cbfae14ecd690e9f6595eb68be75d6b7f346440b779e8e9b0e3537d146cdd774349dd639f33c70eb2c9a8e8339d7a7a9e3cea139ef3c9dd10e3bf6d95d1bab59ec6f2b721da3dd3d118eb32e621dbd3a8d47a3dee18e4de7bc93b14ce870637027b186bde523a22c36e3ac35de6a6ade4d4d4dcd79fa6d446a4cd7794370dc74ee94e9382e4fc31b82a326c151efcae2b8a9a3f42613a5a6d3c38d08bd398eeea6de95ad3199fe3622a68c3b5553efb3a63395a7e1d0894ed14b53476bbafb6ccd697832581a33a517876b83a5f5ca781d394e3544e4e10e8f8e1c27d9cd7bb103b07c148229ccd81bcb472130c36650935b6215304b4ff1acac58ecd47943d8ca0a9d68d4d4f17779a3cd71f98b5dcaadc8eb711ebf146747bda6d79c3b85e397fb761eb8d3a33e8139f03c2a4edd5119e6f4ef894f7ce6ebcc3b7f227faaef7a4f5cb3ab5e1cacac941e47c78dba382e7f4a43af41aa9de636f59eae4e3b7d4db7830cce5481a4ada1a9d786addb4106c755a0b635bf3aa8111ffa686baa8fa9d6fcbae9578e0ad417ab9bb45af531bde6350f877653f5a197166e49a4a59586278326697832486965a5f34684749e7e7f9b11ebef5af72c5f5836b76b46b6cf9d273526edafb360767fd8f927702776cebc466dece4c15d64fbd44aa42e6e9dd6a877ade33a1bb873ea9cf7acde130adebe203b2fbb6ad1f06490979fdd5dcd46c53aa4a36ba030b513646cc6e39dbacecd1d1cbdfd755b0629a514763e16462984936218774d49b07adb5a37d5db163e323a0defb356d786b7def447a748e7ebdddd661aced9fdcad83b1ff7fbc840321d23fc9cb0faf485d1ce38fbf47513eac01dce8e3dc0eaee02c197badf4dcf03291932f6226d464cefead3a7df4c5ad7d068a667b186a66fc23622971336831ddb6ed8d1c2ae9bcaaeb9eeba4d8783edd6cdada5cd63e5e08e4dfdf6d7a548bad1d24aadead3df4eb3fe1161d7fba375bdd1065a5a7dfaf3d76cba6373bad5d7a7dd0582b65fbca07dbf40d06ecfe626372d1e0710b4f45924d3dddddd361d734ef311d7356148ef59b13c3ab55debdc73ce29df9d4f6b734a39b5ea13d962fbe435673d50db08e7a4cf9e3679c68b9eac0de5d9597f9d75263dcb62a51ddffd17df0f0bed7cb40bd9c859778cf48f5686b1bb8f7ed26ba53763e45eaab7ad76aede7e56ec24d54b2d8c1abdf68844abefe1683a70e7a563313ec6f957f486c4cf18adcccbeb56b76d46488fd527beaf912eeca558ca26e9d89cb5546f8c275d60d88cca69b58e2d8d51eb9eeded48663b76fc64b02ebb9875d7796016b5c7c41bc2637efeaaf759c9f66d117270c754b773a762e546698f31f389a7b77e356bbdedf1d16e15c7fa75f9c31d1dad9e5e6acfae53ad62b774348d3eab8f1efb755dcf8a9db1634b3b39add5b18d31466bcdfa987832c8486aee0a0f422f1974e20d5d9bcbe3feb08fc6a0d329eb5abfae0fbb7e765dd7f59e753e257a5d5986f377517a789e7e37307b0962b4742c834e3cc9eeb3a52bdfab4ff6d2e5eff52c6ad1864ee1e0ec2ae8c1b3ce83597c2e08a1ce1b026f412c0ffec6a2bfa5bf572f74c2ce377d15eea015a86df67e4b15a82d3c9571d90b0ef69df9da30df05bbd7ddae4f4ed7741ccb717aeed48e7758efb3d9657771ea554bb73e4fbae93510c2cb779d775d17e7f3173a61fbfaf63a1a9e0c960dcd197212bef780bf3895c7b5cd08bccfc379b625d12cfc93a755ac5eaef6a8d7061e10a7d26059c7362216f462b3ac54ead8665956ba74ecfbdc8cc0f7bbf91dddf69bce3a0f84af19ee1ce6c49feaa5a6eba897ab798e7ab8c353fa85c3a6de534dbd279a6abae52a295e34c39e5d192d3dc32a7dd61a0d6fc87d36744ade061cace4bc582ec3ca7a81e4cbae2cfbdb8e942a0d4f86ebf25977813adaabe2d05b9fe7813b4f604efce9c4711c4fc31b727d4a694b27fdda60adefc84ad97d4ad8e59644b3d99f944e69e9972b5d27d56b839dbf27bb75170d6f48761dab3458d009fbaeebba687843966158ed783a66e0c56a96e66084c08abdc1f2911266d88c4b5e707ca444151665f9280937ec91125cd8ccbe6b566c161b9f5d6ec7089b4e712f9dff9ce8d476fec3d229eccc3cae6efb76ab9bf046c09d1e8239f034cfa029cbaeeeeeabf3a19c755f97d55912edef3cad31f186f4ad2b49d7ea6d4b4faab7eda559b19694b25a96f6af9455caae3ed7e9e5ef8fc619d4783302ed9515fb9bab20a167dd23ac7d57c362ef3cd6f9f485acec2eb4d0c2672b6bfd75127bc72a374a6a57ec056ade8858550868efb330c96ddbd9c4baedbb65d5ab59b1f3d47aec14e9d6ad6b59d67b57b4df579422fd3e2b769e3724f28d75f7593be08e1130073e805abf2eaf77bdd15a10be87e00e2cb2394d0f59f8807759ef917779f9b7257997d6b5a23744deaacd036d773bc8e080daca0bd457b362b16fdd7d763bb719a1b9ac3ef2fd124d779f7d1884f035b78112870dc9a2f96641cbc201b15887b76c6a2a94a7d1c0b0d9d5b195f2ba3a79259156f693e16a45d6fadc8cbc6f9f9d3c0f2475a56b1df7acc3fee6b7eeda3ae6464dd8c51b017760d1e333a74e4dd12969a46d291e16c11d8805e6c4bf7aa97d37758f76d7b76d74fbd56cd69ac6c41b729f7d43165ece673b76ec8003b2ecf50b64617f3b76ec80fbd1ec55b15fcfde7b8075ac5bdb3aa7bfd5bbfd6d47dee5b7ee46fb2a0e3df679fb8a8d8758e28558ac4f20cbbe5f20cb6e27fdbe228bdd1fcd6ed77ea3c54e3723ef3e5b766b4ba2d977c65e6ab75fb8c5c6731d376a7ba98b8ddaea05b2ac7552bdbc3d7ed3aac6c41bf2ea1d6265ad67c78e7d6e4430cd8abd3a96d3d2cb012b9ff1eb265d0f586975f2bc1d9156172d3d9259ab6a4c3c196695318b651856344f0751c6bfddddbd80f7deb3d7e1f0d9e2147996df6ffb2cc7efaf08ac9c5dc15704dc813bf3aad931e714412d6495ec9e8ab724f409f50af66322c26725c88cbaf0ddf780858fcffac0ca15d52d4008f9fc572f3f42c897870c218410c646f1dbb8cd4a383e18087f65d9f206801e3c7076dc9c74e4c061534363e24aa44dcbb08b5a5346d88f81f07913e2bd61b5c0f334a57c4f3bb032e7bcf3edeb84deaabbc964cca91861a37848fff2cbb8a35901d796ffce1b92677db8d227037ff59e91c7d164e4086b348a6de418638c31cef8e980d58d36561fae4cf757362bf11f0be98e19c8ed2381ef276b91eed8aee22382ebe55ebdf35766f25dbe65a58d6a0b09ae7f350baf75ea55e694fc7da7342be0a27d48a0f581afa38d028af69d9f125ae0c36d818dd84528e59c734e58b12f9a1547180ff88b07ff5e8c11d688650a5d06e3d20133f28a8dcfe4135c0fcb0ce4462ef24adcc2c6472ef20a0d22177b65160058592f30399059e216f6ca2c5776f004105cb118171d88e9d284372ceb9485cccb5f2c845a322052424745b90679a2eb4a5c8561560a61dde41a644ba1b6b44a0622a7954fcaab63be414acdca33a2c6cd865848fd6832a08c9a9a9db463ce99d408faa3695c9b699ef2d7343f2039521e403a611226d5b819502c3413a2fcbb64473fbbfbc44ecbcaa4263729ad5fd7964dab571e7bc6591b92785aef9138b1f27d1e885df4a23ee845adf7ad4a84b4b3fac85aa115ba3949a9654929a1203baa71c55cc39292ce6bce296fb194d845ffe4d24e1fd39a550766510418502bb913977e5156927e75ac9440d38b9aa34af5a27448f5ead8cb05d9ea0dc25dab979a389a6357bdb74ae04e4da5399d4cf5725cbd94d2eb97b3f4ccd7efc9523eb2f23abd2aedeeed6530161e6896e6b4b10ac5d5d6328d2baa10058ca512d7a954bcf17143023f0fb723f1b3de7e7c26a5f48915d6b88336681ca2daab57a8c8be4b1470f761b9ef8c8d46da320389e76d49ab18e65c2e6363ed9f77c6c6f73dc547813bd6637d59de992f8c1459f97bb265eceda22c4ba0caaa6d460cf77ebb88cdd8db4554e3de9978458ca277260e0d65f20c07696b509e610115a2788c31c6498d1025fc02185f322bd2bfb7119987276b71d6a2d63ab3552f90b4f3b1ce2ddc9c9c718cf135ab7cc20333a9c9edc8edacb151f2cdd6e3b46a04923ee69cefcf4a84b4b151b23e7b3dd88694724a292512a40ca6946f763fb0a372b634c2a41ab78594524e29e5648294116ee18863143b1f67f773b2932d7a7a414f942483aa12ed4571a427029c81c519a72803ebf0590bc59083f20c77b4cb53b8935dd6fba36375b451587096759ed6ba738e7cd631e75c94953f9da48e95546cfc7b3ccb279fd29a96557f7490e0c0e20c2caca496373945c74628d42bda300a52ca6959cf2ccbb2a49c52ca9e3840bd6e31aeb082e498ca471632a195d288931b92b673ce958df3bd118933d61b64633c3c95560e6c65058248a635a18d95eb2a7036f1fdf778d8878a36b663926825915927c742a47598036dae38dcd18139f0f0f3daec4e8dd269143c0438ed57c7c2b39535329068a307acb711b1a255d972dbacdf934f6641a719aad50bb9d8be0c4dbd703ed9b56326285c9d0d8d82dc34d67b7f7e6c76eb3e5aaf75ec3cfd63c35b11edf45857b55bddb5d17a2362f1b4c5966a5eac20c632162c7b41e3cc75ca7db1f4d6d4783b922de976380f1d93675697430e8d823c5797c30cb88b0145baf4a6439fc97bd3e17d87f7a603ab88963cc9b397617f36e09ebd1808766e54569574414a9ee43a74413a7c49fc01383e82628b65cb585aa39dd28e69f5ae2c8fd71b8968951b45fa5675743a08a625021d5bac665db2d6b0ee59212e3b86a54b1f35ead7e51ad97d1c8a2f36bb0f2f5e10636f2c7bf182190b4591cdbee0f8e8893319d568873d1b7a1add925c563bd6d16b9d10ef0d225992af544b3a1c264b2e814ba0062df94a9575e96181f800772670095ce7e145ae31034e9a91651a45abe02af02bcb5ce7f1ec3e7c1cbe025dc625760a47fbca6a3f5bed1d778c02b75129b89b71b15ce08e0f879765e04ed053f95071b4b3ca876b3e74180b68c9f2185830810540b7830ccec7b5ff19b61179f5f19acd012bebe3bc3da07b769e7ef72cdd9064f751719064f7711fd5a7ab19d191584fb03c4e493a1c2649eec37da84149be5201c094e1f8d0322e16da340ac7472dd2d647f66c0cdc2182579c08c3474e8479f6264c56668d1d0e7334343484840a3ef3f205ee3c15bc0f2deb8ca021864ba7ae2c63b9e894c9c2b72c0377322cb2ccd643934be0bc35e1e113f8db9a34e012f8db9a20f9046a9605e6c04ba0cbb63cf8de6349ba3ed80c0bf6f70577c49237f91149cec36fd6e5facdb0589815e1fc6d45da66456964457688a7b18e7e49c7aa24384d76d8e1ac6ad2e13461c2e4acca2ede32220cab59972adc8f46c1675d7eb3210bcf03b34bcb86e033224ceb2d7ba6694bb227e95895bdd64ed4a9acc2674319185b8783fd59ec11e870b02acba8e41a9d037f7d81cb8e6ad6a55116131c8f7a5deb2203c12a372ad334abd3b4243df4831e702635888727f90edd92f3d6e43d08025f5283967c88023f62c95f926e88023f8287f7e5b6845514b895bd6d499f87efd0bd33e9be4488219ec55ef2516fb43c7834ca87897dd4ab591ea78de271de7c9c3be5a3f2388f8a9dc1ea12a99265a270c5f638ceb32e7027c912a94a5295c01cc896a405d75d5848662f52ddaa4ea36092ac06e1e92457cd616e49303b37260f384e93d6e17d56cd8d09048ed3e43dc993d42394fc9d553c7049c72a1e3a56f5e870ba4b01d05dce52a00b7a2a075ca75136340a5e49c72a1d3a56bd2d8746c15be73aabde6739a05fc74c8f5b127aeb724b42cfddeaa874a139bc45f39b75e97220c3431549c828a96207314db425623a75a7e8d435234c936c0c0f58962409d3a9ab4587319dba5a941c4ba7ae1626a77503b365e9d4d5b2c3adba85e942e4f019180c387c76b400d5e1b3eef0d90f9ff9387c0680c367653a7507f02287cfd6e8d415c08d98e9d43dc0b7326d74ea06f9b64676c61e3e7383674801440928c2ac5c57a813d6964eddd477b2e8d4b5e13770a9810b1aba20000c1c0eaf1d0d39bce645c8e1b52fdbe1b532b4c36b603433ca74eaea7c86c36b6b74ea1ae0321c5e3303e4f05a1b311c5e3bd3a95b7378cd8d4e5d9bc36f439dba380ebf1175eae638fc56d4a9bbe33d0ebf59e9d4bd398fc36f573a754fc739fce644a7ae8e6fe9d425c00b70f82d8b4e5dd4730ebf71e9d4fdf1001c7ee3a253b71e86a0a8eae1f046ba22ddd685a6639bf14653efcad2dc47d73939edb00a3ceb360a1ca7ebd1156149e0efcec31f84071f44786040bd9487edf532e03e7808729c5a04c7c30070360b643c1c004edea41219d1bbfd00025840bd3e544d007001704d0e7022231ff50ac06240bdaa1f80872094870108e03e78f0e1a3deee00e0c107004e64a4aa570b0f3f4093203c7c004d0e10e4444602a8d7c717d0d50b80ab7e0b34d968139c0c7bd784feb508ad49772d4d8e6381adc9330b0c40002732c2eaed4e84d6fb33e0577725a1e1e27ca71641936c2732b24978eabd4e9360b44712fb2d090d3cdb311fae7ab1d324b72a702dd9f90d4b7abc861a149000cbbae135d422b8252732a2f5eedcaa4558d452c06ba845505b6f0d344902764e93505a6f762b09b54e64a4807ab524790296d490e434d422b81a68a05780f504fcf221bba1de9df32ce94197dcb02dc1eacd7e2dc1ae1319edd4ab65c96ff0a1c792e3f8b073c3898c6c56ef759e6b9da6a41219dd223786cf508ba04a7a9cc8080138d4ab6dd90c4a62a8d7c87b288901871edf26a0d5bb3d53f248014d874a6474117065a0330ca937bb2624c619ea9de1406438915156af10abc881d422a8917a81502543843c5392655149164f6454a45e2d4a3e4407204a1e830e4062389191907ab30f8917726d0208380e3acc4075c04187ad5e9c6b3a6cda898c1050af161d8ec30466d0e1324c6006194e64d4a3deed08a8573b0ee711811d60a845505aa4003c7076e8819343016a11dc0e478af4a84558b6de1ec7d9e1a4ae08cb6a91000f2695c8e81ab9390f402d821620003c72904805c8a9b7000f402d82639283532f0e2b87e7d801861fa945d01d72e038ce0e3838a41d70482732caa15e2d3b3c004c60d8e139980400861319e1a817e73848cf711eb508cb6a89808d116ab53029006552a4e6364c7ad46b731eb508cdd624888c7af0389191917ab53079910814a05e2d455731794e2d82b34910191520e7444635f5f6788d4dbd3c6e731e4884010b50591e05240001380c117280eec78374f53b5dea86ce86a7eae135743f4e43573f43a72343678056f57020dd8fc7d0d517a023404e870a82aa1e2a91d100ea36a651f04a5c652480ba9169147c00ba1f554b040e43572350b7323007beeb76fcddcd7d74a703a0d3f11edd8ef3e86e8ed39d4eea747ceb765ceb6e9e75a7c74ec7b16e47dd8efaa66e5efa54b72f3aea5646a3e09b744bce4397e44cba25dfa14b721dba2575030373e0957449ea1606b339ba8906123d68c3e2e82c1f141d4106d6a6835120f1850d5bd34d118461460dcbdb113eb23475ebd228787953c7d32878ae639b43a913221e8b5867a46df66a75f72f36859a65d15fcbd25f1ed6b2ce03a9104658cbde1515c2b2592784dc885ce70da8ed911e1a1a1ab292beb175e9d476b479d9be74ea3afc5646a7b0c36f603a951d7e33a353dae1b7309dda0ebf89e914e9f0db18b8c32ab895b14396edcdba7499178c82a75d7603cec260143cd66564300a3eeb321e300a5eebb21f300a7eeb3221300a9ed46567300a7621b1d5d8621ddb8baf35b8db2c70c15e7926862bcb58f8b911b12aca09eea232335dd605e6c03fa0cb8e600ebc03baec0bcc8147d26561600e7c03b231161e4b82bb5917ec035cecb0107024cb6364018cbdd9170bb32e16ee18631906a11c2b23cd802d19ffa0b08341fc0d19c31de61e0f9391239cace03898f38e43a77090549cf808bb5e947d279a028eb3d23fde13b853a3faaf728dea532b383ee58ec29c7e8603bfb2b05eb691af2870b77d440331f69ea680bb94c21d7eff0807f218866118c4ce9d10f0afe3672f8b4c1fa5671e52453b10b5daf91a8a85f490f8bf21b12aa92ce4551d18887c8e26b82b813ba4cbf7007756aaa8928ff2d3a9edf254808c6021cfca1fe114d5b1a153d7e583e0d0292c955d9e019d8297cf81855897bf4c658c92cf66f72ca96332aaed7143832ec14a86827d4b3847fe7d6e449edc886cb637250c44fe720237c6be478ef145d25db119f6b1ddba48ea58d59b116a99814cd801354a3e76511a259f75541a258f753f8d92bf3a201a254fbb278d520273d80d2b39c028792318086906b35e06631fa98b377435e592f17bef0c0ec2282584f00cee6a963e195a4e6d0b955ed983f04208a5e434cda651dcdd7bdbcc82835ca799c1c1c88581c09a5d508344608d316e469ecda294b3bb3118698b62206c517a75971ae98c25694e4b8b2be04e9d82efb662527d08ffccb0fccbc3be30969f43a3b80c0829508c94fbc20cc63ec15d1ca846a9764506c29645350821ec086127ab2604b4b9b46b6ec1c17a350ccb324ddbb48df42c4aaf1f98f6ace0eec932675a0c969fe9d87e907457963210b6ae79c908af7e18ce910c1e5a582f076c5766207c9d13998c7f5cfade29c73a3a36cbaba42db8cb47f785b9dda5cbc01dd2e3db0cdce16ef32400cccb928572271e16b2d9f8ee0277a8c09c784ad94c77e92e6ce685813b6f0bcc89e7e8e985b12f0bcc890d0577bb4b986682bb7c6479870ef1b090f7131a9c1078d03d4b87e0cec7d8fbc2d8782a70e7a5c139f14fa054e0cc7408b0d847592f679f65ad3d2bb8ec0d8167ccf2a9bc21b076972a2c84d6b60103898fcfde1022a8a5bf97653e6521f47cb815b9d4e0e066845a250ce49dd4b58a56690607b3a8bd34f83dc1c647051b9f166c7c6fd8d821a04330279eb61998135fea333bdd05e6c497aed58bcaeabde957bd5c171a8e339d4edc5faa17652f9b59d22a52ed3230279ec48583ef5f063394a58b8d7f5928e5b87bbaa715154f87283764b77a98f36816cb3008cdd5d5a52eb2a73dfb9ee11c998f9f8fa7973130c3f2510cbcd802583e8a01164b352db6685164b3a859ddb319dca4b66307195c671604d86612026c277d337d6421539bdadb8cccc7d9b1bb93a74ffeb03847daf689c8c05dd9b692ccb7361f6777240056763fec08b2189cb126cb4731206333cea2c69b919642e86ffce4f82c1f9e815cfcd8698de21f5676fcd9618f5d00ac855d1da4cf6227636520ef712bd24f221f273f76f3567725921f76fe383d3f17703e8fb341c63fee1cb2f09992274318f37cf09a8b0ec223e4087a0146c2e825ca24c8d98420413af56c5a4038fdd660f93358fe63c7bd215d4d2c03ac2ca4460c591942a64636cb0ce407dce53119d52865d9cd4314dc413d818710c2595b9575e12e8f3923dde8d465305662b12d0faf04eeccc3f70077187292a9356584fd86ba4d5cb8d1022f2d1833c60bc6581e96c7d8e206e462675b1c25da4ac5e7d13f501c3ce1c43f7bd0767a1d58759adfbe525d07e6dcced373d7815514e6cc733588d6cb957e75a48a55a4cfd7e1c42b8139b38a0eaccaa106f1c09c796da57a06c6ceade230d14eafd5a1edda69359aa2c2e98a3301faec4c2eae06197565429fd5a0a7a2978f88c88a23ff2cce9178f9a864ab384aace330d16e5dbbf5a7824b58a53d8b5df6981f2499d0e0fa6868c8b61a60b418b25af7b0c09cf98aaae02e9f89e7e952f704e6cc93ba792a7007fbbc117047fbfc05580811dc9337a4ab16eef33ff00e911228d5f6a2938afb7c4309283a49c1ce33e3501444b5fd3215ec7c86754fa575ef0a7c458d9ad7e94df61dab122222eda413652f9deb70e2b9af545bb76d8fdfb81a54aaefe841a4fac5ce6b5fa9b2acd33a2e38f1db57aa2e38b1e22cd19e3dc6ca24fb56b3bc2b30673e688b9dd71e163bb557047326f62ac740e24d0c24c29c78abcaff98d50772b10c8310b67a7d29915511e2bd61f940f496c074fdd71141ad10d61b5f18b2fd04a704eec8a358c80e8bed5c9f748c951065e52f7fb1f2bd61bb463138ed38b0e24038ebe532f0a41af404e634776db3acc3e193c0e0f0495fa9c258c9d99960cfcecf6a90115726d949354807e6c8077d91190ae6c877236cab9c1848dfc4408e3d3bdcb4ac639803735ed6e130d19ebd3ed6e130c928cc79c7381d9eaa9bdde5238e73f8277a0e65995ac9a7dcb55575600ecbea53a2ab6e6994f18f2baf582ae3f919c31d232670673bdf5b3e0aee64d8af8ee5be62e97d5d1e372409f1deb0d6d631cc391f597aad6398937538f32b15d6e1ccaa84a8cbc01cfa151c9a4d6451b1cae89dbea68863d566c6a80836f8e2cad0900afb610ebd1193fec5e43a5683b8aeb7cb30a43bc4e058a563d435a87f55a3abe57a93c7060d7a30a43a42e8fa55856213b088427584501d8262a4e0c490aadf1587c9f5fef53ed602eeeafa0ccca1ef24b8db652ca5d5475e896864d6b3dbade2f31bd24327cb47593e77fdf291e5ebc01d7a3e3f08dcc1cecf68f7545877d14659c76ac0b1c55142d47f37d96771e483b463a7a73528fbf5950a6e4494101161d7ea9125ba9e551e9863fdeab04e07473efb4a150447569c25d8af33c17e5dfeaa4146b232b99ed57330c77a9075ac32cc59a956aaec6958c7aaab63156f4494509863b1eaad80e31888bc89814898233f7f584272f51a3e818b7556f133ab0be234b4201a52050919f5ad43fb0ea38de531b6e0040bebd5b12f8646e934eabd51ef3550a3dea9342a051c978131e8c09d383434349445f51ea4539c7dc78185b09d31c6eed832d75feec439ef10b33c860f4e60bbad8eb590023586546d6fa3bc212db98c8cd2a967f9880a3016b3ef0fcbaba277b42c409de2a31380619feabea2232a8e60efbb22b350f1057bdf144f75f98c177b1f11112362ca6c3ab4ea30e79da7b12ddc9f1502bef186cdb060e64895719b6c1a85d3671d14ad61214ed7226de559074b88b1d1beffe8141f2d41c6e6b0ef4a7ce89d8bcbd0d010122a3eb2b2867d65ecfbc501aaeeed3d51bc72f90b513c32e2a3268cec65334e6f481b1143a633824698ce081a621ac5364aa72ea5d2a99bc3884eddd34fa74af63dc71b02df867df6b21bf61d76171bdced3d0ecb47231063bb3234193982157b6fdb1a1153a6516c799a0638b0ef5aa7aec7257b0183b12d7fe9e520eb704ebf65bdd4f6ab97b37d754eb691f8b08f38487cd8f75bb66cefab38476ee16fe1af8eedc7ee8deaf70b7fd8a1e07fbc0ed529586fb428e6d46cc21243b8c24e54b56530100966c2164fd4a08d1fc0e0095e6c626c6164a5055becc9f2d112597061644322d550ccd31d3f63ec67ef4d6b77a4fadc6814c67520e06e8a91e36913c755eeb193f5d279ee9dc3305895340a036a141627376a56ec46340a7bd2280c8846615d5b6914d6fd178685f4b13f319dba6a5b79f1f4534e39e594f049f8d7b58b1808768b0adcf53eadb451f17123d259a9ab1265772976d855796e58ec567781b6ee95d15d1e63b1bf35b0c7fac0340a7b56df1720705f2cf62e82d8e4fb279d8a167b50a7b0637f449dc29ec5d8627f5c3a458ff56909a2b0d87d54588cdbb018968519ec716131302cf68e2ce6650d8b31198b9d79a78b96b0d82f29b8ab63b1d83db65dd445454590d2572fc7550cc3ce3fb0ead3471c186bac310533f4323dde61a63d0616372c7c3ce9b092a8c0cd67afcf8ebbb022cf629f5de98cd5595f195463302aa39b3a10984e03af127b7f188ce94c63fa9c26d361675553c7d70343365aa69b2c49e5a4949e018da25614564a0005fbb624d663a5cfa15194d2f3f4d482d36e4981a3194fc3ee8979b19b341fb722d0cebf2d2c248b4e61f589c91e1b9cf69f4e9675db4a1ec2dc5b9168677d611808bd45050efb3cfd5569a3b0ecb2abf2b8b7a5cab3a5eebe322c3d093edbba3745a3e8b5eeea58fab70677bbc8d2c3fab2348a3eab0f4ba3e867191cfd0b0369b4743a152dbd033af54ecfa4537dfa1e58c8b3f441f3d79720ebe5a070b90a941a1dd14764a915fbae388183a536581a06e650fa4b0a8e622f0ca4b469c7be7275690919ffb89dc5c247e6172377fdb8ebd7c99650c2f31661fd508ee5035c0ec3f2dfd01b53e6004b98018d1ccb4357bc78585e18cc037e02b9b18c795470ce982d2c7c57f8020bffaa559973eef3c2c23734edab2f0b0381f782eb0a835848642f29b8ce32b564cc396cc48c974fc27a0d33dc95bdcc37f00d3728febd67bc21e16cd74bc5f639092a9f44ac72d29a047312cc39978abdfcbe557b3b62b29579067e6f469e4a227941f24b9c5449c4cfba04552521c461b678210933c89cf105235512b21af56365eeca4272d52d99500606616c012c1f61e183ee6ecc62a759699465a966a5e3814258165ec8eaa2d464e527833cec8a1e91a7c50e32f1648097cf6ec4081cc208db6884ad07bfc86eb236a3c9583e1cd36684314346392d1a2985fd284f8b5ef4c2322d6a1aeca73196691b299248b01f8935deb824753412890bcb2f71a9c2f2394ee3eef616cb37751534918606f6a3e92c8de29f69a3897aa88d336d98f9e2c50c305ebe78397a55bc2ccf8977a5dbb07c68069291649ed8d0ecc5f2211f591b82e8348affba218c51ce3827ec375f4318a394d38a9605fb5951ce6959945e58c430d80fb3e875615896695bdc36d86fd35ea63ded6d8f54e222c7c17edcf64a25ed71cf64d21e4d4daca981fd6aba1b2de3c89143631da7783ac17ea7d7dd58b319799dcd66e4e1d88ce0c8b1197936ea883a74c07e3a2809e7c8f5ea0db25d715012ce116adf87b00da651fc67802964dc990d3e5a84745446f0560702eb948a9d3e4440aba503d6d9caa0956a655b8955adcf2ed64e76f788212be379d3815516bcd58160357494e54a11d10790185225b15231cca93f6c7d47c1657e90c5473e81e5ca9181f433de207725323816630a57220b9126ed5926838b096c7f1963fb199bb1cf320b19e22ec7b190aecab3559ebd1c95fe00771f18db7f603a75a919da98315e2052a60251681acbcd7fd23b1cc7fd54200a44cae8b090d65808c3c3fad7bfceeb57c4059505b928761905e6f44eef8cb1fd1b833502561497b9aeebbae845e9c3b2e515bda12229ab116f8a2c41cd822cebb477e559b98e7036451c67c446a4081470ac05dbd7fbef4a112c847934ea74fac128fa1ce0ce2b82397d48ff7ab0f20f09b4d65f11dcea3d7159bdf487a53e58c98ca2e7edc8ad25eb2baac2fd7845870217ed614bbc291f172e534af939e79473059c11f4fd288f76af8bfde914ad8f0bbb619b8b46b50a28ed226fb3074e8bd2296e28a250028a84a3f80437f9bd37274b79ee846007f4ce09871d14e461400e9d9a7f59b2ec0481397dca71a72041187575ec4f731b51b250e97e1a2515c0698d6a3acb3c2efdacef2a3ec1ddc785c8d3c209ee72192eb60fd4a9fbb488f2d329f93e95a7050b61dbe71a55867bbf5c907e5850a8ff740a62db04cf7a161819ed143377e228efc4c3ca95ac0f8cddddddddfdee6e276cb15929f2ca0b19b4800b1a67ae70852c5438f66181843dc13798a1a1a12754ef271e19111060ef0f2682bd315c1b7028d9cb5e387bb90c18c4e0b097c9f01a16ce70d90d7878becf8930f055e1022b163ec2531730c1c27327174cc1c2bf8a230b8faac20b165ec70a30163e08cf15592c7c0e5a58782539b0f03d3c6182858f7285162c3c952f2cbc116b58f83754a4c5cc952d5eb04861e15f964ef1d10baeb0c5366f445edc02772edea079dc0c7410860a1ce4a00a5880c28e2a4ea753a3deb9a77a3f5d29c3888c33b4f0c28425acd4e0e64c1653ef4415b57dca0ccdc8f8c7b3828befbd283007a76f7da5b26a50f6f920ec6499764aae0ea78f7dc1e97926d73c06afd35b0127ab49c52a5a29cc812756ddd35908c740e0f95c947e828bf53e2cf61d1e361c63ce09e19373f28f78d91142f8be519ef405f7ce0f6599cb46c03d08215b249c2396857f16d6db030541469fd5dc8c3246da29eea0bd1042389b76aad27b9a57a0d4b23e507614e6f039d8944b9c31669a45e914ac29681bc9a2740ad61448258bd22958532871b344e24c92b499341a2df6a6459a1a1b1c16a523b03ae69c2b3fb50d097c7cb62129e2b2f1db76845a1f1c5ab6119145645b564ccb6263b2312d8b8dc9c6b42c36261b734e4b3e46c9b3072cfc8bd3b29ae01c79eed42bc2c23f296f90f5b3be94e4c05f9ef410a90e0ac51324f2ec387a2da7b906f77e4f734e4b5ab153cca8773e43cb0f6adca9d6e4e7cfcc8e0acce9289b158e73a811d77684da2cc3aecab57b055bbaf11e674f756c8a290e368a2bb8f00528a690031cdce0940530a478d24624dad82906c30222d8fe468b5462568046161518ad21850e2c98a0042184708755f15a67af66fb08b64f592003dbe730b69f6d449ab3104208218410428875ff12c203420e7b7958a8821958188685a72a68c3c2158861e1e9396e8585145f8099811096a08412e438b34566218410d232b8d94416d57baf0747695c1952bd2b81ef3d74eabda121d5454dc1866d326cdfda8834354307280b3f2d154c81022b8385976386868694e8eeee264df0421562a08535d22843d5386c378dedeeee8e1b9136c35ecda608f6f2f062ef0f31b0d8c008169e96c0c27351a861e14f29f8c2c2bf04161e497186859614dcfbfd7b1b16eac0420674aa0f6110b873c8504cf14498343e60460a2a0bafd329781b20847f95aa1ee420d800d81ec351c1c5ce6f4f70cf0bde29f5b0f0f30f0bdc217dfe65813bdbe7df96c705ee649f7f5d58083df6fb84207f1f0f76e2ef0bc3cea3e04ea9464a2f5729976d9d3ca9c39e59ddab3a8d52691dabb05356b14eab56c7e3c5ce93baf9ad43597a7a288b753a25ce99a79d0e0632ff3a94959dd6113d95125445a4c455444a702a12cf30afbd1ae669df30ff8ae0ce09d5a8b9a1c1c9c7cf47813bafd6cbd9323df8d0af88856476becf2ee39cf9adabe19c79adc3e19cf9d7c160ad8e001676559e05a2b60a10673106324f9f0cf35947a4c455cc33dc01d87918f806eb3174cefc9b31346a5ad6bbd5fde8340ad5a8280c649ea7e70ab887e5fe4c2ed8ad2700fbb46e7d3e0a0b613b2d98032feb38572dd2f6a27f459d8a573a75e3a577180843938f9e306327cacedf57859de767852f6aa13a351f43a76a1e00690f38f84b392eb1b1a3ece8cdd75c77b2c982bb25dbe7670c6177e260ff089e337211d6538985f40c32f9d83d1870a7394f9b8efdeab0eb3aca5ecfaecb84bd642a5dddb5b125ec3c7d75a59b30cc4b4976a58eeb6cacc09d1a25339b4b5e88e335e4afeea846c95b4c70a4637fd229edf240644eb461afd33c7b9ac9542f10b4a567a5ee32e24ae74695aa664de7699aee466baab786e63cfdb624d3061c5b8cb3366fedd9bcb723d6af6a734b0a22d93117bc53d8f51892a0bd2ace75f1b49601d1ae8e526b323d768a85b035d5fb63634de74cdde90ace24e54dd7230bd97ebd3722d775d34b9dcf75d3b3ab8ba5674f337534a58a83a474ec464a951b65536f4dfdb1b134f55e27e2d9d2b963a6aed471a57a6a94cca8f6b6ecd9c5ef41d25699815cbfcf5e35ebeeca2a61d2a827c1611fe0987b94084470c3c260790c2258e96744c4d0912429703e3f9aacd707fefd551feba45f2a81acf5f7f9ec91eaa53f5a91eb59562fab7b4f067e32546106722f2bcf0ce4d299b1755da70277b9ccd5d146cdcb2ebbb6974838a55aa46dc9f673f8d1a91bdbe7813bacea2b61d2f7a1775e91997e0c606c5f07877e49231d896fc8bbfc7c43e6e5e9f64bada6594d7bec14764d3b37eaca82d34eb593b4709f1dcef679b6afc3d96a91f7c8f30d8b1d21cd59df2852dd7aab6f14532ab8f8362424eedbb10e87f4674918a9722a9bcee95f5fe050f58d6aab09ee3d8bdb03de85806fbc61d3a8bed69d183e48e23035b80ceb2e0622ffbaf864909fdd7c324879ad08bdecaec32c6a57c7f651818334be6e9e37396d94f13d58c499d9dac8f8c7955c3ad596e18e16eb5adbf40e55f17974124b279d68147c555ee182bb32cb150b2fb354d13bf430764e3f7638efd2bef3b37e3530b1775ac55b914ce21ca1369eda5885786fd8eb63a3d63b962ceac242a211ec8d5bd8775a85bd9a2dd22376ce7be4c2427a442e0ce45d72890dadc862fb1c5ff72c93c1860b2c93c1860aeca51647feb2d35ecd32dbc7bfd73559beb1fced25c13b1ce7c460fb8f8885bcebb787112ca487ed1c58ef63bd2815d83ef37d4dd8be0d8dea0d1c6147576047416cc7f8f72ebdc0bd9f6943a31a07db3a3938a0513d34ca87465131b8dbcb671e8de531b430050bbb27f43c1dc401ee0d55231ad56fe24c94ee47eef87d8fd2a87ef63a2a3ee0e4ab9246f57dde7f1ad53934aa4fa553542e9546f5a358ee47813b4fd5a732df10230ca41fbbb7594fdc958d87376207419deabfa14e5d36c3f62592f864788f753e19ded1135d2c0d968f9e20b23d34aa9f74ead5278d7a43d8c67ae533abbb64c059bf1cc6880f8dea5bdd05b2f75dc257e49dcaae871fcd5af549a3fa581177390c92772596c9bc3f38645093f3489ecffb7d46de1bf25c718ec0d31b81a73f385859ef3b116f65795afe3da2ee5969547f76ef4aa3fab27b4e34aaeb1b6a545f4c9ffe80bb3ab6fb4658085b1db84375c0f53956f8b2685c603373ce869452319c2605774f43c53c2a6652fa863c2a46ca77022fd79818f888cb097e602f7fb9720233f6b2193a38502ddce532dbecd80cb501d71707ceac8de50761801216f2388c65de8263ae34153b55000b4da0858540e0f8dd2b88b45190399ee37d38522a1fe9af758a045a3a23968cffe29f8544c7186384dd1fa8e2307677331739a6fa10aee46b2d1977ea72b4cc29f8c746bdee73a39eedacdf3342c34bf9956dabbb672df9193724483c60e5bbbb325a1f79f8eedab6ed7a441ede67a391b6abf91e1332d212608411c618638c379eaf4e8cf1952865c8273eacb7f0cf071ec27377e9b3f02fe37e0c495a7098b4aadfaaae4147a818e6700bbd8e3fd04117319d621d74e962e127999e663ac53aa8411616ce36ac2b4bac5fc789a7c7b0d36338b136b17eddfa757eb68ac7deb31a14b432e24b0f51340e934389cb7c29c361a2e9d8636512543a63b10e275e1d4eac384bae636ff29ed523b2bfd7f723ee3cc32ad38368d8838c986c37d5a013cc814cb46f3508a50539d1128aa22cbc4eef1c9b60cfea11464c4acf7e84e9d89b64dfbed5234acfceaa1b6402da379c68ea706265ee58473acd57aa7e5d6a8a6c6ad0db82a5cb96a28785862375ff3e2c38b6e4f8e92b958eb38a045f5344f37706e6c03fc8884976d3838cb07fb19049e93435e83131bd54839ea932cc7935a806bd2f2f0cf6050b93bd77c6c293baabc391afc35962bd8f236b13eb7dfa779c26f4eff4639090451b59c83234a4229de6464cb85fbfae93cee43ae9da62214d0dea2298037fd5de82e5faeda2abb16c814565cec0a2327de6d4e9e8668e0e0756a6cf646755f60b8b6cde0f320a326252f3eb41f0450a50d19c54838c98906e53836c4e62c29d54836c6a736182baa62af15434fdc57456997ebb8ba9e2c8af54f34ce9ac2a551c59951031cc89f5523bc7c01cf8956a9ae93016e23479aaeb4f75dd74ee464c482fbd54838c7096946e3a93d24d35c828966265523a5783201698035faab00b9c636099ae0cabb05f8805ab4718b1eac22d47641587c9b76315a789f6ed5a0d32c251825d075661b5c93c03851454a0822f43432a1854d42aed42d937ecc22e167e87178e55300cfc622104430434000210c80c0da958a5d52384b23a74fdfa85612c3ccd0e3804101d59f681bdb08c85c7bac94505dc8503c6c27396c1d81b8b2c8c45f04c47f3856315a67af6c23316dea259c5b6b942c63fee8e31162ad1e1ccc38046c1633f96763e3f3636fb8f8dcdae9d27a517a814ea152a84891e05195368686604614002f3144030381c140b47e41151d4851f14800f97b2565c210bb428c85118428818638c21040040000660301b34003f680d704bfa50027063e8cff5db507277009cc9c05f7560ae491eda01d5b800002e2dbf7ba603d6cd23521ea4624119cf0ea8a57b2789e61d9500c181efb96acabab0d501e79ea0a303d6149dc8ee8eaaa953ae447ee14e0c41f6697726d546cda7cb5c21739cbee00cf93eab013bcb5b29467ff1a3dd5f41c8da3dff35f6071990d2b49af561bc2c21610e2b70d2675800682c56e0706f886b5ac0a384847156ab35c6a89e6c40d53826831fa2b5b99d00d63cf186546f4e773da70a595a19a2431c032f04d8ddab0d0888214a573b574ea2dd6358b5c343c850a6cbe896fb42e82058d241b6d75b9c311ea06a7d23d75f45c840f97b666cb4ed7f8564301e903133c679d52053ad4eca121f51e1454b15f5fd6914d967af6035cd83d9ec000287b165cc35e4ef804f5e0ca19bff552a6e792420d8bf4a3d728101c72247882bee00a6382f084b811972cc71bcd3cc900ebe13b9be4eeca2e8683e9c0f573e917cd0a2511ef5c9aa99ea9c910a59786709d685270e34fcbe56e297af7f7e3dc2f534b4decacc3ff4e982038c7b8681693349f314be39939a3180330409ffaeae5be80941eef2dbdcca6ff4dcb8690363f5e5b62f52f249fa5fa1209df95f86729051f4816b014c0f8bb479c52b0a05f8ad8fa93e28322206b94cb647df0cc9231652b6106bd7b181324dd0d4051f0733b04197f02179ab2499dd0c148194fc7b878da7544c1bebbfb530034545e5fdee8a98e46ce2b7b03147c419862fb52473edea95024e1ebd10722f4a20a85da4a41992e40b9df2f20271182751bc97f413e4b5067a6c869181fc2888f5a89490a9e9fa6363f8994e8c254b459169a344ed8385f52bf4e7ffe7c8b14e44fcaa20f32c348463033267208264627c016e9ccd24711db5d62fa0d9f2d50658d29c535bc57893eae92e60b08bfb08e9ef440f10e6f934817d83076fb3411cc4dda6f4cf2ec17ab89b3ce5a113a7e1a5ea7a3a5ab09f6580be055cb5ebc7d0b0648fc69d13696054e89cd95b5eb48337492b6015eb4782acb5fd789e334e80ca48d362b9d03128074241bb79a25588384e927deb53938881a655cfb75c27e60dfd855ca6c259fc8afa394252f555fd02d6074a4ab48b2596a2712805dfc8770ae80b5d7f1ec5d5de568f8f4d3e52efa02a92ec44bc6582bef36ba8c805abe75d10614d0745780250f5d45cacee554fe9c60453099a4d8602d3822e05931eb0aa715f37921c380a26c3215bd1e39fefa99e15a3efa78b48e9c56a6f6ec716c4250ef4dc26727360e0ea5f7e5624af42ef50ee38bed6730258bcae7f4777946b751df2768ff2ddbdd502c36868c7639af668f6bd0dd2d91a68cdbd921b90662f42ea16181b22ce4060648e9ec2a16949ffb528622a1b694fbc2064ac9db72abf847559dd44b521db857e82d141c40bca0751b16adb7eb952f282a8a477504cbf0fc4d10018f843ce21c2889ba009ea79cae30bba2fe4dce1adb5ccc00d10edeedf20a7b5235358f6a1c1aa967bd4588311a4bc643fa5cc204799ec9c88a0a844529711717e85bd6eaa1a5c646d8aeb3f042c55f5a8838db162c1f7ea18741744a7e5f82eb6187e105442f2d89454e08408834d9231581fc987d542468904e8656c7e227a6fca31588d717ddcc622cdcac18a98f0571a1ac7feffefa42be9afe3137845c1826827bc8cf5426a55ab67999af134e156786759880d88279dcd05bd1cf546a339eb653650a973daad21b283ef1698249dd9f275da39f1ea0bf264c7b112bff1524c2dae999d389ab998d5d30323add8e794b794526e56965319ba422ea131cf3c2926be78ccc56ac4dc110a5d5efe85dccfe75903c45b032c506201737a40f6980c9f9388ee0fb264626e6db85b97af784f335ce74484e4b5a026e463cb6a6b48b8105e4c79ecb8791d959156836cf00f1b12c0816d37092be98a874a68222dbb4e2ab544b4e9ab42950bbc71585a4e56427061fdce9ba4011986d9cd8db53acd420317289994aeff06d5f4a9f63d89b46197ca8d9b094d286e5832297f118d428171d2efc7bda1dcf866d635018d78072c13c31d23c2bd5c8d5a1f6e20049fe9d39274a59204d0436e3e7304408993fa7bd73e29d2128daf570c61d67c487f89ce62ec39950f292f95add8d2852dab2071839301d2f81227843da7f17f0b171b9304e09f1bd68c8ee14b9c73434bed9a6bfd254870bd467cb65e88ba845d90e57e77fd4eff19330d3247fd9241ebef21c0bb4e557084eeeef3149e35672fc4a34b32f12dddce15febee50c988ded143d3a8c5968eb429e2ce8ec128d211c09c578ff9c6175f98b801f6864cb1978934b92948b29ecd0ae71753722cdcee437f8a01439c46a6e27a10150fa8b6807c7da623eac3beef70f1d2639b764c3b3203894f4b67760171fe4c23158f27bec5c55f26d4b09891bcb402204a7b9bbd94225440900289034196d935e481c6d38c3d54a7c4508db9d2e4d1d90b52db3e686c65010ab9f731cc608811112aa782fc34cb88926bd733a0e512d7c8d0dc3115e134732ad09368367723e675c0d83b5c85790e5ee2996a6453e2d8bdd8d6baa8fe76a4eb3c0e9d4335597485f1ac1d78188fb6ba4c3cfc9f672b0d10d2186039920281b767387ddd257b3127791d128c590be20e89dfbef2a5012c58b0aebd61f495cc0d826e40b7b7840d99ad7703412d45e04e9e524ee0e9d9f248d0e46ccb6b49aa6ff53b92f087f5ca10c805c8116290777891fb8a35ee7d7be988d854de8158beb67dae16adbb94c47b5d3826936b5e467cab23cb08365b322b2d48674d2f34e1c89bb4fed568f4cfd6bd76246d7d692eb1fb98a0be5a032d12c08ef2d9bd31fe46b4479e7583592483a744d86fa4d7c5e30d55639834992778e8abc8e29d0ae26cd0e748025bad7e5958a633e58b65516ccb94095c6a8f49e476e0e30350dd29ad46e1ff4d36b07c25f90494a2f5f58c24c51095f3a2adf3bba7266af0c563d21c00345b9d4de8965dd5c073664bbf2b15ea65720454cf1f3f9b98cb3352b7b09ec0a37ee0ad13234dd4c4e92c48c0524b12e44564466d421f7b810ad29592d243262be8af59b169811ba1853830c2d134668c44517867014cafe3e0327b2e4619ec1ff6e65753c498453b693183661a97dc205c6f957a834abbde7219d1ae758ca9f483a2281902b7590e495a18dee8824a4f6b0336fac90fcc254bffa11e33a1d90d85472e350dc82cb0f07b6b51c1f92f3a6a0917e51761a6997c8003d822e07237e7a286cbe309e9097453daf4850f81cb03234878c1bfaf33f4a191ae12020f1e87577531d59879080dfb4279969eff7445b17138c32050b1d6f7b8c6b97d9738ff8bad7b3269d463cf054b1848d60e908443354d40072a37b13bcbaec6dba94dc1d333b6ac5c4522a85454e0b11b0011089f2053917eeb68a84b1817bf63e91b41de1b6110c13e68105a2983117064606307ecc4dceba134088eea89a603c01a20050786e523d55b23413d2572931c1d77804996c8d538b552bddb3d66c5229f2196343f807d6bafa34f93254140cc90c65c8cf81d7ec701f4c15998cc47ecdeb898789f05d40495b7a4d85f6332e65aece98e8f9d3640c5dcced3d3a9b0d3faa2ac5b5e163b5bfcd23459f1be932d79b4faf26f013801ed4d045d9857b25f8963be1c6f3c526c80a5362264238a0abd8b0d1a3f8d1286afa430faf0e6c6b55d1e10435595f3e30e7344a4da76d04e678e6e89166ea940bc0035d3ef0590168e5ebf426f455e10adc7cf03412a9a1ee96a7308e4fcdc8017d1aafcc9060573b37ec1122b73f9ca3437d163f492abd432a88696c0a3b0a2304b40031717c231d6c6f308387744958ecdd05816ca2e68643375f7222622559cc45fb865fafda11d70d8b159de15d6e9b19f9430da32e43a5b1b5ad263342035d4567de77d81f2cb5da845e1f7ab52ed03c4313cb5bd7e555807eb93c304833eeb45f8c043fa0282460184fa15d398dea08eb745f1ae8b56b4d9403094676bb34c34a6a306ccf2dd93a5978719618eb9ac0e59cc28b99161145d6c7f111cd2446cccf99f12bbbddb913313573fc9c73a131643254442dff171cf3b397de566f08667d7193b029d45b4d70acf1345dfd8a82d095c6b9f2b3e19d682686aebf6032a30a54bb58571c86b1851071c52663e5ded1325e8df5b47838a05beaedea35116b26f4a642f59fe551888311a373439ac14ee16cdf2adae83af485bc14c1d7d0b5a7aa17d37cd5d25b000d4ed9d9002a386d58298d930c0fb2fab7eedc0cee8b6748fcbd18bbce6668556defec9784131dd4e7943bb500a55a793440f0f5569d47056fca3bb6c5a13d19ed7c6fb2256ff9ce16bfe78e6c4413e4488545717b330b3d9b9b6891c581a7a347cf6e21b5551af78b1d5a9324effc32e5507a3edc9ee95b3df13de191568ca8f6e8a89f92619c3dc6f81dcd9278317fe19e906635d1e4b1ec12de7c25450d5834445b86b677ac6bd76410beac2e32a72ba3e27111afc047f4ed5c60d6e639be65385deb2caf7ba8e91c0872375e394dcad45d0daca19d5a7d8ca1e9bf346b066bd0a912a90cd54ce4e8e1207c39a460b28655c957480e889be4676b3072444252ee9c377ffa5109eae9ba00b566e82cbc0fad090350b59aa61c346f0f7ce6102051975af835b8696ed3e719a19bbedf2e105f2334593f2d106ed455c9000da6c58062a63485a0ccadb1588142743730407737e9be6e9be76391f3cb309e68687071908c27f0e6810346f57753dba90301adafd81a4f78d75ef7d51ad9fdd1e99038e6c900097c3174e6355477e5549757a237746954fa6aa970970e0e3910d1a030f4cc78f584f656ec58f629542fc380be5ce335dd65e9b259c1574201b9afc95318d734b0aa4641c80ca17c62e5f673146f47bbc80223cd5c733d4a35654beaae3127ddbfe9634ab9e61ebbee50b1c26d74e720d0e34a6a8d6a16adf3fbd0251827377a3b9e4f46d3884c2bb4a7e91cb59b48bc8032b9430abdb9c01e158b27b2c009d7b9cdfdb3f5b3a5c289b1d52121bd84d0dd81ba1ccbb288249455125b58ab5e98ec8aa162526d35eeb1e6fbebb4244a46a41d294af321eced0e482179f474dd1f9d48ed767f8bd4dfe51f3ff737bd7e927248f059fc39fe489a18e4bf221e05477f11d005abd9a2be8ce4af410fb1316127807e2f8ca8e5f228aec1b176684265f5ca39784725455d79178c3f414fbffc0be9b50bfe1ac6c9d2467c52548e03a2da23df020267a3bb1915797c4fa3b3bb6f05c69df5b1a2aba3924c29a1ee3e3498a95272a2adaea659fcf22b9718834b4b45306b45144b5b83395d5e5584004db4a03ce774057b467e23ab15f2371d7cd3118fb5b309884f8f0b5b6f97878b9cd6e57e598246ddf158a1be7a33582f5046534ac3b7c25cb0c6339c48e1d3c9b8bdb6b0dd45447844a727c13a0347d2853aaef95774c8b76b48022401734f82901321b105e5c17d25eacbbb8318a1947a8a198f268d88977a7a9e981197bf562d6f9904f7256a1e84ecbb4c922386603aac07633c40c4ca471a42234b87b254e24354f21b0266261a62c9035bc0aaeb850af58a6c1dcc75004f9bb688538a6dc1990773f6cc3970b01e103ac191aaefd058c900b791caa6692df7cd09e51293c62424506c9d7414f0e9fcfc1f6c9ba82c054c7932f4169a1a051b55020fed3e443b4a8a846f9caef5f30c6540d2e274a042f631d071bd7526b4686b45505913e5e628a5025f94dcd0c173ba3513f50387fdb7c6887803ed1db61890efa92080af4b9a06461fb0f089afc01a85219e37f22a29a705bb6bf9ecbff049b73a5971d392f98610e3c6cd04ae679d8f3ed865dc343572eba637b06f90ee1ce7be0969fba1284de86354481e68d34205392ec0de2f3f9455338c41f4a2e1edd5d8dd5366df2eaf2901849ce8807a262b261d7890830f75667f569111fc252eb519ffd907636d3266d98e1b6ce34b18302064a166e25361a667b4badfc9e5b6cdc5ed883e3d7753f24788b0d932b0b862ac51b0cdd254b8241ca4f1d1b07007fe4ffdfdb4dc00c7d797c0ff5532e832879639f177a2041cc306caeb6b288dc539c5bf65e90a5ab1e5f95a47fe5d16875ab06e03fb0bd9dfd7a4e790c3bbb0b435660ad380c4320c729449bcc77acf260024d059cd904fb71bfe549e55d0d26afe5b6c9da203a55f3ad3bdd18c9b270c6050ae1a2f3798ce16158a15c58de9b22681a0795b4f32fc158008c45ad20a3f28e36a09c4cdeed415fb112b146dd9a59fc1aa9d5038042abfdb4a2bc542862f4cb88f6b24039bf1c05021c2ef560a07ca97cc846d4812d7d75e1370f01e992748e2990f3dd75e1b9ba5f5f47404c475c740649d35a3dd9037721399dc360ce042d9f0e944c0b3b308bd7d9a975aa14575a82b019e424219047fd0986ce75bd9fd2896e66eeb08718d9802e01930cae93b9198800f8ac5909ace65be6d8818081d26eeacfd531f8159b3c7a193f39985cf0d18a8b37374dca10e64ea61219e60df10d9e9b6a3c4b1bfa580487279cbb2df8103e7b33a699ac4e7340f41c2830ce410aa33a39364335d430f148d1a2dcd285688434b040803ca86ee10e4f47894cef36e59f934d5454cf1d6596211b8ef5c76a9a357d7b1e1e6f6b4f22b875443bdcf511f7d73d1d73e307f3ef1f1baf94b4e09742e91796797d448844f545d1916a5199599521ec6ed251a2a275559476ac52e512bcac66ef30a08964b60b74f338028a0438420ac6f5dabdcb726505f0bb0d8956f43e415c660b3a5b98feecdc00ba26958756dd4a548cd71f90a2b733547606bd613557204f94d5d14e9a984eeaf076e87ae8d2275d0dc45cdfa22d78e544bbecc94beb7d1f86fd54767b8cfc395ef186e75cd1c0d8d70ef718d3c5c6ffd2b43cdcf77e0b6883dbc62b3acdcae79238f35def9a4d96f5a7e4fc5b34814d1ab26071e8b13ea086266347a669ba7580dc5aae067c7a91a2ff3c61bd3e5f3b9c74ed3e35d0b9883086bb7174cc70db67d4cc5ec45f89675d65d778c8008f99fa48b47ef828a1535c19f4423827c617b09fa5d4d80e5a14129edd286a70bd0d802903ef333875941e3665986eeacf49dd5e78862b166afbe5ffd94fe75b9f06cbe0e4bad01d2d53d801d423d8cdf7993cb420674820ab1233385016d08656eb75c0dac95e200b900879f8adff6fb4005c4ad46b36051f06e9d9842a95bed6f0916a95095a5ebada1812018b421dfa680c19f123584bddf25fa5fcbed5a6bfd4e6c54f3c0566fd408d3f27c2d6788039c2156f5b1f4ee74b658cf2d2a558034173cebdfe5aba599670cc74449cab6485d06ebcd63a8b610fe19da3a8cd9d6f1c883068688094e6bb28f71b76e91797a31fde3ebfa44bc21b5ca873c1a293722b3cfc908422a980092ca0a0feb5d8d833d99bf4c33637f1298a4404227dac306a2c4c805a81a087bad4971c01e5bd6bb0ef91a65066a68036fc1b0490a347265889c989c9e8b4b104701a1f2ac54768c1e36398c2bc39ca7fa1d9959cbab5aa57b86e1bc38e8d4a8929c342d6cf230fba4c096dff2c5b268a9f301d9dab93010e79c54c2e00eabf8a6125bcb1d8715ccf2a0b720185bd42161c6d4292813ed30e590fd7819206016285059df073adc5712cbfdd0722ec5716959695846590ffdce589e6fe8998e3a2c8eb85cabb5a91d96fe219167476fccc107caf6461148da957456717a43c1dc7d118563ed27420aa6bb1f0f6996c34d2297f64d05efdb7e70bbbfeb368460301f705dac3297d559ddc255deee3921916fdae8aa756d5b4b3d9b84ae5b2d3213834e283db4a949c18c3dee091ad998c7ee578b53546fbb2e8ce362480dc092e4c00c8f314669bc10e4bfbd222ab58be84f5ec6004fd24219e093ae33c6b77114c53e0373d121a15e83ae600551afa9db56436b2edb455336e3ac1f5e69363580afb4baab66a75087f3e8cc592718491f6884f811c53130da0e2685d36fa59b1f6dee3402a22630d47a131cd5ce999f30f4e9f0cbc03e2ebd460554d496841164b393b1165b32895c6ce3d7bb2c3abe6902080eef9eb4ff02d73aa49524b4b14493389ad0539721ba0cd56f1ad45bd1952e2725c5617b0662b9a4e8b368cce7453dd55e81f98bde6a6c5dba7b8b5ec4fe2ebdcb34e0a65d59e974315f55d40faf27f45ed12d61ff54f93c8d6a88521d229908bf0260e1e992fb899ed42360d52abfc7b0875fd9aacd548f2bfb72425253e3b65029f822c2a6c0d1d38ed779a6c91b00e923c99ec4cdf64906dc500433294ab7fb61cdcbff0d0d828f1d99abf2322fe020bf8e5aa5a501617dfab1bb347442cd624915bfc3927b7eadd33a31ac64cb9b768433c9f32a08d92d5415b400c064e7009111892f722984580e1174bb7569eb43005fac72ee169b8951f8d47f5fafbb85345b893882a0a0c2996ea7d401c6b8b71a73fc87026ade3ab25bd9e285b4354b60aaabdd542c1c5be2ed456bf8f7ea9e2dbadb5578b78b165ebedba518784a13de4694fce952dec7f51e9f8bf42e2f36bb0fe9fdd0bcb317a9d3598acea6c91ea73ce7f67e4c81a0542133403ba182da9bce15c1578eda7b9b9877d1600c776b5097c74f0d8bac10f9def9fe1ec4bd0f9bdfca73c70318fa835995ea895e6f3051621a8a0a2d2575a9c9b302221821d6b7143fe55ccacb4f4409710346e2414ab1b88ba80374d92f788f756100d9e1128213015dba963f3e61e78c8c051b77edc29c801409231251494ec2909ec29e803c3851a66a88d5a5c433239d9b2985004d48a479c3924fdaf1f22033ad5d57153f2873284ba17dd921ec25ca7c9b65319a80051f7910284aa902c3d3ba1caf0654c3efef148d80d17fe9f1cccd2a9e18e4de97d14251c012a162e52d52b69e05500e28697222944730a862feea3133d98459b8223fa138d4e34610e08f451403fa06bae9c34e9cbe0e27f379244a3812b56198a4908172d46d36cad2a8d09655bda74b47f4bf5b32a130f0bb4ab2dcdaa913495eba56f5492e1b80046929603ee6b010013a6b34a1a6d48aacba0bcd3e44a9d79a40335ab97e5a8af463e2b6a3c185079749a20d0d499c4b8174c8a2a4ba348e2203cc84e2c997d1b01dd25c1a4a3ecb0efd406af8c19794d0513e036445b8cef784f022fbb9dbf41220b696a07d69afbe0db052978ae96520b0df6d502f22d70576d74ae0ec60b3f3f75434621417ddb87a21def0231e8c51b0cc9cd4139b5756c237d2a6e5f1a0966c2ec82fd13ae1ca0c08d325d0d4e2b1e99ebf74d0241165b808b3d2588c9dc419107381a6fd307868ca7897226680d5c8620836e32dfde8f2fa8fd26d1c8f16d6201b12c68e3996e45f2dca248e20696ef6bfd87a8c4d7e564e338c8a9e5e3ab2adbc6703e19f64cea79954cdfd05f4c78ed908ce22371a3fab3ef2f8c20a6aa766d33dd806cc6c1da6bc80fd0dc107a166173435f1722aa18c04f617f819c99b56aa40cb7948852f7f61ed3721b2b0f6ae86bcd06683501896d0f3b9359d726baf070a6018fb6a64e629e721acba93c284fcd9cd08fed2147234053e2f31bc7c76ecf61f43447945f1f1db6903135cb41cd16f3ea92c1cf424d3df62afdc0f99623dcf4d8ac1d337dce887fd205928008daf2da2dc4c6c2db0fe9dfa0f55dde60c5ae60e7a35414004d369185cb8012b0d0be020b61747b3725f5a20e9791bc6fbcd87bd0d2a664ca631cb97f771e76ddfce8e0896e589a20e9199f07ea92b5068f1f4dbb98d09c6e969b04a81434aa6ce6f68128ca96c26daafee3bf5d8c9a17b6aac9239595d447944ff71ba5273f533f36fa6749f66c5867156aa3204d84f94919de34e3ce97011d70bab075b858a089f6e343a483f4e90e7ea8283e0302f6d72d6e461b541707fe7a9fef53fcda5d876d1da82360de247912ede4e811f82d1808a46b9690a4f3c840b7d96c60b6ab730b53ba32b325dcaba60e0d157c9f1be6b565daf40dcb8c1e1488c345d804d041b5912ba38a28efde178c26816c11e63b5a8bc4ab9660576e8284b821cde8319e2ae1d80c26e272bebd95fd324084b211cfc621bd4726cb176cc176db5155376068da07e682aa3213c0ec44087ce5ee86f756d66f40f5cac1dee049b4a2e3b46f1b1e6b31f24cc5ba110555882e01c89803961876a55b28f1ecaab3aa2ac6c8d8467788e7aa6e34e9c3c07c7e0743466d08d94e929958b184360d24d146dd1c95e4b82633a7b4c2c85ea4b7a09b873620331872067dbe5ab7f1208fc043bb4a1ee32f44fec45321a1c7641fbba40cf56c153b46da715cfe113ad7111a66c8f9ed326f74ef505ebf0af49647f5ff484ce9cdd92c41171210f2cf3cec215d59741300b20749ebf61c5c94e7b7c7dbad2e61100cd35123bb82f59448a2822abbd938fa148b9c07bcf332c2bb05f4061bd86e9df49c904529ca2d5c41ee4b114064a2be71a0fc0db9ccc9c8090db768d03ca1ad8022e106de4545a5d6983d3c20b684284824024e9287e42c6452b6068a4d4f0a47259a08d4d018684b55ebe4a24c89e648dbc81d63a60634ae0deb73fe17c083d442c176987989eaa288818b8a601bce54591d3a362e368a33ca6e6d94c1ebf55238dcb2a60cd494c34c0bae32d37a9714e29d1bea3d50ccce80159d637425d0a5ba95c64d37c596676aa08219ad871844d8ad69a7491393deb666293520d9d3f7c37d12b4fb680ec8c6fa395dff09d11cde30415b8415c2f0e6caf8de40009ed404d15f16d73f628c47c47323d93a268c539c8d9b6ddba7f78b15acf56d20071067e0e648e2af0b48c62eca2d7e683fae47585bee822b9ceafc3ddec2ebd771ccdde4a9d6b660ce42ab636eaeaf645e61ece7e762a43135f18b26ad0c00c4012ba24c7324e4585cf98382a8d3333970cc999cae9d3670f4380a604baf99b9c5d70ca06f1075e0dd6fb901164a9bf44cf92e7a0d6e121d00686c0dca027faa6bf99420e2a622e748af06cfc07a70d05c6e2df217a98483b061b6747e37a468074a9bc92c95f89d019c332a86a687d04a1e181ec91653762d6cca1825e3fdab6d0e8400fc6264ab8236eb2ca09a71942925b44a5196f54e5ceb9f0b075a39e23926b4cb109cb4a46ca682ab7c7692ec100fd6c11444b9a2795faf2c838ed80e3d93c5f5c9e6eefda77881bf84ae55105ef2fe00e28cdf6f3b1744e8c7752cc8bf15b430d9d3a04cbb9c2c4cf928efeaa2055ec5e3c37fbd0ac2c3fba290de0d0872fbdb0107e216a2f5e8e6205681228ae8557550de02a6b76c28cdc2198c4e2ceb4a2ed8b050b995227e13afe76c5acbeff0e40cf247f7047388d3b1e91cbbd87663e456685c33916c8c24bf3814467f4adbd98daa50633c3daf83b83efcbf877dbcb99fe2593854bc68c253f2d15c9f787d0797d8b736695dc2fc95526bec0d05720b8d3ef1d5bb709740deb4e1a0a01289350228087cc0e76cb3c4303e5f8535a1afe60b309a83c3c110337b3843ebacb462d620f3202f4b6a57342e9e906cd13b800d380f5dc8f98cd72cb07b26ef368ad09700aa31ac17e1ba290c25dd3d0a07064fb2e54a98197a1144f29427a6693eabafb6ef3c7afe9ec80016f5ff313951c7030935efb25ce306f83e9ca2de1788f4b2458e954b675819a49055400601cc6cf81756bb62962af0d0c9229b48ccc58665acd36625451da580e3bdc83210d97df402a7a1dd6d3c0a5c1e56edbdb4c904de41220555a9c22eb9a91815bd3b6ac432916e666022be718695a9f7019a2476eb92da7e3feeedbf40ffe7782c2de9c13c4695e095e5d5e19dbb8d1a51676ad84722558c94467dc15a73ea51621e21b071f7400ae4c422e868268f49362660692cbebb7d1a253830d8fba7660be6cfac9cf81923611da0dbf69717b88245c98db8ce4ea8cde5591372b22506ba839e7504e184f707aa292ffe1e25bede5646d95d0ec3771302b981b5867908f276ec2cdfa408df6a96c73a4368579ebe353ebb45cd09392e510cc7e8cd0d62288368302c1160a2c8b81c0bb33b80c3c26e97087ebad8f2834ecf0204fa503cd97220364e8b4055136aca315e5b50093538e3081e6085b7f6af582d86631a1e4214ce2c98c45fd0f4b6f63efdc148dbffec40d36df27bd2507254bce1378a196e4845915e0ca1d95423835758c21a05cf5e606c359c82e19aa89a44912c79d05be1cc30659a7c0f6c15e1f14a6bc47282ba2c1f0cf24fd81276df2337ae2c7076d2500411ad9257a4e5368bd51564af3ec47b3f9a17b8bc79abd88f07a26cf38e734037213d216bfbbd2278e4c7e23bed671502594656687e4f28406dd2161a8a59ca39dc9c82356bfaa76baf2227867b14941d852ec0f68f49a8976df0fcbd7c4a1194e4ed3b0ef5538bf11f4881246376aebaf255ebe29041f03ce95ece2b4e878f0df75e3923e06d826bdf80e6fb2b5893c64e797208b8123df3dbe3c818b2cfff1a143ea688920e08ce1884dbb3cdbac55eee5b70f6f23e916538c48c2f3a6ee60d0c16df12011f6821169a5d2642ec2fc361cc072b0b8cd82a04d7cb011297bb6ce54357a10dcc3b27ed9ecd73f84cd574572df77c2abbd2b3fb29645a802cd431f90d7f2cd7e691317cdb9e20e45f9343848f4f3416bcd2fb5f0e0bb0bb0f5cf0aec58d36c7c8e7177fd1be09cd868983132c272b8b9691c1ae86e5f07b3f1de5b40ea5dd521e42b46705cc4b57091a3781bbfbdfe1b5d60b2ca354d9fbefbddc2e3505150102850c652960408960022d5151a0eac1793b16dc73e3c7b2f3accd820f5dcbb4a699fc0c2472a783fe064891ece8bd2157a5ca08381cc658f31e558a96c05e712862baff81e19b7cd8098ee18250ebc258e565b5701df9ea115448205f98a8d9d3a8495aa6e619f34ef1e428613b254c4b75f05558ed7a6b51ef2b93149eb89e78c70982caa86123ac7292872988c36031923c14efd0855cd0e4fb94ca0123b1d888fc64b889f17a5bc60d45c481b30d2742a3ec6504a7d25c8e448c5af45eabf159ca1a48bdfe3b85b4060fccaddede25c1801be62eb04096e586a95e8a7e3ac8aade53c59a347dd5c10e459f06605ea3768a90e228ef6c1cae42884da1b0e529f510c49c0751bef13da523b74818c65735115d12427553af7c6e9152c59571325d4b5c1d49ac76132bc4ad0c6ff8c063b5aecba07bc11d1a0c7c632f350718c887095c1bc8a72372c989254e28ea01b5c00eb163a7afe78096147749cc809486a20c57f04905e08f7217e416f05fc7e91ac1011afaa0d337fcd4e176a6f271c8fac82c0643c815baab91c0a40a9f35620243cfc99e98c61661913b824e3403c61de5c33990011cfe04a8499d5c7cdad8033a0939a944042b8f462b6ae0e55149d35d5ee0212f407c9a8e6ab868768b595f38458841845f077f1a261689ca66c013f7341935697effd2b3af7abf1fce57b8b54cc15789242bf35e9a9f888883bad7464896dbfeef23abec196bdb4cb9946d9111fa172b46178527a8e0f2d8a6a6c45420737447938da7ea42a8129c322d68aaa6ed25f28ee11b8c055a09791309292f641a4434d0ef2efaefa2cf41c6be7b29a7186c9a0f35588be867b6395f55783e92a0bbc0b86d4a465770b7eb99d93b4fc37378cee5e507a280e994ce6d7499b3afbd5012127f6aa701e8502725e4e5fda11fb030d287a3b3b24cab154b8dcf1c09d416b8bd9e0973a291c2023b20f2c9efb6f8d13d63f2afb5ee59a042ab03172ba10c5d181144c4b0bfeabc6bcaea20dd3d87a1670244f79957486e3ebaefc3af4e15eab83e468419a789cbe2189c18a493637f029becac0b6c10f53b7e68a32c158c0f5e4df4c1e3805083374cb55e51edfcc7e625c058fda6ab4bb5cec0e49f70f648c67fbbfcb4a5a2060c720bc852fa90cb46443483974b92641f99f10f461da7e63871c3c1106d7e0cf18e68bc0323d38c20e5adc98da28a8ee26f321ff01ba7003cf9e842596b7457b7cc9500aee96fa84b180035826515c0c718cb0fb40961b4612bd461c2ca83d49453763798569edddd4d12ea8bd93be05c5f104f3930d41ffc8226861922f4b9a8759db680e023ec6f26f18ef970dd7dbc953b8ca992791d4fea6ec5187437f960c270b3aa239c3adefe08e85cf5a6318d4b195e6177c50ac8df605608b09d3b8646fd56509e8fbce2c88a016eb077cf03c55b0ef10d3b04ec769dfaa5f69d41f5ab6acca7f6982df66cc0cf4f7b57b61009aa714815986123021427ccbc0e6b9925b9c568c23727f8aa337b4363b74768fc7e7756f92aa2bd79e7e20dafc90607a11618cdd908752c2ae29d052a60c3ff95e68ab0caeb5ec4f64709001d746750571573466035eb39dec3ce445d73cf87ed2f3cf8d9c97b49ae75090da37f99838e13477c8adf3879f72565944cf4606ca26ac95898f4d62f657a43f3017b3b7e4511ed470df8a7a4c0ffe35aa2a3d73a7e86d1f4cf681d1cd296c1d6d495d7fdfb5957bce96723d4f856f4e92cacfb5bc570700804f93f0eee46d53370f1c3ec5ff6fb5455bc0061c5322e6216596d375c827fbd1dbfd5b55b585d5830956eb22bbb5a3057907f6500417525ad34a0427407397da22ebda95578f0cb120ad73871e7ac0d8dd187ebff978b3345303f8fdae08d2253d7c0308c50423a8b216e9dce391590dd705c1ebd4cd8904a8532f462dd0907c3b5214a5f7b5ed3b8660f14944c8ef35c98e37e6feb54c526fe42d00464393b74b39dc4a313d52e061e3851cd41d84070bea280a47b710c95ba274f3969fe71a0a2c8c3591ee57cffcbb4e9560955d400a810159a838d15e0d36c4007b1a2ba58708e6dedc18dc6be25e796e8954be5805c47e4cc4af9003323cd595a471b4ec23beaf9a4413e85de62b96508f2ef3e1c4209c9e552d93dc55fa93f0a29c7bc27a66a64ca244ae58ce51ded150b3f524ef8f84d3f51c277b6575d14d8052caa2f45ae549aed92683133ec6c86ea4761244f40cb0e4aea4d5701fb82ac5ab3214634e9e6c235fbbd071d0b71fbcfc76abe9a7f3bb778f716cd3d69ed048722fa43a76e207ca71b10010c89afcce6d23f6efbc90993bf248a2c2dff5833a84ceab7ccffbd40798f44c0b1342b0fe32575d948b7100bdb719e0540f1096cba158c1d2cf64538d6385a490fce98ec3cc23ce1fdbc0773bec6af1c60a158c260473648491a35ecc32b0eb06ec875d18725f4d7935eba66054c8105bbd4cf1de17ad74fba35c004dc809cd6ba4a2cd279102d967b2512f8a70f354d59e4130f50b2bc7c39825931522adefe8b0bc2a655dddc80956e231c408ab6d09fe6229a00a7421a2adf5b4c37ecf74cb660a8e477ebaf6f48795122a4caf9fec701e3b47c684b0641ea51892d902f600b93555cd2c9ab99bb443a7e585fa633038fc4f1f1b1b9187f5948dc5d9936d8957334aa1aca065a325338be996f8333ef85ddd5c84f71a23f34489fd7cf75412263b06b7f2d9f58fb9705f0d2f590821f5e9b060625845c89a44952220e008b54e3ef7222995c4b602d5d1b5df24fdcfb6f24585a109c574bbf896eb45dbe3984ad1bcd2267e6b9dd237350e9b46db904c672776a4dab94dea8f18425139d30742b278990c740323e47554fd378443aa5fd38b4afde4223b74d06251f11f4e4ba09c24c9c110ec10cf4d570ac2d23e8d1aa623a3140bf6b29990319a59d3e903db53495907a798c4be01c77bc952478461f35a36653a8d5fd9faa338e7b32100ba62f3e39439da90d8227ecf35fd2f19b331cc76503b9218d60e94ce11bfc961ac86c3e9580b57d0d5314c0bc33b246401f6f85e0bc67814082ee34e49dd8e5869fc3917c66db67e791fbb231ac968c3353d32f7cfa163f7472bce1b3c1b0a8f0b5cf03f04046d2ab31b05742c7121e7862f76899468866a8b01726d04379726acc8a04cee04299f27032bdf3e233c5618043513e9a0ee04c817c6c0a239444480482b8587666f96b2514876b247742e9ee4c551f7d4d90c70dfd7f3af7c7cde5a4d014f74ba158730b310b3758bd77a8c0dcd55ef62e39d36e2f9acff746842042932ba39f50afcee96c7a5239ea32ef6b6bd6091e4c8e815fdd33a7b1af0dd6e80700c4cfd662f5167145baed292e3813941dc8e3f32196ccd86c6ece9d9a511e552540360c5269bff484895ac8dd753dc32558859119392d0c16879e114ad335e29aa20fe417bdb358d93b9df6e177d1e29c5aa266ecc810f91f0b69beb694f230cb960f833b1d4ff236654a04de8343b8a2f3e1d7be0538676ae729eb0387c5ea36a313b910c5e0c5536b482ccd808f42c44da298235348b3e4e5c3841e52bbf76f62e950e14f42ed327d579fc5c38992edc67cbda74993290b1a20b15d1d83e97e116ce4859e2b90ce0b7dcf631e40856944d330b9912e00875eb9124d289de611cdf9fba42e95ce671c0ecd0fd9264030b0797ad475aae86d13a2d8566dce1c6ad098d9b60099bb4b955d4e0075a074cce51cc4700da251e7fda195b77d24abac44ded2ab7a4b54642012a233de1b222954d979653c8c07129e58bf4e2c343628236d3482f532cbe643fa7cff548ce3ae19651d74a2090e4455c8c1792e7400e4d307e192ccb8dd12d2a6717c3224635dccec97411509d12cccb313b9ddce210f36ac44ebcc61477601679be24313ae77f4ea8d66a342ca3fbc09f2ac87407fa6b663d246f9b86e383573114d0ed7d86bbf917946d2f70d43e9642e5eaca8ba007de2b47d7c09e26ed6076cc0f2a71ac916fd000ba784b76346e08435dfacb723d8af8870489e4653b7c587e545728c4af49532c8fd6d2e8c6c8fcb324855a8f0d243f52becf435327fc1a6a9f465783f0d71dc59f669c590aac721ec030711036ce188f11224b28b36c48d4d2e8a7b0d8bc1c462409e61a9fc2c768e3f5589690abeeaf98ee6fc6db460a2e2e2e99ff2d02dac45d5b91b6b7591b0e16634b8ec9a47673d227b0678011310e7eb5c14ed0202e477c5633777ee950c1142b82dff5d417a5988126ed98e98666dd41c50bed6f903764cb5da0ae0d3bbdc234ef93c4715ec277afe0752be56bdd305c7aa7112c50b17d1f0d2fe5b4aa98070553dd3dc36a07b75005a0ce769f5ae91c554556b985ba3f605a10487567e7e8e3138b92cfba9481c5012b4034bcef2d10b4261b73f3eb2cf5990cf1a5eed96a3636d3f9f7c3fa3637cce1af68a8f99c1b28d5af6a1dbf58e5fa963580ea49beb6313328ee473dd0583d36954c98ec5d580e0a758248bebae0eba3e437e29054cc64b514f04346416bd7b8fc388dfd5c6c489e6277acf423c16a802e849629d030c93fb3ab2e81ea689f225407e610e7f490163bfc2a27f0b467b3a9e93b8f8880ae3273f058a3509a430e4eec03c8b281ece974b2c3a784c52a2707508f3f0b3fcaab2ead7ee63a497891f05fd36d0d9a0196e338ff2e56616f8c1f1a5aa43ce5c876effe1177955a855303cb0edeec603f9aa6d372dea6248c432271c79bc67e22e408ac9df500d5162893d3321fec8263d2a77185a511bdb3da5036dea6754b15a7091eeb8367f0390d0bf3d6d9b672892e39cd192eb34d8af3a54074630b3f6a930e69e13ab2282db9def9c67a8438e11d4c82319de7311af3ce18e5e0551423a0504fe0aaf64dc890214ff89bc9dfef897cb630c0c8735785ec2bad8d0fcc8a3cc0efcbfe9f5ac7e5368c98359f6e518ca1c9f182a359d43ce7aaa3b52d56a5d05fda721ed986f5174273c112584d594eab757190bc233d7f556607fceb2ad32ef0f099fb599c50da497fad41e6a06cad488100655d01367925f7499d9a5ffab270ce2fef2f997e8705f24522e0709940a750b7bc05b7cb1d19d307dc617eb8eca63034f994d8c45f48125bf3f05f1fe086e6efeb96ecf194a19d87fb3cb5cbb4d7b8d1123e91f930e7598344a227e6996f21f31bcc6ce57950eb5227cf0bd5bb56ae0b8eb9dc6d9da3b7eea800934cf886919eeae8d9aaa8f00d6a6d117b96c24fc0b5d2171a16eef7fb7344c80ba2b91a4ca7f12ce533a58f9a6cf36b2d2bcd7ca512edfe547f80f703e6689e58976a6eda5761c89b8317ea33c2da9b384b4576a81b8b2e5935a177f94c8b4484b72bc4bfe36018f1228198bdba715efd19e90d96ae134006623ed6c17f6d91e57d956b9340f0e178e610aed04a1cd795975557a18a7fe5260e0c0aa372da325b1dc2944173d621d1e56f18fa0530424764c6bc2a0e701cf99da61a1220e2cbed8980edf7d09a91e36c82c0a5d5fb87e3d2fadce05a8b186409e1e4eae493c58a62daf333a2c8fa4438f23db6e910472a0556a5208d4b3a3ab3f8b62150a512cabfd73bb59014aca6c3abc6818c2c7f4db6885c1958549eed54905ac2896e1c7d7df99164a06af9a291baa966fdfb9530660daae46672b8b285477e638c342f62c1b9074ecdbf2a92a1c4ea8f28118c023131b425055fa19d79615466a5f57b27be25edc79ae3f75cf7f0bc414841d8781c5c2cf4bb91cc301832efd86c605ea64f28542809889d2962338ae208ab8663c9c4a01e1effd8a62fa20048cb13f40a918a1d195cface52b1709acde67372a807700ae21a9d2248a21b09b14fc6df5b0455ce55f047825ac6f4b6c4e9f7e69d5bdeb79570d991806a1cfb98e1df20e44a31d4082f9f8c94184325fb8e6abf22714890578820fb05046b61c55001c2bb352eb94496668ea1e8f3d4ff81128355fb86f829d3921705beaf88b414e72ea46db94151f27f04a16e30f90b51bb63942f056880b811939080c868109d8f3c5a425c5e067ea53c2c0a226e2e43c8038491fc20185688a5660879038893f8035e7fe65c1ce475dd3611c0712671a960ddeca76314931c4f9c2954c973df9e9ebbcbe1d4e1368aaec578548a7f74c8a82783cbcbed9b74f0807d1328636e16d071719c4c319d8973163870a29c411f0e6634f2558eea5cb810c503f712f16b425b433fa3b15cd07c756771207a579483dd836156f46f20d66cc2cd4ed973dcaa42bc87a68dffcaaf10b552194061c676a91c09cb38431328c76e1e7c44b508af6a89df100c2aa6c27907eb7728d8d0f6c6ccebb34705300b8d7260d8e81853a96c412d03623d71cd714f5745bf6f3117ec53609048465da9a5ef6e779c89763485adde10a24d7487405b3b6a52a9d4f1d8c946878d3e2996919dfa6b25adbdbf28c534cbe369944d9ce827ea1199946c8f931ab4b0b29b4bc72b9abf2fb702c6090bca3f94b62403391d6a1e056dfac9298ab854e000a820464bba7015cb5c62d52edb28a03f839f0633c4197f6134c8cdec42885ee4631ba919b6e6a09362c6fbd5167274864a6e15925a6c78f21ed359dca3a6f2fe0efe8317f4c918a1be6b1eec8622d588ec7abbaa9e8a0398867acba51c1ffbbbc396f03f296c864551a0d02427571633186ab6395c6097a3b39e70a05b79ba6521d4b1dc55aaea4d17853a3be2ff8d4b59c75dc7cb3c2554935cdc00a2c2c4cfb1061e5a25314266afe48eacb7da596db45c7e9940b41dc0f4cd9a0196ca16f5dda7e839c588f168364b970942ede6c2114f205fb3007250c82a23bfa421c2c382f7962c1b649766e975d6e18131c004b6e1c128de7539fad5335e3ae4c9bbb417485428199649a2dc38d374f4a3715cc22c8bce5dc40d4e5cb92c49cf607036f969669128dc92f96778ec22e031e5b4962c4424a0367cf16440086669a69b9904c4eb849fcb1c3d28f547881617ec4c46f4c1efe2577b128b86d617ce2f0f34299a386c95edd7ba882d6c0ee8450f86a0a910bd387d8eb99a184e3e6834e541ce3c0d6d3c68b37d2311d308a431b5cb5bab291b311d36a67d869fa0022f201a8f98e60af57baa808b3308e69af5c005613a2120ca4af5349cddb1dea9aff804e775c13ee72b7b7cf3b95562a38496c483fda1c0d35a38135b743943b14f97a51e911d8ce65d78b25416623c2209d37dec793078be11bded716255f89f8dc8a9c297fa4ea7f6ff88d973cbe2c56bf243632f85ae6152460314156d965326052a9442d34ac54b2b68ca351ccb8ff93757bcd69838633a58bc253dc20f681cd5a2181ed5b3f8d9433d72e07f3dd3ee1ce5240d32465adc037fd3dec4d4933d1b8c0f14ee7c3140a95e1ce724146e228385c08ae128ed91deb582a355a53eb14753ad30cc90cb391ad6b496c783baa2b19aac21141e4fee30691499b74b4d41ab1b5192cb247e3ccc634c3945b3001f6cd38f8e63ff08a2a694126c58beaa652f91d8e1be3e83bea2cf905cfeac5f946ad253115839d7190f2a6b4846c43b9a00f79e05354c617d7bc14993e40d1477e61887dd7103dd86e7f4c215ed993b2d2a068528d5e1b835df4fda9664f7d1d26b9739ca9260a020c3203dbd7217daad85afbe95b4c085abc60c5b5080765c4ed41c875cfac02eb9a262762764048f8c7388e2a0bc2c8fa7b010a7cb9d150095920186742410e8fbca129673317c2a4579a1dbd7c52ae5b18e410855bd4af648458d49398eecbd24e72acad88fc0b77d276bf621f68c2f7f3d1108e5057b47bbf9a188fc2b5f4e774009e7761ef8ed0900118e0f00915c7c5cd73709719f216287ec17572e11848e2d8809d2797c3f1a97eeae6ffecfe26323add60fb272a029ed3fe06c8345f732d8d0adc106659a88797d853780a5202694fe3ca47e4aa4c6603ea2de37f12181c2abaebd91cb467c68abb0aedde416194ed22b1ff8346814805edb7c0210d0a5b8e0b7af5f87001de60d7d0fc7f931dd8ed411f7bf0b05a00658bf29d05e3b4d87aeb8074f1b72e546fe30f31732a90bc67dffeecc2d645d8a7ece89276d1067e4a732248487624fffa8ecac5275fa563dbc1d4ea15548724233eef2d96b5081f099fdf1c90e1b5916952aef5a08437e1cc7759ad400575e268a8cc8d3bbb8c676e596113352cadcb472527065cbd93b362737f11a71be494f6e97dc68bbb47622c599e0e5205c5f06f2342c1788a50b961a4bca199d1d4b5c3dfc817c0dfa4a4cdea358b22a646aee41905e1c76279658be21dec2d83afd55fb65b1d604c7ac2bd2354a80243aef52777abe9e2d3d85725e904d39aa87a15c1b66227a94b67f5e320114a30aaccf809ba8563d50fa4f13cb22c3d6c049496159e5e8b3282ba1818891b365f2b42c9a83fd1411cb06984f805551e25cb9d08f927987e42b322bd274144093d20400c92e46976e0968433d4151a367c944ce57e6ecba6f538351cb478728cefc62d802ec7c74ec550ee76a384387aac840a11ab07d987f483c715309641c3a9947fb27671dfa327d6d3b47df5fba1dc408a5e6c0a221fa433b26b8814341915ec6c6a7d56a4fa3b0afadfd531deae6cd30f98684de95e565385a7b75baa152d2bb0306ba25acc31cd87c2fd059d3cdc99ba8d5063a6ee40b3c81ee9f1e7072597e0d7419bc52a0cd96d1a4ff39950f1f48d77117066014b47a4102f6ebe272213d93d6b59ff8c574820cd452f7ebaee3a1ab807613959791f1ed76b8a7d8322e71eef62e6bed865c4300539faa457a36027df27793fa3ef67df0ff9181000a02f5af6514b19ff0bba0359d2f0e3f89cdc986f1b06ea86ee072b456a6b136ca3662f0b78611567c6adef7fcb193443435380e3605315e9ea5d4eba382624be346b61787505ecced7ad4a90a5b696dc74963ecb53b8b1b23f219aacc2c741242a7b127b58073e4d7ec55b4961188e7b3db8df60a94ab3b9a50548ffc62af3d79cff79acc6cea86fea966639638b4028b46706737a161f68ed3ca815bc765ed4836c922078e319a035a6658c1bad897927abf8e43d15bddce039e894ce9291884970ef4b633ceaaa0f749711409cfbc5fc0918228288f22cd680c95e908cfde2425ff522a03692ff988a0de80232366ba87734165a6d9a3f253a50403037c4788545e15e25fa41f48f03db58409f819e9b18a33c9a9520ab01177ebc8205ded668e8ac88d029e9f00625d99c19edab457f37765565335e21f3addde63f57c79991c81ef12891eb8055d02605cbe19363082a95aec6e1c3ab796767d62edea21225d1eeb98958baf56b5b664e97b1bca42274b4436940571bfaaaf65544aac7f2da9d102bf00dc71a4c738f909f31f7b0c28bc572d83287ecc5d373abaf5e92a76706d9d6fc8372071cda75eb5254e8a80410e9c2385cf03a1dcc21b3e890c2537af59717e9a83b0e7ce531e396b36dab599e41242482a1bd886d2dea0dcbb1d4f086c022acd4e4257206e24b7bf689dbd6f1f195c371db4677e652a4323ea37a884e35f3866444e1ccb94db253ea7d8d5f4dd6834dadfb3120a31f89b458560b97a5140eb86664df5a2ceafc3f23a8d1e2654260842c3bdd872665df793ae5eab0cbb08691de22fe225b83d4ed081df30e2dae98c1d4edfdcf283712ba1ba46320be48fddd54ccf5964e99ccee9764d68055d3c8a286e7729b8514aea38929b5236777e2e93f31c707109f0f88d218089789f6cc5cc171921c9dbe458e96b94599964a3140ec266559e784db5b3b2ea0eb13d341b98c4518aa7370b0f93db8b808a824dc97c09ac1eb8d50b3a9141a77abb8081b89cc2470ba3c613e4ddb74c218f12ef423fd3a3897738c5649d608ae4fce6a067304a05ac18c9ab35408450ced8f7f66f33e6b0bb7f9d1cf5793fef96a8d6aaffc7b136449b2826ecf2ebe6251a6d700ccc5b8641ea47871233c425b194e5bd7119789e7d34eb2540d912a9f47b0a732ec3d795022fe454b76c7cce1499d6f7fb55bbf05fb71b591baf090e32f24dce1c878f69f288f7ffe4766e9f2e9804f87c9c47558da6800070d6d9fcc021c0da1c2a5544f0096eaea8d7d110341eadbc4a4dd0e58c6f2530a6c860e2fbc9bb87d4d9a969b531d616b777eac8a23ce7210c8c63b0cdd9f9e7a0f99481c3aeb284baa781ad6e1d67708f9df4abd9831b4ff079e2730fcc88eba803fbf0d051e1d69f426f9be322cb540c55a9a4992cf85c714740f3ed680273be08afc8fa8fbc688f28cc36749eb4b3fddd1c940d2fd1fae735fb1bae9eb7b56bc803224661ff9576538359e796ec11810d357dc5cff320bfe857726890864bd3703f6833361f6c04fb86d5fb70e5a313534713512778523b033505384084c18082d5b64e368810e62ed09c2b3ca93a21d4546bed18adf09cba1c26c5dca571624af58e6bf835409a0339f748cc4dc9800daf11b510ea3207e2155a624183ce7d8478bb35565ca23daa6f16cc6f4ef679606cc553f40787868713c5932d0eb9fb2cace1e8ffa72c0090e6d4fd8100be08a8952deb60d0c89f91fd1271bd7c4b8902ecf6e09c3a52a54ab2fff4cebf4e372a547ea7aea9883b6a4e7c5bebc5bdfe50a85fa0475bf73a7b5cf32e8995fe1a55f00c47f93a78543ed404f35ff50b407abf3fa1012777968d327874b2a7d855cb030677cb8d1da2fea4f47329488725f2c0ea8628c7df95155b614178eafe26aeae77545a3288dcb805d42d28c524b601437e8eface67831fb67106f4b87a459c1917a561f7a49a1a2bdce4254e9a16bee8c34b83d9b92476823a844dcc6d8fbdf4e6d27e220f30cb8a71660e51e19aea9c46cf996e3d78c68754269fd150ba0c06bfa45967d8de314a80f92aae4d9a6dbc17b1cd20de2418a3205af3217ec8d4a9d6a0f27bb6dd32d7a53e3b6df5be28ed2c719121f96023efa6dd2aad89391d0660ff93ad12bdac4773507df5e2c6a00b5207fb0efa7498f0ac31a009b1a4aea76c43b818b1841744ee1ec05d4216a19531fac06eafd65927eb34dc440c360ef49cb791c37a7cc4e39e55f080fce67fbd50cfbc52b3b57a516856b7021f3333def9cfdd331672616bc6c77128a1cb84de7625fa2636ae83bc952c3cc6daa2e97e6de5b04512997d055ee4018f56d45001912496b58830166e4024313c71f972c2cc37320cbeec7d2925675a607c0f14f5c365c967a4174ba03b437d203ea5eb021c69793a6a6c892dea868402ea135aa3469947b7029a00861844c05f545470c4ca4d1c2074685cd98a02d139a9fdf95aeba128a2daa9dd8781e322d23951c109ac5e36aeae5905afad8f1be7b3a123da347159ec4dae71d6923b45f93f2b9faee531403e0b1274078f7e95f93dd9c80547c91920ebfe249f33b5ac20f6e78aafbf378851b317c2c9dfe03cb042f0e11320b0783f82055e01a2322d709132f9e503c80652121f4c5ab3019bdc9b02bdc00d48b3c940cbed9b13acbe6f38727b7d9956fa0817a5c9d74b52610a057de9d0713c89287049a699d4ab46586e5fd85c712d0d11f01d51696c8c49722643df9ba822898112576052b556f032cd30661815cbf66e4c43a7ea51a9a26b9bcf696912fc05c8fd704d0003864e4505800811862f00a224600b71cc14c8a02d86da204318a82410f449d6bba0eb4560bd3980e0f70ffeccbb8d6033b2eb0abc2b75efaaec61302545263dfe54d6e4864b8ce00f97df970631233c4224eb06c50caeafc452a70f1b6d10203bb4cf7fc852e5972f7752f4010aa82b3fffcc5f2e0b83aafe7ce23187d447d426e8b45c3b4645bff3b1fba6501af18248b076531e4e00df3e6251224ef906380b166c156361212cdca1c540e19787a41e32e5d423746dc245617f00421b1bd20d4811be166961eadb6d9aac975ac360de38c0b57b9eeda3ae64239e216d92b5f7509b260ddf756f5ce9b3a1d6563235bc265422533b105e91039816d49d6a30696ea2fa1d97f91dc61214553f010ff80a3e1989c998e1f108c0d7b0292206d8575ea5884a62c5a14a2e9eddde515991d0835aa336bc49bdd357b9b3651a22f67d213d39d9eb2efd0d8200efe9cbfcad4c663b6335a9ba4e1baffbab58f04c9237f9c2c0f73e15d1c47456d31369bed6fdecad58830ef75f7eb66619c29a8df907f52bc74b03d4f29f7bc3ce852e8c5ff5363eff08d3d4d2a6a0fd6529a427cbd7b3cbfa916e7c4b83487a301f54d84c5dbd54284c61ee79e0b458431436f278213fa45f8afb7dfee1dd2f68284c908c923308f4e3da98c7190292fbf26c780cadde4c30bd2f701ad4b2432a2888e7164abacebef54ac323fc6600299ee5d025e5e54ccabbcc51a1219255e0ebd6813d452b51e966cc1162979cd5e9f2ebe8a9eab1be61a4da1de9d4275c9479c36fa542999383323026f030923eb0e8742f4291decf1b72ca8dfa4456356e8df559e2052146c943fca05785d413a757c40be845ed28bfcd8e185302255b580ba67aaeec24708baf80c836be8d1d1251a45e9da8612602e155320cd7e02f46bf2fad28bec156b317b995f06698a5f5a9100a32aa84285715f818b2cedb843c2fe2dc6cae5a50ce667311c103418f04eb4da53efa976bb94d240ec4b0c69fe75e60c185ef77ebab95d9a7d2b8a2d993ca5597810c234dec0688e5d7c901f665553d43e163b13e10e97dc22afbc9212e6b6b19d8d2078498a4e46afbc34afd62449a22ca1fcab85cef09746bc5f5c461f48132e95ee0d165c9c1627e1ae9b6373aa0ed3bda7de2c19fa890d764ac506fe28df12f5fc90f77b9230ac6da5a2c642509ba12794286272c4b7eb78b85e89a8d7ff75eab954843b4e4e8618d4e69d1f9d37bef2e8ccd6711729a14a2430c0ed5d934bda4577279fc5c734c4b082ee68a40cfe213e15e402fde77d6833b0ffaaa94461d3ec37814f6f3ad3ab441370cebbf1c8caed088e2a1b4917d58177f29031dff12a70bbc053446b7956f1ffcb389ed07bb01e92d3efbaf66f9120fa2f027c17d3fcf5ca8b882de01915d971b02042f66d11eb845e9c3bd7cc6c447df57244654f62b075aef9f643fb7eeb7b1520ac696bb9e09204eb5aa7374e20309098ba2f93d99303ed69d0aad204add197dd8c7d5224873c53c20e3e04f9a325f1ec7ea7a5188dcd771aa96730c31848cc1dc04ad40d6e0ac6ffea633aa8f7e8abcf0f6d50814aa5f7ed630eb6ab16c88dbe4b628b038194e88b071ff8e8b347028084386914c58bb373ce8f13621ccdc4d894d9c06661869a04970dd13b94cea56cfc6763ea7a0964030dcb8721dcfc5a3cb9f8abca49c8d8818ffa578ba6f8538031d63ac4c45a8a851626058ab183527d00b921b320630e50498d50a5da6d0b83b40b70eb8f35456f6bd01aa3afc078f8074f988fd6285f6a5ac8867e85b88ca2b54db6e5c929899fe836721e2c7a22a22f1ccbef0046cae01800b4fd803041be7601d8176359b6ced37a27610dc337a6548a4cb9055a6c1ad0a86353f990001edca34c8c7f2e980dd3d4a7880a30aa77f2db3e0345c17a8f9e139ffff46ba802031afee31f1b68b4e043c1938d5384bb68a1ed7057a7209115a122c7247bdc7f5de31a01ab19ecb29f006a3d03aafe5f1470f20e7c6de66c1fb2687bc1ef7a7aca397b71dbea870b4891c7458ae05e3e2b09d377644bf58b0543236e9f8329812c908e23b7e408aac3a34f43f2d7a81c57987947fb025b683732aec33ac4fd254249fde6d9752e9eba578f95929c2d648d8cb626ad75b8706f70e5516fec7ef8519781f2470d0e8beb4e7dfbfecaa9260611d199b3f37ad5f36489dee75e73a626152cb6946095d2e745eb1d5b5a6ff67e2d69083d8a489e56efe741a0fcb2fee1a7eef9396b8194e7b1a6d4da1659945fa0aabcc00afcb82b52012eeae0725a4a78f76936d5da3cbd41f22542da9cfcc324b6ef7faa8557ae1636e6f0970df6edeca6f11f25a04fd24cec0df696c79654369c086286dc2993fac24e7dff965e9a4af10bdd771810040bd5b56025737b3079e18d2c7754b99d360dbeb4924dd1cc7a01c558df1a7464f093de15120b2397ee05a611d1d51a3bae71c08ea6089fe237cbc953cc006085754eb400c1ce50b5702c03e7fb3340750bcd13980db914c41fe4a8fa4cf6207d542c13b31ee087a495474f88e98867c79362a13704035a15af701725e87b341f9ca6bb6dbe38f7fd2f04201c1f122e4803f1cf3244b6569c1a2f207a9442226517c0837d280b384745113c3b59a531a809d21ba715322e97d9ea74d8db3aababe0a8a217dc680c2b9d72d4bf5614cfb9da81f9154209cc9dc4c31a725dcb5ed85b0d573c9b2fefe7db63e715936edf082b75b45e1e04a8b34e7bd0e9b395aa5dea7c163b455c3dfa9f9ae13f80f8496d543f581238ce5ba7969422188b3600d82a1c4da4575e20aadbfe49a2d6a5a13012f112d89a28afeed61e339799a67e12c6f22cef946d1dd9ee220c7987887949da7d98247b90fdd92cfab7645dfc6e5db96e7a17541b172964cacb9e867425df4451e68a3e8072d4b5b3501d650052d42664eeec237f6433c02322fb105a19bcb7d7f84c33bcc09494628fcfff28b8d8adb6949a0b65b4a8ba40f5c170dba6511142668ca8f9271d7db218d97c8b67239c3b36091e642f8b445cb3a40dfd21dca80a432231dccc56a7ae31b7a4fe9241a6c9e6f7295a03dcfe1ac242f2d7ac850b15ca74301f240b877dc930e61124629384db2e9655078ce8ad30aafb40828f81816ab6e7f5c72b3ea27cf1ec1de02abef63fe87d822270a87de1a95de274ef431a9e613938396975ae62d19643e7ebccc93fb78f49b09fbb46c5a283bbd6df14d31185fae10fbd8e42b4e4d353ca1c133fe193390fe9077023cdc215b98e0852947c1005135c793b48bbe2908135ee75c1cbf252d5e4e091cf5a0422f7f0009a5accbd0ec3da4e33506957122f0a23b3a295f4b63883205993c7f6b835fade933a11c4b74dbba6797f95701c808563a6dfd8a038873803bb064dc2027c89b751c52389f3fc89c6ca552ce0c2d54589fcb01642b9904628f1f6413fd627d5a35f81605a1fbfcfeef299898cd1b681b1a097352b0bb58e98b3b131b620719c65a1d698ca512f0469167a3c052de2c8fbe96234dfc03f5c112af7ecb0b8f6ccc3072a20b90a1501065529d3970f4f273972397476ed08e8aebb716c82cbf4ca90b646e0769fa5637a6c23bb942bf0331e9dec4210f06c6605f326e78c838faef8d524ba0612bb642ecfea64b7cac69357d3bc2b889bd1f1da0cb86fd7b70b167e4d49cc889f3b4fef68b9cd3aa1a6b0c3a81916938ec0b995449b8d1d6557475a15fc8602404c530da465e8803ffaa555bc0555dc6c630e84f95b1a4db24a95c72939c6bab721bbea22be88556603d2adc2ad99dfa52d90d30fbaf2c2d557acdb082855fbddbf2cf029980a1fb9be8c76482b3f83c924322774f4b55c6ca280dc44c88d90e9479db9236ae4da2f4b8c67d329309c6fe4b9d9b58aab3e6ad3bc76d32911aa766d13a7c4f59a730cdbc97131c4894a5965e4ff7a97682aab9074c70fa222121ca50d7e5551c94d323bc09db58e7f49ac71ddc37770b8f7a777b8714f26be20665f87c799adbc81cb1034636e8e543475102252cd6d6324f42a67d24a82750204959ac4d58024cc20c71e67ce01e577abe12ec82a3828642ca634af58be3a2e0f657ba274fb5574ca172e47179366e9a9a6929f4ad7cd733038e607f13b5da541290b7537d02c4aa9511605f7a9241598389d32dce3c60154e81787ae8c72ac576c6a290fb4560569d0c00d37e92a49711fa4fdc83eb5f1e44ad74a78bf6230508147f60ea2a0309eae5270691bb26dc9998381413663d67c10a152d330381e437a55f83b79fe4d0b18d26494c2461406f926d72e8e05c5f1fa36575f51d3fd6c13469c8f43a956668be6f746259dc5aa0e7985417ccdeab7353e2b92a8e64fe77648d7ea2050f8bbf93dfd4c0abb1fea6fbf8b4013bf514e63095d5919f13a478a4ff7139237786b8550b370c48898918f8ab45f3dd944a1372582e08eab0c3c649f572c2207aeb05e1749ceb3714bca6054196737f40c6e031e8bf3a821b25e7b0ba53546d60fc852aa9acf86059e62060785ecd325930c3a3b76ef68543c9bb52485f4b304d0872882992ba56182bd205acf2c3054ba46123bf989c7fe0397474c5e3541f42e1c3d7482fa279b692e1e8b91ea397a82c108260f427ce542111d090541946b9a13076392277c92e4ce1d7ffb51860b3cf4efcc0a79a11e30e20bfa463fffbdb37843d62b5945762e1334b8d2929a7cf24db00bd1f9298d7a800cddcd551ad84d8525f70b8cf303797a6fe1574d9f02062c52b063312b2e6b51a3a6abb05cc51abf26d858a4f84f27faf1d84f7b0f3a277410cf3d91236ab91740d21df4637926cf1628eb5c49d12843e1f8b5f2ce0d53a5af01e8008ec6ff02e53dc4fbc12b0f632d8a91f37aa79003d11257f36df5a36d61b0fdf7faed0b53c639fafb211019538d9361b45313fce3eb3e44c7c9697a296f85ddc9f666438c4a21540cea64730287c28563baad30a771cc228a36aff90465f9d1961f16ce90e602edd890aedd7cd8b59e140699763fbec2b167c43e09f8ac9bed2b346989ccd73986c5e5807598428e61f35aaa14b648e67fe5fa96a6688e363141c7b74dac0125d8dac15415938dd210c78ddf3269113a484e3e7e30830964bef11d47d40cca51d9448494c664ccfc3ee058b161bfa52e66f2f68167dc38e82f82cbbe644509d6f9918feeb34934cf7d88d90cf4c77242ae8d533033b63d3d47da3558407c64deff59cff12bf42888925af0fc3412397dfd586b94c331c9ceab7ef1538db3c10e04fea0df4d402caa7228c5c30d049930ef92352cbb8d98365ce3e0b32b7c99db35e7b7406b287eae5be4ced27acd61c45a45106ac0c7a7e225b65f69683f7f19311a70e8028f7ae86e2178faa15b6c3eda420d962b9b2f6267e4208d972efbde5de7b6f29a59432c5070008f60822ec6fd95fbf7ddf7f34dedf927c0dfb9648fe7df2ef7b1b7c9ab28774fddcf0c5b2f5b052ebb2f256d95f9bfb3ef241d2f5e1bb1e2c5b7f4bf1c9b2c3e0e3bb4af0c3b2670c811ccbee75d963f06f1c7ff718fcfbf95ede9e57d2b7bd8413c0e0b3b35788142153ecf601b909940a9122444a4d7531bde079bca2883129e2325fad7f1443b2ec306e384197065b7f47fda28bfca1266dc6cd2386df2a7b76e9b0f5fa45f8bab4213fdb909b27ef708bd9f53b55975d7f4bbb3edc3dae27770f08e3720de3729706750dcd0bf67a892f318b2f317790b7fe569dd678b5f85576f15fd77d14e5ad38f7925af7175cfc298a5a145ff0f0318c1bea502cc350c43455431173eb92f7f5e2781c77f7012d203e9db6b53b393e8af1efee2f3eceeef3123b10f6d2afd877b0bf5b87fa6b68bed32ff1c7171f7f164318f91714c1cf39835bfcfbe2dfcf4f961dd44f8a9f37c6342401ffdd36e4dfcf3f9636e4833f8a9a8be4ce0f3ef8f9c5f173d97df805b31ec7edf3e239ef1efde4ee097ff479e9308cc16a685eb0d74b7c89e3088a3fbec47dc1b1d31aec34388ee5f7adb2fbf056c75d3fab4eecb3abecaff167c51de04da678d264d97a11c5bb5e7cd7933fc9fd12b5cbb5fbeb05e671fc198ea358761f2eba5ebbca5965a2f8f85194b3e2a07857c7c56f3d8ab2e35d3ff7e3c85defdadde7c5c79f2f96fd878f4f82e2e312fc165876bd7d5ee0383e388a8fcbeec3f18b25fe717c70f479813eafeef3aa80077cf8fc4e4f2d38f478e2f3e226502d38f47042535b2f28819fb3fe4bfebdb7cb00eb459dc1f1ee8e318935c653044397ab267cb59ec6a5c1cf5aeb7f85e35f12bf76217e7efd20b979c49defebbf0ffe8ed5a5feb1ecb9f5e25bac41707c4c6d445cda889f1f3f69236e9efc19bfde5d0658fc3e999fd32dfce3d6bba7f5e2ee79bdfe9d9a750b7ce957cd8661695ca1cb05bac02ce6075d601641171f071f97df932416aa2b5a8f1f13d515aec77bfc3c8ee3d330048dc52dfe8e6d8d4bfcf56249be2ec39f21cfab1c77c7465c0bb94a4c5465fa67e8a2b5f587c4f5ee3ed808c424c620c6baeca2f8ba145f6bb2f562d93f70f760fc7ab074fdabe4713df82329be2ec96f95e358564e96fddb3ed8082c737e16e483a5f85a3f59f288e0e3b2538e7fc43ed8682c7b0c0eee8e8578f833dcdff72ea07241950cb0786c8e27429cfebc26504e733c09c230aa8b72f8afb2bfe0afd66dfdb8bbd67af717fcee3ebef83b36e7d7fa5bff55a67f2c5f3de1dd77eb7bb7fe96aeb270f71f1efe7c95938b61d97f2a881f1085df0791f0fb349f597cfc7e67fb0b0ec3f21e9abf8f77474102f8b7e62ff9b1bfbbc3be862eeea6e9d156e88f4d7cfc1a2620fc3ef879660cce9027ffc5a18bf1f1ee2bd0dc041bde821f1e3e7e5d76cdf5f78eeb70dbbcbea7f5e1bf76f82dfd3b1697e1e7b2b74620fff5367cfdbabceffaf15b657fc15b4f4312f4df6df3fafbf8c7d2e6f5e18fdfcadbe6b54598f95ff95f9ff72bfcf0cbfee2f6d67322504e76fcae9d22890effba203fdc3de4bf764fcd8f302e1f378ccbc9d7353fc7a7214fcd9e28360ccbc1c73fee3eabec7e6c5fd8866139cd6370ef549ab2c7e0777cfd5997fa69c863416d02deb297841e7e876139cdee33e0f7c190c5f7b7ac7c862e2cbf248cfbeed6eef86158bd3b0ccb710dffde7bef95fcdf1f719e8f87afcbef471bb2f85edffad6775527c5b73eb74620bfa55dd5453eb9533ce91f5f2cc1d68b9fa26cedae39b6c00fb711bfe77eebc57dbff577dffddaf37bcac3ddf37dfe2fff8e1dcb0ee34e123c1efe4ed53f43fd3b957eae31d1e0f9f58f252efb0b9b177f569d142feed7db94b3e2bc76eff8387e8a72569cf1776cab3481729ac765873d17ee1efdf9f3cf90478b50f33d2e5b4fd2bc6b6c3dfed6e3ff76f835654f6bdf2a7be99f7a8b3f96aea729c9b27257d9613b2cf3e70aeab2e76fc10f6f7d986d5e2ffeebc3d2f5b81cbfa5cbfe82eb7f95e363d79e55a63f7cb1ec19b76e3dd92a27ff3a8c4b963d06cf36e3f7e0d73fee144fda8607bffef1f50ef7acb2717718978bbbc7e0598629fff2fee8df9e814e82fe82cfd956cef0624a7faee005874161bca6ba5ac82ba0dc84f93489cfd045c7e7ee28cf356c5143c0d5863c97f718bcb3b75e3aefbdb8bee575f718f0c97f2aa539bae76ef53a6fb320feb98517e87eeb3812b83367ce98e15b0d5d7067ce9c79a2fb99224512ed13e3f7bdc721cfc6f1e70ee4586c250cdf8e110b43a8dfd5ce2b7bc731cf16dccafa75c3fc62197fd29cf9d3957366bd210bfa210bef6f6438a5f77d9fd7cdf87296ee399f6373eaa4967e39e7cf9bb54ee1bed2ba141e0bfa050cacce8b1d999d5e92eeb3667fc7e21d8b711611d8fe7ee7bee31e7fc7755dc7ed7dabac5e1a101983e118f02bb73deef9c1fcde831904c1bcb90d533239f3d5c1ff8d0ce77e3962ea7b5f529ea99da113dd9f0597dbd72ffcf6be6531e7ee7efbeefdb75324d15e0d79bcafdfd790c547bdbd6ffd7963b544dd30c2ed7f6fc75b756ec5b91f3ad15df3cb82cbefdf7fd5158f628280ff521cb2a0299ef453efb9efdfe7dd7dfe1af27c6fed4f9ef3083fb9a4fcdb7796dd54611f97de5461ffab11798e56ec951f7eafcd35e400f7db8e61d3013adb9eceb62d04ceb817ba331adbd7e82e07ee8cdb3580c6d9f675b653f5165ea0be7d1c86f0c32bb7f5c70c6c7b4e05748bffeed4fae3eaaa0b96124a78f97275d505abc6bfeffbbea3e05416db2787c7744c6fe5eb061aeffaa7f2bcb949da036f45a82b2aa722d41593db113200823f68dac1d4c15b968244d211a83660f159b301892f80cf1a53162ec204c172fb3cb68675040ed4155de601ab93e3844443948f1ca08499d94740a57c8620f89d0a033e210158b31809c09acdc901bc6f9900ac3a4295591174907e3e9358a1c1ebf729c5b168b547e479d32b1d829c0a9afaa6a8d5d4831e666ceae491cbfe3fc8f1b6eded7d3ba70aee62304786f3a5f876f75a03af5f6178990c33e1ed6328426fc758e0f4c826cbdf1ffc1e0b413effce15ddcfefa68ea7136eb0ebf29e16a7d6ca9aa5e2d4a74af563b15ad541ade2f56918b3aa341b8bf5926f6f47c0ef732ccea962ab2b36bcbb7c8de866a5f550695e6775bcf7f87c2ffc2a6dce1a10af53c5d745c7ab34afd2e6d7a0a943952c4efdaee6a82af0ea5125aa54654cfacb5eeeb8bce17cb3add400158bab240ab9caa832aa8c6aad3db3bb6a2dd6f48caeb41a1bcccfca7352ba3bc8619067a594524a69ed513fcf09862c686179473da0df42f33955d08d7c5559576593520a03e5f3d2b7f46b7d4d89303345b245114973ea66c0ce2916299ef42b95bccf2c18581d0d4c1cfb54685784ec97bccfa9ac0c4c15b688a949ab15e754412b8de3dd55d97ca2ed7c71076d9f36a1edcfd7e966f6d6a4e40f0a4e4d8654de20805a009c68ee11300efc6a1fefd65a3b67fdbed0d086f9791d97b9236a11e0535f7beb9212573497858aeeaad8269da38eb4a6e530e48926f9ace5e0c309ddf1596b1a13d57485f7d748344159426f7cd69a9a601b3e6b370cf1cc67cd094a4e931278fe3c6b075adf1b2e769d2e4114a1caf08b175f7cf1c5ae11dff8dcf8dcc060ad97bd367cfd61b9b5f0f83874417efef06fd96ff815af78c52b5e91dc793ffe2bbeabece1ebf35b71a748a2f5dfdf7409f7f1b6191f7f7e5dda8461f83dc6c5f0fb733124772f81ebcfa1f872bdf2ee6985a5cf0d171fdff0574b6cc5c41a1a180ca65ffc2cc2b42866fd224c8b592c818f1dc06ed5d137aeef37fcfe4540032270372902598e2f6a7cf16dc1eeee37ae7de373e373a34bb8792e3ec71d70dc01175f3feb8a98ab8c71dc5f1cc3fe3596e238b65cb017cbd7c34a9e97ab04576bfbdc94e073e373f373f4e354c207609090baf9000c125130a4ee69bef97dde7fb1ff6afe83fdf7fa50782860b0d7eee9ecc768becfab81795ecddbaf81c176ffa129fb51ac660b5974350088bdbe039b1ad793d955e2cf35e70be65274b570bdb4b86dc61d82ebf38b5aebefd328be85f73010b4208acde33dec3d58b67784d78f3f772a69c5b73686431244d893a58dfdefc956cbc6ee1060dfdadd87b74010d4a106ad4d00be458a47e172ddef2dec5d01d83c291ec5a7803d8aaf05977c7b02b7df02b6ad0f27ff87872250eff564d9ef7b3b45126d3fbb78bddd3daf1f770fcddb6f952f0b800dc3f2d877b0afcd8661790de5355f63f3e75c669b6dde3561c8a27b6bc5dc7d9e8b8f7f5f63df5d1cf6e48400483da80f83fdad2b6a1ef65d5d81e2610fd615340f7b3d41783d0cdcb0320cc30f79f8b9e6bc6df2dbf0903f7e0bf2c79ffce3b7c83f8ee56c9129bee66d29a6f89bb70dcf0ae819fe7abbf55491df82ef02792c087b2b73c576afb05b92d303d7dbd205dbfdc55deffa5c53de2a733d4d09967aaa70fdbdf7f3b7b87b4e157b4e153f3c0cbf85b8c3fdc36dd9bb6e9ffc5b76fb35ad9fe1b8536b4ad793a5ebc7d6e6a179fb34aeb7aebb6d785e6fbf05f686bbfeb5b57efb2df4b6fb55652eda853c3bd645b7fb8ff71efff257e616dfebb721ec674892246cf37cafffd3613876dd06c5dfb19ef75dbebb6bf10a40002f0a60c7729f61dfeee9def3baf74280d9846fc3e37af25bb8c83da70afd3fe193df227c920cb5ebfbb0a467f80c5b2df26febdb3c990cb70dcffdf05b106e3d55907be630773fbcdbe08f657e5849fe2dc5fce21e8b71db8cdfa2b5e754d17ad7fff071dbf08c1f7e8bf1c3ffe1b7cc613996aed286faf387367af3847ff76ec1b8f55491ff6e3d5584ffc367386e1b1ef1efb710c1dd6370ef67eeaeb7bbaea43e1eb81600b59c02fe27769f3c43edc3af5871097ea2057d5e2f2e64e1bd32f96326cbedb32eb1684317e393afcbabf5e77b5f2cfb4bec2f7e497193f7c3b2933f9fd2fbfaeffd0c048323bec0f7e28fa50f099a24c9327c31244b91fc9d2a72dcc9e7eedf6f7b7bf3df274b9fd77879f2aeb9af7124499718b2f048d103431eb2f4f4f83704bdfb0f2e2fc62ec29f378451bcb86cbd2ef36bab13d318bb421721dd5cc8e37d98247f8664d903fef7e48f657ff1d92a679569ad1f7f2c56f5eee2cf6f7dac1c7ffe8ef57985a50994836f49b21cc9529c618b71e6992758431ef25b3fc3f075393e2e5dbbfbccb2c5f89aa705b8c5ffc8ca71477ed8423f7ed98873057c2cacbe965c6587c15da47e6bc9177707b938ee0e83dbddc56ffd8efd7e1c9ffc58958d2f96ae707c3d7edf23beb867958d20e82a276f95dd070471adf7adfd6c1fe6d9afb0b77ff3d3bcb5bbbf7e862eec868d9f6f8945f169ece7dd7d4017e2df1fcb0ef271246d5cdf433ef8ae0d3e09da11fcafeca40bdce3e3b1b430c6b7dbc6f5d6c6f5e08b4f7edbc6b54598dc26fc9eef5d1f7eeffa6f770f826587613bf91b2896fd82bb47bf6bf7d090a52dfbdd3e20d720a711696cfefbe2ee35fbbeaefd0c83590b921684d9bfde5b0b92bb5f3bde6a6d77f7acf6abaddf7b1effecfa5b57c0def55d5d01721b97ebc998de1d7c91f7c9fbf6ef8e95e2b7caacefc3cad6f7d827bfb5ed936f4990dfedfde77dd3f3be0fe4e2dfb2c3e0f76e974b0cde9741ae03f3e7751c0b92b8b7de7a2b77bbb9e27ec795d8f2aeac1307bff7f1560a78c8a3f956439ecbb95957561a15a73e0e59dc5d4ba0b1b6b8d289f90dba6e7ae9baae86ad9238582c7df9ac393da94cf407a58ab1e2246584f7cf39f2d128bf659d322c036e9f6edcdeb010e575fe759a531d9d01c1bb6703af9f22040070ba3da6a9a27e68849e2ab0ade2452a8db010a65d8c316d73fc5404dc3eddeea65345e5f829fd689b137cc3107e78c56f4190d250b5c5c1324c3d75d75a4f1521932ebc807dfc9c9265a27eae1b9d32fbe266413c44d3ead96ab7de5d4aadc8ed9bafadf85e5a62a32132ad41d3b76f8734fd9f53c5b4d6dab0890d07ecac3ee530d47d420c2bd484e64c682e8b12baab32437f50ae64a858545c74eb8c12ba1b43c6f60099aaf22704cebd4fb20bf62867788c83a62f00fa1480396bbd566034497efa3e2c3a863268fab56610e478dd1d0594763c586b393e6b4e31d0a7db71b06a8a532d43412ce9329b4f02d1530affe18187a126ca0c3102658359bf4c4a9cc9eacc2b2a2ca9d28484872339d415b7c904e1f214c8784fadaeb0ffda5e667f2b3bde3e328edf5e27bb2f539535e5a0ad92056297ea0a92d36b03bc36401cdec16b047630ca550241295e1fa4599d9f1d3eae5838e2a2a4062eb30a0a91a0c3921ea28e5ca11065d6412328bc834800e07143103060806898753008dec125a626d0093402860c18333d5ff19ab164bce7acac5c252b0baf9f95accebc32c4a5061162a8502531ab79c98923567a20ddb8818959cf4c40f09e9d086043983040927890c18559cf355e73d6e1663d5b2ed972c93997bce7cbf4e5fa5fcdeafc0c4122091352419854113173c2fb27f553f483460e423821840e49ccfa37d584f78f8ad74fc2cb98282b22199c66fdab62c2fb67f5617d6182f88804f119f9867c4dcffbe7445571e8f72f89d7fe01b19ae2e34906930c42c43c31eb1ed612debd1144d1a26a1c7d890232eb1f4d09ef9f1014de3fa36fd6bf23221e15225e15af891785578f8ad75a35c2abf590f0fa1ecdeac0b480a10273038d2276cca478f7ca90f931450909ad880d66dd338ae2dd43fa711233d5448f15a0a48066dd53eade92c7a49367dd6bb23dc8d81e66aec2f0da652975544a554a56bc7ea764753e10c3d00eab281c969499d59fbd5be255c9081c08297383285a66bd63e2b5732aa207276a514d9ed821c8ac77355e79efa478eddd5417854cd7834c97d411754731de3b244bcba2599a90149515afdf392c2e0c158e0815ce0837846baae19d73aae290aa38256ec92a8b13e2f53b67c42b774464a34264abb235d9a2d0f0be51d536a75adfa478fd8d66757e928420e2ca8ea11882c0ccea2674822c4f84a961048796a659dffa86940224459c2829528647d2ac6f4abc6f4b1b13c7fbd6547b90a93dcc5c85e1156729612aa52a2525abf353e4830d8890310450971a6614e01d2f3de1610490da8f18ccfc9875cc3401deb19306a0a410664c0d4f2f9099755ce3154bf1fa1d4f91bce32864700f32380913e1a317ef18a9d2b26898d6b1901495550e3a78bf58bcde304a2e11254678edd769ea0e99ba4d5517a9ea2a552d592bcf87a82b4d48387834cdbac58a00ef36abf66bd4e2fd1ef5b0547a54e1958a2a35e1360aaf4cd6a956dfd2ac0e079ac2d080ca911aae8e6610e0dd26c1a2430a443352003364d6ad1108bc5ba410b0ac8478a981134e9c9875abf400deed926de232c8701966ea55185eab90d59253959a8ac2a5f25eab68a0f6984124f1ea814a548fb8d009b2562860cae8774a842bc008af4f6b56676e01631565c6142c4b9e661ff04ea5a8ac2816af340cafb34e87f0dac42b75e21fd0a50f2c0efd0fcc1574cae857cb3badc22b3da2463a42e480c20b3ea05003221d669dd256f03eb314304350104e8424d18264d6271677002781d561c0d0103b4431d3042dcaac8e5075ba58cc034db6d44007252a2c2fb306f0ea24c8cb1324559cfc8065563f565730c0064b99188a98c490d1325bc0c6eb7f4c74bf4696ca525d254e9f4bd2dd5271fadd6671fa36abae30e383172008c0ed635b65a9f295145c1cff8d0cffc41feb0057597103d8b9624a1192c3411e9a1ad1dd2a71fab88bee9646d3bd5671fa9d0ebad71aa77fa974af4e74af344e9f22d19dfaa03bade2f43f23fae3815ea68b71873b8ecb60e118ff0718cf2abb97a95f269e855bcbd419d17d5271fa1d0ffae3a2c318c2250d56f13b753365c4ed676f4b77676841470b3726d8d11b8b009b43125dfd9ed315504940217037393dc0c2edd7ec19d984ea8a3e3dd0fba229dda191a6965fa36e88a6e9d77b6fbd2ff2d01bef5f55d07d5a71dbbbbbb1d1545131de27c498d55a5b60e2f5733e42c18603f7f1e39fad87226d756ce84f303634a1349b678488b09ad15d43657680a51983ee1de740cf89a64c6e1455cd382fb33a2540a3667538ab999e20d079e9b43a9a2ce72ce3f28459e312e4c62cc638834ae9409ac5c849329334c37fcb1326d42cc6fc6186f70c36f47f38dddd5639c29ac5f0400c93232e124f68b3181ee460c68f8d037119b3b5c3e50993ca0b54b318d6ca6c5607f417a7deecc4fec3afb286aa66b7b45f66b6a49c091fd1d464bb41d3150f87eb83dc814f6badb5b6566b6d190a66def491befd5ced4f3a9b15cfb6b73724c1c5169230ab0c46e6e8ac56ec3138586596dfa9c2c5e75411bbd2fd43e2f52f161a9144a909026c0373b6fd2d85787d2c6475b6af9f69b8013a031acf9c397366c6fd0c3b5067dc3e21c66cdbd3e28c4a6068adb5d2244e5ff693f2265eab0eb98e96cf21b94aa08906cf338fd8c85a4a2d28b3351cae78fd3a43169562234be956e3f497f8fc0185307cfe400348159f3fa040037e8d2608d46aaaa04f2b120984eed76873b23af509233266fa319393d5117f80b2c4a866756a8d2685a7ac8e0d220a1424b4197d4c6575e6148d4675abacce17e689314dacac0ec5a2d166f43befbf1b8ab55f232aae77c755569c3e09accec51a3716a7210577a6bb63254edfa3bbe3258a24c5fb35e2f42fd375aaa28fad8cac4e6b4a852cb419fd8b846575a8d0e6749530d6ad599d398380931b6ab36d772c44bf5f238c6477c7b4bafbcdda6a384aa6db9c546e07fdceaa281f414ebe2089a186d95500bf4b96e0f7f20bb5440cbf36cceebdbbdb78ebb66ddbb6ed089023438e341d317204c99126f846f7dd3dfa3e1bdbd1e760ac8f6224e5c955121e5752d881a3058ee3b8325715679609d39531a363434537b0aa68341a8e89c5e7930b44584f3f8070909624cab84003902d4374e810ba4f2e98090aa27788d010a321484394862c0500491332316c53583b5359b49d2084bcef70f041c36a8a46a3154d2b3ea15c48b20273d4d84a641881a232909724077149708e0b02e26e50b352c1eaaa7015b4d124deeadc998ebab9c0b7ccb79cf16fc6703426161d5d86ae2e0f23311b0f9a0d8ee3381b4b16677615d82104840b423469821add50da82e078d9dffc1be9887a102511dbb66d734aaa38d3a973d231272026b015aabb64061ad45052e4860d53dbe17d357280040b8b101021ab17680ea64e8750ac88ed6e1b91100200414589a91b4ed4588a0187922942205010036048822161f49c1153fa75e3fb2cd1cdc1a9e2cc9ad414d59de550756f0d6ac464e4148099240a125e6234294ac5994955baa42c3a46f5615652c5995940baac213aab29f6378a56f86ec36297a58a33999cf04e97dad380f27184146dea870a4559422fab092afa1c7c0315138d461b9ab52548a8744cbfb4b6e10a0f4846e0d071a60a11e7a0304dbd128d46bb61e71391a329ce82c6c091103a80388281c80b1d22e21581da31cb34ed2045a94b15d2961b3bb66ddb3c281c61f8b6e50863a1728cb18131c6f85f18638c8500a938734893913b1382443686c6e98cddbf5d7ddd7bbbf954032b7e2f8dd77067d4d5f8be1c3e88703e6a463e6a44791e90e76d405aa4a00091b141a204a912244b90ab20616e92292aa09089bcf130caa954b2fe66bb51559fac94b95b8f2c281f522e6e8101da8c9428f23c3041bfc48911175ab04f555438221b903e22000cb1309563956834da0a768acfa72e49537ca776588802609c829258a1b2e50bb52163862763a807d0933913cabad124648408ea0612efab0e1a3a883acd41e940c20999b1411f04a0a01c7529b9221d1b9724281381410993991e3678c84185a288d8d1022786aae2cc2a2bac6d474cd6b67933baaeebbace46c98ca0dad4d15471e64c87912e082101942069092b288799235034688814a03cf1c18212f5c1cae2cc2e8918d8d00e29411b10514ab8909543cb41b3f8ac21a992c57b7c1f13d9c7f7713e9ed03c35c9b2037b099a5d8a3c6fa889ba0d0960a9c8063598aaa10b121cb3adc692238e5a107aa31ee3388e13e2f3494a88739c10dfa91d8e39f14d4181c6f7dd23a10f0428264bb0902300d544871098121a36a41e731b6744a3d16c701cc7711ee7388ee3a4f8ac6d4992e23bb5c34c8296c8d9fe860c132923334c154d39e24616029210aa301c61aee336900b908a33873419d976b820d9b6aeebbaae9362a3a887d1891fbe0c71a1e11a59e1291a8d3603b5e2f3a90c0dab8f869397291c8c0491b14451b844ac58000aaf8cb80d6fdbb66d58483cac265e14cf33810b2914d1524311962d94068d1a8eb82071b832d168341a6cdbb621f1f9240310be6d489c470d4a70a083c9d298210a542408172162c1082b3ca4e0d861092d5ecad019f70527442f2c1531a30895419d1852b29c47960a4c10dd2e451b96a128dc86374c0351c599474940bc190d433c6f83a2a1c95601a5902703781e71c76ddbb6d58c549c89a46ba2a3c4aa7c16d955c5e16a612acee4fd8359e33bd55b01ecbaaeeba6a470c31ee5c8b15816677641ba1b3c20dd1b44e2acdab66ddbe6930dab59c58f380e828ab04aaa00c9c191a52e4e54a1b4a316726818333b583474cc4bd0fcbe2217aa1343b187718ee3380e28a9e24c201d071aa2635c97a1a2022879a2a3589c873dcff3bcf73ccff33c2746156722754a7a29c654719c38559cb94591816f9b0f1764dfa1508d2ace44525ac23b5f9864413aa65f5a731c571403ddb69a141af0ed088fa21870962ce1575125898d20989078a274866f4f925841094cc056849d18aa1f400511c40bde21959be86d83b28109dfb6190650835a8f2540aa6c192a22074a56d061bdf07044de2b9dc3711cc711c9826744ae74184bf4e1008ac81822221b2ad265a2d1683f6a45e2f329074848fc6f90f86acc20d48113921ce0c00c9131403c0165bcd2c2cbfee69fc7061621483f9088326586c64442d19e747cdf07250388578409e873382fefd2af2129dabda1392e1b0fa3106c288204191f9a70497262e88711cfa3128d464b61d6631d35e2b356cb32e239766032a387a61a80be9401a7e018e2a08840dffef0161a9ae041fb21680832445b0a3dbe8f89ece3fb2060658b9921c61471030eb22e0e3eb82f28c000d12c5236723a8c31c6dc638c31c64ba62acea4eaaab4550cebf992ac8a337997718ecb09a55ce11b513ffc887a42872526908cb954474fc4a05b34b9a82f40469fb3b140f30304881e44486a5c258d1163c46d78f37edbb66ddb6634a8f2bc6ddb361b758a4cc9d456140119961cfd900407961c9a58f203d3b8212500412c51d28214500c4b2c11a669c78680a31f47f0b87203ab08269e8864b9524e2bbcec6ffec1ac40a3e306401ae0a2a50b0f514f2021b344d40d476e7c0a8dcb575494ab868ee997d63f33a668d972c316a11f3c8009d2013109d26fa750ae42d56472b442942d51636c808485441422f520f261c204114d946ca8c1ca17a41744241c8a66d8249e500842483b60c98e17a058c8a188235e529004161f62a8f84094d4850c57c404049516acaae83022ca1589c40f5716084a90952337f458c2e9052d5f9478729f68d08a3c6f0540322cb14456161dbc70894214c5c368cccf146afa559b3203d431fdd2ba0643a5209583966367474e7f53653a8c355ef637ff5b78f8e852e3fb54a0c2962546f4c0830a4492e021f4f148c146b76d3cb0f8e6f10d48063c43b214021a76f042840e23926c6095c4880e2a090e74bc289203092d3b66a8d1c4161e32e42e3530b7711cc7711cc7398ee3b82f6faa4c0a070815a5815ef6379eb7ff169912a44c0e2398642da105a9c6568b5205f4ff39970c8e1050542b7469e1398eeb20e77d37bbdb7122a4b057eaf255652ec2e410840c25709081c24191ac4d0a981bafb732b6ddfbdb7f7ff5360021b058b1f1e586171f665c16ce3d4dc9c139cb3915ca70ee86dbeebdfb65d0e4a11944335c2923e40c12503f8831527abec55cb8db9edb6fdbdfee5575ee6ceb806fdbb66da58f95223770c1515464b661e1db6ba02e7c1b9a6ddb86efbdf3e6b290e7cd8b30f7d65aeb9ebf5369d68b2aa359bbce5aebac77bbdbdd6ebd3349c764754537bb2a9b4dd021c8a921a6be2756530f6ea02f375f307528d5c8fbc40aa253160754214786f3a578868ee1349e81431172fb0bed814e9d1713a7be0aa5100a9ad582a943a3541cea83065743340b0572a2e29891d1a92aeb76e0ba7cabd0293a75844e71ddac6248a7341562aaf8ae383a45a7e81053e78515ce7da75b78d52faa8c063d8ae398265dd719f1beaf94bd97ff20a7e7d4cf84499f7a5e6743d7dd20997da8b4ea198b731c54cca191010400008316002028100888c482e1445213ed0314000d69a0585e4815ce629124066114032110c33008c300c400020c014831a60da32000f8766f5fc569e37ce1860b56be27b07018554a9ef36ad1b87b81902dd8f6c31186433e4ab5ad834cfc1d9d6d09cf5d60fa0cfcff8d9c2e1db5e032dd6ac732dd1673fe72b74333b4c49fdd04ab14fcbb065bd7d313e73ac9c0a8b6fb3efcf7c3f7f1a192a79e1ede62dd232cc002ea4c1b34faa935315a2a46dbd70c6776217288024a60d5ce3492e5afd5793c731bcbf368b4a71a71df7a94d0b68f4d8d56cf08d5e6291d05aef62ad45102c1e3448686402aefa37e6701dc002bebf260ef5cca1c71f6010e4e34284a0ba87a009f5ee2ac8a985b38a3f94ae14cc515e760efa898b62b56e92261dfc6f5b75b796c4989c77b88228b662bd5d8670168d1d465d0ebbaff4f04d35f85137b41e08ed67bdd58e373524c665792879578e83e57a7a086603515867b5d7ebb15f054ba8a6db1753e3de0155478c5f2a538a9abb215b4b7708ba50662c3ac20dbaf02abc7cb71fbaba3a6cc999eb33fed1374e8e91910722cd748440c6363860955c0dea69e6f9204b8bc8ca0072e878391138589b7b7de44d5321a8327a3000b17a70ef52e6b081781bed914ddddabc8992cd6c1157dbebfba2585c2b9a7eee29e840e2c5d3f031d845a21bb4930bff784f3d496111c5d19aef8f05f82c25b4fea79a1558f1d50077d1f1d131014d2cd25a4ff5177c65768b59e3b187884f2adac07606c1fc2f69d9d9cd2437e2fda1f44a29f0229b1d233b2fcee8408bbc7cd1b149d12249e601d9a4328ea809d2a917e5314bd5b924227597e2df10df63af4350c82969f6a0b89c2b107d13f0b910e8155097b1e4a9a71de3f3850a8372f3ae180152fab754af28f7b06decfe42aaee060efd5aef59e3e08a19f017ff1be01fa5d66788429544bcff8640d79efc1b10713fef60aab5eabe68402a6129bfe53063a78b228c0a8ba73023ce0930ba9d15de896828e15f4ba1b3dd7260a5791fde63eb54e24ba6e8f366556aef420a331ca300b5dfbad6a1562dd2b9e6ae543b3106deb13eedca9e8e4c4c2ae3d72623099e61a7879acec90b0b1c4602ed3258520783fb1848befb1d0fd8bdc5d9ca159b42709f71d4a1152fa448f78370c7b082c587d1428e70462f08aa029432c5fc0090cc0f7448c3fb9cb28b5c4c8056a12bdfde11746a281664e9b02ec55eb58916e00ef60bb91b79ea8dcc1fc494255949b33e8d0e19d9de975488c156571c65b4e84e570c0703a56cb7a6af1ad0ef3198ac21e15be6c36dd62927b470be64f1d5d8d6a47ee1387b01f4d2da0a4e11a40d62ee4d837aca32533e5df28cefca097df6052ef764c1e571b308cf37a030a75eac18ad651e39b583068a46265d1507889c77ff1cbedac98b1b9464e32186eb1cef04cd57eb86e37cdb4f5c187b0931832624eaa2d322811456a470c51573b77e2cf30cd7064fe03a76ca54dd133ea65c127310aaa0853f43f4a566c2f32517d11e88e63eab3164ae3ee365a3fb2435e70cf826e4d68619659a2804554914064292a230681979643f069916fce8ba6acdb82cbd60c934ed64e8b45390a5371d16f897705ea1bfff44d6839b8f3223404455150cdf3ade55707dae7d088754ce2c274c9594654918c5143f89450d1a3ec3a3d2a0bd46d340eae2cf49f680d71a55101b424a920eee23b07a1063477388d6f4aa46e72095bf93ead51a549675d078b18058876e5e5001765175630531a592c8069ad489a5474266c65967d0091355aea7b26f71d9fa19d3136944aa297665507095243171208f6e7d9ac436a506b90f9912f9f187ca5d041b7d9e8059cb4056d2c45bb5cb895a35835332cf71728e92a5daf50b25e4e7138db344e0ac187628f4d6caed0a2f9bff895af93df4e042d22c39a6d2805c24b194e786f1d2b819923121f828d83b4d7606548661793f4d9d4261b27c6f278814432b1f4c33b0929501040a3314f8d12500e82417c3abbd7d0cb01172eedcc3aa3bba4fe28e7495837cb684e2f7b44bf2bdc4823abd3ca32b0c29d4e5f3ca7045a9699e8c5d52c3ceb0489040f8138da2e1fad67c035de345dbba2335c4fcea9a395b62e095fe28e17e1785bee276d323ec46402849b74b52d58ed3b5a4b9afb8ce55349485102e482b1f0be9e972a9109700519198cffdcc9c434a1019479900b22c7112a22960dad2e6ecc3afb2568f991093987bf03e1e352c41d96bee8870836a5e4b67f0903cd6de8c01e4543d73294af13996fa782aa5b099ce7dec6e65ee4d9e5bb35a0730cf9a838de53371e0711dae30ce5d97882609cf8b43956128a43104cef711b47fdd332852e6e6744ff44177e5e2ac1b49c11804ba39247b3ce7f986cf6546ac87027c033ea128742c50a7b6ea88286fa84494982aea98cb5aa49ab63847f6356422ac22284ea42db37456976b41305efa520921625ed73588cb21aa0b1bbc2cde1326d8479a054e08d744b7d882d66f3f6c71649071197175c18900df60e7edc3fa460a453b629454c9a11c59d8a063a8c35c484d1cf1840c2d20658ee55c06851615183dabec5e09c7f0cf46e4919a873afa623dd59797db490dc6ec478a4940e00ac37c28fa9c46d07d6fba9acb5c6825c6ef7520bac313820d4976add565780e12095bcec0bd8c2bf73f5b4a104060e5d491f4f07caf17728a69332134183de20d818a4f4bb840e8d89a678ee23a49dea57cc35a8a5d2c3244e2e58a98a5e9a023097009e4bab922243199031658f76cdf28a886f55f91387f00fcfe9a9131d65c71b10ede54d6b44cf41fa486551886d36f5e07bb6351925d1319669914cc145e4e3fa84f607acb50ba3ac75525a818e560065e3b6a60727964c7ecbc3972ad25a6a2a83edeebaa4b250aa0028ef43cb03227280e7b00abeedad5630069ba25c4aba27658eb87702b8ede192007302eb2ef7e3edd04e08f97ecdee2e520b713d715162d7f8db93f612673eeb1c9102520e949da82d9721ddaf4653dfdbb531dfc7f2c228d4fe228d4091bfea6a2ca951a6d5362c66f9c1ccdcb860ed11d4f4084a4ac0a000663298cacccb3dfdf29fcdbabf4fa5fdccbac99719f12ca8a39608cbc30173d5cb0d149788d37b41641d3277a090ab0a88b965e26cbb1cbd5fb9e361b9255adf6ede5540199fa528168641684fb1ed381dcade5d3c3730918a8fbadf9f5e45e1dd9786d04d61bd6870d4cfe4d065283ceeea730e1085ea40668149e3943321332ec4a407621da1fa9549e2d59395bc3dd2160eb7345dca0738c41b88eafd99f7d9cac2a1b3830650452226d2572944aa038a8b62eaf4556c80ae9c89a72f246977e09b8efb82808ca368f8e677033e4f5a302e1571532e380eb1fde703674779b397740e7b840defd171191932ec0260ba318ef2bd0ff930007aee761f11676a54d497ca50f7eaa669d5a26e9fa7650a5ddcce88fe892efc5cdd0c0ed0a25289f7cf929f4cce6055cf21bebf2c6f8d50bef163106bf87518d1b061491816bd045489a5a09f8ac457863724b8b6b05452716683f0497db2f921ec487bb464528aa08638245e146cc18541c1507ae0495951235e178015d8186e9041cb278943fdcce4bba8db46413995113ea170089d871f04c3ee575622679e3d1cf4d39abbd902a3103b85a2833200e40f22067ca2c34f6ac990ae8dafe66ea891e06379065121df41df5f29abf94aa24a3d389140abd2a6fb1b0d7936710a0994422710e12169aaaa27b7a646b771eb623b5cd7d481253314ac9df68503bda77700426c1eccd368cc279576b53f9b890b05764cf718dc30ec474c092d062861e8a5c500b0fc3a98e4119a506dd965bf67712aa8e947505bbcf1e142c0f50c494f7f92e294fe76850b2a8e08b040afa141968d002055114175ab4d0af0372990dee1241ed2b43f74e5306f06a1397cea2e296ad34695d8a0c6bf615e99bad850bffe6e4658b856239e3c485c6435ac59e9fa466704cde5329ed11ec7de88072dfcabeda0565b96835054ba6d55d6ef95086cb9ecbb2ab9390b38837050d4af539da454087a4b79eed39e709de23fb92f7e37cf4dcf3a8188ad7ca0bca0355fdc937c57c41e6d89133ef86e735fe9bf40c060814e2b89c6386614e2eb7c7cbb08ee9bfafca2087af37d5167a9c55201102f930bcf888d3e74272bb94f54b3cb61e914c24ea708ef969bc024a90959a1b422ec8f207d6a930d710e5700f6da25409f9cc55e0432723c92c32efd970eb8b7a2440a7a6ebe958addb7f855130d812150e6a6a401815826086dbe0afb1e450995a2f85a78ba636ed7477b852f640d2887039f7aaf8e5534db96279f5c51817e6812d97b892fbc39aec7413f25437a48b99a25d777088216031e4ac63c55066854b8b0fe03ac95cc8817009bb88c869aac2957e6b3e732852b602c2d5bdc9ca12faab840b6a66f669e7ca85b2d6e5c4c5e53aa2b01009642a0b494e02c1a3543147b61bee608e729b8a74d4cc69d63bff4cf9ba606489b1fa9977dca6055e96020c1de2cb086f3a05652cf08b1391461592db95e6ebfd41cd5faee909edb89ecbb6798b09742abd319a93d62e6db7b2f953f1a35586564e6c63acddc341170511435e5795aa8cac8a0e463d06499400e9d38d06cb61e5a01cac6c57a6adc0e04116f780f063628c79c6f9f441bb321965ed8e07aec1f40e4c54a7418ce4ef4ed31a2618520045646b4f3263a8600096bb58c2faceeb8abf09820bd62bcfd514c6062d38a9d513257202558f745dcc8fd77c3f5ef244b8ec3a5b7034c226d5227f7f3881fff61dc1acafdb866b6259b3e956298116fdd72ceeae76154832fc987a10e4e96320deee18242680ce186d0d713b1a1d7e0a4d2208241c4873c516c8722af9ae0d42db350a258b2f150065a14c492b88b662313af20a01435ee398217ec038906de85d228d75d0c819755121edf3a4c86db8f05ad34e0ba58c5064d5c3d7a91a862b59b2a0786fe415fe120a5fa2f9ebef09c0d9dcd62a33c322c730c12a00aa5ff3fcd9f351168a8f6aacac6f2afefb79bc4b8e2aa875dae3ff90b91be94c5aaef5ab7ccd41aa971a35905aa525b7c0af0936ed9e5f379655006dc7f488c4bc4d7bde16d4a3e6999a4e350ceff08e63394442ca264e0e57aafc2d14f2c39a20e69c0c010e2599dfbf42f4c4f4507749301e8c03b2c6e9265cef932d1aed0b8ef0b94766f06e49a74faa12180718452c19edeb8af178481842a4abd709c87e6e4e1ba7506059f27ae998db27d8e114e4e33af1ead7c8a9bb8564af17afe70155539f942f4dfe04e091170b840b9df79c625194889f852b379a5f2be1763681017140845bea9547dce727b0223aa90e1a36d88831839a546ac73c5050ca1ad9c1590887d5d6f12a654164829eaa24a523e4221e835f2d13d4988a8f7432afaacaa3184dddaa7be09f4884acc9825d75482bbd1da79ec357619bbe779b5a4a3b940502b855a6033695942d223d3a7e68f8334c8133b8a3b3d384e1a3b0c3bb0aa9322914337d516e2ce568f7c3aea8750faa763141f094d7291543217a209202cc988ad17eef06407ea68d467aeb996c652a720cf1aa705691d53bdd50fef18b9864c992efa88510374bd05e3e6abd071372b8089b2ead0ca8916a0234db48f2ba174f42008ef744051dba441a7f403cfff5c9c53d7e20b3e10fc86a602796cdb3bf0a8f1e7590923251af79386ac30be5b730904b5900d2faa94c219d354a3d64abb20739ceab54edfb760040f7c4951e3bc430fe8af7c415703173eb46a63e61c69d38519b7957518ffc98248d31005db91090744b7458f99c469850b1a9e322784dd0b6a866fd7c141d8417f2d833759244196101d65d83ae8ec1fc1a905f692690196afc2fdd629e8a77e34e732e861bf4d9fde34e9cbae89d2c1835816568b3721a8afcb9dc1a47d631b8a0d583a208d01fe181e1d488b142d04d8859e9e9245307423bc572705fa539fc449ae631f9e25dbc0dca107e9d5349378b2ccf3acf21f2da63416d99d9f0c68205c542c7cbdbac37d49dbccc81a85e4397349184252d4c1efe636f79f163d15ce75d13c2b98890bb36d0f7a845a9dc6ffe6d36e5cf2befed34e5513964810b38524d7c1821ae33ae8f17244be22d1825a48b7d1669ecc758f998d7bdf96a6cb9496c02480308e6b04fe024289bb48cc629c83e81c4d69108f49f4ac3c9a71b13397dec1e4f44512fd4844b73a11fdfa4fb50be5900b6d49106b77f038164ef84653a19c5c0b74270d61f634a590510b1ba35852c070c3f111f9330d790edb2b06a2e67540f05ddc8aefff3d3b1291bd6e4118263e915045e9566f1ad31cc6bc8d6fab32e8a246c62cf433e4225cf6ccd10e1dad86a09bbd17bb1fe8dc67cbed8eb9085bc9e5690db52435c38c520563db2a8f1556ea63b5aceedc4ef50bc13649d509aaa697be153979657cec5409aa992055ecba8e31744ef0f6c78cb0ce9b721fbe167991434735457c61e437a664d451a868b7446114a988898e59615bb676569ecf389261f418944db42369ae9f2f89d1f002534feb09a527470f03d1b38aaae1af331c08f7a2008932d4c6a952ce51b2fff206585b76574f3a675b4e8808a9ed75ab593979fdc72f809a85dc1689f9e3cc55b065e0c584f7893cf7e0966ab96f833599d3aa6e0077919b7706cbefa95d7a0687234637ca4d4a4dde887b21e78fd417c1af858a7a8c444513f0426cc780c5160d5cb3792453afde6a5619547ca63c93155f8db5e8a38adca2f551c2d499005a5606d6504656d2484c26681c9aab203e4773216b4d53491d691d2cdd3ecc76dd5c085e4a7f261eef816d12ae07d41e24342168618242e824f08ae81addfade4cdef2a5d71c325235101aae34b5075ed826466e2e7bf3b2af8b7cf79be3b1c0999418b61c7086fe11ecb0aa80f3b3224a88745f9a00ef9e7509a5506d9e9d2d859798a78405112fc50d1b841a490edbb9bb9a9a0a6d223d269e55a60adea2bfc27d4eb6da0ed2c9262cae5cfe5f08e224e418b64b4b3ecf4a034729b3aa11abd544f2e36195fdc379d7c561219277b7611a7a2cdc764dd55f4f763dd1cf8efdfa2c84b8c5a730b8332525c05e2e48a1eca8fba0f56e9fa0bad5132d3e17e703b966fd96b4f960cbc72a9720e698c355a884f8ff169d5fe3e22aada50e32630eacb9caf835e7801e165927bc8097e220171ec58302066408dc13167242b75b8632a1bef3dc7dd122e7e320e6c616587eeebf618c82f65f52279aa69c7c7cf23e2a425f865dccf5178b03df3ed47e2682590fbabc161952690c74ed71cdc94dcf53b81e34d111ed4285834592d0e81e0620cb4f698d579279a23f36e9b85df581a142b3e5906d3d1428401e0de0275af7c14417e2cd573f9f9bd26421a04b80aca55dcdee8bfff98d7c8475730c71913e0c2eb8027e48b1917a4b9662b2881d4e35285587f48de268555a8594a016304d308b881cffeb12eae7527938223144c88d9b785f2089c78b6d1d9c0c47b261262903f9ae5b5814268647846e693d8a2398b0921eef46a9ac303f87121f47b5a1dd088f717cdddfb84427e9b147239b83bf7a470c7ae3b9fcbc58edc15d3295ad18ec9ee48d14a4dde89e85b04b3696f7ee1d63934ec58dbcd392a80cd233bd9c85b47bf3dafd2cc86a8bc040f809e5ee2cbdba454eb563d88679d9d7c6d361a9c61af9d3437510e93468cccdf28164f531a976ee6d7582c69e52b0144dad6cd7472ccbdb13ef9eb6b450485ff417af1a86aa28b4a30cc2ade4daba49e4b9360c37c9c72b99bf86562e94ffae9fffbc36413e822255a34c6253cc3838d57d95db9ef5076e8ca94719e4c4b7a05c94d7b15d347046a02452769125ba9e4b6d170a4f4b22dbfa3ed7faa0806f88b65cebb304bb90d07892ded64c8601afff6fd0f48ffb265c59dff46ae16d8a250b4c3b93842e3e3706bb752aa209315b95325b1bdfd5d67d33921c43d0e5bb73c972c5432a095c80597fb4d0b84a7c50460f0fb0f6da38a3c502eea0b8a18838074d477b2996f8f3137437179e76d422cd97f1007a61e37353ae4db253635098e5eae471260f910b9acb4a16c2177ed129fbbfae728f78665b7053b70bd90c8cc9658b65203bad064f3af22c05df1a4853ad2b1c8d1949383e47d340dba3b2fa68e5f83834638d2b14ae286daa4ba3dbcbb41c646c4ecbb563a33fee1a35d1ff388809121bd1172fe3dc908707c3726eb883c388941191bc4b990b4ae5fb186c21dd86a8f03af7a3a9e766cd14ce9443985f70b682f949ccb85c757aceb3a799874ae98709326cc1354af6c7237f6ae51b34a28e21429530b7aa67aac7eae04d490bae8bd5dec07c304fda25d2d57998907df870f2fd9e29580f8eb22a8787bc7208f3218cf62a0d08c3fb1d1647230b5657ccb500f83936ab35dd492fb875d320c8dfc6a5c6d8d910fbfd72251142164841e257dceffce8dda3063e398d405bd1e808b1ab8e342011515bbf63854f9c3078ea3f8e8428c032f7f5c3e196ff0b0a140de18bccd31c9c9a0c76b635ccc5657010119a5cbf50ddd5cab972242587d1e7ea40743cf4b0617e1db4b148f5910469966ac5ba29a98923c0c9e4ccf502e3bae6b985d1eca64a6e3fbb21c71563790006f2c95922d698a006aa0197ed3b2a7d0606aa475838adb521d56c873354639b0116581e5a1691bd4bbf1dadb2befd27940fc0b285e5e642af43dfc265cc27c8032a3675c758a498e9e1e0c005b8ebcac27171da77190e019791134dc84fe513d9012f10d814198d44c6204d06474138772841082f0b45282a678e1ed794832a18ca1b241b9dd2daa00510557e13831b44f5cef359679605f16e84bab66fa16e3cc6b4da31dc385766494c246e10208f7a538249f68776a207b1c7a0aeac52794ef2daa31aac14db56890851af53e935014bf843d0c172f9ede4f2e23947c222c9d3c9d7b0c4652b46eb231eb4c8b34241c3b1a1e80612a5634e7fe6033e0088204ba2c4875290758a34a529b5d9ddf519cd8518648c379300e868304810b6db4d3a6d4644180c3c47e941352e9c0fc9a227abd78e681411af88df499b3e3c954d301aa7f247bba24e6d283019b025e503a306d487b13a9e5f41f550d89a5b616a25f3f127400cd50034933adeb281a91b62fb3220da33ee5466e54c5f94b1457ebb1fffec7de951f46021f9412ec7b184e8de0a1f2ec961b6103fce66d848537fab5fd023c37786573d942d337c6124051d43d8753106369e03bf57add8c5a8272464a0f05253be3c735a444c0719c97fbb30d238ac536b212156e0af069cee49a27603205c5f55fc419aa6e7fb592f309d9d3fd583cbbd0c0686e4e9935e4c1a9fb14dcb1b1604e5ab681bc05c8737c30b5160a0562eead05f32e4ef3cced9d32dc2e665c9969b52a339b445afe037b228e2b20ccea21133e0e44926b52445d83fabea2e2afea86695d23f4a37a095d237be062801ba1d29e1e2832c38654112db75cf2a0bac99d54c75f3ce7a1da3fae907e92f2d76676f53defc0b06a853af642371c43f30700d99522450ec01f163ba088045ede3496884b0280adfe853df0b425c64b40a3dfa74c1bb02bc4238b8be8f531e93d005395fecf0980bd189854faad5df8f709945ad0d96aef0737bcc560b5c807791df508a2fb035c684218a1a87b3a8b05e779e993fc459dd875581339c763556e032ec43df012ae65fe6820c68adc9cb13fd11fce1cd75374667deaf6281f02b088fc3d2310bcbd3e156c262ed6e5dc2348ec83fcda0018ef6c6fb13deabf309e83931b7cd1271a8b706ab3040d5c29df1abc691ce3d62b80a2752f4b57f18a33a7d49646ba9e4744ace2d1ff61cfffc5b3c2cdb9afd3609e21085cb97539aa3a9b20e25c17c644b759a1780bc2da320409abb197e35f1d3473ede842fa19eefd2ee135ae4702b75ec7730b85f209583884df6a82efe1b3f5f5093de809d36ac7a596b49d5335ffa0804efebbb36eba5decb0537191edd801cc329d00e0cb4a2f2403df1a8862229e6b89d612e0a02b3ab922c7909014b5e4e49e3057eef8fe34d8747c89db93b384f53d0b96923a2781fca95f3ccc28fe5914b13b4a352676a418267a43300fb0cd40fb421b89789a9caf20a1a8b51abf691b4463d57cde2e5e354e02c6e85b08e709797f7958423bdef071fcc1b0b9b19b43bb07fb86e278043a45ad0d087da47bd1064fd6242cfe3811e21166481eddb582538cadbbdb30db61ec21c5bd84183674a5eb20945a0f298af232bc7f1be0fc2c7c8296977b2ae383d620fd5bfc13e72655a92d44ce9448ad3035727da8398963e139038d48ae55362c3e94e01f6c6b45b2628f2e1aa3dd8941d748b73ec5e8fd2a40256d0504e5a9c05eb27665ad7b45161c5f065388360c6e22ce82b937e0ac5f17e6c1ce8474689c80574834c53aa9d8910233b4c838531a23ef40334390fac3a19352b8a9265791c46caa3e48ccc03611ec8e75869a4a3e945dd1dcd583efa0348de1463153cf964154a7b3763a44e8dd821fb2aa1e0ee404b650c376460d0531502b728c9412cd4d5a08faa8e80c2ce47683d0bc039d1d364ba74a62a51a46f39fefbb7e501945af109e425a97407254ff2b81d33a7896285a78e93a1ac288bad7990b9e817dff24f3e4278bbe49179ee96acdc1ac9c2e5eb676b7cedd738ef7d3a108880744b973fee3cdde4a891938595e530fb41048b636a34dca556b91082f7e1a4cf9f77ae828e131cb69bb4d626eb40499b6d2eb598f0375e1bd43e3fca521464bda743da5261c15bb1ecc9701d1d0710daeccc1fcf63c1ea32453ab4b7c8cba526045da8122a318a2677a9ee5d355ead826bb6cae3328706e6df711fb81bee9dbbcc858352d14b2b89ded88f9dea0e55a6980021802c5153ca8227c051a745955194071229f802c28d5b02600653f9bd8a3a55f992ae98913a0fcc56fd7e3c4ceb338b4b59c16a5649ed9a9aebe523fe0b949b02c67b8f6161e92853ba3c106d0c48e1d07c2c567129213b1790a2eec792538bab8a59abd96a912673f568c4903736663c6c79de4fe14d620c3d7e8dc9984174e7212b312c90f30e6ce09cb7d16bed888a6683d65b885b96a62eb7d9c4baa2d28dec9f2953d8b9d4183b02085c3a0ee6196e6bab1224c76328828bcdd2ea5789f0de683721f8030ac25ccfb9a7476368731cc58eac3ebc08dc4d601a0334fc69d2f9e11a155454314d389ead58986d4d8ad5ec7f369d14975363ff1b2f58cd144daae9fc0d6e3e686859960a0fac10031340c68cd78349b77f628d23faec5881a97cc61cf9966b56eb17fdf4ba1909e79120f9bf2ad8542edabf7502ddfef63a63595ce0252026301b0082de2f7279de62eeabea8ec8e4171feada6d5cfd570cf6c8b3366ca096bc9dc87db76dbb5a40497c58b8583c70df0ff74ddcc576200f3fd003f6dbc70e3d0a6888ce3ae36455051ef08c068935c056875f657c20b0529084731a76ea97e8f813abaa1a75766f1405b65a058fa68fca3f1175eed13c2ba80cb370cdf98179519b340444c22ef125f2ea1e60bb361c7ad0ecddcb0d7362056a600247bdab4fba653241857e7974f76969d0d1a335a462fd5f7097a03392a9d80cab01069c2a5a01a43ce4a10af372f583c4c4e8e1ccd005953924aaa5d54b5265290ded2c551ef4321b75fca3d20c537364584cd29f1a54d02bd614baf8caa90d3911ee633cb177e8f2e0dc3e82798013c57fed7793a0674294b56d1867b142c5130ca7bf49541cd02202e6b4027be1c4c51d9eba4b8833555b6b71f2a6b69a0f79eab6dc8800d9420eaadf884ba26ecd7aaf210f1fe2fa8d9ab26f63dad2f6e3938838b37e21c88adda57ee288de3bd7cccbcadf3f0912cf7b6a38c2bc6c83d0e1c0c392dd0d2619e0bc1ff91d2d73846023a0ccb8ae6c567b2b7df107205834935bc7a9632c84b331965f54573d6dbc9f51415ca65ac1fe198ea2e1ad91ec5214b4cba92997bfed4b045783a6acd9bb19b94fa8b75d5b5b8979886e775a2076a6176985c2fb87b2c1d94cb955ba1954b47a78b55dc9fed8ed05ec519e972b5daf77c7f9c56f37d2e8957c50dbf87bc31cc26a9d83d3b3d443b66c68cbcad9ef1fbaa365e8f4c472843e6038fa2b244251a78203dba834a71a37188815cc54cb92be5f59a3e21a89dcff42855ae977cfc16a9c7624e0d3fc3c90e83efbac792aec796c217d2395a2a9af94ab31e8cb9d18d4bd2eb4207c9d38c43dbf863c87d5d6d64e40b51aef8b21ae705c8c9b08898aa230b42c252a815b03a46ca8851a063ea6182a1a3cfefd9a814b76588c253a288439c711995326a0e5c8fd5a532e25551b12781ef5076ac342acc33da3f7fa062fd513034982b7be6cb0b047c3551451e76b903a9a207544de271ed929cff3fef25373d41b24500d19a7ad925e0bbced14486e886aa92e6841e040846cf973ccbcb3a5e787b8cf62c6d20f592a21dddd56c12020dad7c9c30fe4778519c4cb52edc38ebbc39df2d801370e67bd617af8bdc91a4fca0deb8a873ebb6ddff7cc299575d3b17c771b101870cbcf691cf5dc08ffc09ddc049752ff83159eeecef0e6bd300b94a1f4beeb2c9cbdfb8a7517aace21146258342a5b03ab1399eae0adea8b5ec417b00540d73ee34af58db9af08779d5f2d6383ffb5ba3c0580af9cb7f9dc8ed5eaa2e4a15dde714be24350c685d255fc37af13a8e0724edd8c800a4ac3877863de63096f7528dd46446cc03c740e4d00b5f0a4dbe0a352095055d63955ebefa6cf242a3c83f55ce4379b5b6eec3c156a39b2aed09954f20ecb18cd778587b87d2750b2d96751091c291c5946935b3e284a5c7539fdf3a6b6e35bdaf61b979ef4e1e2feb5cf6247c196cb763717f3feea70d23ca68233e586ac7ec31d45d80a9370683c27295c14692ccc8344d4941c39e3e28888d66b0ae0bf2e546c9631d67b96c84ab95848097b671c11050ebecdcde27bd7d186f7039c7ecb1f1b53ee7e127d5b81ccc3a399ed973094d76599250e88980172b36863282642541c0a5a8eb060b08edc92a7ad12173033caea6b03e2fd77daf075a3dfd50e6eab32e18e5b54a2669502cf7d6806a450d26bfb45c23b77bd69b64aaa559c12dc5a33de8a08c6461d9a767464afa2b1cf70a12567ec7db98b8390c6d16ca4ed23fc6a18c74c4816da1d0901f9b112fe6bad093056d232636ca94dc6d6ed18c4da385c9813801cfd6342408805640326c99b7acaaee5387533eb79c78c023eda4e59c39a281dc326f86e2a3e9158c625d67a97da3f83606568d40f205735baa519a5c82040b0dde0da147fe0e933f78c93367e5d4f12144fd5a8dbb1703f11d2ba5ca330edc4ae95f650cfd6e83e3160e58c571e8c54bc6dbc7923f36e4c5ab0098cbc6c426c7752dcf2690b356d69b9249e64eeb8dc49b1d630798d82d73c7304390b7443d4ee88ceb41216cc88a28a9b7dbd98752d02c1be8cd9c55503ef240575f7c945cbdd72880a0a3c258b7c09700a580b1658236e63bd510c7988e1d0d77b343e4e6a71125cf234f9a69504817886f0189faded90df981ab2a660cfa0046f52710bec352176eec2e4c32a616ef6d0a03d2bd84c87826a213aef697ce4a787d9e435cc927759fa2a395347161fd7f215744e6ccf11adb392af499291d5a27514e2d26d1414305a9b69c89925b5eca6da3c47a49e9f4dc52227173879ec55af3834cd2944b2e329d8714c0c1d015049f1efac3f03dac6dbdd8f5128520562e278c8be7d97e3473c35f30375ada3c80c225a089a7923de0eca1a32803fef099dabca4bc534df8288b7fd0bcfac6a2f867598b9bc60d4d8a650c56041d810dea828cba9e738d05163313fd6a3d3ad54c868009bfe73ce565283821e20bf5cd7d5174471e9e663f184c7460e253f43e9b02e98a14c8802f21d198c789aaff95735558b580c7c0eca2910c8e7f794e8f6a400bcc5954161756799be18b7556989979c0437e412b42d0a1cd5eccea2689a46ee8cab46e3b6ba220ae9ed1e1a5f4dbe267283160d01df75c7a96798c807a610157e07e3b38a880534939e7f846245089bc916c1e28951f365e028562e397e24ea307de1f5f8e3d337da4280f3d99ba846bf4733e3692d0c826ffdaa4c09eede6be094269c73e5ddb39930b372952d7c4657e61e0a094c7cf86885d8decdd39f18936539d66e326fc6341eb6bd99d0f30c0f06088f87cfd903953b0e0233d4b9ed1dd0d2ccf341fcea5b7fef9a868d43a34b561e1868f7f44b8804e72009bee806890ab170effab69f14ec39df0b4d76c583511edb2718d3e295b517c6eba6ea63516bbb6540a3fe84f32494306e83660f792dc0cf50abef1bedc96cb0cb871dff81e33bad40f8e06938851575fcf7f808013a8fb48614bc6fc9d83cde719db3d99d5e161130c3362c20cc3c4178caa973e4d53c9710a99811163a769362a9b93506d87de91a3c9541921cf38e2bfbb42c71739103d470fcefae45d87aefec37a3504faf926ce2c5ef4ed30de23034b107a5af8cbe6e3dd5893a599d4c79b4d7210c9a1babd92fc0e93834aa6a5f17bcdc032fe9640dda001b884427be17389081fea34fa64a1ba7bf36d291cfe0aad1b55f5cdfcb005c275780fa211b2e982a995d2eb28beb60e2e72697f6aaf77c6e7a26a27e72f1fc7cc5eec8e4def776aafac7213520aeaa1c251b640cd2466573b280365e84cc52e81f6cca33e4b55564ee2d86fc7490ee5f217fbcc4a33883e49194673a8a70daacb2161f71161f1a3e826e58b7c6eeaea0ba58a519e1cea495182f105e8cd905d42482027565edb29065c46682191122cc2057993831bc5fb51e61704d907d3651e39887478545768b42b99f8fa58c5cdb82156ff279a14de5f2a879913ab99988ab7b54cc788cdeb83d6fb4099acb6c8d3b1b0bb4471b281fa21bc7899d0d6165c3a79a26246fd4b9bb7bca094dbb0ac789ca2073ddb57d53e2fedf94186a9217e391a9f334c24d1fdb94e3eb32e1e0295fecbd2bb5dc8b2c21e348b8271672a980eb4ac2f1b2977ee14aa0cc4ec8b260d05ac57e65552e37e79834d6a44e6db473162868029e42e552a4d04026269f262fe4328ebb1708bb7a812f9d2a66577707d43037c1d14e037e969e14934a36340d6c1b84519366793e125e85af4d97ee87ac10b375c3ecaddcd6e520ed764cc57c388322dcd6bbe4e61b697f274037d1e802a6707e3936fa48e01de6b110eeca6791680324c409808ca9d0856c094419facb73bb9029cfe1753f34c1c79557afb5929635a0fd4b2e3f6d216ac302c3d69f11afd530cd54e967dc62190a17ddc59d1f328860720d525331f263be4871cbab01aab96994e97237c81ad2b0211314f606c969a8a5584377c81f6aa9dcf815cb295b25082df9757dc8a6c700e0ea84658b824ca999fca94ec39f2c7096f22368ad625372fb6b5752ef6b9550aa52734b3d54b82ec8b5ed29f06b43d61d7330e2e83a0f3a8781ee68f1a8128f5a754fb86a9ebab9e333cadd01bb4288aa148ffe81aa58eb64cb4e9ad2b113bac3f7728a5af616a5075377b0849c4f8b713b1d1b5fce50a1a091baa71cc8c91cd6eac257c724dc79534e21d884f5f72a67088281b7acdb39c31676904390b20eda36f35543e93c8c6b24240b78e25cace0f91ed9f5b925a69d01a4bf7f0bb75a7107a927f54e2cb7b701698d639217bc40e20d23c8ffa27123ab493ceac89c6e242588e71bb520541efbf6b17d49ee68fd02415ff040348f562eb576c5cf94dd8951d48e772dbb9c86c8bed3301f38f99a4f311414a30b8eee734cfe1898337ae09976cea01ffafd661084f996d7368ec9288e171c1c4e1d2c317532170440eac04a8ce6d766b8f7cbcdf2364345f39b00ddb86410ced4b4821dec75a451ceedc09d96c95505b46e1984e09a210980ad6a2d083998beaf32c4da6f39acd3ecc555fe2ab23a604631a54e068519611b9f3423132b83cef4e890cc920b3313c29961b0eb7727442ae0af7db238f42b082b1d1565738024e8aee02a140f66c97488923920fa2fbcb49f7c69b61a71e1b18e715ee683e50ec3d9749de75ec452423aabf22f287cb1413c7c88328d781b32105238c65d16b021505027f818857046a2a4dd330531c43c3d653216002b6d30fce668ac16c217f05968d6d016a8a58ad2cb985da744b151167af2773413c5890c538cb948a29fbdcc61450428b9c90fbb784686022a76bf30b62ee129ff8b370d49856a24da48c0bc547179d93705292e413a49f41bda2292913c3a7d0a413d88a6f0029b396b66eb20c5ed0f125699a2e0bad4c6312ba51760ded4cc06672079ea47b4b9304245d527aeb5345d74d92a44ac0331348746c29200e011cba5ec2d1f7e07c4ea7dc15e8bd3f4605bcc93f808d91fec790c982f6089877fd467654bac36e0165c227aa8a6046e2f210f56ab83858949f830da32736b62eacdadd3383100c17514edc4b88f5b675d25beae47b1386266b17ee495e8f63433facaff551954093c7701b98f688628b65d28a166856f8c2f80e0b782f0312188747d787c157854dd195e6a77cf659a1b3b87ee258e68ae464c4fd23677167c65b555c0977978d8da283d02ad10d2b1dcb6ce00e3b01c05d8a6020763a427a2f6e144049a84a8093d698d0c6a2fac9af095d2282f0fb15032ebd328958a1948afe896c43b239312b34c41cb0a9a5e42532fe6133d0a6ff71cb8ee4f48432f6cfd7c8499ce30781f1d071f9859b760bfc23509519c00a978e7f00851cf36cc0e8105166769f65f367c85b33f2af6f3897126d612abc3c757946870a557468c65fcde9e3d5f01455f8dea844f4ca275b2f041f54c19d3db3e2a2b7eaaf7aa480e6220f85b58c49f3383b922745420e01ff708f4ff0e3c645fc16234db3f2943ca3048b602749dac035cabedd1609ccc228077d03afdae580f6fc69b793bc124ea95da9453c1a2a903dc86c1103027a3c0cf2d9e41f354980c8b9b38f039cebd11481cc9c883533668791407a57f0170fa717f6034244a9adfbfcf09c2ff2353f0264700aba1e9567238ced94e93a110ca62fa27c95fec0d6d40f6bcf94277ca55c362441848f2585de3ba89403f594fe391ac3a5d07521b8ddb72c33afab68d2b02f4dd284563b517b2c6c08b142ba452f8633e445ac5497305a9b19d8d9e4c3ada07092a883c0cab9366bf9543f1a2329d51da799f30ca454e824e0b4bf9a023262b7b38c8af1c00d5ebb6f470707e825a0eab740848705bb880d8c0e66c4bf7de132213d1b8d0df13f735c119b6897313d6a1b546ac79949c4cc1b17a3fb713954ec6ed7d5358fcd10922cf280edf7045126d76c6aad513aa43a031308514333a7c3ef897c22ae6b6b3f0a46599d3d46149f9f7c10ce5971ab7cf17302517107baa8fa86994ef6fc600ef477b6a57b9ceaaa59c4e2b96d2b81b0de22ee6f75499207dd5d52ca08735e3acb8d23a3fd993bd764c4ade3405131cd65f15a7f565729de2925d59cad152cecd41c2e287dcba3ac57b70e0ec2694d9cf36559412bca1cba2044e5643316ad263883db80d454496358e23c10bd8b7fc89526ead48fa23f45f8f7137f623316e8398ae7c1066e838a00689829eacca95c8eea6f1d1dc441baae8d3a0ec85c7966a76969ae8438dd7c07490a4d1b2cf9b49a840a6039e9e6f14eab94da5a9298d51680eb508520000a3884a4a0c582b6281c24394c3fa003b2733a78ddb1170da9b6cdc9855c84eec23ee0d188424064d8d71afc033b9ba3a3d73d8ce27fb14cb08c59d094a0749cdf48f87cc53ab0c808d0751a238fbe4f6ade19106144d72e6c9a62ef965b82705051b97a631c08fa563cbb31091d0522c89be2178406c671824e035182db0ff3eb9c2ad135e6aa3c3bb2c97b2f85cf17ef0f064909cedc25fb4b20afac34a754ebd42772099b0c7339da47e0c9b4d16154bcd952dd039072377c3ca7ae2167f1357d0f1281696035bafdfaae6625e7ae7941e5bb65ed4db52cdbe7fb8938750ac6d79013e0355ffebe7b7f360f84b4b023db828fedf7f92aa4cc5727569f6d685c6ec0f60c3bff502d129ae20cdd82fd6897461bfcc36cd1ee0e0341973714851da96207f9889a8d211badb9481e9a6dfa3efb904b566d74fc7db4e109cb545a8382c9e9689e4a5b834f4e6369f63f2ab941b4d8aeb764793e76cec416800570b86637f52fbc3484d1690e5ea7df1d8d86b4949b6f03a4466e17ded5c65cd58bc45e87b08ebf74a8f635283ae6f450c99d9bb21fe0b7722d9a43d62514505e51e6f64c86e559d89d7fa55fdb1a57456b9a859c658f381e1760408f10086977fc7878793209234a2bfa2ea5f932c7781dceecaa048dd3f28dfe5418c187116b25efa73b92294160b5ebc973a47c448438fa56639a41b0c8526fd0fe73035703f369f2e4338922566e547922a7965db4fd5ba3c684a1c08716aa61cd82d940de11263ebf33b080bc47ed113476c3301e4b7d18d9bde29136b0c64e9b9b942d06d9d4ab6f71deb9279fffa3ac694fc1091e12d25b512033e285d14a9e29dd045d740cb5a06bb0902bc9241bee56a79646380865e7d4525bb7816b0b31929cd339ac4dfba6e887cc06e2b3c724be8317099aa17e3132d3bf53c39c95370d602fc9596eb0a354491e589517dc8358756d3fa7fb5fe73f60896171c1b4c8155a359d8423e3a19320ab8e50c25cc190510c2752cc27f180508deabb02e79b99216605a933a3281f91a316cddb4688519d0da379dd4fddfcb40908b0fd38a860d60a6ed8066dc7cf46e4034a2d2944d158daf5be9d0bef09b05f0ba0d36ca7779fd5bc402fc7b7f6abf057b8405f93c455324109ea4751b928075fd472381c7a99883b7547e4625c0ca7a8921758000b3075c8417fe4b76e4516566a9d1cc40780dbb28cc9438bde8526c8f3e25e337a3f6a58957e5b99c4fd66ece30937ca9612af30c8873b667d6b570246f0b23f796d96d9076972745296188805a0cda098397b2f1c137efc0a45426963ba1a9b484d0ca44d4f696a65e5df7814480fe9704c0944d224481b305bb0cdc40fb9ce61bcb649e5517c5b30e9a86ed0c604353914ef1aae4577998b53a97aad748e7d49e2ed895cf0607452a671ba40bac941bb82e19e237086262cdc6e96097bd586586e755fa3f2b205d6791e4c180aef12ab7f59a088b520101e61fa81871314b47a511bdec1fd17d048c8084a8974b5fbae1d2e450d66e2f9613cc73c938bfdfb0c939ad9193606c64921697bb06efc5a7dc0d22f8c33db15508eff12556f6f3430c626ce9c3d4db410112171d51e47fdbfbc886cd7e8b7c93d7df5eff61a22b124e9bf3540d976e859d344dacbc12a8cce1e4fed599bc710fffdf97590bb1ee0594be5beab33f35d97f933a5f0c674f847128dbe41f23bf83b14b9bcdd832e2aa3ffa130baf1666e215b2843ff266a34c4e225c4b6f788d5915dbb3d6df7e8515f561f4683bbe27d216a967bdd1182a8b9aae5f9c459f8ea4dbff14c1c0065648a58247503965e69877738e4294130bf4f01df0e61b496348dbf4a50030179646ca46c3386d80cd9a3ec76d64f2186afa27c921733c3187954fd510a821694fbf27de4fc12545002fecf7f24b5e82bc37b75857c82905c80e5e9b1a98f77f6fd5e6fb3362ad28ab93d999e88cb8b2a57ca4403e56db04f4b3624ee15a698ed605d87eaca0408aef075a8731615a6e6260592eee2d8551f6f84cc67c8b1e1e8582cfd1f87a74ea3e9a53492fad84e153d80fb0755054856515b7f6d0ddb3b382688fd8861d86e11dd1b1032844f702ec28f47db1fb6059a2c14e96c682f1e2cb0b5f1b1f857182765e393107e24fd63f0ede65eb662dc46fd4e79f3cef45ffde623d136e3087fefaf52ad29b78a339eaa7bf57919e84ba21c520b83d7c3316b6bfaf44830a261230685c4a0717c816f964b79267231fb34a01d41603da6b3e7a5c4090b24a072d36e1e5a613849c042202b4a591d4cd90add1829704d8ab240bd0fbf6c2083f82235eb0896871b6e6d71e5fcc0bf44f8c5d96e4049bd6bfe01ea305478cbcf4cf636784f7315f8488a811b237d97b93bda59432a594023f0867075c072d1ee2674ea2d5abf500e78a19f26b69b2b8cd91cf91b157105b60aba605b62e1974e1b6949a159f6fc456ab85c2555b60ab0605bf5a60ebea2672544417ee10ce08bd936ff02fa980903d7b336bf4e92f8fac8dbfecf93e80a2933d3e51c6a90328eaf8e98d8459e55f6e238fec8cbf92ea3b54973f7c6df9a416a0f6cb2ffc21a54449e9a5c58ba98cd49da930b37b94d2b3cd5a7a51ea08aa3a8a2a4e474fc74f83b2371d29e7e3b4947146df063f2453cec9734e14e4c048fc26ff76721e895d28155177a51554f75f3925cac249ddea12291d11996afe9253ca89460e94a4c007072e433de44812542965bcc2cf12450dc1eaee598aaa3fccaaa683a94177d525ca3214255bb7f198091e25b4e4b4d737d892c3653c61c493d3de44c112390a683ac3282773cdbd1718008411567260d8a2f850831cfff65ee017e4c0f072831cffb619106a95e34a052c4521e5879160a158c31f5affb4cf7608faa77f6c909ed6b31a12cd4789d0c6a8fe903d757e8c578c524699e3c7e3b797c3a7f6cb1c3d3942c0377ab2bc38c74f839dc35d3af327d101f9cbccdf7a614d1512520209258468201da87a958ad3999c9b4eb78c0e14a3021c483a909c1c71e0404746645a01406474e11a7d7bb5e0480921315cd0c30f56da93924a2924a97c2ae9b350e5a48944f56f2add93eeee947a4deda654484a2aa994920a492aa712934eea990b4458a841a7525e41424784442584c468a2bdd93e379ddedcb3d65c4e22eeceeba8d8eeb5cf67a4da4072faf6c94dc79bd2ef66243aa946db254f2f5e9ed62095c92e19a9419fd2f98bdf7ad1bb885c3c8f905adc0383144627450b4ab632e14626384a6856fc0a76f4be41116ac20680d06073dbac6cc4255db80a6d8022d4d8885a832d29c21f524a95df34d218594750b7873a802a7fec4da73f1d3f3a72602f7a92488c2bf5007589c29052b3d6a20deb08724f4750f4666f1dd5ac8f4a9870fe72ebf5a194525ed785ed5e570843dd90488df4e5e4f92ddfb85e7af12f6f252389bb1f63c47120b4eee3f4a45cd7a377bcd2aa9265bbfd7a2191babc38beded6188ff8d403d41dead9a9dfac13d3cf3e95a9549cce76eb4d67e7ec9e3384a1f6738d48f8c6beafc72eccfd9881d0daf5d7e3ba44284b13acb73563752f3d103c18245d08426d19508466d580d075f4e2524745b74f822d7ca20482e2a7a9621a8d31621f5f669b61fee1d0f177538ad3523abf5f9bcee49a611e1016b613b26d87fca902144050ea8c40f45440aafda5d060f307846b0b5cfd631eff8c76516b368ce81aa959e1f5a7efefa466f5f7d1de64dfdf5ceccdf48070f34f7f79d909cb65d12d144a7afada311f08f778ecc3405e0b5caf29bd25c7c43abfc6c244b70d82295c606fbc0005f85fadb64783de069141640dd7a8b67f31c3a1eba5139f6c9074524a29a54356f8544a591097c06cc1b225cb16a49f6d22af0946916ed5c174db514a690d2f29a5748aa29ed9d61446dd6a7a130faa8197a873ce30043664054b0f6a861d1e9c64644b9688d125d8249fd96b2ae9600ca13186c6287ac0112d4e723043872a5f0451e43f3b3b3b3b14d56d02cb4f518599dd043aa5319446511aad39a791f6c28529247812c50a2e9c68e244494dec791925b8075fe6bfabe148ac3e3b329072461459d0c027053c400821a124794a29a501959ed92a57706880650a233c821d7258222bce50ea1c257a967c802cdd80071e807e9638837f0062244155b04bca2e50ba20d1854a972a5dae4cb0c8ca22d7ca60848c39e744a2d433cb549170e1f131f25106a09e59264eaa0c5058533851448d231d1c79e782c445890b13172ef27b4e27234bdcc867f6ead9818a93cfd7cc28fe830e66060c3302b680054570a891544a295bc0a467d6091424a8e0b4a00aadc90137a9f4dac1862b54c9ce0fd3880b29d26589054d413c1ce1430b66a8d2e4a293664a3db34d4c5713976ec53d6001948427090f37a104171fe40c46a2163f1e021423e0c1bb4285164f0c9083244048240798528080a704cd43ab0618c81048d1ac58da42860d5820ad20678aa0cea8c4a7a786193f3fc42574cad94350cf6c9327393d4871308a3003885a4730cd9e39e7ac01dc160c8850fa41674b08764ad0d4aa011526433d5958d1848a24488660220a5e8202113899734e2f50c06382252e909498c23c60e1f3c3fef8cc5e5be44043723a519fa794d2249fd9cb8a114a293d32e99473ce395b3eb3494c24c1948c78545cd104180eb89282218ec44c0c30543b4c75870b4f8dc187062aa30f4f9aca90a2c90cb8d881071c9a96605133d1e0d233cbe303b4fa2864785006233559ae64c122bb1a5071850a9c28028d20271c3483aada82a9c89c734e1f2cfe460723451538d050e3014456c460869452ca23788ef03902e80826473839020aade9608af880c940c82f274c4eb804c113844f10401fa59472ca939e59295384ba2943ab4fbae8a494529a44a9679649d6245c42c0b3faac093a43d0ec6186288b04c5876ed5c1749d122762031420f859b2430c6ce841874b498f11343a3832e79cf309979e591e1fa09c219880b3c80d5d84500c9a734e1fa6c1c8c61273ced9c44f4f9db30b23974c315161aac27485090b53964b4a294f52269973ce39936891318184004668145ae0f080a619dc400436b482b2700e60d028988ecc3967154858154a58154c58155c302b78306c87244600a58b2052a054844311a9170cd900c45bf46cf1d375d184a45b75305d477d7ee89473ce39736861d89c73fac060ce3989a848a97332c00826a410ed4044182960a0268a90205269c2210bf32065ca2cb2ada61e223d3198a1092a579431c50e3704694e6a7072290d291529b5948c948e70b88c9c9234b1fa22491a34bc6afe28e9de61d066008550f402172cc528557ce892a8142519a38603423e33e433fd97771aa2e326fd970e5dd01714e4362cb4424242f3b752f991ca9f9f0f29634f174918116165890bb468e584febce3dcd3ac1e255a80c1c36ee3c1cef47b4533bd5a9a2b5db8aa4dea0a00062732fbb241173e5c64426f52e58f15aaf6d4cbe88f55d5fee837e312fe58d5f9483dd47f5dddafd0a07c26d27ff350ef71a5b3ab9a16447f058a0dd1d10f37e907fd58f019f9d86fb336980f57353eec34ed0b5f3e290dcaad614ba135be7541a85952dc8673e473907c3937255dc8413640d0d10fbb499527cd63a1a591ef82db7090cfc80fbbed0b57f2b518baf8610fad51a52fbf87aa1435ab7bf9dde25ea65e7e1f75de7c6df3ba6edaf754eddb9eba679f65ee5aa6795b9d6a59e6bf7dcb37e6530c4ba5af7972d3718a5dc137e86f8fd3da17ba50353a297d4dd3b49a6d9e76653c54e563f2b379ade02ce0903c567690908f2de9d6538cca4109294be5ea12d1e0a8aeca8a142995776cb8a2ce87ffae1529439523c031d4fd42dea9feebb510797075c3f8313b4e357e40b8babf30a83535dc2e15c7dde3bce89a01fbbc01e9aa7f541085e153b1c7fc99480b127589b43869d525f2c28a9a82db68f49bd49c9a74e162317ac199c490f3020c2f30c8d91e069812e44499df9f82dbbcb035980196a51c18568a2a538472b62f8a0fda636fba766c21b2621e0eaf468aae86027940972e5d2a7df684d03e7a426c3836afe773b47f1beee38717ea0bf94fcf79bb3bb379fcd7cf4d27c39e85c88a9dfef4d9c9f31dbfb3b353c256fe7ce31142972e5d2af6352a5cdec9882e5ca308502f2afd7034d8af79353ed33f79e8566856bf3f7fc81f4e833d4283fd3d9a85eaa9fd28342be6ba60ba12cce8aeb0c6319c42b3bcf6abd02caf3e600703cd5a221a7487bcc35aa22c9c845f87a22c5116a07e5628028e66b16256959f544c8bd1acebc4195d2a7fe1267d0375e1d76e119ac5dfe4d4585190d39f7a78ca2bb799ffa7ae27271d0f763d8fff107f3abf987dfa44724e5fcc5edf03fb62f6faecebe15f8c04e65f1fb35f8ff9574c0ff9f4e5532239a7cf2e6f73a8b739996b2727dd3601cea1bf31fb42b8c668dfc31ffbedb95e5eccfe9028d90fc1de7f4894edeb11fffa21fed8532f66bf18ed9300f6fe3db0f72f663f27fb7a5c1f7f48fc62f65b3578facfb9fe944417933dfdcd89c9e857007bfa0d89d2c3fffa21f1b1afc0f5f4e937c4fffacd3909411fa74f7f9d3a872243f1f0be93b049144ff4dedddd45f174471c649dbbc7e67831f1e85d46d7de7c637997cbe8f877dfdddd7796a09594a247a9812419331a9b8708a80692a8bbaf0c1ee3e717a681240c5ba217bdc0a060c418e7082eecc4012da798456d04f14f9b4ea43d641a07b46871db11ec8d50fe3c611b8f21de1b8a035a5013db76604b64cdec309109f728a50efeb1bd2313ddd18b2ed4d0983e655317bf305e9d3107864e4324380d7dbbff88daec5a674289d18bce8bae63c7eeeeeeeeeeeeeeeeeeeeeeeef6eed81dbb3d46ef18bb638cb373efeeee6e7a799c53ba77ecd8dddddddd172653bb4fabdaddddeddf2e4d7f5c838893fca9996b91892ec451e3fcd5aa067439258cc63a9675c47a5ded3f757eb2e533ed03bd5c631d5df75b3e7f86ed51e58d3f90adfea1c57b23feda2ccf84f28adacf36b2c5332bab60d6362863504283fd25744be7e9e8ca82fa9c73ce2c75ca55832858ead50c3a18599768063b35ecdeb1d4ac6837e59c920a23536cf01abaac2e111622a8d2617589b078e261745b5d222c8cd8a2937589b050c183395c342d17435477da415d222ccca8b12e111741d4f06b5890ad4c7c9d167a47dcd9c996c61fdb1b0ec4bb70a9f179dbd13b357e41e20bb92ab634aeb323f6872de8bc494f676b7b2d34eded0497cd8eeadf0f88d7f8e9b0ac5167f79422210658640dafaac97815596c2c2361ab07258cba6a30fed41590882d0dfbb534fb0171922655ba252a8327627bb3756f56a6b4064f7589969a6a8f514daa4e2461e2040d4695488ba42a80ba445958a95ef8a3c2380144939aa3ae134048a95b20d18262d42cfec6d22cdec249e7b410fc445a14556f356b89b46052f91d8b1f015546aafc118c2ef4b05b2ddee9290a3b1d21b2eec7ff1ab6944519e9c24e4ae56f28cdda4f88f9dc6a90b134c83244d99fef4627295de8ad9dd9716dd31085162eea2e18722f4d27f10fb1549977bc1a72939e287e5c1054198bcadf646974e882c4267bb35588f9d213a2e76de67363e919e61fb7e19c6e9d8a74a1b75a595d279a6250433faa5bafaea1db711b1f729be8ad6daa61b7b8d4fdd05b95ff8713b095aeb1709ba4e8826685f2a8facba3ab8b38240e1087db5c8fa3733227ba1047cb71446f96da0db4abd37caa4625298b5ac55113911012524248088c4cf6b8cdf5fd7d60a5ebc18e6afccbc648488c52f626003972f4e4c89123478e9f9a23474f8e9f394686547f2c52951fb50bc382196157604698513df5604698911759fbd4f85ff863d581d0acdeb66ddbb69fba6d5b5376b5cdc53eb52f2f66dcc5488c1446b6cdead736d6766f7e7bb1bd7d6aff6cdf3a7a36e764a6e22cdd658cddd18bfd537ba8e2748cb1bdfe69307a777bc72946b632a15caafed9ca832b263b62adf111e6551ed755f61d781dd4a0f3f62297dca68336e74a7de18abff0555f08d20af33912139dea61de979a55c3861ef94c7fb0bd86d42c5afd3bc86de891ac353eb9448f3c458faa7fdcd2a93e1f2faf7a982f7cf9d4ab1e025c776952bb15e505899b5c0a616ae81d1424d6d09742792508fb532f08d7e905912f6382ff8a2ed988821d86dba36f27f0cf8f070827b9f2069bd5dc4e6ac7c845f6f38998aac85937d4ef0f8150e963df55fe420eb58b84aff23bd6de4e9069f0021bfcae168070955ff39a0694d043851f2ef0fc307982c4d01523466a567b7de2d3f7177e75fec627c87c21cc077636e8c2af2e758290b0f57a12b8c6aebb37c2f9cca3790ca9198fd3675fd8753e8fd327d3600b5c43ae930989da4fe9f3531d2c014be31bfd8030d8a07f7b3b4b54fce92da0c121357e354b33d4bd4cb37a790943225be9a3ff71741b0484c88a49e1ee4863ac608a087aa8a8b2c3173f1c21240b28498880062bc2e822c78df82924d0d2430c94d20023872c588aff94a225a1ba446048a97589c0681229138f3342fcd3c7f81a8e1a6b6a046b64a13e3b7928b9791b1bbc4ed83688612fe311a934667e5d6d3991c5e7fac1c4a1eb5f9bedfb35181d21b68fac499a65d993b035fb62b4f7313ffbe66bef4fa4b2176a5548c5fe44a4621eef26b7aee2baa84442429240f80ec6d1a0db2a4e3455ecbf62d8e914e309a9c1ce38ee37522735d87d844617f6522f352bbee49eeb7b77fbb491f015c3fe83ebe367d969b300911c0df317427bcc1362336d59a7dd4c27f6a673fd09c3b00cfb0c85711886611876cdb9c4d4b4b4c5c867fa4acf2c31352d6d51f9cea9b72259231d359636c22235e62827659e4c2f6c66f4e2c79a60cccc7cca3466767ed63614c7cddccccddeeccccddccccddeccceddcccccccccccecccecfccd4c4b454a5a80a965695a22a430c24f9879bb9999bbd59056ee6666ef6e68689d2b9dd639472ca3929bd2eecc2b0d329cbb44cd3b60d85e21aa535c769dd755aa7525aab18a6460d8d3be840631bcecdcddccccddeccfd5cdb99d9f9864fb62164dbd90050a835959939d654fea6e2a73a33c7df277a946a7f4c8cfc2bb0e0373f4ea4e5a8fa1ef154ffd12c678fdc2a342bdc220c348b8b388151709bebfd4d68167d7f1e7bc3efbf6375ccf72f616ffadd3f167c8675cc4f037bc37d2c4db855361c3a206bb3bbc2dec4547f16f62656778ea1faa251fdfb5b6169cae8f8db9d053362e6e72386fed64c4e14be12366905bfbe4fab15f6ff239b2ac9b8ba4fa0208dba0221e3285db8aadd4eed07e1092182b8b24744edd798a7a97f5a083afe30524aa9a44f6964d177a794524aa74b8fee2e83e8755d30bdef36ef335dd30dc5a11da1c1113aad2f29fd17942b2ff02bfdd91bd060bbaf12337982c9939099d4e69e12d8a79f583254fb85b44de77477941a3250ed5eb9bf721b1c0b1061ba8c3f2dc1673a309bda7aea6ab04783fd263ccf6d87fffc42991a7df84bba058f0f7409bbb259f1ebfa4aa131d0603fa703fb882f9949b3224c832a271d35facaccfc39bb33b8524a2939c65d9acba78b5c7777f9afb599cf5f28a5947476f56a96ec5879d3f1f5bf8448779fd1a3f06b59f02eca96b3024953761ad9caccf839766d3c3690ea4e595f34d332a0e5d2a6bce87b129311c4d0a1ea12290179104a3cd1a783a94bf4c5525be9baba445f1c7d61a42589c809700023082a44588ef882a14c00c91225b88105614c611348592405554abeb6f8c000a84bb445861a767f44b75a92ea42892d6773e2cfae85002f66204a7a41ed972b2f23e5eeee3a51cba2863001e8ef9a6c1083dad7151d7f07b344f52a6bd1e2848c2533e841871298c1c389c806486a770004537c5c5085184b39c8e121ca786203a12edba00ae0b1a078697b59c90193f224eb42063a5c453c397531c60dd4080301d0945274ede0238968a241fc18f193049222865660a488a6277e8a3822aac1154a72a424d1ee76a69c537a0e9d5697288b14527435ea1265b9a24ba7aa4b94e58b1fb2e0201ee9527589b2b8a1060552851a572bf97d083be77e41628d9f1059fb190753c61863e470f7978679798bec6ad6ee833146efce666dfae31772f426c23074370d59fff6f6e2d8a17a59d1f12ec3808de8f63b363333b3d74c05707420666666de9531cae89f51173f2d049d7f18310cc3a4d7808a7d74c73077c73e8c3162f11dc3b02fbc40a73538f663942a905dff642961f405d45088740c3b11c130f90ae01b7c03fb5953a78e02a49472625ba977cd19575ae73f646afce40dd717eeeeee15bf06f9ba3ad94de7d7b1894c8e4b744a4e31fe5ef1bb18e3e31801851863f4a07601a57677197f2158f7b7777b7b57a7b3e8d1a34777ffbe69defdafe1b5577fab15ce85e336cb3cbf90fef545a04ba38b5d3a193f1cfed59c76bab006c352a9ea410dafcad8cef02f0da6d47d53173c948412be980271fdd9a989185b86689223421939fd1cb437dd40ef31f4b7ce0eea9f265dc8423fb59f85e2a535c842b18170864e4a745b7b38077b9e220fc8c1becde9e19c18ff622ae059beb8a14b0ef615b8ae2fe6f4bdf00210404a3b39d817e31f0aa7c7984983fd0128140a8542a15050b82ea5929fa53cad41ed555ed7a0a66ddc87c2aaf6a96aa0cffc27f985a7df06298f215d4f9f3d7fa14c90f9f1dd13c2d53f7afe59778de4242723d7f27a1120e0f5fae8101d7dae614dcd0a1ad81bda2f43580cfb9a05e0909f759ed6e0f629af6b708b0d6ea8e79e8ed3ee719d41b87258dd3e6d665f74fa4d7df446fa21733f737fd94a5e47cd66a6d29d4ecdcd1d03b747c7d91baf8ed17861d7633e2eecc22eeaf9b8be3f5e180eebe02a7f848b5e912ecf6fe3540eb0c418638c31c678852028020e994b03619873ce29658c72ce39e79c734e2a93fe9cf3e79c73ce39e79c73d23989b218af06e35ecbfbacf5c2ec4d5f57d7ad56ff20585313e2a8cb9fc6044c8db5a1c0cec4117a267e6c400318c0001a9a010ca0460000a046f9f5589a88c3d3f14715642b13ca569d9fc5b6e189e25fe49f9376979ae68275aef65b5327194997372823433ff4255fda1bd61aa4ef5b809ab597a31163a8f377e3913a45a02254fe9691f906f97ba34647a7c8e347fd85d78c3b4b6ed3ffc5d08f0ff6604c3d337f3a973affa47dbed4e00cc2356ee9aec71e5b9bee99dda4ce0fbd3abfb083e637356fc276624ff5e7b5f125a75ad4ba06e7778fdbf892cfcc5fad967aea0aac7ec54bdb742e9e8f7de84b35cdc27cc9c7d81b329675faf97ec6e46c8450af0f4398cf79747dc1ebc6f5281bf5fa8dabd7bb7779f5830fac74fed763980944aa63dedea6e3723301025f31ff56b6686f3f191946ab4e692578b06a40b3b6c6991a135077082312737d831a87a9caccbbc594d6e07cb9f2199d0546494dec023a194a297dc875663989482aa994df3b5a46ee90bf5ffefb608fca6d69660c8ff651e977c89479693a9c4ffb275f4d747bd3354e39653f8592ad2a95e238d5731cc771dca75435384e95e2388ee3525c2ac5a5b8a9751eccaf525c53a9548afb58398ee3388e5371a9944ac5a954a9544aa54aa554292ec5a538effad4cba738eebbf73f81eb3a95aae35ef559a75275aa174ec5a5388efb6cd37ad3e1a206e3855d3b7f69d42c5fee61bc1a2f3654355230a9ad301d3c6f301da43e4ba9388e53715c8ae3603e5698974f795c6dd4a85123c5a5388e4ba9384e954aed731cc7714f371d8e53a5fa25f52f302a984f2e35e8af4a7d3eb8907bd5b683fbd4679c0701ae196b5cea371d9527539e56b9ef069b7bef7460da0697da71eedc39e3741b46744dbf9ff7c67fbe8c2d708ddfa5d988d2b1518392b75b4ad47e10d92ea0db02f512a9cadf98ead7f97bd3f4f70bb75f1ea897db4b2fecba7d463d858a7d7b415a08574a3f9bbf1f7c6045d543377dc4cbabf3bd4af95c6a5dfe755dd7757d3bff7a205eaf6fb9725eff002bf71937f781f6210a3545973dead7072a43793164dba88fd2c7a874dbb67ddbcc72ee47ef18ba8e2e67844c5d2232802a0f9614d6e802591ab4f1a4f3333a9c66c5b47ff5974faf6faf33ed7afa3d45c7b5719afe698300eaaf8fdbe3b4d644b71f3eebe07a8a8dda4c20525be07afa8ceed528cdebcfbcaf9c777a218c7afad3f381faeb33cc03c255faa8eb7a9427afc7696cfb56c3d202d7d37735c804d4b91331f9547f99b6e11c9f52fd717caaff080d53c31dc2e9979e8ff94238c4fef281bd7cff1781666fe8fb6714a31f3daebe9d405fcaa7d80efaf2e9d5a08eccd6fbe295a89858e587621829b2a2bad5a859dc36d87092cff4f3eae81fbed1ff719678f50febe0bdd17f7de1aaeba5e9fe7186a2b6bbbb0f393bb136b167a620a1ab7c2a4317f2d0105729f2f9c5376a56fc5661d7ec051d8cc437fcb32ff440951fba50a5cf382b3548c910aaf4637c1e727f46621dbb374ecf7de1aabb7ee3a1ea5d4346aacd92ad03f855da6c8efcd919bf613dec25d5b38f93964686ae7f583f2cb75121911a84b124ca3ff9b91a3f366af0b3c8eb8e0a61f08fd5bf70087f138eb115d0658d55ffe2a9aed4176fd597d08feacb7396faf2c29eea53cf591a643eaabcf4e2f1d7eda6a3fa56e095065db6aaff163e29952a054c52fff26330d54bbb649316c2cc9e50467bf1245324a34b2115a9de571e74a9bdb0972ffc0156d5cb2b1178f924964f16d928a2f32184ab333568a388ce87ea85707d791b4478933335e844cc8d04f9f1572fff6282eee5e55b35584617fe12bbc7978ff5e50b875449a5410f7d0902b4f295065fbef0072fd597ef88d497976f75462793424a9168d2dea8541e57eac509a994eaa347cd4abd3f2a4ba9542995ea3381a97b59aa7ba37affecc5bbb6333a985749a666bdec4deafdb394c755a2b1374078e9e56bbcff09a91a5e0d0ffc52de56b9b46d3b5e3ef5598d942742839eaae1cd148c27b3782d704d7d2634a8f2b64aa397174f6e599aa5a521a3231a03a96e7df94cd33c48d5970fb1faf292f3f2bce9bc3ce7855db99746324bb354fd1de7d9f8f8f2382d8d249566c1bcafde5f1661a7f7a59943a77ab9b4375d3d841056abae0b5a7a44919aa57ab7a1f2b6d6f062b5f1bcd5b0f1fd006b57b394169bf5f272e965555f5ec0fab2e4cced2e5131019dcfa8b44c59896a182aa2110000a020001316000028100a064402a1581ec839e20714800e7194486046180ec38120876114c4300cc3308061882106206300524a51941451d97b1af5afc0647bac3f331645aaf548e0f0907503a70d546511123178403d9c6d78c9c21b3416a5024236f73d9ebe24ab74fc98ba3aed114f40c783d20662df65521a48b544cb57b3120bcaafd63a0893069d0b4595cba8024014ffda334d17aa87908d8c6ed5b3e816305ae3d301d48899e0bfbeff6612bff26fd713ea918d4b57b7b385444219e4806f39744209fe993b0def4a1aaba6a5d9e21fca548787b6c98b3d3e1af5fd0a1b6b19f19f4c81a05c86a46e0c3489f4a745818392943e743442a1da186a31bb8c165a4290494b905575a6362698dd08fd5f8bfd1dee909ed7faee7c8fd732a9f1f93b575bbeec4945329d294af7176022e3160d4af49183b5781c80d86c626ce36389a241f665cea6822fd522950f45a9221fa657e50cb29e862b7d5dd8cdd502a3fa83249f6b652b26e9b6cb0433639463b57aab1b6d1f501ce1e9403b8330d0994f74dc959c792cb14e2c64d3a746c1f803846d84cb78321029141ca2eb6ec837e9baa2adfefc6f9941b89489ec13608e431eab07701669a165a52d62b961a3b0646ca741872763ed8cdb0ea32b822612a52f8cd45626b2a824166632f1633f483cd2b812707d433d3f16b67a64a2a2bacff4cd5a0ba36b6a0f162fb1b84cbe552e916a34bb7b639610d3d2176da61ae5c3e2a3ae4b606b0eec7f1f96b1bb893681696e8b2e3ee1eb78f6a96cb9ab4fb008dad84fdbeb1887daf02024d834b05a2cf9c363c3ed6a6d75dc4879a0470f6c6172f4c71127481218961a77b00c2ac025eebd1866ab5fdb99ba899e040d2112f0838cb73dc2f9eddc3d42740e88480ff3f53a274b1ce86c2b22e49d8953e597ebe8c9a20978277c22e6a4451aa8b9ec87d41e71153b4d6bc62956f2c5f5a4c7186aeb08b746869329e261606364ef0a511be286511c2c8f2e139a3bb07b73fc62739f8bc63b4b25aadaad61cc02751a0669dc9ff67807e509ebf2d33206bf617274d87596c7f59ebe1fb90bca2e68508a8722b8756c967fff573000a7d62c4e0a845cb40f3fc0d9085e2f378b0b266ea15c0a57abf01d5e1bf87d8d8cf5c6ac53db04e7a49d89b9e41778c86ef002398a8cc89b19ae41e23043b726790fd76fcce0ded03329953380547982ef383b29c61b70b1ce66e5125fe880a0888a360ec713cf6ddd72a267eeb6d11439478093548187dbe9dafade91bb4d37ecbfae9279639fc98bcefe31270dc551c616ef86cfb792fd50745a771f1e9904db5c87fd81d0df2c6e953fcabe70770e4cb557d93cf8079a275a4eecda82ab2cb1b4aac41a9558262265ca70af17e7ff240dd2fb11a91aba38ea8d13b3f113b02cb4a3f089b7885c4c621278d422dd50685c7462d2b405e55bf8e284cbae4cb44206641fcba8461c7750c0ab1795b9402991db72cca8615f4b777debc816af9dae07df415cbc56ac827c90ff28b8005471ae3e5b11e3836f1c74b9df92e8bcad2e74b128b7e27df0cb367fe6093af31388e104eaaa297649a08610abcd607d79c0e71901249adb01f33108cd6de278d6b5890b3a8bc920548068248985579a6c1387057b143a5f61ab8f61990acd6d17f7c7b95d9ab4726f1bcd4a55219c446e688d831cff66372570647fe0033d4bb061629e1287b4025d045be26647060bf4559ee585dcde6e50abfaeb7e653c3ca0e38ac1e0326450a0a429f20068765a2a515ee2daad8fa402344013a98a3eeb3b1628535e4a2809cf98459691d5eae9a7a8203783eb35b3cb6d7e14d9d5fdbcc9717665677248581cac0927ce74253a28048ddda87dcc0782734a887b34bc0dad1c1fa849c31015a6569d6882e31e5a0ef9be47a71a3e08c75268397e63bfab6e89fe08be08d966215ea5047de2eda7e3885ec11eeb3953f2534c86e626f82142fedb2b3c70ea18b364699b03308db90bfbc0e04ee0d4e22a7258bef9c44d92f12e0a000c8981599cf427127c3ff86528f61eb4d789168eca290b270ac37e59e898311e8d8514bc0cb81e3cc218bb11b5d6108eabe1220f368e0f976cfd4903a600025e9fd30625d79ec152ee435707372a613564a1ebd40f7bcb86f41886ed17088f0bc7faaa8bb4ca65fdd40c9e2e2d5c6d530a247d68395d9952a0397b6cb1d034a20e6e4ff614dac67a20ed637a60ba03f7a5e78acf594e9888f3cb18aaa9803c60cf039d96afa7f6820b6cd63d1e903484a8196ea06dd1a07c4794d8020bb2135ded9f48588bacfd20839a7cf695561e1756fae4613ccb89dab8eef1a992e514d0defdcf29318c1417b84bce24df3f5444ca021c45834079658bfb60c9d6e402d729f2a2b8912e771f9d33c2c9b389a373b7c8cf6e1808b929b47f221ae275a08e9f5a32dd8c6395187cda6e14d8d851112b01fa92ba9d1b1e0b030c7d50ebcb5d5ecb47065105be3d7a6c69f0cafcefdd45da7085741cefe4c612d932f55779f694e3ee37bf4fee68d7b922fd5a87cc7fd757fa1bd421d10f39d2baa0e4694ac7bd9820ada5f2d8947f00847f57eafbd7a24a18fdcb5ebe38323105ef96dcc58dd472d41efcc00dfd3ba723d0fcea052fd0360c9328215705f1e2a2bfbd1883ca3c1fd4e6705892d0bf61938ece6d3986b77d37d71dce75ae8f0f56c02793c110942872d03749c69525ab062f7a287c0435a04a70bea4b5d8b8efa2a2ebab4e4cec61a98676696a6daf72b5fea55b34a17fc38305661c42ca12e2322d1f8f502a16b0337d482564641401baa08e24cd4249175d6def2613acd30a8014b00e05afbaba8ffac109e6dc8000f38903269839d7405f83df28177ed1b2da341330b206c5a66fb5cc622785dd0e747f5135c1d0f0ff5d36727725233ae32dba6da0f0fee58264784f64646002c2fbc7c84982310f45c6f14b7a932067c5a5cc2f4c2c43d206e41794d8bbada83a2c9d5f7fd50554d5928bc12f0e15cd5d3dfd4d2895f979eb32f3e7da624de3e2967631086b4d70f7f1a52acf4849487dcb02ab0b8e950c1ea829df468df5d87cc43d95e139b5c9c0046d222a6da6c40d6cf81ee37695bddca6da8651aa1de3b76fb200b70b06983f3085c743f439ad1e95ae57556607f8fdf39a161b6c5a6a2ffddd5e2114a3d03af9ca2d68f4a99fe6f6324e7792cdce6f80fd03c343ca44a5072d286544618d3654ffeaca5598c08c2990d65f5dd18b700e421eade3d0be941d000050ded48189ef8066002274fbd7b32381e5f5c0a7c6d544ddbdc31875f8dabc82c83512978a424b52c3636b2efc141309c93cc1c7a78e74e4c50889278fe2eba843c1eccdf12922c8936fbe6ad0e60094631044621e8fb509eb8306ba4401397f047e5b47429c593603c869fd64efb77cdb3334d5220e237c17a2c8d3bccdee0002aa6961e4d4732efdb90e0e6dce57b3bcbb4147e78d53e58c676da33db6ed805d7676f3b224100cce296003992e69ed99203cd784757af1d7b48b2859ab375a1655b6486299c02e0eca6affb38251d4b3c41d8ab64a227bb8e10a648c634c62e2a014b2692da7e1098a0a816e268735583361427dff5be0cfb7983dc189f019692c29d7ffec66dbff076cd017437e9976fa6d380140b47acc4acf812b706ec8bbd7636777e8f893fea8ad2a4181d1a54027677bbe5e20d2aa31012245bc4ee8e59028a4ae6c751be654eb28c1c32860c5b206eeee2bbe30eab4e1b75a56fb7a496c2acc869d3b2b965bcadd4027a27eddf2bf887573c4f5c4406ba40f5dac46a1a0e256fb5bcf4618e87ba0c9b513bd827d8322e912b6fab18594e121ac5717813d171535d903a577d8987c4abb5a9ba1e448da5018fa5ce033af7d3931b9cde068d5d1dfabbe860483e86d0331330c60ac811ff9d0fcaec2b637c038fe619249bc94f268f72ac9030964a81c9b2c615944fdb5ffcb21246fd6830ea91e59148ef56ad6ac6216ed113b2d41b73ffde328846a09a8661686be44cd686d376dace324ad5638e01ddfcca746216802abc23c546f05a32cc0ac4de65a95e0df9bb9f398dc3672286dba17f6bd97491d9cd1ee50d85e01858ab84b288bec9a02b043c96d36b121841472115d67af07f312cd16735f761674cf748cf8e06a88fbbcc49627a700063056ec624b6a75a8fec12e6e83e064e65635380d559b83a27bffe9ee0fa2209ed6db3c68e6f857001e5bde4fab916baa13bec66398f7ced013915e6646db64186d1e1d65a1a2c91e5b92bf821ef68a8970d7e7047d605802a644f53523d0ac07d750146688613f6a456b30216fb30cb54a81e5886dda06d9ffb1742310508d20cbda0e4a6f96e9c66b80fb084504aecb828cfd9bf9c4072c2b2390d72af544466baebb4df7a589e1a11846e38746c3949545f229a3131c8728dd7c3521b345b77dbf1cc19c9de563c5d9d0a5fcfe8f78715af4f3c3d8a9ba9b15c83bb865234061a7595fe0d7c04457bcac58ba5343c4738d498e80300878e28ef3e28f7aec8e046c64c7a29fd292501f007a5c959f431ea11316309a3d7ef2cc52066bf42c3bbcf8d44773c6e462dbf3791e40fe22254d91bf93c840e5661ffb36398fe7c103c26bb44057a4ab35a4359b47703a6c6a6e0fa08c8d6f890ff20568e627c55a6a9b5152d75546a51126d179ccb9b005fda0f88b207b56341907e82f162e92d696f13ae40b5dab60ee790750ac6416e7b21d956518cfb7b1e8b512f06be25287383a82b8e28de3cb00ae0cd66f85d0aa3afc74d7312e4412a4f2ac735e24110bd50e01f3d1a06e427a2a7e118348d10a49a837898da665c4967ae7d56884019618a103dfa196606b0e1b92431f888d2db699e1b08526a84536a787de1416134d51f5e713383bfc6c2f5a58919ff18a3855a8d84daf7fd7d40320b96e53d6a9e4cd6e74fa1199374c19fac833347a1ecd73decd26ecf4a6d54d0a18772e88b28c51164952a538ae38b559d056c0b303730782140d14ea79a50c74d73b79355787b2e3163b38b0cf6fab288ac53b8b427d2e14b8c94f0faa681a4561476cdc9b2ffb7f6ecb529c5eaa1aeaa2efdf8af003b7ff5755d60e93fc5dee667f953cc8940c2087b3ba63973c1173995f08156ff755178a29d8a689cb84824d0afac54c472e557ba8c0ea3971f8010df720c69a5f7a16a0e1c03d0696f021298afb7a580e3fe0ef0a14672fc841c0a40800989d697419c8bac4eb398c1ea6ba86039f410f21cd33d2b1a074e8ec6880d1f594af07046fe0d222c29b5e83fa8880a8ee142fe136f26cc31b86e303707365d2b82f3946040ffc7d7878f061e90bd557b69bc6f3294018a92088427d89d161a0f3bd2a382f9cd9461a15868e231d6ca74b91cd57e786e6793bbcb28284828233ccb539340fed8e12fd25f2719bc2c7ea8b46bf5a3751f99ffabb76f72eda5863ce0df6af5ec5428b26287bf840eccd05f87a60e9953431e7a20ac221f2debf0754027bd08861dcafbfdbb030b5b9b69edf74094388d2d80bdf8e0d1ddc7f05176be7eba94be2b50ee0e986460e970e599b04c71fae8378249bb4ec5f4ab98cad54144b420b20c56b87e916360e0c9c2c1149def9a6a607aaa54eed25efa66a07909730aa9a6eb6293912d7c545a453d6b69be6101b6c040a57c6ed3fa42ea2a9a3ec4df553dcaeb46eeda5d798b82c8e89da1b99d8e6887051f1bfd86390d57e0b58d36488eb7bf779cf1d69f7e6fdd11138a725f434975fc4b2424a254ed02797250408b7ae6f1f0092679d81ac0a20160e2f70d452927db62f7a5d17e8571a3386530abe332271becba5e9b4fc4aacebeb12996219c6af5b31f54bdf16b1be092c186da36cdf1f02c8d24044e9b79df1aa264bbb53f37b1c281d01198ffa01a1a830197fa505f74adf2a80a5fe3916fd324910007f0158914316e6216f6c22c2223c82871761be88382447f6cdcdfbe49590d0151145121011cee42228fb14fee0cc09c3ccce5c9dcbe5b05ff9fcdcaf8340c9e8d2c687d7aceb7b1998e675e799bcb9d0a7134904e69c8a286f977cc56a7b3b6a1724ca517eb2b48d2be989abe13229404025f68dc58957c69d1634a0efd11c991c268ab6eccb5b85f8fdc3062694deebdd20f026eb48ed8d99d6015a457f8190955460b783585b76b08fcbeaaf56729d77a3557f577344d7a0ef2a364e03226464ed775808801fe9647e57eee1332bca2385093d5f4fbc0966aaaced8a77f6c4ca15df3dddb5deb0bfb941a8b7ec1af2a0a547133be48abe8291efb62fa8bdd3a6a1811e9c69f1047ece70860c3df65029bca476cba234b800ddeb30acd1973593b195287aa01718aa7e37b5e24a7bafd03bd765d395cb0d58b7fc81c3b5230fdacb9d7cbbe0d35772102f57a70d740dc8752cb639e45ab0fb293cddf43d942633d5bbc2f6e0454d18a80b030df7a2df788e0775a403e2fd39f86bbbc70eafc99091585b7de501f51af086430872e3efcab807b0e319f603de307eb6aed6b7de53baf30606fbcb5dc10947ce520d082170923c42cd86ae0d88b5326e31f121046811231c1017122a929dd81754d7deca54f283eee8a2a030bc3ffc62f0f55a45cd0b0edc107650d3a1bdaf6679de50098f91a40a3000139186a08373e3fb39a560354edd4c75a948e756f14a078593ec047fb81ffdd13a14f9a860744e5f14dd5c859887be419129c5924536424d78e6978d2e16b960b9fc36b841102562ad938c8136231b4560ceb6fdac4fad27b7dddaef1b2b17619ace7e5434c014fac14d038d7ebb94f059033ffc8bd8c1a2b0c14e6a10227c6297f1c1c5f5915c5d70d9323377aa4f27c360d5ef8c08e76c3b3df402ad11e8ec756ad3d760f251ec8c4734cd66f12fd2daa00f8c695ffc6992ea3b0f37696bbe5036cac7b8c1280b5fe0ad9640ae1e2533aa427073c79870cbd081534f7578ee1170044be38fa65bcd734771cc71e42245a3c2ba35854e1691b46a963db9fc15ae35acc70d65534f283894c859f39026f0bf691e3b3925342ed63833920657aae5a44abe43c9b8ef9dd571c063a77b467ba069fdf0d30f8b017fe6548fdd4bac60a58a3faa9016090e900bd4160412df345f100019848ef7a10ee6b475235e1c69ec29431a42e5180220f4f028d49d51e7136ab397eda5d33e74de76045e6f71a8f15d59bd1b0ad9dc876de5bd14414eef65aa10219fc5efd1e87d75f5a99316acd334cd01bdef80975b49ec2acafff0b28bc9bb3500cfb144be3cccca8e0b06e5f7972527e8cb8e1b088f5fed7bda96448185f1d3f80d096d499bdb22a8cc363cee8ba02101f71cfd03213b493619769d0cb6cd1d6e222262482e6b2522c21f94e1e6fc6cebf59f6840b7b4b380d080eb9450df4e311aab74f98a669d8647525ab691f268a62507d254748b2e331c15123a18180205949900bd0158fc796c2f976058f69725d78c6618a37605eadbff36c18125abd574978b76fa4a239a277bf55e29036befc71e7275546cace99fb5182203f56d8bed13699d6f5399a90aceff5951544ddcf9a6c728f96436a84717ef79056cd0aa0c462f6438395e9e278dd45eae8bb74959b9cd469c698104220c036cf8dd66631a9e396634c9c7d0b429511c66376a83c145bf95d15a03e6cc50df26053b0a410024c4676a9b4d90f2aae5ade50a1fa963c4bcb552ef261aec3017de336dcdbc54cc5814b25f85bc3d4e0cd77f8acce1d92c93dac978d8679598b04f61b960bc466330f05ac361129cef6cd8a090bed7e084c64f1e4f327decbd991ddd39553a38de3b15d02c193564c0a9186026cef38542e5a864b77a5f4a5273db94a21e8e0eaabebfe48bc2a7b13b54f0eefba5dd307ccdb93b9dfab6b0d58b3b9f9466007b54f677eadb38392f9686fbc76e0c64f54c1910f298f36851bfa9667391938c1782ef5d8c2829bfe95779d646611f3763cbabfbea2ef058430e49b0f8ff9a3f4e8d7f86d5b65e9820252b9fd4b0f72580ad8ba87f0d02123ea5328d9820388f4a53749113478981f7d7f137694454a23cfbc21ec483ac428e57873eae73a9a88fc160a5794609d590ab3ccf8c4505e9d6f0fd07870d8e1d5d330e18abbf3127cf183df5a703f77675043b3a743d535262dedb40345d2c5ecf78443b5fd9f88e35d75bc3b3e343cc6696871ebed2867d4369f8ec010e84606123c1f439c427f729132ca98c0bc97322d2599bc0eca7530ca929e1196d3062df8141b80b3c8dd9821ad08be5ab3f9590be965f4d886d4cd7bd5fd9bd1d3a0e013b8ac891c9daee42c8777d28e6c17fff844eaefc4784e15bfb433bbcdf69bd925316e7a8d146db536be32fcac544d8de424631cb73d8a5b56ea1cfec221a306331d398c804ca80798c7e5d31613a3dc3b8b610ae4798fb2c3abba4b1f5cf5df0bc59a1c8edd3fa334b713257716bb1ad5680d5ac5c8841c3334fd2b8aaa37a09cc33798f04f51da93c4d2427500932da7d3cadbac0a89366a79fa2554f985951d75055a2572380c205a49d37724ce712159151d3920ebfaec8af60a1f438b76cd704845d6a4062ae8f9147643249e718461b2e500f58062213bfee43ee40ca4b21e4e6818595adfcf65de8cb7df845de70ae9476b539022ed5908a1c4a5c922d6ee5a29bb6ad121f715261e57bc6dcf8105c1ce4c61e36f642db5b1c845fd11b94323c14fc7fcaa80550a5770b5cda8d8a4ca684807f079c2a69c10df0ccf63e73a83c87ce0c0686229425b800739ffc4b70529cd96144bde05a216b158d5aa57104dfe6ef5f2755591df3dd21158c9af213d140aa6899df54ec171b5ffe125593461b0216e7dfdd82dc6bb2a1dca4398a9ee0dfe169096a8cda48640984e2a8bbfcba2f779bf775734e76e58cdb8cd67da2192420247d06435af675eaa16cd0ba666e675daafe561ec7edee3fe70da0f26252f816cac32602c143df7ac29e26d401ef039a7c88a986a1c302d4c98dddf0a6b8771920b1a9b43d8112afbdaad77e70c5fcc78b05d0265c2e1e898a0571667e331c03738d69b7da70f2ee3ac82b93f3a0b329b3e0e3c8238569b8a06199dd46ff48c84d5248906276f8ffeba645d2579d3a80cc5de6d9a32cbeb16ab1ff09d233ae2ef55388d9f5a1e02f50dda5f053ec3884fc46a32e676cbf68ef2255e4d3cb6deb72369f7b438190ea369431cce602dc9f80c02fcda3a58f3325467bbe009d01617971471b42e6e5a95c5c66fc70c51c99f03ad92f76e2f9d361fc1c90513164463a48e544562faff2e0d65ae07d5f02ffe029319be7724503030ba4c9bfa1673654fdd20742e8a6a02f0023be6f1222a4c07f68bd1048d9ef38be47e0e3e535933e678023d3491e733004206224b40030753bffe5ffcb4ab4aea2d4885e9ef2912be9a7c54088d3fa011a95a67cad9bf50649f5f00b2dc4b2fccd9986b3824804042de0a5ae802d20380efc4b078a5066b1f81a42ef16d68a9f73621d91a7c913349a5d3ca9839c5345f3c20d15b63a3283d6f7bfa321aa0d52676b3d0632126a64747ba334a20136e1e56db84215813c6b849b106c66ac2ecffae16111e1520784831188a27d88e604c7fdf294733d90ca125a8bc6c2d8561a2f32fe8cd04f29e31ce42185d341694e14c0f8a4b556ba75319bfaf8236f2de90f317668e5979889979a12542f87f78cba4321a117d95dce817130d6a0e3bd3f1b21d6e49e703aef04cee6f0a7a983144087a4dd91010772af3260c33986e3bd67973a70466e0338cdefa11ba18fd423bf9da1309bfe370e7ac217dd637373d8a837332e1eadf62efabe363e2a8d0ce105110aa934880ad7341093ff9567387fd70641125ed18738ccefa533af0ae470348718c486235a5fb98a828ab5e743b6f3693040351c48778f2b76d0d912b1e5715b079ae12c4d953c7a3bad5f110d40628a17905b278a45704e9b06297da1cdde40c3ac1856fa6f21e6094de3f02d286aa7056242adbf81860128772d063241c68d72cbece7315a44427eec1e17cac1171d83c7dcc78512914d13ea299e01e1c33885b89fe27ea576200f12fd75fcf354c0989e0100ba971d4f4765c3d5ecc13a737751c7c77a9ca44897423192fdc7b18311ed8a388e8928b3c4bc857b9156883b5f4fea93add594cdac567a7bf6fccc1226cc5c4a8434ea98483745303cafc492cab9ab599dba21961c5d2e540e1e584e60863115d615af5b174678e15789c072dbba1fe8158ba96186bec508c26deef2d7a4150ea928b87aecf27e62337339e7cec44ed1858f8bd34d437cc97042edad052a348f6b109440767ed206aaa92261910636ad58f8950737b558b8ae0f249d7e4a2a033b0051266b27461675dc8cb455d9a08207694d868eb3ac71d2665a8d300c70e9574b08e12cfddcf5c2b898df2a1c49256090f5cf6f9d4d9990aeb50d06fdd14e563910a6ae91179feb1dbaa0df48843c2ea533a840ed8e3fecd1c20b58d3804605cd0e384de809c6226526973fef26cc54263a7a2f6b19c63fc320fe9cb682983361520903058ae02fb9502765db79e9de11ad923cf44eca28143ebf39036ed9ef8b03f45611b8a62e71c103f76c5e522c1226dcc6cc016ef80e3d73671e922706d140610a9fffc1701cf06a4d2dd1a7c5aad1b3e4fde6d40d7decb6b3091b1359f38c0b359d848fbe337a314c518ec952796f873450f721fb0e37b38421ddbef7ce07fda743968d9f6343f532ffc5053c1040c8e01066b765e74d027fd1f61aa9e323eba3627980de3547dd97d486fdf7e71e8960a3e5ceaa8f7cb1b78d493e0bfd687605c6c01231ff34ed88257a0aa35ddb91595963545e46f36b8cdd78c4c481b623a073c04c0bca5531116dfe643cbb8e63d5306a88156555a66ed20627d0fd6dbe0359a1aab794468880cea4f325448fbd7d062d6e40d166b13398d8fd1929b67485d467e16d955548a45c5db409a1ec76d7941a85d648a78c629d5c0762f7859bd25835e08aa28455861521a05f30201dbecc24897ecf1f9d796b254ff497aee1e1b2980be4d80535b96c99df810f0bad718a66c832b839470a954447637357e56bf5e2b34e429e5befa443f0ffeca409d7ab1fd90e2bf721eb35975d9591eeeb2c2f3b0ae6f19f2e3bf266b391f7105d38184c8c18c9f37f6e2c3cf16a7358ceaa05c13782f1c8203cf09ed903e095ada7e50cabce09d9ba8f1d215a32af8b1cb100c374e53a022599afb107ef7dc99e0f53acfb236856ce516a69a4565ffe017efdfa46efbb045134b67e69092513633f0c530be02c53c9dfd956d4f94e7d5fa19e5cc99ed239270f6061aa08ebf5d0eb715af3e6cb08c72efe7ffd113b4f9ab06272235f6999fa9dff1765ea7c94a3c9afd6867765be02e02d65dc036081a8b47ee0d01d0618f8b0cc573c4a0279672763fcc768bee2078935651c7af515a0e9ffadc91a27313ac56360b45a9fdf50927f15072d471e0b9a9ae469bf5cc2a51973c71e8284064ecde949f9191795e6fa619eb1ca0e83aaddb1c3ddf8bc2caf76fe6ce07b13757fd84173f70902b503d5f34b8507b586ac0756f1d1d63310b8ddf1c10bc39ad7c244603b9e6eebeca1c7a83e882c23c49a65a5952988f5ff85863a0d1f82cebd120029aa8b3b7c38028b2eddfce825409ae10728eb6662c96b42d285d10eb3c71387cc260e9a13fcab15059104d314ef9a19840bcb413e6d24175f122e922fac597a3c9b88e6924112ffea080a50a732c6675ee0175c768af871bea4c36c68d043e46c68f9b52749b1870a522c03414a7572f9ece45cf37c18123ebecd186d56e5f0207f4609a76660c691d44c01d11d8c38afb3300042ebbf3f0aac8bd61f7bb94e5e8e16a4ea4239a5dbf6545cfdec6b8f299ddf8742ab408f36f87c88c3dcc216a75de946ac74d4dc3d62898e2d0fb58bed736e084c2c2016d9a45a59d016ac1c7952e596dfab665f5482f1739444873830ca784b617f0a10e678260394d38177f01c95859f99d0da38434986c0b9d9779d73d8a6acb2a8863d8a0e3ebba149cbb0070f12a84aa258d9128a44b958cbd46ade069e756bfeb0dcb4a9b20a1cd24c376e7461009d9cebfb230021ef7aeb91755114cda143ad4e8ec621a8048a962e96ad7a319e6227dbdffbd17b65cd912b4a3e2240433a0c46ed092eba96996a06ae288d7efbf30200842607bac2c2dacaaf543058c4320a9f4837f9d3d09b41ab6ac6d00045217dfae708f982c425b70e63f15b0a9ea81f3efc647f31d1e7df0f0d3e294a9929e8efdc2ff59a48ea3a89c893a16c66242f2dd79bb692913159adeea5a8edf8aea6952d31cbf1e3c32e61102e6255eb61285c2804426048ad61153326c87573348cfd05d6e98e5111eddae794fa85eb5378e0afdf00fd096e9211c98668f3309c35907c4ab69173e00f29f6e410bc1131760eb314e104f3833a072b30543aaf4ce7a08f9bb3dbe4efefe5f89c8cc7502be0e9a29cc353488e648e1c81f247661dbb117fb01bf2cac73988e3341644ccc0b265c539642eab291931bb8745acfd5ff5a8ebd3785487062bbd8ada8a3653d7aacbaf7f9b20e70a4d5d568033c2049cfb9ca23dda37ef3acc71918ab9d0ddcfe3d81053e1161c9b7512c1b774f31414d7af44578f440744340e79e80e7d090918a729db34b11e4fcbb9c0e79c8f9fdaca844c5d746dd3451a26b9d2f9855a0c991afa5fbf29944f864540291426d8a48512e5bf01250ff7b09fc75dde5c0c185547a440e48b38623f46393744661ad55d992f570fc0264c802ad46f7ae8ccb0431df68b5c680f0a240943f70d88499447d3389fe75f3b20aa1a61ef173a846a02f2bd762aa30ae007e1a189fde9598176cfc41c7f3a4967dcece58d86f3dabaa1b61670e31a7210830f916ad95e0693d361ee79b773b5cd6751800823fa4a0a1f05220881619190410b1992e419f971537580fd31771a0c1316cd4a9c699af89d7a497ee54cff40841b383c1fb292bb89357794ad716eefb480fe128f87ae9e06526a3750b0d219b262d37da245856e2077e021594e705384caec0c54e3b1289fe4a57ba7cc7fe49176dbc4b75ba600889d41a2227751d71608ae9d4498f8e87d903ad4bceab4c389d598f37604ebcc8c2a345185374508f4245f48354241db2cac2375470ec19073db80985d0cbca811b37ee78b14fda4fdbd6e469614ed8f1561dcdf68dbc0c100eee08926c234cfb921bb7522cce99efa0b2e82f263b4e6066cacfaf107ba87d5a8666849d1deb54684e72254b6c51b0a16d067a6e00c1ececd8f0c3f10c3450809ef9b6f8017fb578fd5d93072f48c0e34fc872f5c0f8e23256a58b31a43d6901726ce1c7ca9444906f618b714b41bd48d738f83d5e25ad368ccae479250628f78f6ff6779a96e5a2285b6f6b85619e71141cff4df568004a8e5e35b11ced185781804376b791a826203f90f9709d0442ab5ca4fa052b21d7b8b4bc467d98f1f26c0e866948e5bcf61b6428fc1925fa4bda7c9ec55d5d0f0c940e43b5d804cb5e2a46d611df4d908a26f9a200c36417730013cbc7f8977dbbe229e3f4c79b6fdc77a350089ae89ff337c8733dae21528614462c552cbe88cfbf7642eca95cd7cd7887a550db7bfe982e281d237c3e63f69fa0a12b654977f15d09754f22b881b8c6d36de6382a8c71692da916c1b32899414cfba61d71ace810044541463850efc8d4d297ddbbf508977f358747e05adacdf25659962a297e08c2360df915d381dbca22f0ab93c4d50fb4b9fc8f8f8a113c2e8bc92becf74c90dbb798ca7f8a4d0f86aee569e8ab16bcd31df5a0efa2f5810a7732aaa6009a339d96a5c027ac48d5d2d29982802686521d22c30c9a6f79302d5788a065df62227800c6e917856eae1c12b81782f8d1add432529387be00bf71d229c3c491fbe72bed65172c40fa00301142d445b12ad93de4be9f68259e186fc20670653f488e297f79f9d6d9b029173f1f90bb0e6a1d48eaf3247765048c7414dea6efdeeca6ed628750af399b5273c2cbf3e376d3b78fa3d618f584d3e32f40e90a8caddfede3651c1ef5f7d19f8671ff0de60f8324c10ba607dc99611a2b2465821e3662f7497810c23ef59bf7238fc2e6dcc03c20034834109e9e43ac7ba16fe68c234973da1dbb2d62708f636f703af16244b34ffd7bf4b985325418ce627c3e779af384a09c527030257ea138e956efe6d66eedd9eb41dab2d3e303f32dfc052f3b5d6960678aa10331fc0a1685a72a06fc90a9d8aadff5e0a4efc82e1c5a613e614fbe14973e36bc8c86640c032cb90648da02a2324a912a8e222dba4858436868d02e6f3b8ef588e3c075fbe0bb0970f43e5e1ed4dcd6755bb42c24efe9d7e8ec82954590d9f109d99dbcd60045f41a369f1900c778af522c162759f043b8b8d641b27f770dbd32e272b8712d6687666e8e524d9104227170f54526830f309fd6337947e1ee4b7092a61a43d0639c8ce620176a82c7eea803ec9444afe9a668d0f1f20eba263617c9851bd03da35808477e714fcd12ca51ec723f3aa5c4d7a3c1a9f40426088155800e8d7fccbf2c1380ba5f2d1cb831407d53cb998db9583e56fdebaa03894ba7e3f1762ffa86069d51db4f9c4b2c61331dd3124344d24a1526371c68f3c60f38a19c6934ce9735d70663e711e07fdb7cd5b7b523a98112906265d11c04a74df6916cbf74751a21c04b0f7d5d018b85fa204a16aadd05a5c119b21124fe771c504221a14c6ed3c5ae06e970e9684d95d576929d48c8f2c6850991c88f074299eb23ee5f4d7b0f169305feaa99c50e00893f9cb048b20aede8e34257ac0b62ea20964083d8211b6992deedb9f2dde3c0ea0a74c49e750ee694c73c2d1b4296d11da8e074893885c2e36d19f1fa63ed223d4754e4a2547a5e3e05886b7401727ff2ad22127dc03e60defc4c1779385b63eef0170d7cbacef684704a3d74ee1f3646fae33dcd538cac07b4a9d56c3ba7056a3cbb1ab8e55151598c3dfaed3afb4b8e8911c0642bb8343d61e7446defc93b5e67190d722caa795c8cbe46d7fb4d571d9909e828548acd76c9d251e1e64d0032db59cf1ac8a748b79e38aebd42d1488baa31bd26725e45098c142310480a979e40281eb7372af8c4f47c3507da115e88b7c0df525d210108b3d4dd4ec7a063359b33cb66107cd9aa3a0d4adceb937f63266fbd8b6c61ad2c3f5da143ebc4f0399e31147a5f99776807c2dcf644fceec9616d50b6ad2a77bea89f25420cca4bb1b9114cf362577fa630ede49f9fb1736dc61c1cc3d471b902fd044a12e1dbb3d041740aacc15f3adf9dc7d2937367375609239ebf1338121e409ce82c071ba39941b5a2530973800c4eabedc36f4e90f20aa0db779d495ab88e85b65f2cb223b01b4c89cb74ca73dbda6196ae429611024747c8f77aae641c51437c6161a38b58ec40a6536defb6962b9918cc5d5932f187d15c02341d684f833e06dfe7e03ca40e1928030c5c00521bc49bddb692c7182262c8adce5c33d7f2440b25ffcfc15def498ae83c27e3d980f2f55f9104b9faa515966f25421a51891f5f845bdc9dfdcf73b219890954f738a09677fa409356d9f2a2cac86d5eab4d99f349db2d582ddfface17a3258940683844f1821b9278343fa1d9f842bcaa048f8604650e69673c0e0e94bd854d3a157bba60fcabd27021d34a3c6594038f75fcbb54ce24a2d3e4945ae2df09d2d3cc7b652a6d8b449c15e2db6bc8790b90be4f7cbacc086077d9f176ea909a149e03564cebe31fb128770a7c3bb170321608c9beab2f665c81f7c419d8f6b9eddd0b9c1b2fc0b1c967fc512cffdc93d1dff433c4079ec7db5368dfc071401b2f479035d01313f90b74ff70d7ff1689abafda132a1fd13b7f1ee1e80751d65b220ab6b72c461340becc1122127d32c9c62822ebc3b679e2542b6851158f677d9e2815865895e001789c2feb394a365091f81b264038603c6863899a591b1f59c40bf47215ce9bf13c5442cea94ae9e4c61532905bfb0e85cfef6b6258baa6f51eb4b51c482529ac343cc807f6584a579f822c10ae5b45abbceb39ae80ca4081c31e726fe52659d7a1d4c63c43bd6a4727cb2024f8ad7a1ba8d3ce2af96f166f30831c773c8f54541776a93c7940a59aa2375ea8b968db7addb74d1450cd2c713adf2ef398223842fa28a1c34fcadc2e9886e1049bf90425c2d45ed92ab071f2ba2fa5c45512d38447433e98b272dae383d0cfb857748b13b33450f934fc7de054df729d093cd29e36b46238b0dc9f23afc4613e6eea0d591fca0d5fc448209a5ea5187c498eed0d83ae49b3420dde5889799d6e8042c246cd387384a94204050eb765352ee20ebc435e997b0d615bcd2eaddcd8d7f14a56a38933718f5fccb4a01b91e94f0d11c53fd5d0bab1283cb3896bd50bb31823c6ec268edc2d8fedfdc5837e1e76ace6c8a03e5380d75a64e76bfd701d9e1aa9208134e4c5a0f8a36a88f845dc854493a6349c05e3270104f408f6240077b8a4c8cdedcda45d64544e7294f8d13bd4b9372b4b220a3260f03ab7e75b2e68352baefb9025e54b340097a8229358ec1830a76a8d4e6a7d7843fe96ce369eedf40a6345c087efbf80a7a35d3f6717d02f215a8674513e652db159d5eec4862f35813722940ad7e13a485a74eaede6d942727278c52b5e6bd75731804ccb962ad09992faaa9a41f684a444c3fda48a45640393e95d93cac98c457796d51e8b7d1b544f279b99ed997f1686c95b8604d1107111fbb322e5497541d4401f852c4b5e8efde62dd665dbe1664cb240729e626ead6effb8402fe75ecb52e6162b09f3a1c99e0e82d7908751da4216a6e68e00ecb1925174e0fd3895b0c69a9c64ff777f2dbcc3db3c312ded549149990ca12f9044b3203d72db67d1317202468746093bc2469b691cd61ec7ce7645e54c512fda066627fbf7b5fbaddcf0aaf0a57e11837668aea376bfd86fae6cd83a1aa10f1b84d7e88f40e96568b6f6dc49d767f9029e3d09c439a1bbdcc2f9e22a489e78a8a5cc0c39d87364bd9fb71ff27fff151d1df7cfd8c442e703911b95cffb133701c484f182d0411075d4183ecfa1cb7d1c0040f853c83eba28a4af7035d26467e94181480a5c5b4f8a380b6f7e5da5d7bedd2ff832f6208aab49e277631600dcf1dcffd9b04128ab4eb487641c7785868f034db7e4ec269abec4546301a11649f96187930d0d4fdcc615bec6b166d8c8d8fad4e3e21274d3abf3921ea81db9f90c2fe7751e1cf2fe28fdea484d9a3760521f4cdb6a49b95736c3f4ca4fb6467d7bbb0be89c7c651dbe6b4bb2994bbfeef4b4721a54655fd1be7fcf6e77a7f7661a3f4a31f068757e90c2584cbf6410d8137986e3b77a4952af1dfe9a166944ef8f71c76f81054f1726fb31b92e9c60869df7b685bcc12b9d2083125f215d459dcd155337b92339e2873316e0e82dc1aaeac284a42f64a5f274ad0d20b14b3db55fb157cfe5e7fe59b792fdd5bff95dfd62659f895d3577350e0521da1ca73b96b3c1140454fbc16be4927ba354ad48470a2472e1302ac1c0ad255a27567eec8eb58a3531ec250be8e9c3cff6f7ef069db388e6c4b4abeab1abdc7afdf3d188f073edb5e5b6a2bf76150838d08f0730c1e2fa71249fb7816193b3617c91b4068af744dbe809acc386741c2697dc73f2a29bf8128f5fdf44e584c7a5760f689c0820dbd0b7000e40527bea681e48fe120a91288c4001fd117ce55c33da362c0b0564e23dcee56e4d1f7e02afa1bf508c725f5d28659b009f5beee8a5bb097d29a2314cf000760d74c664384b9d7de3fd5c0da2e499af67bcc20aa393868b10c40df3682bf7e1435c7762f365ed1bf6a5adbc6c42f7e0e01b885bf723d5406c01be80b6b3acc9021f72717bfe315506b8aba1250463a964d3ce0531b12c51fc5190e1218870b73a05c9c6eafba04e02a87cf17c86cc74970caa6ea6de3dfe9a8b1daf931a79d95e9abc01d702218f21ba3400edf922696c6be170a0d4e60c8dbd06ac8cbd639b1895111f7125acddc738c5f3a2a96a6d5a51049d8bd64e73c5ef719525611e21ecedbe4db420b3c64284572f53be731e12cad1b3c9352717f46b10fd1b5f19eca3701931ec46bc01782db6b9ae12547665702a7ff20206e175941a0e51c01e45886795a2a87ca3a8844d22693e2205ac11c56bfec52fc905bdd7f35ee58cedbf93ec0dcc963b4a6106142aea35873bce2ab6ce10f53086c3322ba8cc30d6337dbafbaf2a96447de48a22340f03177c2cc1cb6749850c4643f265b47a40b2a3b80a24fcb1dcbc52368900527a1dcc2198aea825252db40a4053d6d50d9431a1a566c300c836dc71bbe615434c7fdd56b44e813b255f98ddc98c5140a3affee03ff6f0d797b4c610bcbb74d05afc7f36882f1bed3396b9b8f1ab5e9a82bdf1aa14b4bbce4c851a48fd1a7e540a55c58f741b6c4fdbb5dfbac51934cfbf63c106e516c8f12677888e97b6f615563db46daf0c67fc79a1010383ecb3f960614aeab0293e5631ab76790a316f85d2b9765258e2639a6ddfd2e1dceb23360f6356474b722a572e9406e18578c41f1eecf10cf4ea402e6e290e1dc9dcedde3c208f4ab97e6c38a50d074c9a223d83adfd966ee5226ed194a85b9b5611c692674973b820ba75026d7c1e4544f054c2db0788d02dcdf12877b109968e7b0071df69ec1be55bc0b8d51d44f56bf55c55a490defbf0f2b357c7544300c257192209b0cf604154ede4bccbe952c493eeade234ded76dfb0cd47cb95e6e9ad5569817177b95cd7915c957826189b772882d391b56a831038419b942742e38200e42569e6b3f84fd348802fb0e221d2903af00fa1dbb8b9c316b55a745b039876b7eb302d5984be001bcc75fd4997fcbe3e605e7f10df6959253cbf4c1b7aec9542373c466dd37f4b0eb4caeb852dc32f1b5d683eba4a8c3ef2f4847b2b51b5ac13b50258b94cacdc87565d6464bff3b9b15ef6824e8a94a270d11c6171693e0f256c287e3de293d6cc1c9ed528e9691513637f2b558c1e4cc7ca4406a7f3b53b49b486af0bc85b8a51638ad1904b382b07b054596e493aa03e48710df272a3970de191e35f653e1907e47dcc609081ed4abeffbd3fce9857df195a000ac9b8daa0efcb6f60e508e44ec2016922b70b584fbff284581f29d8db356f605f29d2bb1a2f7ea3a3692a4f4d02f2279807838bbe07db34552f445ef1fdef3fc642f0e00b7413979bae753b73be3bdbaae486ea773e48cd9c1c4d8219616853be0c18dd062b2becdf4aa26eea8f3dc2923c3ee6a4a089c233b96ceaa48956dcf2e0761f96fdc3d994aba92058a6fa44dcd9b2082391fd214320346a611cd25d3e1fd17ac3896ccaaf3eb255fc0a886cec48090a5bbd8dcc06e1578524d6fbb709d0fd9173c11d9a1912f458cdc6c0f98061f8635b9a44a0a5d539d5a61f09b9d2f571e9e4cb9f2df25c2f2578f105323d6cf0640103cbd1b60b1366d14aae4638618e7e6719c7e88f715f61a27ebef60545fffff7e3d60f8bd16d89f11e775f7962da246ab2b0c06a19384b140b67ad2d497e755b39385b578725b846979ca5ee79c20158e9b3bd602e9f8a6a1ecddaf7fedb5e51243e68f0c67709009b597fdfb5e829c7c485c8f7c936b0838546e0a45214768a65e519eae603bd6922a4a3c07557fac549d69b4fb516caacd44d622c46b5e69ba3a153a7e0eabd751912aedcdc56d5e9a48999be69590600e4dcb29be49cfbd3dcbc662d9179f3cc18d17fda027ffdf11a3bac2e1aea1ea94bf6621d08c476b3797a1f8a58420bb72c4d2d32d692a7e14a6639d81036974f4c69cda9cf69fc084d401dd3d0d558f511d45aae05e7ffc8e59cc17a631476efcb251ac6311b80685d0eb6698f9591887f0514b2ca3e832df08ea0f8529dd4b3965ddbec7db9e4272a842f47d2a19abbc8c591b9c29f9471df0888f00681d4104f676d1ae8e674c90d3f079de6213fea7c4047602ee776d3ef1b9fd56a28ce28e31ffc10facb9cb7e639d5f565bc6a7529bbb91d940836e05f12af18a3524f8763bc19117228985c3a07c8e320614a845a5ae7035a4322d4c8572cf23e66653d06d68b817e9a21b5a700424e6fa31114a78f6eb10d412109b27dfbb6d1f7967d38ea49501602092d76cf4e491e124937f947d833be284cb70a531212bc5d8963e0eb362b4de191be093ba154c6e3213f6d533e6b6834af89e12e6ca810cd9e50f122e8dc7aa9c66fb4e0f595fff30047602d5435f75523411cedc59e60960006097b3c754392e6378f12e8b80708a062fcc042a5efca4bc574d6cece1bad199f1fc6fb041b415b37dc1da13e8a98e5034f43bc7c9ecddb9d800f2be7b17376ae63cd26a79cddafef3c7ffcbbdf6e387b230d64e45cb64e445e98732e2f4749b3ad6571d766ae065649adf961389620588468471642717c0001a7de8d3eb363e4710527d8028573c3a961dd8c0880bc699917a5607707a28e97e22fc49d4d79345dcc5891bfbe4f60ec34a1c5252a60df183daf4167a58254cfc5ec8d253ff293f07f0e0a0c1f7d07e11e5b23e42fe80df87954618612c88585874ee402666dbb388de3450b6866e9b69d545147b382fbc862f953afc8f50361c3a7e969e97d6e310fd7377245e607afef0ad806cfda7848269efd690976a83b51fdd8b621ee4422cbf8d68fcd3f0700fab41ad7b76c8b004620e38bf8a56c616c5d00c091177353a760dd00fdf2ec3ad6fc203d332eb7276304601cf69a531ca05338a7814dfad478d69f53f992b2d94d012665e74df7eea86b9c69c669c2cf45ddcdfd2d4684adaa284df1121c12a7a2a47d37a4c0b2b51d3d1076356865b109a06bb442545b9d518cd819a7d08facaac907380a149b1080a61af08a29df851d3145adfcb10d885efe4547c43db87b2db5e92e971d5986fa70e0d0cd5d4a207bcac9923ec9e1a33cf64182da1ce7fee2810ac5f1084996c81972bfb889661d338817b43bee00ea58c645d1a53d0818a844210f63fa385b1033f3f63bf5481d6d8fed1e18fa133878eff0def7b1cbc9558e83739c7805460a11a67b96340659a0852154b060ec7d4534de451e7f668cdb8f1ebacf63a750e1704ade5d7dece2c63c254382c7a0ff02c0f03be39a3b451de3769593624ca4d8ea50da52aefe752bc5fee2ed5e0d486c54b01edc9fa05fe7eef5b55caac8c39e72bd7b943e9d67c3bdf6e210558f0bf494123f0efbaf0efae06c1a9a5dab786c6122eadbf8932c8e7a3eaf57ec27f8f3c87d902b052c4b5b147d0398fd64b8d639c9ecf714561a3bc4a252593b88c8d16b1f5a37b809d50bb8c20defb96f5ecc3eea0ea079981674567a4172f38f3f07439cacf1ee4e250ca64484d2db0d8905ec0dfd63a9dda28ff039e0e3d274a4d7366374649046a40628504452708f20adb8e2056e70e37e5da035f8acec2d25011f227b08d5b0945420702914a715bf58e0636b1e5ac7099d57608a639b6aa5a80689baf8167c87e631f580ab77d5aaaef9179982c0d9d75ce392f609b8121195441c6c9f5e38655e4891589acbb5cf4dfdaa07ae3bd7e3a54862174b0093caacd19bf7ffea6e3057026771dfb3862e2899633f42135e7c34799965b313603b6d11a6c5005d736739045cb23fa5b4e96da02eeb869413db98eaafd9648c5963da5aa2cc72b0c886a1f1068830123a0e9c6b0c280e726e49db6e0ae86c137bb98c994933a7a1838fe42e490d4c96e742acf8f1aa84ef0aa081a5ed10d5b91dc32bfa75f79276dd5e3e6016e77e6289cc9e2c8e938eb1bdde277252ee149720ca0b0dd08d5596eb63bdeb4ee4c9471a42b478799e59723da085df629a76e9715e270b8b8dec7229510dc661869f2d85f3b9f5c961a206a6d595fc5838fbf441da984d1736b9aebc5082fc041095050ddd6e6a8ec5c4f6dd887d068141e6082bc8a8e2360897a291acf7e9c8e72bc279b63cb2443e1e2a7a0b3f9477343504d51d5571afcfd62e502fe14c7dd6f4b2af27b5f5f3ab24e44f7908a091afad4b1b46fe60e274918872ca06d08ecb81cac6a05ad723a06cf13631ff2b8db274932c1eb09a901de411dc357054345cea55caf36ff46b9032484e320c416342a0f61f05098ea601f532e9f0d4c1c59869ba0d0d9eeaf0c427a0932bcb8e30c431f60da70ff5241f4d20bf78a15603de72f7c3b6b8679188e29b10a72e1e0010dc91d05dca1d2b4b6cc4e1718454b6586378747d9fda14340f193fbfe547fc925b779f644691f161f17a8baa4bb1b796abdc6c5ddd05e06ff9f8317f7c544e6ec6993bb5b17f459cde43c3f39a5f9f66493edd9ddbb54e6563b416d8a0a23fe1d0c26db60929c85187a0c97c083db0f10117309afe57021ffdcc0d5c948a00451f16c984c7dd221d25e68eb88ab13eb96f80c66309089e1d2ed7750b9aa33d55e18e374a1cb4e5a4ed93efc60b88cad0f21b6ee366abc3db181d85f0efd3f8686eeeddc03312692b5128579a58b0b78ec53656c2750b138d76152fee2bc40beb8e7614dae26be0ee81c3dda23b578289fb2374f2d15902a80d8fffca3c457df006aa998f1e3753d4b4174cc278d1c42b30a98f7d791d5ddfe0037e5a374c5d64b419a08a291d5143d8422de42efc827d0371c39aae8f339148454307ddedb1bb3480e4e15ab5fc150086fa613a67d04a15b948dd883ec3fca40891055e99c6a81313db62f2586a441cd0b3b0e5a8c0e81ceae206f84f1316f5a228e196f1b74890092b9a4193497eabcffb0fa6ac3224b185fe9c78b728a2d2cde4023e6b0293fa8a9a8447e13d9fe527603fd278420778b3ad2d15bc5bf3a5cf23c23ddf3b79822050efc783e5cf0444bb68d3d38c6e4242f341ffda11ed4535ddbbfce9db0df41af688ce0ebe58dddaf95612b2657a5b2e98278b3417c1d996b9589fbbf5daf74e250c043c650d8472670d69ead0c36e024776f553044f7d721942d91e84578948ef438cf84e3b0777fb192a3942ddf4c7d7e96fb815aed2dfb0fcdcc92cba831d386522fc8e99ee450803215f39ba8389a211e3101d4cf8c70b8daf71ef32a53032865a01616d2f94d1e9ac2041fd5bd843adce272769f597b3eef717efd51380e911926983e7510922ae2ac53554f9f8f6ce370947d6d29b0727c311e1cba0c510e9b4e96746fa92d7f0c2d9e373f3baa885cb6c31012a2e9b4ea6d5cfcc3330c23fd54409095afd1b26b5f7f103dc5ac9e25e05c8bb8c5f497a70fb60005a938b73c969855caac6cad61a9294216b271af0dd156eca03258544869a1d06a2e0219e31f07c4fd6949d590021b40ebdd85fc95a8da53c228fbd70c3a5c13d3a5dba399cf783c6376af26dc9b1840b2c82a390b94011d460e1dbffd56fc13660c240d45dd5412cda084111465edb526e1f87332e2cf062dc2f9dd0db7e48f7f5ca51ec7155e398a5cfd8493020db325a00b56a5a2a93e61ace1f47a7a0e93dfe64a707b2dcd40fe0745243675606c136fa5d82818fe6f6d6053c20466a250c84f54d8c7fd7b4f6cf98c24d588ab30c63019f7b0dfc1bf33170ab7cd8c5738da395210100f6fe156582f2d129993c6ff55b049ff17870ce5cda07f8d5d8868259921184b937d9932d304d1e8ab6cdfed1cd030a9596dbdd7db00cd6e75c6ecb46227f94afbc3dec066abd6b604d48af000e34c015c6dcbbd2bc2151de509a47abd6e6d9b34b6f71a0b6e8871b9a7c0d973f7a44c07fc4d998371a884fe81286d451a73bae28dd5fc7c6ae16458b23089363c428ccaa50b3879d84203b39b66ae55fd916d72dfec992e7f3123f16b6d34075c7defa2b05bed8d5cc1540fa9143b07655322254dd7d5e3c9563a2bea7d3a01f45609a170474b57578d4ed8987de064afbc0d38513e7502f45350d8aedc0c234c7b0a379d8d55c859aa9a152ebc2b38803e59536503b4b96c0892fe29854dc4f79c9d334d7b418f5c06443e66356f40f8315972b9b43c245831f2d1925de2c038585cef29017baedd319e2f9dae0fb452f27656e35db7677cbd8dfc415353cae4a3a1674db7e43b78e1379ee8a63cdcd22d6e2f0a5d8a37454f86258bc377fe1d78958ebe1a2eec95bed18f1e10f78c97bc74c5ab6e4c2078b62e872c0b5baf5f43f3dc5eccd373fba276fb973b544c8454d3f143f68771467ec1ccd7a7bcad64b1c4ba956d6d0f39ed73fda327b9e4085a45fe5c0ec7117bd7e5e944340608d6fea2c720739a2e6d18ec005a8c4d24f1c8d5c752c283a24f8b0e1b5716d68171202dcd58af981c64211a0d0bb692a638f223145a18928e10282cd70098098ab77b50aa279bace1ca291f004a7eb6e6a63099b580768b73ce3cf857ad44606e370ba7668dbf23d6124f133b18f4f59c78d66980b7fc0a031d59694ee39c6a07d7880f63ebe0d2696afa6976ac404260191c7f1edc9b93ce13c4035a00999b98ca66000f2ee2af84691ed8535ba58bbf92160a8dca1f5eaac667cbb6e1f4d80b3d9bc6411e4fc4d57331e208e46a0d4a0c9bf902e81d6a09c3faebe0fa8e97415700bfc2e0d58efe2611af042b2220e0a14f9a1bda28369e08b01645f8f77c0b47c8f598f02896e7c34f38817162553dbc4ee03fa59abac56205812a9030ab9cd095b2bbf119f20602ecf0ef4ef2434b4f501641b1a3a37a243c0cca984bf982878d0da5c65bc6df3ef7f06d0f3e4c7417bfbc52e6a65c140329ea02dc12bf04fc413ec8590bd7713b9b794294919930af20afd0a241269c78e911ad5254592cb51dc4f52174df2fcfa845cf9c9f2a49fdf75dde827cfaf3d528725c51d5fa5953a2caaecb16012f6c04fa4ba9c4875b72c5b2cd8347314f7a49f1d4c3247712f42c11d4d2cd69315c82879766ae4393b1864ee47d412f947d42acfb1871ae08f3d7ef2fc5a6ae409f3125f648e7275219be409837922cfa789491d30d3c8f2fc91064a9ea69f3c5f06039b3b234c2c4f989e3c615879c2b4f2645922cfef6252a7cbf35954526725cf1f5956799accc8dc4bd12493286ebe4908529ca9998890b99a9a07f24c1754f945e6a2496682756aa666ea42a666e6d84293cc45926ba6d62912ac67e690295217f2c4e5da43efac842f4dd4d43a359f7b1394e77e079ef971144772b93803e42858a766ce90a42e48ae5c4df022c22fb299d9eaced4a40e29734fa37a1a99d4f132f734506a5c52c725738f9a499dfbdc6892cdd45040d9b40226ac3e713fa2ced8f123ea2773636565d34c8dd54b9856509fab3fd2a832575fe5d630e6becc1387faa3c79d0dee878f881e89cd5fa895395a1e852fb33e712f50240ef71f3e82e4e61733240ef72f65c817b8779067862fb29717264c32ae63756ab402991ac1a08b238f5f2b73ef79f87b107b3ff2e77ee4ee53a4ba1d18aaddecc2597b4231a9e33df7dd1332f5b5ba1ea9f33df752a63e2ae489fbb12ee9195d89ed913aa1efc9dc7b21dcfdd7ea5455223f2ae492dccfb592dc3fced446d217dd290b99fb7154cb5c0f3232f7e34c2d731fc23d6412e7c8cca389f485492671b86f2f3cd5240ef762ea3a72e88fcc1799d499cf79217d499cfe0ebb4ae2f4874299e36cc8a32671b8174d7147932c733fbec832379a643104655963444dd2f58c4f171b05e5ede5cc0766cf3f0e8bb2ec14f73d872f75da934aca8946d99b20157ed889af0d2eb6fff63fb8487f7b204027d706a9b3236f9fc30e2efa38899470c71f79fb51c3c6717f3be53e32f7392efa73ffc3c520a9c323735d2c6f5ce6b6df5486ace14568439fb651ca46416d9cb2e492b8f39d071f28809ee684ea2bd3ea6aad482629d1836f4f2b32050079eaffc2da3af512797e3f0098e4f9ed1aad741488ab17d695c4b1f4b7d04f50080d617f8bebd3fafa89c4f30dd3075ffc6052f71dd95ed329bcf9de9c53ca39e79c9544676ea154fe58c3167706774c9243ff5c9ddea250686170b9b06758a564dafd9c117f45e913fdd1a71aec13eef8233771c71ff4c71a06e913fd1f3d77687efade8449fa2f39b8f5c71f5674df853fe88f121ad7860d0eb9594a9c233457557d72fb6be8a966624408d9664896fd2f37da9e2d22c27305c14c463293bd9668e635c592e3aeea22a1f2a25dabffaa2e123d72fbe601d474bbd967aa0ae469d2ab4493382f64bcc0e47bd792a16826717c884ae2c89f81cdec40a646aed115f2e43fce78917900491dee65545e2f30fa23573f31baa209fdc29f5079591ea31a6497d9814a062671fc05f6cace853c80248e7f098efbcace85b1ec3d5d2b7b8beacc35b412c7e98b177df297d80bac4fd605b09958080bdea827cb9fb12c6d96b0ecfd944e2422903172328d32f9656a9d7524e373d63ae79c331ce9b71bf1978ca94f32b2eba431f0bcf94311797e464e794e79afcbf99d67383620db29d0b9a9ae92bba9362577536d71c7cf7eb58e5bb5b8d589bb4bfa7d4478280823a52ac50e2e3c2ae3a8af51f3fb94bd53b21480ecd37f66af1527cbdf9eb8e3977d7c2ddad4487221cbaf4feef865db29549675cacda9ab8734cf10f7568b0ea9151cb26d3d3d1b3884cbfede68bbe28ef4f5a2d1b2f41eefe958c78282aeb8f3e50d361331eba81b6767163216c91e6e7078d234caf0cab6d272be296ee83de97236157593d44e924de9a45ed3393b28694c28354877b36c3f8dbc7ddd41e993ddb6b95551cc0d5ba6df998663037227eb93f58be54e63b9c3d910ebd26f1c335fe5b7bf38668656bcb7edc0a60d9b688eb272e762b9e355d6adf7eddbb45c5479fb362e17ebdbb779b9b83dcdf66d96903a1f135227f4159b7e7a06fb3b68d9fe6632cda2b8a3cd6a34cdb21d6960a4a076e28e362b1a18e8c3f62a2f411feadfd066e5286bd3e3e48ea420abc5ed999f0af2cc7c66dc71c635e39a79499defedcfd440ea84defe0cccc52ed6c9b29d715d599ed9d8b79934e6286bb302a1b8a093cb729106e628fb9eeddbf4d0c0469b5738dab8b2a536515cef6b933bbeb4e6cc0b66aa18fd08fbc80d791a49193d01bad1e1114de2d810a4491cebe48e1dad47e2d8f78e10831ad97e0c3f2fb85428e691fbfa8f333ffe232908ac4d2e11b38edc7d55919e2053a6190948ea746f5fca948908f28d6c7fe6678a6c9fc4923af449413b9e90edef00923aa3c722d3ac77602242e745b66f3ff404bb03510743ed20db1f677ef269896c7f24059d5612a7473fd2c07864fa16962dccc16cdf8649a7444f69604f03ebd4c4dc09aee7d1665503c0235b2b6ebfcd6a026925a34d4fb63fc1111037bad0b2606d72e78f2fad21332d8963df8d6c7fe47146b6cf632675466fb7c8a3d7e005d9be4c4beaf8834366320d81b27def7321db0f0160ec68d97e17b3f6de2ef6f198491dfaf6675a96d6208f2fad6cdf41213c320d51308963bf04c7a5810de1914721cd5fd93ec5638eed937d1095ed7ba10f74725d60b9d88f823cd2c0b2fd2333dbaca44e673b7fa4f941f712fc422284ccdc852789635f888fec8556dc777b436bc3a4cbe2daf4f4c97e17daacfa74caf6ad0b6eff68b3caf66578d9e63187274d238b2ad3ca64cea67db556266aad3b4aa7365a69e158dfc894d61f2679fcc1448a550ca986144b8efa913a5ea6358d4ce9b829c9348e4ceb1332ad6ec8a468bd3c5631321d2d0dee587fe853bf354a13b0095aa7b6b0d27efa447faa4ae254da8f4e8d96fe4b139652982eee587f32ed28b4b64fbfbed129eee9d7a04ed9a731f6659ed2a94dc5a4535b8864669e9e4e859efed6647bd2a9980e6f087f981ed942cba2dab656f6f76c002208b44993d9301b8d2725df7a589da27f5aa9723b19fec31a9407f36910306a1b3f7875f3667794b42935bbd168342080a0d16840d068341b4ca136ece0a8c9591fd8d01adb924e758aa66e9f7eb0610d59e7843b4a5acd459aec445b8b65069ef56c0aaeff487b8e53ba4b96f7c211c050cd1e9f39e6c8a7930f579e9ff303065a54a1c9d02909061656619cbae583e9cdb030cba38c9267a53e6ff2fcf93713c8ccf33fd304e24fca32a71f799ef20442f6a63071e78ea858b8db16fa09fd0401e901c26242c38a090dab5ab78dabb5d64a43cf941b0f2a133d652f019934936ddb6809ec79816c2a7ffb3a1c8d94a078dbe6df1bd9dfdd81a0797bffb1c16bc81e9321a7f3f62799529f84ccbcbde73c5bdec26de33e26dfc7c45379d2d485b697af8267c9c9a55de8d62a2ce108ac24688156ba240d20cb71148b980eac08c309b5c331440620a50ed94e284cb2d34e2eed938f770b85508721c167a788ee8de829c22863270bff243b5e087758823cdcd7df42388648e8bd1822a10e77618c1716f1497692ec04f18d8e3c773a23a53c9fc3444c909334d94eee464323a58a6da6d8660f87609f241125e764194b028b3cafa0ea3e0aaad4ef401dbc0c765d90ee441fc429fd98b8e10bc799bfd1fe7d8a3b2c527951e82df8743261411cba0c8693097008f8dc7b221107f2884425f9e3055f24ca4184670671f7417cfc7233b17456bae44e26139cbfade1c5f4cbfb7d5ddcfe29d2e08a19f33dfcdc867e823e742fa92cffd0a81eedf859f4de86a38fefb97034e551a6f1351c65284b02d1c050e6a3ac71aebcd0479e79477c38955a3ed01f47f5c362a8cb51fda290b21cd5edf9207d071188ada3c0ffc050c610193d9864e77bf0c1b008f047a105898cfe0b8bf87e14523c5258eea7aedcfe236565ef25c8c3dc11852747491cc451f241fa791bab556355e6610a84658e62b9e8d6de5b2afd8fa73c5296abdf81727f2771c719a31e7343fdf9358c21e51014ee6b410779bc79a4b22cf32395e5eedfb8245c8357f0a469bc76f44b6ecfc0bd12bf237b06fb8db2bf7d7dd3f7131489c00f4b6cb1535a29ad7486c26f846da3b89f967b6b6d18137a991de409853f407a833bbf659f4e7d9a96e3b8101e891822776f432fb950380ec161fb121462c350d29076ca86b64f1cf591734ca606db4241c7a7ef2f5b5c77bc99d4a9af34bbd429527bd8031f59fa348145be6bdc64e9c34494ec9941a90b59fa3471c4ea8b69843acb38f938238f3f4e906779943327a4c8a3fcc9eeee8409b23fa9e49fe3e21113bca4c0ca011a6cdc60c7df0617239082237ed43843a684133b7ecad287491b7947963e4ccac839745e2fc2f52c7d563ea0e376963e2b2fa6d085d32d4b9f150e7a8c1af470050f1f0f324041162ba8c1b105255e662c4096410713b420852bb0a8c8c110ca5840cd18583c5132c612516400850a3e435801122a2b684258000c527a8049c28b2862e08410542046108a38c10f8250042220e18c1a4c325e70630c2678d14411980003190fdbca150324e0a019a16702410211790219ad21a81184296c3006106cd040055020414610a21023890eac30e30750a86009256810c6023220041390718413ab2642f079c1620d348410052762c0b133c1f864eee1b37467cebfacad278b071b3eab9e52c8c98df15c45d9ffcd2185ee0558a64ffe35fb9b68d9264b7182d1aafde4b106f7eaead4288385cb746a3ee9c49de0f37cdf7ed02d3d59bc49d47b566ea5758707c59d4fab94acb16bb9ab6c97b36f7421023d12ccea8b8afaa2b44facfc7da1ce6179ebf0f8c3942557fa6ca7a8d7853c28ec8872775339b5c4b9e36759a5d4912d7126fd66eed6514efaac94b8f6386ae5b5c80f483ecb463b561e2b2bcbd9f289dc90527a0b0b696587ca1d8940171758a1cf0ddbdce63571e7bb7cd9274a43ead4bae1eeb465caa93fe1ceffa6a5d937ee7c2a4396db6ad7dd169ebbd75addbdd6cad55a7d78a21bea3e914b6749239595972aabaffaaab472d1e20d43e545eef7a9a24dd5e6a3865a5caccbd7cd714b2f94042f30b556558ee7f47f215a1bf1c1e4c4c061e1c8a1aa0ee4716f0dcfa50433e3305fd5e2f2a8b45f9dd2c29d1e8f49a76ad24c958b958b575ebd5edd1cf2b56305ddccdd29a5ee4e2975774a69ccdd29a59d07ba7460cbc7327aa9c194db64727a6ab1de1f393236e469dbb61da55927e852b29c833cfe52b9e913e6b39df22ae998446546f562266846a8266332b27483803c5e2d6dc3965e661c6626e6ab5a5ca777dbb690cae8b833c6f278d0d059e7cc273756a52c172b14595759141c62943502795c1693b16818aad928c87cf6627872ceeeee396bb743d9b3d6ee6debeeee70acefb56728b7d94a78cd79558b3b6a014517a6cbc106d97d1995e40eb9d2a34c83488732ad3fb4586b341e7aa7d6da38409021586260622c37e594f9787cb65394d6f0a34f49f098f96ca76af5683ea9e2bfb97753ee9cf9ea1697460a9c1486a03c5494841819eca47b79e099af6a71696e4ffc81496add16eea4afffea2a37e8b35a28e08f861ffd1f3f71ca1cd55ff3c909ce2973b14e196bad86842338fd0bf2d055aeb59a6c267bd8b9248e8542ad734f15f3036f4e6f230b734ef972b27127b779fbecadaadcb0726502191a2688d1276e294b1f13b87c8bdb92a58f09a020021db12b0a721b20812a51020c7fe292b2f451420b874209295aca65c9d24789237c0a17b4024de2824040499c01fba296c41667dc952c7d927832e5de2c7d9260a2856bb3f44962c9152e98a5cf122c0ce1eec8d2670913d258e246d36e284b9f253f4b6648d0aa0b48739372c3db5390a752f74a9dca2afddff4e1f9e1da12f2c297465d39aab990b23cac3d4a108d46e4ee6fa573829ca7fb1cb1461119f547714c91fbbf375a546939c8fa803a4555644d624c60e092d794dc2aae4f0e9599d7ae92bd0173a9cc1a521e59a5e562a7d151545a8a4abfa1d272a8f414151af6acdf674b202179729a3de47e3ab9f529388447f6f7a64ce2d40771f023486c6e89b37d689b1267db8c08cd6e910da5c4d9421edab184d0e490575571e45a9fbea48e7f5599e55abfd36871e42aa94347b2293139606fbca48c3a4aae1d6b0771e45e62665712a77fc33239602e0f43308e471eb55ce4a234aa5f8aeb8d971cb0dcdc9458ee25b2dc75d5b158f216723f69509793ea38ed3993905a2425ecb55c6d0179fa8b24568ec03206931db417090d26548c505b899282cb46d00e3aa630a201a9d031071322d94d8209481b3df1c417c40d110c4ee00551020b7c35d125a19504d777bb6022a406cd13c3097b84568786135c9457a88d136c6bc0ac1492a848e0c0a8830a2c0ab4310185075923a83e597590365ab48a3ad558a20693bb45135ab0d1c3c66833123fb666e973441b3c9650ea53a54d5c17597b7169b2f43962066dc6fd2c7d8e58820677260a3db82f683815aeca17de73391e5028ae0b151dc71d65e9a3a4499e8fc6a559fa28e9318092958fca077547a659faa87890c7fb60ccfe48a5b6b4d66de3381baa58f0bc68aeaecef33e4b3f101459fac97c258ee89b78fc7846e0109aede8daab32e70c3d951d20cf0eb0bb5b042eb191536e13e9595a5a660b69f2b8b0b8b8b8905676b8b8a85c171797918b087471f9bc2e6439971ede14de0b10eee749d348a3caf4b797ad2fcb31ee38fa19fd746a46a1b9e83dfd11d0e88d51d0480ed0c9ed989027fa54764e644a69ff480d298e5812f5237558321db96005521cc9a8c83f51faf4e48e23d9cf08ca68d6a951ac4ff4797878d47214fd0e8fb0c0a3d7888b116ce4459fe88f5c7da2cf1a3de9131dc94650fa447f341bc94031ee38928d642359a6aa6d7eccb6d51ffd8ca27091e98f689d0233fdbbba4d5a9c5b04d11f49a1a38a4c47ac4c7f1cc951cb746621893c5e55a69749a623a04c7fab73c4ead4386a9269ab53e348261b35e9d45855a3279d9a5fc4f238aa22013e764f64fa4d271dfd64fa1e10ae912ed6c572cb1c661cb5519b5c0946167a32e5d154956954a11974ad391b1ce279dd170a755f37b3cc22d5ed747adb2ccf91ee45aaeb59da0ed31027655d856012677e098e3b43fa9238dcd755e6beaebad686829e73ce399ff4a96bab4f5d597dea1f65afbf0eeb8f0bae37290acdc5ea4585c958b24e4d2831797219052c2a4f81274de30b2d778c562cfa545f7dea9fc95ff6e8e718cc5eed3a65a5951355579ffa47d9a39fb5e29ee048e7b1834d20b36a91fb29c51d6ce22e063ab91d4ceaace4fece8b4ed1af501ad52feb535756eecaead49316af7498201da46d1eab2bf757978b313b6cbf8545cc9d1ac67c921d77c1fd3c765f963e539ac8341c3b596e2e775ef4a9832db92fb4281e0862350bd74817930df0a4698c212873de7472fbfbe5e0101ed9fe7b1ea67d92b256f99efc5854d90555f6ea37738847a4ba76e5d5d4fa5433a54fdc8b54979a642632a4f82233d54e7164ee09997b931b2ad97446e6fec50c7b84db46c9093f85cc852f58c8dc836b5c95dff12abfe3612c89e2de7af545e626562ee5f105e6a269658265ee54933af647b5af8c2bfb344dab13f73b54f05cad3ac5a4b91e5aaeb5d67461bc4aa53a6267ec646337cb55a5d684409e4a220516dbb8244e7b0e8d8ac6956f0f88577a42524ce2f477b40ea80bea6ab89bd2a7fee956a3a051908b236bef1dcd728f82dee090b8dd8fa35927e6fe163cd2c8723f0b26e1d15746171f993bf0e84a5444787425796461b1b0aa123cdace322e192cc038ae0c177d02011e42c65107145a411a7472c7d015aa6511c6d5a88671e5fe108b4e792662080f08d1012345460e04b1010d64000317b0400580a0c004241001083cc0013f34c007061059400f3ceca083021290030e08b8c1862142780e60809d9a1ca4000418400d407468f821a66690210601c090f3420070c2c73e00e002abe57ac17ac45c3cf2fd3d649d1a7d7fe8923a3e0acafd52021905c917faed7b37d8f43698e64ff8e67b609b77019f1e857bbc0fecc20300a31e6300fc631fef58948fe025ef3d9ed9f1e6f7f8dbf1fa7b0cee5c9608df2658b4737b1e8f769c060b9a5748e3a2710d81977ce0911842a552a97640f0446024ef014cc477007be085c0437c11dc81378285780ee0223f6223bf01cc810f028f9f01bc81d7000ee22f8033f018c01af80ae00bbc0530069e02b8020f04b6c04b0053e0278081780860097c04f004de011802ff001c816f0076c0ff801ff00cc00d781ff00fbf00cc8027827d781ef0027e069bbe074ce475c03cfc0eb8874f00d6e1158077781c70023e07ac80bf01e3f008c039fc107cc3db8011f03c78c80bc136bc0130cf1fc1347f002ce46bb0017e071fe083e09acf78e70980837c0170fe1a30017e00b800af836b78207800ff03eb3c0d18c8a7f08f17310d2f034efd0c587c0160193e063cc3e760013c0c38860f00cef917300c1fe2003c0e7ee1310eff31ce3bfe32cc943ef51886ae4e8d34aedc312a981a14770c5d234ccdc599efa779b988bf9f0646134382efcb51fd1fc017d633dc178d8bc6458345e8729188ef0f5f2e0ef1fd21cc450f7c7f18735188ef0f652e76e0fbc3998b46be3ffc71b1c8f7873417c7ef0f815ce4c0f787412e06f1fd61cdc50d7c7f8dca450d7c7fcdcac50c7c7f4d8f8b18f8fe1a968b17f8fe9a968b16f8fe1a978b15f8fe9a978b407c7f0dcc450a7c7f4dccc5097c7f8dcc45097c7fcdccc5087c7fcd8f8b10f8fe1a5a0d504d504dcda432ad4c3d2696a96572995e26982966929966a61f13cd04640a32d56c542e0ab1e9b161d9b46ac22548cc3a76b2005f09bb53f3fd362f1b984dcc466633b3b1a1d900d904d9d46e5437ab9b9e9b9bd68debe67503bb89ddc86e66373f2e86e1922ce82b6177c2efbfa1b9e8e3fb6f805c04c0f7df04b9e8c2f7dfd45c447d7f0f958ba7efefb172b1c7f7f7e871f1e6fb7bb05cb4f9fe1e2d174ddfdfc3e522cdb7cfbcbbe3f77f1f8263fc673ec90e0bcb3111989f098b903e6eac206807c6b3bf07622b8e3c11387485af1016c64259380b7f425a08140685b51a55cdaaa6a78655d3aa71d5bc6a6035b11a59cd0c0235b41aa09aa09a9a6ad5c36ab95eb0986cf643030aaad9a86c56363d362c9b96a36c5e36309b988dcc6666f36343b301b209b2a9dda86e56373d37ac9bd68debe67503bb89ddc86e6637b41ba09ba09b5a0f558f558f9e1eac1ead30f452c6d0fd8d1a72867e1abc04028f8411aa1d9aafc12bbb7324b47195e0b863fd1902e7fb2b908b01f8fe1ae4e20bdf39df307cffb6725100dfbff5b818c3f76f2c1765f8feade5e20cdfbfb95c4c7dfff67251fcfef1fd5bcc451abe7f93b9a8f3fddbcc4520dfbffdb858c3f76f341707f0fd1b908b04f8fe2dc8c5027cff567331c8f7732a17f3f7732b1777be9feb71d100dfcfb15c3cc0f7732d1779be9f73b928e4fbb9978b43be9f83b968c3f77331176ff87e4ee62202be9f9bb988c3f7733f2ee6f0fd1ccdc5047c3f07e4a202be75f87eaee6e20edf6f552ef2f0fd76e5620fdf6f7b5c5cc0f75b968b44bedfb65c64c0f75b978b3e7cbf7db9d880efb730177ff87e1b73d101df6f652e3ee0fbedcc451b1b964d8fcdca4665aa99824c40269ae9c73433c94c3113ccf432b94c2d13cbd4635a995435b59aa01aa01a5acd8fa36a6635b29a584dcdabc655d3aa61d5f4d4ac6a546118140285b4f0279c85b2301686afb0040502b8c4923010815986c02c1ec02c4260960e60162398a5086619310b07304b10986503984503982503980503b8e502b8c502b8a502b80508dc4201dc3201dc2201dc1201dc0201dcf200dce200dcf2036e69006ef101b73000b710c12e0bc02e3d60171eb0cb0ed84507ece2520076792500bbc072c02e311cb08b0c01d865760376f9b101bbd08660172021d8258807bbd40e804b2a03e0d26a07977a405c62499cfe8c4bad20b8e42a002ebd08804bb001e052ac065c9201c1251d5ca201977ee092884b295c9a01bfc8805f62c02f02c02f30e0971cfcf2027e7939aa3f00f80507bff8c02f3347f50300bfb8805f688eea47e197137e0972547f0ffc527354ff0d86b1c130260cd3e3a87e1a0c53e3bd94317c5f9a42ced01f621dc818468a83fc42869ca15f6670c5b8c61cd5ffb8ca706561955830965c90290ef218baa80e6ce81a7b40197b782cb8a38c4b860b19988b3cbedfe3a24f0de390b89e471997dc99a0e339bd108b0be6fb4ba6c7d80b7d216eb5ad42524c018a5acf9d99c13d5e8eaa747525ed2a5c7d72fca3f519fcf7ce5c459f3c6461f589e5c9063e20e661c21822303ff3336111330a25ca70edc07c921d8f6b723dd34ab3eb79ac63e8eaf18221d2edc8dcfc481cefc96561b9f84ff3a39d6161b1b072ffed71f1c390c6da993074f5e47e4e892bf318ba441d0f0c83e58e0c8ec1aa6e278439aa4357eeec3058eebc60b9d32d711b06092471e90600c193a6d13ad00442c30a9b2ff8fb3b14a4ce0c2b0f248e5b559e2a598eb57705448fc52b17278d2669b452e95ebfc21d6790ab835cb4ef403dfe63d72a2cfb5b2e88cab8a02dc8454ee528ffdf2a4c968fd03c7241aeec52dc0a9b40b838e40b3c903a5c15248e07896c7047aec66db56dabd570fc531eb75af61f372a489d3c87143f890aaa824c6141a6e8079190c82ec57d177d67fb200d461e4d2edc3b961682cd5a1d2915c2fce63871cc0d54a5aa374c952acff71ba615ae0e6ebf4889db3f9af2fcd01296640fa2b6d3b5ec4f663bb78538078774a8d622b44fd2da234276e3bceb426df856f107c4f5e6b1dc5e6d102e762f5bfe102e5e59cb52faec9951cc26f3857eee2b388487dee9dee3aa1477fb181c68911b16c94d933aa1ef3f32a78c35594d9b406618f385fe0e23f737c1bde3755f102efa4eac2573cd5efd336169e49ef5094a9f6412a77f8631814c32e40bfd2d0489d33fce3172bf479bb6c80a6fc70b8b3062a70bfbe52836ee4440920c82524652ca95085947aea194381ee3562317c28afa44781d53b21129255be123451559fa38b1fd5f4ff087f98056edc850455ffa30ebd8a9a18a86f4e70e2d811152ca0efdf9345449293bd38729a5e47985285e4fc0f24b963e4fccb24f14ad2c7d9c54917d9a84916de894f491a227d3cfa1532a99be37aa6f85cadf082b6276908e9299c8edd0be8dd9a1bf07b9d3a174940f1e961cb5bd0d6376d83ea607b9b385456441647b6b3fc687b9637feed8b0882c7a903b4b4a900511fbfd25f02f810d4fbf3d185cf803668c2b77fc3b8607fff93eecb0c43d4a149aa8bafd0639395f589bc3bd14c2948bf87ffd464c9ec5168ccbbdcc5db30e219879864298f21616a15f432134ec26bc6f8bcb7dcb2ec76d61911a16e97032f1fc816c59fe6902f954a59d49411f2ce8036ad62f65a71f73c3f6fd1dc694fcc7d2ad7476cc61e075ee9edcc903f7db4bb087d0db1258174bc07d08c710b11f7afba190c33144b60ffdf6a110b62187b7d09a6a58e4ce9e4d50e18d2aa4313af2a9f2f63d7b1e4ce38e54760536726cca7e2a73f1adf552e93ff383c15c0eb17414c6accce517d2b760960c0323c625fdca97deab204f89f41ba944927d0ad2f6c73072e84bd8631e469ffa49d8652d78eba1e2ae7cf72d9894372aaef72d78256f54dcef5bf08e580b56c91b1557f42df8ca6fc1a3bc5171ef6f54dc162cca1b1577be0d91de6652387e2093be0583998514ca9e6d20cf0e7f39851c49eb898d33a85b3dcba3c73e3bba119fbd051729707f8fd1b4ca0b5e23084d71ebf49fd8c8d69acd80badd5e74503cd690290ca8951f71264d9a2738bf7c49f9574295b0863cf3dfbff76f38d2b73297649f3cdcd59f747c315283ca2a0c2aa87b6cd4940ceb9ea467912a7e32f2497496643c5a45342485525cee4c3bd5e0947b8486bc2c3b9fd3279538f3edcd1f8944edb574fb6c4926876448dc9cb37a208fe7f0d1a74d43a2981b32b551d854d95f4e29715ace5aa7a80cf2f044a5b8a337e91e89d35d7354eb4073ab6a79a42b1e7ca78634c8513509776cd52af7b7aa534b5a7c952ae88da020cc1e1f205e0a2a243508af1a94570dca4b8c076dfef6db7be1f785de77dd187766effba58767a63bbaae7b89e5ed8b1df39ba11fb72f64f20cbf2089a3bae34a2b28afb4a4ce9ca12f28f7afb478d0bc598dd04173c9fb3d65cfc9fe63cbf50777e65aa92867ccf9bc90e556a226dc71ce96c83097746a1b6d5dd775dd297739b9fb91bbaeeb9f4b4854ff173f724efd8239c57ce2a7a80977e6a294722667a5d968141402c21657669bb76f8b2b4417cb45ead370ec62b93e0723c6ed62f98c1bb23935b41fc43f14b3a1dd420987aa543af990e131f0d643deb9d3df72825092995d98d3a920a4942333cb80814e712519b95d59a59d1c90a8fea9240b311947eef769738260c21d67cfec716bef2d957a3e2bbc93f442d993bb42eb6538cd5944dededb32edb621eebd0e674f9fbc54b2e1cc15e764c7e36c72809c9c7e538b970bc7d2f7a4ad6c836c32b1416091bb8adc4079d5a73a6eb76d1be37cf4ec42cf0b47235d2c84bbae2727670ed2928642a15145c9a7c515627be522968e3b7633a923937b7b0d8121cfee074a6acdc9338c89491c32ee781313cb37aadcdd6b666362b99f0b3f1faf5a05fff12327e774b2d45a504a1cba85a31123b9823adc398bd0f7a73e4c40c9a365228c92ccb8fda02107861195479c27c771dce44690b71641dee868251d9e348d93e55b4497b1c4824b58b60b6ec1b2c72479a43f4d32e57db732bb150f9b78b858ae41b2d9aa9d72dd3623f21c93d8cd6edcd685a3117296ab94c92f688021d71f51a75ff9d183efadbce4faa34aae3f8672fd29c5d2d797a470a4c9dcaf84230d4bcbef08c7eb520a5d422951371c85a36d09a5448942306409a5447d21478411d91231b3b59c8f3672ca9486c8b8f32995b31ddd99604e2654c6689db4d639e7cbc8b0d427eb61e9332571c71f3f3c9cdf24cdc6a53ec99733bac69432ab485a4ade7c0b47239f7f9d4c6c938929a549e6f0cb584751d3a7c41d652cc86c7b9a9489146fa3e45329d9f15706fde9d9cf9940426f7ff426348f484a506a08471904308184dc4301705f737c0ac09b74ca2dfe2183833c5d439f96dc1ddcda7ba5481b2543a66fe994610a60029999520faa419325190059fa4051cb4dcb95fb8aa49964f9f4e548c78f0bc7b9813874996ecfd18f898f49a7e873f3c96cf5a97f5681c41da70c36651336e74f97ff24f549365db52877b2df3e959af62486d328937d3465f746eeeb83d824c2329e7f3844bf6e8242b64a5fa034818bdcdfb653601b31937ced4da0947e60874cc54ecae7dea5fcedfdadb5361ceb7321adf5b770bcd9f60ddae7dcb66ddbe69cb252296715e6e62de734f22d51cb9bcf3a67fdf9d2b271b7b7b3ce6964d696503ae794b2d6496f9e35e5954eeab3c3f0af55764b299174ee69a594544a2929a5524a39463592e94b3c92aebf2465ea5bad5b2565ea50f0a8ac63adbed577778e1af9720d8550b9dfbe7e11eaeed56bad95cabaf16c4868a6a157c1737a49feb2535f3ee1206379fec0c7057278234a29fdec4f5dbcb0d395a4256952489a9c73ce39cdf0a47cd9547abb682cd22a6fcea64eea4629a5b429a5948e9cdc8f524ae9f755e95ec1c293ed4929479e41c1c245577489145acc0b7fe2ac9a1c69cc5e5834935e01490923365bf3c9945a963f32e4cc9f210d23cb589fe4cf39922147e288a670c79c1b6c4453b8f22b386486943a756f6ed29ba37986a3119906f54905c8f3688b3e9952fb49838b97f738933780646154d1ad564d89f203e36236c9b327c8888462439de3ca3e99bc392e9d72ba68fe0cb9198cbc9194413bad9b7b16dcdd662114eadcfb4077771f8944a3da94d27577f7d1ca9c73ce397bce5e2191585826cb0a69c4d2c2d2d2d2425ad9d1d2a2725b5a5a462d22b0a5a5e52b8277e76c90a7766738d22659bebbcb6f3aeee82c27b56e74b3f46b5daed271adb59f75959c95e5573aee68ab1477fe07f248893383f205b76d7be5ede7f6d5c91dc98c7e8ec02132f95e15956dfbca71dbd36d65c78aca5d595959597919b7579661bf91ed6557ae901efd4a190975728d7c13e4a9d9c3af2ae1ee7d856c8686c463177b8386861c51cac69d53d22d92e0495452c71f468c5b59669d61cbf768cf4f963e5030c93064e98302206498db9238fe20edb6926e36b71f3b25a399c4f11fab92914ae2742529d73e6916c4ed6d655a83d119b3acb3fda8ea1ad229672cb445e74f39e794b37af56aadd5370f19b1caf2eb9c73ceb03ef7d2525ae9104844d029fbf28b98aa16bb97b7c3481ad5412eed104622823e3504ee2d62081120e953bf6809db350aa2f418acf0a3850ca0308213171ab535bc287924b1914719931358d83772ff3d23b7cf09b2c83e2868229f3c059e94128693d2a5941ef6a94f934a2929363971e587a2b8f2bf77c9bde4a494748ee1d94eadcc1dade2978eaa6803b9cf7aa1ae0b79f6e3c04d5447f4ba4aef98332489c624b9f20064e2ca2929a5a31d2d9074ca2aca1d4a8933a740bf99db255cff4ae96d77f749a54b770f05def6b3f6e43a64e60d4ba5d7202a2975ce0c4b29ed597fd65984b9d95a6bad9f1541d360ab75be9c6fe753fbdc9c2f79b839b939bb7e91ba71a1f4e60475a040ae034f8eda08859ee32aadf2762af4b3561087ed436f47b76f411e4b2d07853b71f0e7be8237d46dab75ab35fcfa04053fc329f597eebffd7cce39aeba83377848792aadb2abe049d308c32cb727414adfddbb14dcd0b7a853200e524adec222dfcbeccd482ca88009337fe138f327e4f4823b86ae1eae2be4a97f44e3b2b7e7e647ea802c2c9b1c0f73efd87b1a572bc957b4abb277f5c306c10fd2aaece02b7b38d20f7d10f76cc3b12aa95de822415036527b8af8cf6cc5cbcf0029c306b129050fad58fdcecb87de7bc1d5d69f2e8aeb33c74f1e43184d862e71e6dbbf4ac9fd398df2f1e3bbc79ea75c55509f5a0ef7db438a396e2fb258420f4de9af478397d0b8bc47434353c2342f174c83050d8d8b068f767266725abe5b7eb4b996591ea626e39279d1c86464649e867edb9c2722b860f68d72084791050a5434ae9c1f49dc91859593673e0cc3e894f7fdf461585207fca6429e605a30ae1799d4f1177d892575eccbb83cd28f30b5fa23c30243054c6bb4f2238c55d9f1234c2df707a233a8c4ccd4a6454c2aa5660000000008000315000028140e8ac56291589667d2de0714800b7ea44c6e4e1acab22487711cc418648c31861060882104194043531a81007177226b3e4c1122c786bbbb0bfffe329b9b5725f86d4a61e0b675e1b6006e4ea3e39d20d2618913217dc84be756c5ef1020ee77820830c309efa205f52ec9b85aeeec3b19e78ac72540cefe04a5cff25976e6422b2b8adca413d966ef098b9b3f02c05bb2ffb95a4f0778eadcf4818001cbdcd22bf7721b24f3ccb3d98bd10c4d4ac0fe0baaeb0de19bd48c3e13ab2e5da9a9215a34232a5407cfce883b6f42a3811c1ee26f2e7582e425b99c66127696ccc10c082e5b94ec797c0ba10e4d4b2871c1a36bca492d1db9a0e5a816732a88d606728a76bb170d641629138083350be6f0782a762dbb95e331e37fb72090472f2a3ce0adb8eb456d78187f82bf5eb6ebfe2729786af2801b7fb22cd8893111ac736cc909904224eb3624366eb0263b291f47fc74b9cbc4fe98b76e2fdf1c4efeba471ecbb7d313d8509a654134f57d53e5f11d3c86aaeb61a87e93b95430d313af5035b6712b959fabbb32c75a0b584bb1402ea5a412508b7d5a25fd754046be2a3d065a980438416af6c0001c47106b49b04b4c759b886ca4645cba9283027c3150a936d1613aabd8de04db4680b9747da939689c6b96278b8cc3a04f7bd3cde554df1c1a8090a756129cbd895378c6be2b1617b760e9f65d8ad9ad222f1be4d505facc97fbea44e31d41c5ed9e1d7675ef4703e347021dc1f0fdc1a8728de00f7f87aa2d9408349eac5c54e5a42facb7b0820577998d353c05af30b5851526bb8e38fb9aca040c5ffae7d02dc0aa30d47843f1f1bc7a84f882cf29d30771caaf8ac6af3f19d2b419e4b118eb796f377f90180580748fa61320fb37a2c3d01bf4ec41201c8cbcfdabaaaf673abaa8547d7046238459b51747a97180869ffc72524a6102c1808baf30a1cb0abf8419f99cc161615bc9f5391e11019347022707385a21eccd386753980b8d4744931a5259955177705c4743da4afe65c9ce671a6043cc8d494d6142887f2e9da272253df0c1400a147633370be1da1136106798879e39325f337729d32fba3cc2a5fecd0414f61618cd2cc89a45dc7ef6c07d5ff4ba4406e1197e59f440a0b203755a51a3cc4aad4a2b4d49da3fee403d34e17b666730b62f4d9ab8f88bd1a0a5ea0dce9200bbae4488a56cb7b5318503bc9761fc6c9e76174185f98a13b2ee7e7669d441f64920c4d1a1227560e2ad57759c9a7b0e4f7a453be7f94c0c13b36434fa52e311186cbdb19af307a20f96e4bdb11c1b301d86fac7844475403ef98b347513c08acfc38ab4d2317c0f57a24b3eca814978f5e8c8eeffa76e04991b941571b8693a4f5c92580c42de44f82c661c3e2ac5de8143e158a667a18f6508c1bca489fd1e47184b53dc7b01d35b0dc3c70a94cc3c518767b6cddf9b406e00c5b14e1c962482c92b888ade94e3c2bc759c997b7231d61b781259b0d4e50cdc84ce02a2c21cb200b97ed0a41800c14a57f44a3dc568dfa7439204dba40e1a12e305bef40dfaa2fa43241deda4762d85cfe3c9b1d94b1784cf8e1c8ccce333091e50db866a9c7d3d7d02d5e1e9e59cdc4e6ff67fdc5f367017083c01cfada28b9d3779b65937e7a016a7df1b447ca2ee609a0474d104e32fc090335b8cb70894a69a9b1bf266fecd73129b6b97bc625ec46e6ca7fa116681a07d50e86e6ad0c3045b6cd3126232e6b0e46be726595c5fb585cfff2340285dda1394e87d63403a1df3090693217750cb671a5b5a20b50e7e05c6492f4d0fe193bc826c5d3272405f734090fb900366d34ea3c24ce54b03c9d1859b20c6aa500aceb891bb90051255457f86fae054688712c2ff2b852c026d53392417a213e67b2fa3e691bc455d48715b47f9f0f67e0e007506f6dd1ee810d2b7163f9970160e0527468d3a9e0f53312e6745f85f105b400f2347df2329c52a4c2f9a4011c93abd250027c61c227cc955888a19fc08c60ad81028e997eb1b9823f6df63462e5b93c50a23d30b3e09cd3fbdcab1c34002d230801b319a291dbe230554143e813f789d633a62217fa16664f8b4bbb147506ad78dc8496771573f421f3a931008b05f32790c1c520121aec842e07f4d747a6f9e361f8ddf91ee836a1713b1dcb706c68aee0323d90eae9041afb69436836b0342fdf60f3954b0cedf5ed75c1351e9f6d84aaf9071338fefb30676284ca9d9f5b158ef06b2dac7865bbceac5421887a4d2af3dfcdcca00fcef314de63264a0f8d65928f12dd15086e31647b079c4ab1f9fd4b0c3e17069d2ec3da754390342f1a4c97d32b14e41c8f48829fc81e613b05119e120b835ee15bca61c5b7b35242faf1d0787a176ac96cd506c4803cc37944bf33d520800d1a577866cb74d0deaac64d18978d49b92e803f1dd3514f39f8de72baf7fc2aebc0d1aa03ea7a189549bf8b565f13c522f712d16e5d875d83973310cca3967a03a8413d36c36acf96e368759242326ef6feb841a9070358e889f30b2968d368d9ff5c829eef08f2d20b1374a1dad8ed89e7386f6c67623b5244b48db7f4ecdd4fd9f0c3de894a036b277c20bab3d41c76d43a9cca172c91e98dfb9c5be2b475b5e2ecce6c3d7b90f0cdbe3defa7566ba91506c498a7a31cc353c8320d60fbb98b1c9c78cbd16335829f8006fb75d9b9e7d6d867d5f57563987c5a04dec0d1af162ae4bc568a6f04ddeb9f30515fbceaebc372c331ea2c48a3c47b054c21a28d26f6c926451702330039413114767ce1210cc57908ffc408fb31de3f943350aef70f4dd825065f56f112107e354a51977072f3b5f3349621b5aa3360563404f1ab8f76c390526d43a9db028d10186f0f181c1ff51c68e4f71c9cd5e5c5d40bbc70019f1abb5142eb97a557fdb4813ef8c09dfca26b280f5273058ec0fcbe36bbdead870109eb1a2d4e01cb9f1b597b1fbd8113f68520571c82be31e3c5e67f516420e09b6141e2aab3e92f640ea0d95529f5c6eddb5aeca494dbcf5295c651665c292111eca3c120f2c9d0a5c41fccbda32a4e9838947bbc851dadf45dd087c8e7621c6c61576c6428d77adb659db124002ea0a3f6998cda9355f236bd28a19884431461c9fd37e7346241ebabfdd2433ba262856937a6e54e1056394f945f7777ceeaac0186da46ee12763fa1f373d758710ef3698e3022cf592f406a1379cb19248e908215f98c8b87179d99c95bd5aa3add6bf568aaf02fd8130c5afba894164b22d1352263edcd38770116d5cf9fdf1dd83169974633b63baa9dc150494e5ca7a87038889271e75ebe16491aec01269753202f7750b0b5ad4810c042b976940aa615283af121d8f6e8514e0ef2a9e39a00d612c2169bb75caccfe956b69fa0b08fb99b9b680f537e5fbc6fc14831f4832815c884f8f58c54c18c6a50cbd7ea92c0d8b7a8a25dfc161c621aaf285860befd2681b71f6697c2216a9638c8a4998e41cbc9578c600de0b4c499069268af71389c039d225092b638ee64ffd7c753b3d331e51e7c3dbbff041fc7299dd40cdb50afac11e1937aed79209ca673f8e2a4a3795b6a2dd5a9a0d71502d4f5d6404c78e2ec5f2aa184f6544545ab92d28f4eef7f1c00b87a7584669d8af085dfdf06b336ece40bdfaa0501f6285d8b2778dd264fe488b33ff6119956bea30a9ceddd517b8ddb679a2930ca266d6c27875c7cf6926fa5b9f5e1cf87690b9420a8e1a94cb4016d426f455c3e0dbbd035af83c495222b2b2c415bbb5ec3ce51ca7acddf401fda3b98364ae3c4504b62a59360c57d767c44be34cd92839b33afb1fac6e3c09609c4cf1cf02da11628d36572b56ca76f89a944c685ce591e608420ec8d2672a2fb9596c76519d62ce767d15055b422cf78b3bf7f32bce23be5eb5435de961b1f32c0e0f3482da02a581f877b79f0566014c37493b9d1afd1c7b50050953a8b5e6d1980b7d743e94093b94de1ce2ca3de7818d71da00190c39ed82e34ea6b7d7d5576be8e5faa0f3fa83080b36a024cce7c37783ccc17b4bebc55f284624fdf551b835d193a1a86ce1312b6c017c367aeb8c6e80ac3b7fa80852f60d627f2ca78a75490ed4f8bafd6904f9b9d7ee400dc9f72ab9fb8de6476d57fe1a74004b208dce00470f90cd062ffa1af0dab4ca4493e2e8ed49dc440144ca2a6ad6891a0e599e837c78834baa4de132bfc95d22d038ff100e67929597ef6ffece75f393514e70611da8681406b36386e526e70c325947d673bc2958d9de40fc04422369113a2329d894a47810010e181a627a1a1c127715d794af1e43630b7bb8dbd55aab242dc6a9c1580d179a9cae42a622e52ccb6bb2b7376cadccf4810c6043866727ae90454e475ba340ce36a64b34db5694cf204950028dfe88efafc441a83faad514117035f19897b1a1991625d0e565f3f6cae016984d96cea3d40fc6fbd2c830bf16a064bda3361f57b8168a1e67ebc07ef53ab9bb3ff91080e845106189f0889667ee1a9b24aace8ff176d311ec41d73d1e5af0a9408e528c29cef4862fdb3df57d3c752c0b33278fdcae134b68a090860135ac616fdf3a5ac95aded0b10443da524153c30a168350e6ef4da09ce34a861146ce638ad9437dc28edc7a081aef022a4e0e4e34466f77124e76de17a3cddd5870b2be814929065c921c103927772667a8b0642b960f1499f3ca14479a4cf808e76067ebc24f0255218523f8e28439a228e8f124d64e0ba3ae71990fdd431c534b60e3ecbc01bd8a03793000afd7588201c84401ce2e73ba3b4acac023bd24da6f33c4831b7e25ef3a915f00a1cac9501591a6800281ec80c8a080464f65a29cd334dc9521da8821e6e4875be720ce35e6a068b7976fc61baf836008b5100a103c910ffd205a3871164dadcee095eb67b8513242cd446e0631f9b6273203cf741681de0220a6bce17ef601085bb0148557883c6acb0e349cf3671c6a94054a9dd35729e28ddc2c724280369af95681b3807b1abdd67152db23bc147e5ee925c59d304f3d9edf9232a19d8423df8ce08332705e00f40dd59d05b1a4c1d107d8815148cd55d892948a195d74f0a0e2dd6c6ed0cf81c09ea8bd1e6e1155dd20a6d5c212c57e7f21ab937bd302c74158960271aa101ac072d6f7d7585675d7c94b6b7296c776e3defedf4811db44adaaddd276292bcc1b1ef24d85fab660c2d7a996af93d7b457773f8473442a14d67c5288e8fe7d36c6cb669747796620452e991e9f71b2ba7a56f8dcd1003997cd6527d83bb62533ac56d4a2a4f41925105123a1c7e0c76fdc3c04150c4144115e7343c6d3fb517f53c7342ad21c989c12592376ac9e93bb34791f590ec46da672cf2bf39884fe648c8a1d2c259b1affa21b70cb25a21bafd3cf64109d12ba5718c565551907f10c90b13130b94d0ad6b57495cc5737b11ea2b62084e38f50f1f4dc42a064fa5291cf54bbfd2496fcedb8f89dcf30055d24fb368868ceaa9829027a22f1555759a7883cece0b7dd470a8aadea0222ca2c1bfc4d6407270aa84e4c18ae49d4e2904d3b4cdecd54845771948bb7acadc6c84bf064fe9a922da0fb37e0d3694e0e43f5988a5188c35be0101f4c7d1ff7b8b8982b5d815ae0ce2eacd1968966ea453e367477ddd7514d817266f126ef8060308ebec3fa843d59031bc900791b8ba40b2861e2bf281f27288f0529d8406cbe315cd7865cbc861b82d4218b8388acd182614a9c009cf80410ba407ff900b7a7ed2c7223addc200c518d1ba1b5c26c1fcf6a13ebee3ec40d4d32b3564150ae8ae8348f1f1a9d84a155468b26bec5a9ff8b455fd3806822be97ca7144e3f134249236f71b07c572f6256b4666d262a88205f5823249a4eb9cc3483f20b571d51f9ba828274d4d0f8ba4fcd6ce89e1782f0b988dea8362182cdfcb82358da82d003b8952029cc004319c68d21e409d0fef34c3837ec42b1f92c526aeedfa87571f704716096783fa02dfe335cbd24380298b0ac7adcd768c61e53513e5d90589d10b8b9fc40ad454e1582253e0209afaea2217dac357f0e7685538e680f5960b96c8d1a0370df3df98c260682df508bf76ce4ae88a538ececf6d9dcd91ea3386faad768853899c4f514f637132a572aea7c60f3000ef011f385514cbdc5d2be5697a37f1f4b646eb955507c5c742362ad1b747993163779c3c160ab278ce9f9d2cd73f1337c1701cd29d6e686296fa696c15475189138935c00d80f5b059066e7959946856334270a3541f7228a0309b0396bf5d5b191189f0efd1f40997519466a19c7486225a657486e57b1f0d512111a989f22b3bb8db6a9e410a9fd242282b6e9e423c6f58715e08c1ebc12996fd22c0a5f23836f2596d8d6f24196d3f3ecd802166069d449de27cb8f36ee214182c3e26ddfdafff7a4b1d12d177ea50abe42f065bce1287e2f31aaac15501c03358a238774b3183953c2196b97f50c9bda2167f4a383c41726cf68620a7efbdb139b95574a1ec85fc199df4b1251d93c2fb828d0bb6db09f28e164fc3f9c913b6f07746890b7fc4f28e61adec7f46c1455c52d99c219230e58542763b801259a5249b2c87b29a9258a7f49b2487b39ef258a57cd6a3f426d9e158a76456a2c426d9e1c4ba60caaf718ecd78b4b91817b5475a062d05968a3c804a1438a4d4ee8230182d1df79fabd580575de01e72f9f79f8056c32c43394a966a229cf8568d9a37261c4d3cd80b56bc1dcc73bec2e9d18ddcb53d941614514752fe520de18a277801eb92558589d9ad20841c4c8076e9622aab0f567716dee937dffb3bdff79b69e4acbdf377beeb37dfe5ec63359fbedfefbef77f8d17692c0777efd5d9f758e18673a9e9bc52039af269572c92c7605b5e8b73e83a68f7522b8581925df8add71204e5472079463e0f444b81c3bbf4e23d43577c367638d41974e33dfd72d6c402e1efaceb0bbbb701b84b5d45b9174b6ffd6155f94c786837a5965e10e1bae85cfe4bd959f924ca2c5ff74196f0a38e8da1791ef343858c0ee6580330e4ad70ab12e6bcc6d15862eb6d3aa518dda9c47487869b672ac8b853dd17d20feb0a973e09b8b997ffb018b2e45b09518e2135a96794ec09fe729adec29d4ae02d8c42192ae49eb97bd33bcbc01d6fd7883adaac07ee13b614fe3b5acaad3e705a6579e3f0703ce36d42a5f20b4ee36d7b367960bd251a0f06934a5f1263cb49b77a4db198807829bc0de2312cec9c5a66cbf8fc69798abb938940916ac28e8889973c0c2de320699876afb8c7439894adfd498c2ca5a6998126a33cea1987945d44b176a538d1e77e9fca7e55c86545d5bdef7ea700c1b84bc4cdd28fd936057738bf747a41137dd3440a35634967ef7f8653d5a715efdc546d32b2894d920c4b108b8d56e7bb9d744c27b3ac94794dd83c6848efcccb3b286c7c5dec5ea75d4aea563995bb863d9ba4f42172d3b1fafe20719c8dbc2383f8552ca163ddb4d4bcc631711060f8a00ec73007b56e2221ab9fa51ce2882fdb4d54206c8cf52070e12f8903547bd06dcde4ce83ce3ecf7ae0a0a1de3dcbcb85db19df32a434f1d591e20f7ac510d1825645d8f6ad4c465d381dd763f580232c8d1832718c494841b3da75c5ca8a73f7e84065dc74cf8dbda6c7140fb6f0f170fa88f6182e3ac5c329268f39610bff48ef7028b5ac87e2ce74188405f0d070cf69d43570a7995e67c3dc9dd42ddd9c207ad0393bcb8650f5e48135669aa37d2d42af7aa2f1281f747f2f4738cd4c2b46c453881b2ba9a27a393e878f8a03657cd9edd30b67a48a2e271eadc34ac3bf7a53547fd3791c7a49fd0c468c1cfa9a56acb95050ba22b4a90cb949680a7420744733f0342b34ec23051d8e1375e80a45c528b83b53f5eeda04907e05873db983048fe48e9db34e9a2b01a84b54ca85efe676b098425a7378dfda0ca5328d52b57f1e1701c7b098c9b55b3a3394e324091b9b3af326207bc2af786fbbf6479d0c9d25e4c82d487f3d5af8a4b3178abd48bda11817885a2f9ae1edf1c940dce33fb8ce3dc352d5d25505be410a1d10e884fdbf0773322713a0fecde381f7671bd41849d2241742ebce7d5eb4c4750fa9b1f7c45ce80f884d29b582b1cd1591f544c771b7a4431bb275f96360bbda64ab5f7930928c4f6c1ee965f897e0b70639ba7bd07f007e5378f3238c21eaa872aa580c41c8015e034cc398e00276d930179aadcf25952e0b5e95083f8ba04969c1adb4bef5e43b695c8fd9557e2c960f847e918246ed48860fc88367d0aa7489d9368b66e14cfece8eb7e3b60a11b699297f7dd05df4f7a575e621942120085cc52006d835383f3f6e2a87216deb493cda4e5965266db0943ce541fa67605f113ba00daafc583b5e1869b70ec1e84104a1f5c43afcb26893e18ad3d1f6a2926d0cb173687fa3b1960da4ae39b842bad60aefeadbcd7d96e48e3e2a1e55126e8382e38fd9887141abc9ef848dbcc343d92dfda6a01cd5ddf02cee476b7a3283ac4f6d432180c42d849b0ce50149ebdeca40e76c0e98e59ba9fdfadccb83b8e6ac50b432340cf1f60592cbba03baa32ec59f625f00c29e0ba98763cae95440e55e0c761fc48afb7ec696746cd48d41c5287ba050dcd6bc1fe3f1782a2b18a6a22114c268dd906261541f522198560e49108645431784a9ea5045c158394462182d0d5520ccaa6c48387d81d057cb42462bcc35fe4641fe25e1da782791afbc5f6b56ecf77ff7dcc158ad1a947faa7117e9eac9c9f9a14f04770d73be58dac2089b1022001621d53b197985a56be7f0c9af6f9553bc6a8a2b6360ddf4d573da8e4e82fd4930a7fad75dc953a2b53b9776067f04ca118c089c7d6d8c88d7fc869b0cc846db042308a26a34f1143f82e6f60e2687f8a1bfff4c5a88ff89731856ae8b3d3bcf86e46f576e566449992b0ae64eef9769a8be4a83dfb4950c0123599539b87eafaa07733f8a2f62aa9a41dc24390fffbe5848619292acda74f35fd119885a3815f32efea97c0cba94f604591c142eeee8e0f911029d193e03999025c488b3ee0934542ec5bb0e1d5188348db0113ac60ae6f879f0aee2e21bd7ceacb0233a9954c5adeb25bc893e027dfa92297bcb15d04f9b2cea4164b4f5b68971e6dadfb1a325184bfd253cc0bf863389814424856aca2c0333d503222c2069fbd71188c21c61c2f74bb809ccfa902b3ac57005ec4d4b6056377332d7d457e634241e6de74c6557e1b35db4b9a5d80633106221d9dda40d8b29643eba2d28c9ce6b56c7c03d2fe6000664f1853ff3b0eac2ac3da1011161dec030d05ed3ae1ad2dbdb4344b1bc4aeb0dd03105e7a71cad52038f6198c91a26b31b9b5766839bb4baac480f3dc45393eb120a04c30c241d18116e5cab031764bf1f80c012266632e8b2fc69b18c778d6fdf39d654f54b7749f4c789a09fd1f24ed165a4aa3bff9582bb15ee45a2656a054d2a235e069fac79797435c8dc6a0855c3b4f3fc3c9caa1b2cfe658ccc17ff70b84809a457aa3ace6579450f2813b8c4ddfd49396c64ca8a46b3754dd303547c5728f82c0956b27dc58087f48bfc5d0f41acab90c89c2c2e66a3cdbc16f8fecb2a7226e544ec71c947b68cd0a585d647a8229a1db655296017fb154dda96439fd9339b29518eb14715837b69f24d88dda03d2984b7a2a622e6847cf65cb6a549632db97de4cbcb3679a1ee6e9020b149f1f941668d1e2dc256236ecdb207e4560c03d56264d32f381dc86e6fd761580072c1f5faf56f0665698823abf45864163c41bccd00b250cc19db42e5548e7082b1688a3f7153cf7cd078ec724c1a734bd74e87c1b33ce1bd17e9005991af6048ce5081eebe2baada25a677840d34625c07bf49d15bcfe3d2bba1c047e2bff8d44a14e254ff07a33670d8555feb24294484ff6cd01b088a9d024754e30b9531e160cfffafe1cfb8d1c35c950f361466938ee0a18b97356f37ae8e1f1ba040aa6123c7adad3e89cdd409e0088bfcd489f684d9828cde4f82999568d8c1068b7a9c9b347b83b0b0d085bccc4b0915eb43159c30ed20ab087af25adf1183cc9da4c4ebd3624a6b5354e5481633962af93c1cf4814fc9ceda15460dae6054d8317d81a41d7ee745a7114ba4fbeb1cf96a750947989f26e98701badd1b8e0076b54bc73f9e698ca76e83b34202d9849184e40886d91d9700e1873cc7b2f1ac94394e989d1142d3b0150da659b11cf902281c6bf2703fed602bece5969c8abbe02ce6de953f6bb929efda095eaa8a5285d18bc5982b6e9c40353f311140e1c3af0ac6042c44330764ce4203602cbf2cf3ffc951d012e60e01a8408851f914d18c34bd8388806bfd4abba80322902d9fc86a347550ee9588085c55c23d0f6621ba9126a31a8a14beab90b685a2c3e28aece6b5b0c4d8648e61f46f67e5a06af2e1a932f59f9eb65ef3e8e28049f3e6561dfe5fc757d2ca37f6cae479aa49b322e7df2560b8b88606602d73aa4077b7a4dea1a0219b6e584a87abb00fcd10050c50c6ecccd0126c80febffa0a55554aadbd63489c8f1218042136a19045af938c8a29273e8507b801fb423f7ab9d3fb4c2d6a0f63408fc600708dea59dbb3501c6542603bd005035d54e9083995d3884fb3eefe65d5afb652f99a0a02cb4e978ec4fdc1a5e5471c9d75cdb70dc37427cdbc667f67632021723341396b7ec8ec413402607cfc2963946fd30497b251d2aadd748f3ad08b52616eb5b039f82c844d0ec2afa7c3f8f0dd94b3b4825e959afa74765ef4d64fe079a46e5eee72f4929002cd071750e87c09a9a573952c983e10d5d270cb886cad4bd6c478822876cd4d92b4683b3226d6cbe06b2b0efda35c7ed75e676dee1754796b9fb3843b3ade3ae767fc2718549c648de0b0dcda15e35c19e4a5e818c74f8342fae536cc54f2356a5b99c6953902da8aab00994c046cf37c022a0ce42ea5a1436cdb4e0763ab8d11d8d558aa2126434895f0287085b0b16c719fa863fc103c2abc2409745494ad48ae164e16d94d2f786312d84b91e08239788c805b1775934095d40aa4522351e9e0423bb94ee095194d95c317d9bb35025262d42b1cbbc05ed707a8f22250dde8e2babb36a04a8b426553bbb0a609057865cdbcaa6e15055a53b0b886c1aa10a5082025e0a11b9c0ba0893e60260c4b67a0000992680332311c9d030300145103c47430740604c021885c00c681cf3d78449b20747d38a96ca9168923503d0d2a2c5e7a0771a4897e5d1129984d5d5e198fe02941f0fa402203e74fc04afd42781b976df4693bfee86c51415aba28210ee9eb500faab86f231caa0e5691ce29e1be75cddeb86f28e59bc9280dc6c67427144e958ffad04da2bea993980f9a4cc4876602f34991c17cd06410df05ef2026e7990a473ff373673631dbe186992aaeed158ed4671861d3f8a25ef46732a198f2439f3a7f0a88c6545acb1c39a6ca2eab55c586db26e7ca9f52f7d82c5435e17cd0a551cd2eeed96fa7cad826e32517151b02b98a68ed4f8d22ff1bf710515cbcc138238c8640b2156e11936d31079b1a1a0c1abbea0255c21247c8f00420b3d62571b6ec00098518cf5e3054b7ccc9d3246704457222118c4cf9ab1f403508232c4749e11621c9062bd834cc0e417343cc51ddeae71defade76e3cbdc391aaf93c60d37a41abb15046876e20139c5e2a27179125363844e52eeabeb788afb03bacb6dd1e1ae469366c821f6a4fc20cb423e762b100c057abd0d1432999fdef8b8922d98f51661c3ae06f8ffe36409190960fa4054f251976939eb5ab0bb009821513f7128f8a68a397fa8aa0196a2433e596f236c9a23ac07c7412a62a1e84e8de27937a9bc6ce0eb149840072a6ef1d5403dd5107474183a5395af9a98472e131a14c27334992824c0466055d3be25a3abc95dff5cd81358558e3ffc9f6f0104abb55f3e8c32162fb173f2ca5eddb9593b0106bcae9a5c34a1712ec0528234ef74640aa425b884dc778f22834406ef13443a86bc1a2730f3d7249945893552f7d55bea36848599f9381c32f2be72280e63bbc6b5fecddcbf5d9dbf40868e100b6c4a2748f3a647e132aa607e92653ba6777c896f06a76727b7e4c96c0563320bee75ca466c554287a7f592a1d6d84dd2e9333cb2165936552e341d6064d8736031b4c94f3b695a7fbca2fe017425658bf7e4ea11bc316bbcba9af24c2b9dc9ce20e370bb174da54277c795b0efae75ead387113bd3d413ed916989787e9ecd958959da38ea24aa2169b5748156c1e52804018bc09e0fd8ee2ec62cbb68ab9de6f4100049577d116e675ef4921d9c71ad378c9d0953925bdca133b6003d299f3e3a131ae2697ad5b734e2acb24966a34da17b9dd9460a800b8a3b1ad6caff5fea8980f3655ec72446f97ed73e457e56bbb7409dacd74e7e12f089f1095e0036525100e794e7c887d3d613778039430514f72941e6dc24b03a81d1e199f3878fd137145bdf36fe8333322448626a2bbe1ad5aa0aaf5af0ca3147430a702ff67f24142f1f99977ee3dc79950191151855e279371f6df86928e8fecd2390df329d8c1a21abcb8a67b1733b4a8a6c02b608c87c7ec25ef07ef764348e4bc0b817e0f01224c02f2f6aa3728238d8b0c1d634efd5c52328490475d331baf578b35da1b24d3c2b84672f2e25976dd8fae850a218f8bf698627c5cec20d15a3c25e945ee08c413163929539dc45454d0984b42776830560638dcfac48106b8c483a1b96bb2871271b5414c798f9f4147b08659883a6212a3a06e88fed157fd955279e989034f00063bffb50df3bf299e78f283b9d4f234163cc833b006b1185e1e5d060d209ae221240a3f162814469f4610de188a450d332114c5ef35ef5ae3408d767f2546e8dbd87e0ee5df60337e8e0d5e9a97f6f3f0c1eb9dfdf043791f6e59423cdd9cb398862e2349ad28db423ecd61a6f963d8dd77d625b589ac8fb3af1b667fda4de7bd149dc519a42e1e1fa14b32e08dbcb86faadfdcead9fd8b44db9b1da22ee8386270b0d923c625ee1b62db5872e578100424b7beef2b00d3a29dd10bb158b34a1d3157f4bf7823cd18d30a202bfae0108cf16087f52f34f735083f5924e2218e17813c72e86ae3c33c5c2035f21d8d0608d8a859a4901e8a5244db926db8e147138f50c174094fcfc0490f68d32183050bd8273ee1d045be8daed1855a86051dc59128a1bd96f11be57074b13adb55f101ffa37b1f3e40c0ff225fddddb7adf1ec3f08e3c716ebececcb067ea1eca924e947ef13f6048491e1c61ffef673bc038311edc065df221dea5592716440d9e493335e8c7df14a75412f30fbab654ebf21fc773c206e7299d81b3443f52facd23df15830d333cc60b92ec895bf0fbb0b3aa21edeef5e4672d6fcf97c769eb847badb39c64f118e294a13b7e7b2a48abfbf794ae21be25260cd61489641ac736ca6375f41eba50b29cf320845eb36680ba03895a377f8930fe4282c52702655dfcca53e78f77561ed7e909123d9fb45230508713df1fd39541796b225882c23679fad5720a70b5a89a78681b15e28071dfb2e7e2abf06205e597eeffeebf7e17b6ef1ddcdce2afcd82045418e84e62d6426e85ffe0db32ac2273dbdd57365f5e6f709c9c2d3590b599377b1c155c9b0fc7f08628ee53d19bc25878418cf1de0e3a08b2c64f240ca68b729fdc5b3b7262ac82e6c10a87b174bb45b243a14954d944aea675c24c78955917c37a39cc3f23cf33ec484ca93e1c539d2dab7408b4082aa1c22f29512d34f58a275f9107e72173fb6e25129c5f09fe9a9178a77633b91b21a394cbf1d9853eb507368b0edcbee0d6a99875bd51fa5aa4e615d3d320da9f89882f50487f2dfc8d3e922a66512faa8611e60dce728822330962d85f98462d57453eed3a54b438e173812be1c36a149df630f570dda7983ba82a02fc1d55f43a0ef4eeaa21db688c5fc6ad137478a377471d1b08a3c19badb096c317d6b3de5db90adabac88ceafb490b46fc30a7b37902631aa8a68c1ff90379cd94d1501bf9c1fc706a9e12a3613c7ebea13d19cec1f9b32983429ddd8a0fd4000fdf31fc57730e2c3dd1360c237bd752e1f330b9d79f617e9559df21190fa919e71233c146238a624d717225811fc3392a60442027f34d8de3924abed2a50e47838db258e869d8fcca4ef576dcbe63dc9341ce88cfabcbd854f48aa33556b34e8ae54998430edc99fc4505e629e446eeec0c81027f91619d9b3d515cc7e9aa38c264c2521a632d9f63e4eaa90feea8d6a4759f3619b835d30de958fa6000ad33f5e34c88d497d428ea1a7b1976de96a12eadec3fec791db5ab18c513b2845261faef80cec37f04da39e317d38bd6a9712ba902ed7441d2fa1018918c5d1dd89f30c4a4912704986e53f43b74bb5cb16b663c91cbfa6c05e2b8843c0c454a1a23413764ed985b28e6dd82e87d821f698096c5b800795c22a9253bb7a462a701666d1a4a8a5cf2e7b3ac41c8a35aefa82163dec1394c699f88ee6a68f5652141a5558ea6d1a67f01a741f69e6be1eeef62ceba015b5eb818cba0be228b9a9db7ae3eaffafccb185e15f8121be3a71c1c0182fcc700552a998d6e6ed05a085dc0fc2322bc83aae657369a16041ddc894a612b24cd1c050b2c2e9efba5054d92eed02a260efb76d88ad72f29f0e8b441a555ed4ba65718bf00b725581a3a24c98dad144a1455a1f52fe92101724e787b9b9d809662621e1abb839731a18aea2beb02cc58939d681eda3bdd036aba89e703551e84044bda185f4f44d87e40727f7de34d01d60f1001e879eae6f737ce2fbcd51ac1cf97672508a50b83c4c3f5523cc315d504c7f93898b295f0042e998bd85f2b71014afc4e80b9c70522f7f049f4694a86c6b331f2867c157f3761676e585cf957d46a7a91c8f99a0539cb5ad87c423d34319ec5ed168aae96ec40f41c3ea1c8fccf6e3a96e9c0d574b1e657d9f1b36bc6ca47e86d614cb5c3a010a24e1452677c46ddcafbed505cc77724ce81463144d346d033c7588b379ee300573362528a7637191136f1b027dbf4d3910c62d04ecde2e7d8417a54e765434cb9907a966a57dd10f432155cde645f24e8a010f6c30eb8de9bce98641bda493ac0b73e526cde24a9d470ea7a95245ae9abdeafa4b6a8926a68b3469e8c3d3e246f6aac0498f0fd2b424561ba36675bf01f354e24f630edcac0083c170b26f0544136371e72b60e688212763ffe271e3cf6b7bf941a4c7f0d80ed93413b9fd26bea8d3100e6915604dbe531b40faa11427abad46a4c2cfead4bd6f5d0d0bfbe714dc97b1c0e079204b643e1296b69291b4aa2c54a71e4ba4451ef65d9204be4d3aeff81e89cd462d71fcfe150916e7c63a8c8bb0b505a19cac8c32a2e96f73bcb8876606e4f783e49aea3f6aa87a15406940bcf36dbb231ca89abc78151bebbed7e0d9330294c8b58bfd70d4c717ecff6289a3ee4668ed972a76c18dac63b553a94f13518d076e4e20e85bbdf88da1234a5cdb34f5b6f6da3074442dd7dc823d33111d8997662bb437bc9c91161124ee8427c1a6552898b7a61e2493fd476639ca229861b224a52de76637fb90b97efb6155e304fd6862283daf4179a5a750ecb1d69e5becc6517636fc95d3e5a30f2f161ed04fd7c73d1afe933c3989cc364d1c7ffda39d036b487002759e43b44ac1b0e7d12f6401883d5d5f05479f3407b2b75076a8852c003704598bdc53238346de03dea3e1b7168f317fd2f20128d909e62b81778aec42b64d822dd013b11f4ea91cbe27cf6db5e6efd1af9fb4e58c1d805254e413b1043619a50273558364aadea4035ed78cdb384e784b359e351d76812272c403933ac82af808238981c69887dc37b6c8db01b7a4ae9119b1ababd004f682bd949ac49eca87c53227de518eeba256dbeb5b49dd2a7e4699345fda66ae3134a1a57a715e796d775eebb084b1b45e9ba78b88111b31fd5095864e659a0cf55d4329d76b37e3a593d348c3431ea5907a69a43099122d03dbc64b90b353ef156c4dda24e88db6a410700c9ad7d649312b31f33e8a65076ee0856b855a76db56399640a15e68a57bb4a5130c9145a6bc892343bf9366c91bb27c86ba4311a33f863a45a3d4d75ee764cc62092b4d862cb6b0d226c3f6faa1048c911f1f24725517316b0779f395db9557a1caeb2b0937cb3834a58cd10e05a222da9cba35a9a86e30aeb5dc65442d0b1a6b30318c210ad2a994a7d86056207db5a87271c83f9306b2c6faf657ab0c7293a2ad1182a396e8eb1afaea2f988d655eb6f042df9759932b2a3038ee18be1088032adbe693bac97946d60c668464860300c63bc6f9d3f1c4a0e84260b9235e5f74868fc5416d48be18ce12fda2db96ed7bad9e3f2c3e7ff1d54712da19214dc6a313d6babfac6109c131f59b0773aff925e02b33eccb21f7d2209a9b981c5b7757064782f20e77ccf32f61df37f774b11a63dd1f3101479e2216d2306ad358f766de988547c2fb1b8bffbcff35b916148f79335d01b69cb3dd45fa3ed54697cf3eced0e4ee931b3b33c35d941ba883d228bf75ca0c77b7e2a331c9181c7e32a867c15df29617a517258ae38ec0a96588e36b55cd69c2558cb4c3591b0ce3ca12eee001d75e3704a17f44f1b859fc0efe84e8639787c5d29f5138e3a623e93ea01527a579ccc1870fda9864fa4fb86715d186a86e58ca2145dcc588da1a687e3860e0c8f0572db4f5da72431386e0d7b1e8da8cfaab08316c4ba0123eb0a35f02c41a065f181327d0dc6450e0da25d40a0ab266316d78a1151716e8b3859257e7d231affb4c80021992ca5d4f1d943fe091fb77122d95669a4bb17304f2ec98ed8ef31caabe9a641c9b09f8c1ad72918bae3e51b0005514b8d97eff7e4809e3c465f098498eb47457779847b1c87145665cd9a567519063a4e98fcebc9649af32497151c736f297f8277877cb7b24744e983b7f104c75ff61628ec528662166905d9a24bb1d3d603f90fa41f1c280d460cad3012688946ea818cc765c0da12aeb6474b0a4f68277ba918343a1cfc9b5a8b83491ac78a98673aab54c333e1461835e8940834f7905572cbd9b654366b8f215b90853b278bae856012763d44805f8500ce69993ef869361b204b5059b51717e4c7a8ddf49a41727183bc4a6f710617f4ceea5d8e9d611b4eb0ff5e4821396589c831878c2b8d578182d35f7aa218b59d390fdca0215d9c626f96a5d9eabb7ddeab558b77412a911500639c3937611bf59c113ba8c97c4173951142dd23b2d2a0a5816fbd5e7729be630878a43f4ad905efedd21aef7e28cb515c29dd0b1dd0e8a733ea2265c5b0df78f510314a7959d81d96813783a3264c93eccb496cc7ade72e5c7ecb4e4e0c24c835903ee77eecc65f7fc7f65d4699e40f82654bc65291c44309aa8d95d8adee182871c7abc8953a6e35afa5bae08b8f9cc005cdf8906df3f29dadf92a2234ec91615a081ac19952fe2d142f01a0b44347511908649e42c3cd5483aae91659442474c7177db61c69299b10f1e6447da032e7b3520046df19b1274fbf36b1c55df0712a844f036779755123210ebd1997c9d95f5a11fc379aa080a0ec172a60aa90808f20bc3d0bfef405e00faa5216a49827e784a3088f397df18051e0ce30785c337a261f7327e48648f4f389af37599040de882355d5763d48d8d9d036d7ad7fecfa288065ce0ba0a4b92ab925f825e3c8eb86322642ffb60b81bb0403063f025a0e379f9623378099a50fdfcd248c7947a55d0bfb99d0e9ed04abca78e0ca104b3e6235984ed501fa3a9c3e94fe8c0f3df61db4fac7f4cf06b89f68fbc4f044540dc40c40a77cbee48bc0468c8d0dc23cbd2cc89338d30d73b0b4f90e8aec816b603da4ba9347aeacd60ed79ec853514580c9103b6b2a4c3466524b612a0589aedaa945a5241faa5e0cc36b3c60188b44d08a183aef4686833d4c5aa40ba71b40ea821517ef5d3c08400ebfd7cdc7b6ba9c396e0ce3b3d92f16cce27132474733a5bdfae9c48f39c14d0446f2880f5a79d6e7b80862b7c9f95c553b7955b508cce5bbbca305437aa41413423a8df45088e2311440985771bcf0098f0432c53f48098a53f8732ce177c240c4966be46681cf7a582c942d37ec4056c6c76e668bf1ac8fb2561601f7316b3a176bc083f9f3f1d9ca89ad87de02af0c9cfad2c44cc1c46de31e17abdb549360098bac264d77a2d8793e0b476bcb504dadc43331b9f405eddeea110cadf542f26ec3ded2bb2b99026077a8fd8745b1ac965bb5bec333e4a9215bbac72267303bbdb1b978e50b60d31d04105764225f880aaee4f3c0df4eabf99bf3b106a610fedb5af4c9b0cf86d4c056be6bedd199a610f10bb40708c5fd1ff2c2ce05da8a72192b7b6beb79a2b6aff3ede6b3c59a3df474dea0f1dc7cf08610a921176c3b0e27aa0251b50fd33a958467a3f1d61f91b242e2bd1a27c1c3956920063a5a7a57b126268460080042e69c1da60d36a1aace23d9e4c89e4b563899e7c4c211010670b2ab35c51a526149c8120d0ad687aa922c5887df298f2b48c6493414cd57cd66b9803f825c662f04e5d94e47d33fcfabb48b593a1b83760d833272b1c1435e98da70175837893d710ec0280e5111c0f60152e95e8f92530acd8df0a4fed15703f754b77a62c97c0e9be7400bda3e99220418a28ef3718010306633b315531b41941c3edfc01a0083164226267aff7d334db57dea3f34e3624c9be272c9371320f253f0d2c763aa98a8e8360d09e6874330643152cb79fdfadcba709c078e0b0184bd884bfff9ceb1dca0430b793b521e2f1f97287aaf8bc3b2ddec0ced00f2e7398b5652bbc27932e3faa186cbd7a7d82410c8a1ea55661f02c4ac29aeb68bc3c48eda1298cbc027a7e1948bc5900b75c35045f83d554dc207729c0a98ac355ffdbea66fa1298844b31e475b3563f18d17bbd45fee9f04e934dddeffb8136c3f006928f7026d82a799d8070e0b3c93114e7a52238228efcb3cd394b1968908e039d5f5d6f64699065d1841abea96ad7b768c15fbce7b101970f403139f0b71e29909f4ec03a33e7b77113cf55d003ed33147b5bb40a07cd2698ec07327215facd5758544d1623f56029ed41b3cfa85eaf18d1bdca9b867de49ff3229d58a9a3032cd47e2a811e9fb1b9c098576e8e7930e6324236ff348cd53cc9583082f37715b472f722c66681194ce38ff9a546477d779a329e60ccf801a4cb29443a808446d1e2155e84593ff0cb34f0fc54bafe66dae627015e60a887bf1346ae4c9b674724ff12631a220bafbbff0e84595ebb1b36487658ca2c811d87935f38a555daf1f55b9b35a99bd86b2fdc5b1a55a2d55f2acd49212cd62f7f69a25c89153cf6a96895d33625c56b273bc836b67dd8b42182493acb3b12a21546d3199eea5a302b31f3cd740fd752e4af7e51c28c312d751f81e48f7ef540c3874ec63c6ba2fad44f5b80900a593ef1c293cefe25480254b38913e7585596ef050df56309e6def004bc0f01786d9bdd2c636bba046acc0e0e18782497bdb427c5e9fab5031d52d4995842faf89e1c7e118d9d443019b70efd0ac35f7e41ddc18cd9c5af4f8f5246e5d5094570c3d3c1946828ce8b9d97c4dc6d9da683d0c9ea056579aee0e9b095de5bd155266af83a9aea62da601482e744f010f604f4facc2851459b57e43d20bf5d6725bf96a0124903cbc6ce877b4cca0f2a90b502dd676f20f5f6eedf6c4ae72d95456ab09965bb9f04cab52f34088fe7adebca3365810d39186f5fa6e1660453ec439affc24b58fe9587c919c5426a5d281311335dbba4b17746ca9155731f17a42ace5a2db1ef69adb53d4a11749dad2f935bbb20d99e08f654891c2f699126983dfddee4deffa21b8384807000745893a1be45b4b39ca35f1168c497208dbf2d50d1e9caaabf4b7f24548070a86044dfc94656be9102ead399d3c908e6b810bc90e797d00f652d5ea4b989440910eb0de7729917ad3f95190dfd1ce6238817c5c27dba103a4ee2ff8cad596500a167fdf4b1b1f3829e28ca97b60cb3905edab72d65f8ca4530c81fbb73064c97f0dd0704e2623c733209046c43bb8f6ef2ba1c98b6f8b1ac9b41e35473a17cdd6b35739d8d0f2dce2b479d5932f8cf75919cfa9d21e5428ffd5cef77878c23c5617d6cf41efd9a09febb96b8d9342681770fd6fda68cf32beb50dacc434f4844e3372b9a9e3c89a0db35547951eab4a886b125fa97ffc302c90a00b634dff9d5e36805baf090b8d0817a32291207c4aa01b25f3bdbc1e119f60ef8740b3db7035de16ee5b4b53e946015747e47b98243977279ae53804e84185419488287a9e275e648883bc9485d6b08ab9ebe6cc4543325a845b432f8f89c743dbec3d62298179ce2d69bdbd494229307032ca9293ea5fff73be9029c5e0a0c27344482c82b33b8bf24701727aa8dea2c1b7af5a9bf56702f96ac35ed58750e9e6698ac75a19e9d459ec28e395dc269893b654b545b42107ce3b822dc0eff91f9ca13ac948e14ec3212f5c104b3e1c1ffdf5595f047da1471d9f4934d169e6f2c6b87b4dadfdc465151cc7bb8458eb5e86f9e9366fc0a7857287dfb99d15a1d4b9a06cbe013256797e9cd96b62fdfee0f837d6487b258de09d102da1bd2f29153304b276633ee2dff1f6808b422946c3c90ae24dad5b352e04a88e42b6f516b7a0eb0cf24cce84385b68319f7a7a45568c83f1126514fa12641cee0a6f811c6889699680da1ca11c11a11b7e658bbc5e6d48cfb0c807398abc27634fb3dd81b09f709c798cc1c34b0b712ee7437e49368761aae2c8c20704ccd8206d9e96b0ec813acc05f40b01fa275eb210e6a4154605dfb209251cea397c98180224a0deff93e7efc8877998c71c4f0af22d443ed710689551cce249824164825c3da1e7050266be23e6239586643af9684ca2ae6b67ad417899287878442d2dbb7cd57731030e4d67d7e2289dbbfd4353f91a07d4587c39ec18221487dec76244556c1deb516413cff0d0b8cc387e8faa63fed4d7966e69f86b1a93c434e60efe3e93d54e04b4eb14d1c56f15a8ef3e382b2ed1d1ba6658172f8e5ce620759802c15ab96257850300bae07291ef344604bb04c859ff29d3c582c546e86da8c0d4b8b5c1951caede42d13dc64bfc8b7642352eaee307f2c8427b22488b1356c39f21a656622288481f84a09e9ecbbc83bf27d5896ce001e3b0348f16148cb238b27bc0e86953455020648287a21a694a818a45fd5f709dd41146ccd55980ec90e731241e35c4b854214d4b27901ba752a83ec199d592cc9ec9383a4311ec0f4e8b1c9274de2ee3a3609f446be7c24c6d3570c0594ae3b19c20a96b5e04200e7895fc18ef9714e44cef9e44cc52bc6cf6f1a05a0d67d98ea1dc057aac1097b44fe26557dd708a7b348aae448be7feea6c387759483524017ba0958acf3034878fd49f9c00836e9ac8ae14af60a0ee67e56c192e4579440edf121948c5aa8bb01d4ac0e4643749fd22418f4c7f743e344e6d83c4fd7ff5ab9f2a88e7541c4816ddae967466926fecd3dbc2d7a8721db0db7fb5986f676dd22b6be91ac5db432e20c761e369b5bb93f4c64f84c7001690206ad4c6f136dda3b199c98364f348f3bbd1008f3601228e6b6a413d45158d73e42978d3b1b6a740d96318a160a88f11d16c063f338a08ceb1b0855a08e20900e3eac2628d32ce4e27ffca56d4c8210be16a36c4b654d598620bafd62be2896720ea2da996393581425eac7f25d09f124bc31b0db36ba1189846d1b377ec5792e189f2efafec688ed6fa0eafbea203261748f624d807e08bd043b7f9e855518aa69eabe404c36dd724a0de142960410a89b68c0b0c297fc5b56381f45dfcf0b4a98284558d30a8a23195159cd0eb591476e1ac972cae787537e038f048a86050bd0c817d14c8e37af6adfb39f93eaf320564d55708619b555052333f273c5db4f1e3fe0d7ba5c54235f103a53bbb62961a9e26b7b94b032ef11c6937d11b07592de0d5b5453888428619b0d1d79671a7e00d277df51d72052d477a28f03e1c0b3ddd9bbe595362c0aaa5da2e6114dfc61db06622bc990ccd75a945ac6fcaa28ddc5159103cec84ca21b6d5cd755885ad3ab25160a90c28e183ac251c2f1851b933613028e15cb8305c0575e9fc7ee9bdb60573b1bf12bf5b71297f1ab889336dc359d78bc2b29508b9ac98b729438a33c63f85584957fa01b2aa25679909610f0d79a65223135ac0ff3830b32447f3d99a54aa83e2cf88ec49046b002d3f77e6d6d0392f822aeaa2517ff1004a3f4eb252e399650906852c2fb6da16bb2dec31f69de47011c8e8cbf98a8d7935cfa7aa1b598ae6c5a770053cc78019bb1283e483858035e5e7c3aeef233ab4c80bc7186785e5ee67515d883693ba3c5315e6805d75e6da150748f1c1b0e8adb6512832e358f131494b28136db1155aa9b9ada90291465829c9e87e0e19e5bd064bba3cc4ef8c8f23c2be8fedb235f3e3390f08379853a19fe0f701364afc89e3153dda4926f78d40645a38ee4a4ff21131133358f8d3400fab3ed1452819a3dc8590e30e5917fab2d150114d5060856968d11555bdb7aa255174df81647c40492724359f67e5747527efec5df039d812338cdea26d2dd9dc781343a884713acc4469401c560934c3a32fd35b3a83a76d1cea9a2a5c73f857b13521e8eea572e6253fc4618309e90b59a623b1ccf2a678b6017917acdca1dbf519d3244b346575d3b7a8d0fd49f8560b872163f4929eb6be61e6e2250b874db26a79dee211979747da99b93c78ea526890aaa1137c815705b5954e5ad7c70735dcd46b8eae3b1881a0d136093ec8aba2caf7640b0daf5a11dc2172da50bbad64e5a049ca0b44a62b783d32a6104e5f4e8107003a815c58fe076f99a2c84a113d67a1e64a45ef16db4b516135ebc5707dcd0846b999e247d889f25b12cb60235eace9f4ef7fd50e2ad4821f1b6943539a48750f77bad9b771727303bb0b7f19145f9c4ce66f62a2a367bece286cf5cfbe60b5b9ca45dcb2c345e0eaab768de9f4b842c0e9b7db47fc2fad3c68db9d2309fbf62796cafee775f391198a0a0b3b9d1be50bccca775e05b3059b420762c01e9dc558a8a3e2c2c3075a5da1333b374d07915d91d75d72277301e3564fd0eed2773c30adb845011137759ca5d3f28d34953b0526e582143a31825ade33e7b3ba9f7a8990c7c562f3019999fa3c36209caf0f0ac5b3b20235bf787ad9eebc1351b585b41f0a7b715076bc3af219bcf41b800d6cc3737b344f4bb157de637d88e4855a3ac0126d8bb55b369a561a68af9cf6ffc22937bff5750db97a371c68fb3eddab0348c75735a636922215bab597d2772dae0da4ea65db6d3e7defd7104f9b716dc09f6fb5486d1c71eaf1345290e18dc8bd547ab9d0a39840eed599ba2d2933864364eba85d5b5f3a12a92ae33ff556ff581e63124903120a91d5813dd779f2cf11e06355a8a8bfcb47fbf9d3d3c11f50f5731ac4fcb3f2f9f92762a9510ee01484bea2319b0eb83b0562544961a76f5b6a5947652d4dbaa5583c3792a4ee803c976e9d2c1757424ffd40460c4c86124adccd43783d25051cb3d1bea0e2591c3db4c72123f5638a70939a52d6920f044da9b747189d5874c00923e637b32743e65db6b86bd0efefa67d191cb41062e9871378cf71b4b18c30a1a6ad10ce822b00452d80986bbea83e755977e45bb5e1548328454c29ece273bef88a3739cd9bd3d85d07b1e217c2e32daf1836f474bf6218d424e49d447a13c1217e2255337e8157a598baeee0329b823ea9d29bde78873cbf0be0253686d80ca4a5978354cbe32b1ef915f817a624d4d374a38babe84af0ef552b2e406b50bae97012b0de089b9134c23ca400b0e0c5cf6c70e83ca08c5602c056219dc4cfdec15f5e40ee2403debda22ff1dec255ece8b6945e32da148e1aa68dbe06e7651a0fcc4299d31418e274a57f0531345b9151c278982d30a8e5678c7a7ae82bcf82badaf6041ccf8e2df2bcddeb77fa114d5bcd041f944b06ca82c91bb3d91e808859aa127f4aa6a6c92481a74414e04fb881600a5fe22dcd222d4120d9a4bab264514f060761052ef8f2b723ccb82d102e73b344fdc8f37314a075477eac49c3d381cf6015b0d02eb37f16a290566c68f8b2930ce773868e1606e8a190469e6d1ee2ac095b960050be207d72e8a2a26dfcfb7b5df77011f7fc1d257f304755c60b62628aa619460f134e081b3d20e6a24e06b3be4ce7fcef31164b4dd78df04607e1f82d9819a1f40b6e0378f0e0539fb41115d00e3f3628b8d471737e0c6a1eb398643950df100fd186a80f50d00d694c068882e7e4570fed53972ab75b7fc25b2254af494e30088711d212ab1d123e995963911ef1464a5d10da4d1784824e353f0da86d99362aff8517ef4455634b8bd21f29cc9f7acd06054609e667c31df6a91747fa84718fcc528aa6e7ce427be15b906f8ff586de0e9c14170f36f974c27bb82382f366bb1f67e6eeeae473987f416779d5d11ad18c00ba0d6792863230adab59aa31464c9ad0148ae083a8079bd4511945cb1cbb8a7290ab5cf2b729911e4c77cead6f98f82ede9f876fc0c64b7922072a3fa67fc44cd4e82f0c03a99c36644bfc167d6cf1a776363e555b173d46310b257281db683d73d31815f5fc70dc0eb76338909004c7ac51abce1aec1fbc229b4b010ff35102b9afc307105ea56ace8ef6f25ecfa7c05c4e9b49729d123d0539f35aa8bfd2cb55c7ff936a6132327a092623a19355e296667d1f731e583860fee4471b873fe7984a6e4a7303b515482df1fbfc0bbd64c7fb4dc8e31358e5e69fc79074c2212073b21834a8342436d3604f4b1e99c0c9aa4e62dc3c203105e94b4b5deef06057047e3d0fc6788a23b7b034ac14fb8a89b36c2cf5f64e07772df3717a748c836378ff856e430314ec49f8d4411bd0c21445518873dca6b971968f21713260b7257e9b22434e2466bb51026daee753656c5e15330ff02154d240122c16cde00eceb6f81fc40c426385ab6cc522ab0f49cc6f4d10a59d01f49c55db168c0bca7f9311b7bdf881ad0552a6e3f333e69ace51aef89364f23a2850982c1bddd2c44d711a897767a675d985cd1f1aba7557062f70d1c8afa69131ccacd843d406b3a21809c886ceaf18a9d338c4af905af8f673613a2a62c0615a565bf49152b98c647c649453c73ac85ca32e489132c29801ab3ecc4280e2c924c10e36378e0e13ea372a954c86507d21e423e7652a528d71a6a0abc833c3f02e98ae950044705c765147cbef562bba2d9c66a9abff0337bd4e4231340e6298d407b17da1cf92753dad4bd8b9e8d68671ced529934480be1c252467bc720fb9de12f1e16e093104b1e5f080b6d178dd0e6c57c657175a7afad5e49a20d44c59d28505e77942f67e74e0b73af4bfcae508ad0ead7ac0d499d897a8c1080fe40a7970cde4230fa89730883dc5d16420b1fe2d6e6f42348e6e5d568d3ff74ec2e3cd98020fba10a2676ef399fbce121ce71d4b3225f7209bbc9adbbbccb3ddf6ffb31c729074817d0d65bf3294d6cb69dde2324bc9b971369a2a9e88dbf61b38a57391240d35ba2030e27ad6c5b65f0281380a70bffd50a78493312d517b868a2db2ce5c60b00e740a624d0d87381ba25c67654e1f92e008b169377c2b5f0a00ca5705cbe6907e74a9a46b3843ec3acdf1c9224e7b6cc4fbefe1ffffd2919fc6a00c8383649fa0ee8c43ea0a4320957d3e2e8010edd9949326477ebda1f7ccd9dddeaaec6236d7667300bdea321f5a2ff51d33e414deb3e0d2b11f5ab27891ad2bb442b56bfc98f6c3404e5b6987e88acdc413757074ef4eac0cbeb619efa7da730ad9edddc8f07fed3bb2438e33046240020669f2efee05ffe94f2b78714ae880307d8512a4866d8f60530d565944c0de5fb91c7d384bdddb41eb2f2663ab666e6826a66410c73c1d4ea559f134204e0b5d320b8ebea9d817ed22cc6f8dd044d376039824467c2cb684983ef6b3673ddb2e8d16487c0d488bf7241fb36fa8b1159d575fd6de68eb608a60b1aa795d5cd4f2a339494b649f5ac35f503ccdfceeceb88bb7ca0f790a2f66d91052ef01150398700747d3fa04b8e4e5dd55d60a2a1a2fe099c3a99642afaad6317d5bb41a14bc59d459a8480d865395a5c10bed4d87563405c70b87987e3b557243cdf3903c306ec3974a39119298687b2e21ea1818fd84af4405c5f2be6388dadbb4fa9e4cd30aebbbe81dbdba6d83720b8e6c9ff9a92ae255b18c90e4dd77cd18753dc3633ca862439325e7b6f32c12d0bff3e3940ef972beaaacdbadca5d12550bb812036e3e5f6e3994def36a7873d7a2d4ec1dd9d8a38c68cb376c19b77d0f26946357b33c3c2e92d753253205d396d39b2ff5454e4c9e0f51164d1fa32e39cf6385c9a54de9378757f3216d397fbbd508c5f9d11135ac628050dabb155c10f30f575656cb0d8cb3322b89e18fc271e40002d34d1a6c2da61e887fe5f1b8833180fa152d5cce920102ebfedb59314b760da771db161d262d66b870383798af90f22de34d137285e8f83dd00c4c45b149c9007fa05529cb124a371edf60407005e7dea98ca1795505031bf0176311f6dbb6cc2c8219c398ea171d4c1c4245a64a989f829ef2449fb5b8089e6d1e727e66c23ddfb6ce217541c505ad92e8c49f2cd81a79c8ae550cfbd1edf2a06ffcc8e5a1522b758e79f20be1cdd589cbeb381c760f7b60c1d7f3688d73cc02ecfd21e49690366db0785897adfb3bbe574f45e77594883876a7ad37f0d34ebbf092b58237805af3048683b6b101d785d4741f9006dbc448b146c438f765a472baa5633061247b1758e0b663f1945b79c83f0ed39b5273f4097eed042ae93eeb6dfb0f37c6ca92cc4b59289f0fe58fcc28966d66b22ea082572a3a492980218d0d71595ff4d7519eb76e1d6428a565ea06e5ff4049485fd1ad5e9ade58045db954fbf7884145111c7d7adc42ff479dbf9b8765417692191d55a034d08a1e6a6c196daf7ede2ddbfe91a49d6d453c902331308706c53a7bbf458902770aaedf85d5bb14f2845324c305d85805aa18c8259dc1176110207ffdff016762b601661c632b79e18c56855b18f80566c230344ef09ebe4246acbb4a00bc4a6f12ee49725b862fd675420e023c93f2c0a68f370b5327c51031db926187d072f40a204b8736554b7c0fea6315458ca92dcb2d07d40b114b37f28e3c78a682fea332fa7131136f3a53e3b2e2701127e1695a0ac0a62ba4b6decf425de0cec097dacd19df35161334fbb97077aea56d9b586530f650d5d09dee7874fe6305cc32e36663402cba6f7815c015a01787a2d5c63a99e8cc380669ec7b651921b6064bbe37d040051e1118928aa1875b1b0dbc9c79d817363053a7873fbdc9db54128c29ee4745d11e402ec0761715b87ca2ce3eff076f783b2103375d62ddd2b1cf2b927acd3ad88cedc7ca258d5619761079706843a13f5a102ef76f33a744f850a7e69e285f96ed93adf3a61240a57b9d8104893fa28a175366ffe4e8dcd8877de2c28e050f4c3c37efb114f26c0434754a06791e66ad6ab833d8fdbd03d74b3d88741582eae510f1c8204a8c8357f3514ba661d4f1f56898a4b956a6480ae6a5128a22c04136a396d2afbffd8a6d8eb8d2b37ee2ddf7a4e912dc592ed7a2ba33b0a7dbd51679664626f44a4c520e7cfa2298b8a70ae3ab39d0250c1c30cc0d2f9484805b6293822ce95e897225c72751c75fd4304956781e5ca0a203d5dd3a87ae52edc7c1009f346365cce6de71dda78f5817c6a304dd8dd9f5b4ffca910fa5c7cf312f4817497822b0aedd914e0faea0faffbdc9255747ef03c6b7bdb7b63f1734ba7c1fa423fdae91f6096a69b6dc226eb99b6c6cd16254b028581388d0c1515d585dc4bb764f1d523e496b0c188d42de90b1ae04eec49f7f23670a21257b734ebc5a32fe3442edf1868541288bff763a561e45ca4c5a3bd21cd630e579fe3d08c90ed04e10d6349652ee8178232a524c149110f0f5641ab40623e3f374883f10e95f733565077eadf7c83e576c4d13337048d51a5c9c84a2a8de0ac1b1c41ead4c7ff99f12ae7b5798e5941b9fe16d3a3f1c5e34203bd1caf832e3a249de6f3bbb1c9611ceb38a892a397fd6c46753ef935d0382d264d943e4ac2538a13b3ec494733f98171533315a2936774aa229c5bac82209d3034ae5eb938b1d3f50c8325668d6df67f17403b029001b350435b65d175d338627f690f29d3459f97a1c563b309e9d9f2430bf2a077a8f67e762ca60a067cc9227b878da7c622476d0c692c5cf2baed0bc378ea405dad01a770c4fdca6bc555a9017b9bd4eb69cb7c3297e5b9519c9c4149ff3590b78097ca66f6f3a67c3d6d111f4c43b5e7fcf960a13f6cfcdfb19f01f17be7d7340df96e690daeffc91c3ec03d414b87240f2ab3f5d37e401587d449dc2b71adc094948f8dc671f662daa6af501870ddf609436653a8e6e85226d075cbd997012f060777c7c114f42a2a4d4d8469022185e3e41ab2dca0bf4f8e04d2a08c4b15ac1d84b954fb2a7bc86d68562065e1bba75f2ab8e83a2ee41a60d6be5b4cd958e2f9bf63897996b9b43a98523d9b70dcc69aeede0e9619efba9ac6905a9d54f87b65cfbcb8436869f61146260de5a6cbaa4125782de8848f41eb8ffa2eb0d218cff7c7608cdc9fc7bbaed1e252263f461c7b72a579c15113bc437bc49e604f5f610e25515d8fe81329f6bcceb315468d3ca8c66db471748f40542f05f2012d08846d5cb63a28bdd6cf4ddfe1093c4b8986623aced7348cdb3986b9f29ce60776b6d79f8de76a031ff3280a6b7ad1cdcd8d4322dd0199651e68b1b06fc371a46954a6205560569c0b5fe806fe243771198c6b0e5be0cd85fd0a4af29348ab23c16ca5673e570b5fd65cff91446db12974d70580bb180053a42d961e6d848082233e4f95eabe100a5e172b95c3bf1f9c54d3ef3a98b14c688df82377b927554ce6fca04895981b06a9054770e323fcb38f9978b3ac7a20a974b871c883f5aec536dd5d80047e54ab69bc162cc3b86656924c9f59307c411e59cf555beec575a012fba0d94dc669ec1252a9d60b01d15977e9bb3675c26cbca2fd5a60243a9d6a16648a5b6ef1b49ee35ee110b1e4463b496439caa356e5ceb44ce878c8366d6df97d8f179115317050c3a3021e4397292feb2b496e21343e1d3913b70fbb6d797bd727085879828a8d4530b2f0e04a061eb342a1d63cb1d94335b7fe1348229416988e82826db19f22e5a4d644446dd4cb34b522bf8293f4548d0955f7161500ffae461c181bc8784785dd367c7e890783a286ecb454489616049496fbc89d6a3e4a51235bd631a35eedb83fa5a8ed651d4801237596a349fc15517340f44e45630274c38477224e6fed242a8646a2fb5fe79f7392a5614585e7f864355bbc059472914e8ac2d1e06db10b22f36e425274a0938f4d69439c377e4696a4ad77a38778d83bac53b9d14a0d484d9546183a8a52340a0857282c61a4f403332e0f2a044b3a24cfa2be9be232664857f9646063ddec3bba4bfa73b638e7901ade35b27e563daaff24e028fed2ebd547dce914ddc6a75641445e37f20a83428b9705e98055041952aa13875f9f9d0a9b01fab3cdfc7267469591ea0369fb4c739121ae5b405c9476f27575869d0b127fdc2dd9f65b307f7df1174816f411049a025b9557301e19a7039d69d932a2a927ab26b7437ec29ecf603b25741b39d0c4a743b085a11701bd4ed4dcf4cb32fc71dc7daf91304b4e3d1eb9457400a70eb9cf1ad0ba32ddd9eabde4b98c1860ff437edb7bef2df79632a59402470940094d096077f7be942df7eb21db93fc916166103b1e0db2142850e5e7aeb02d4cb8b52a7f3f0ede51710fbcca2fbc40ed15a10758b5bfd06b34a12117693048498806596acc9f710fa6b3f38ecc846850870e1d0df2c7705b69ab9a79e15209b7256caccabfa2460f3b8ed2e131fc3628624fbcd3208ecc7114b77d2875aeef96b1bf1fe257ba51fb2bf50ba9ed956c7ca190ba5fe3b76f3fabca3f84f6f7e5d3b3adbca0cacf36d8802a3fbf0e476d2cdee9d3c69b50e5f76ffb41421b06a6b29b80be54adc503ca5b4b2b41f4c199610c0974874c0cc7b46cc254cd0b49757d7c3e2a3fa1e7214d3d4f448131f53cc1051c1e495092fb704ec8393c4854391f7db01f5ed5d89f14501c3aac5383c957b221ff921fdf7c417a601deea8a4a74fddf7f3923e611c03f5690ad1e0f7771ef778dc24caec9b1fdf34d84a1a5ce2d3e0a86e5ec8446af306cd492989f40f82a18cd7e801479fb86a9ac7685cb2e11f6b8ff8c590e12f05aa2fd070839aeca8000f7fec5fc8ecf06f7da8000f1d39d820100c670de76a063162d735eab8f1c2300b4c2fc3b64222cd34f842600e44b9320dad3140b0b1f7678fbf1d1a9c69b0ff86cee946f6b751c7f8d7eca3591b681928bf8733c6c79e3b6c4e2189292851af77ccfb2f7e2a6c1b83ca2128cfc9c363fc657c6829be90ba83460c1e42a4ba3e345126c68cfce40b600a4950a1f237a90a600a494c2196f885800df610349c9546880ea921a794d054cf9e75e70cf3b13e75f617a92386615f383daa04cad5356cc6488b51bba17dfc8e1aa9665e0fff18721d613f3fcecd83e9988edd15526e41ee6e5c373e10c68a710dc62d4c8fcb9a404bf385d4a973b33537bd928df9dd775fd8fd0422be7c0cc48f9db7b133f3fcee37ef6cdcbfeb3eede7f4686ced3e7633ba76dff4cb0b696cedf143fc30105f7a67e33cff7acef3f123ca17aa5cb90993a0ba752b7f251b51763692eb93afaf8b689af3b0dffad45d370f856c9ad795eb5318021174aac4bf35fbcddb5ee3ad33bcfa5c18fc99972d0cfee9611ec7d810dbc2842b545dc74904adc067876a1070876a903e85a010a0ece1bfe6476ffe0a0e0a74a5b53262a471e9f9e0e8cd2f74f9b5aac16e2422918adb53fc261ad04a7b722d4afb4ef3286965857636234a0aa54aaac29596aba4124a47d248e59735d8d3cb9d95113f42a1f2c7d5caf0f71adc982410a46a63fafb650f16b52c5ce609a971912e9d8d54d2604b95ecd94a3f46fcd468dfca504de609a911a180ae44f1a4ff4a6b65ca509fb6da4f77fa84a451d90a953ead131208d51ed24e48b0861a529dda5c8e939b14d4901aa94d53b53f3a92dacf52a8ed48faa4a4f9dbc546f911139599b5269547ac1534d45e696d8c11954739957788891656e5e629c3a2a8875b5de96cb89b31ea3866766ed3bcd639c118706a36149ce6b514c630c4aa66bb81d3bc02942108ac9a2d05a77df6d927c407746ab46f5e7f655ebc7e6545f1b1ce865ff384d46cdb28fef3f7bb68903fdca138aa41cb132dad853163c709ea29a9625e6939ce8a8a04e4a985c15125ea6c227b74b6b867a5b53224a3478fd33c21355c777dcdc3537b04cd835a69adb4fa84031aff4282c6972badaeb329a18a1061b54215e3a649eb437ec04713527ac65d324e299bc832223cca8b7451c6dc46c8bdb3c1d702584e8e9b654becd58956e8ae29ae889a47b4e3b8853bc545c1b44be003eec2d13e5db2bbe17fbd96c9ce46fca2942b63471b39bb9cc0d43047208421c08422964f9f5ab149af80829eb0a054cf846afb97fd386a4e4a492f4873fa4bff66745df95f892851020ba45c9c0d1c6a0c6ad0d540c36c28fb9922a061f643ca86a0f854ce868af868517090acb6293a4b38d60d0fd0ca688988ac8c966a982f9af4862489f8489cfaf3f3f353453d2eea11f5887a443d50e2942825c628343e0651972529bf195d7d6a48ca38035a1953b21f8c0d341bea5328ea8922d4a730fba97d0a39284091f543da61c70d0f10b788f4349494911f97921395ac8c965919fefb31629d935212e93f5bad6161f44ca3b4540156872c0d4b809ed1570f1683221479d3a7ad2b9cd0d8aa610c923831c851d9f39076a84e4ecd8682b2a1a06c28281b0aca86826aff6622c518ed157e8a25547edce65e8a24b4042456ec8358a9d8d72d203ef601e1eaa51bdcc377fee01ab3212a9a913e6d6c7914b16e50757d5167b0f25c4d96a3b66692be82456a2432c4874ae58f531ae53db1d5279752a47a8fa3ba261dd31fa9d470ae7a6efc67480de7ca575512a9e15c799094ea23d670ae587156ff3a9fb90a02656779944631cb59dca8b21c359ff45c31eb499fb0da506afb37570d3e41e7aa3693983f4575afd8c6f8fb82cbeead70c21cbf6b4d2e4496cc9259a81584047c583024e009cced2e33112f4267b3cb417095aa627f47ce8488911a7223152b83b432c01ac4a3f26f06f8dbe36f55832b4a98bbdb638c1736316e4e307b815d204c83dbadc90b4def85dfd9701c735adcb62d6e9bf7c6dbde406773f746512844e5b0ca5f78811abf1f9d0161e39bbabf31d72fdc060eb57d2606496e518c85b1c58ec60eee1f948b5be4330b839f6914cd9061acec1c4bb039337f38f28ffb071bf3effe00fad8987763dcdde524b6fe6d6506f78c118d180ae13e7046949189cc9b64063d861ff4988e01ee4fd3eff1f3eb6968d51930e331fc331eb3bfc90b1bcd741d7fc338ee184083b9ee18d0beeeee2eb51adf460334b42a3f1a5a8ddf9c81e3a60425981eb33478614c0eeb6670ad593703ece516c5187f5b09b306acc74406acd3e8b6ebbaaee39ea2f87361f02f6f9a48fe8ceb93251b5a0d82abc42fdc40f54f88e4cc89cb87667d666664649814ce68f33faece064da552ceae03cd67033e5d6a996042846b3e1d87a3ea59a77dc8da873e9fbfb0f3dabd4894893aeeccc70aa7fda675dd0ab74d8fabd6893c1fdc0711825415fd8a154e68f7db67afcdd7b6ae0721b57bced3b8d6e96dcb5f9d9d0de698d7ef23e9d20df002a0510b11f1b503d368a5fd3ff40f1da7fa90cf73f9d08b00424f5099e543bff961c1367dd8545e3eec29a50f5b0a8b0f3b4a0bfe45f1ee434a114e57798cff17ced9e20b2765f185b4f4d597cff4a9f05e5ec57fde4d121f4170956afa128b7795a3dcc7635ac5c233fd0aefaa2a5638a1a677f997dfb2cee6c5f4d3f462faa48a97213b959fa7aef06265e1e994bc9abc5d182a5ebe6db0e46dedfae20df1f183d6131020f42254785b57785c597c252f8810a4aae93bf27d1b868954943c15bfc2dbba051d6bf6db6f9987fd57eeb1eee6bee96ddd98619d8df91528e1c051351c501e0d5e7fbd0b687fb8ac6dbd60f3b1ff0386bdd28d7decbb7add784545582ed2a819b2912a43d6217f4e4a49a47f1094c1584983521a6992a376788c7cc948269d24fa24f037082491aa94b5823255fae8d07040b967ba80ca5f1829a9e0851248c121e1509709126ca85a5d263620e2252091fcc811310075991cb1810d706a48bfcad6a001291870adcc1141d504be3062a886a423846a3849e0f55b7374aa267bea28ec310f67d65c3fbd9b21666aaec7993559f6cdbf3c0c08037ca1ee77a4145f88f5a9e9c0f51dc0e2297affc7ff70601fbf066c0df6c5963fd81626fc1ab03215d06572c40f931ad4237c6a20543b47a76ab05fc69935981fc1beeb69fc0a52e3f6f8d1357e40bceebbd4ed6e04a0ee77a403f114bdbd4a95ddad52a5e67a9a3e72fd760f4840cdb511caf6cddcdb3ebafea8524587f8a1ffb8b155aad46dff1f5db7ae1319824cecb82ee3b8661d1e0607ce4b02a415e055aa54fe5e642f1e06872ee6d0795b135738ce8bdd776d36a802e68a02268d5e8901a2ef5e87a8e3e84df7eb315b8da8a35bc3c2c271919d99bb9b998cd6d80ab6854932b9d6e636e6362fc96e5c5659324025e76dcdf47244de1c648901dd73afa3fb74ecaf70020d628756a80aa91152d35152ef86fbf5186d850f0d6287ead6ec16e0e2bcadd9bcad691986a0fac7abbb61808a61524a7fd9c59f7eb94b778fdd9cd825a3fbbb4fceb63049e26f8e98c30776fb3e3e077ac8975b85d439378ddb368ebb1b5ea54a9f22f6d9a67d105ca5625fc8f337ef662b4028e727378efbad6a5977c3a562493266d6a428fb8074a472b5ada3926039620e317a0e4ea552d9c71b1363ffacbe655e921823c718314f074e9220666a0fb00aa9c9fcbff026fb21920431537f788dbf5b802fec6808a91dc310c41b2ef55a80574f02a431779f52343f202d230b64dc22cbbacf36fce317f6fbf7f08f76bd32b62e8c6ec1b630523221a46eb2530057a9fcc5e658870de3a6e4ae30d0c8b5e5ca987f3d76bdc4ae777ee9915d24afeb9d460f8cb06d9fe2c61cf733f6b563f1fa1fb31240f64b2e02e90bc3be20bc5efe35d92280f8fbf92b7f3eb0ff316bf3b745ae5329308c42440982589550c492ea2fa47a4743488d3f3b057475205db1df26e79d8de8cd2e9aefdf2980f9041bf63b34d82fc0064dcf3ce3a44b0222481868483532d0190ce17c2003de05630c0a7b6807cdaaf6f300d42929bdc925414b39be1d1e53c351a51cd7cbbfbedda1c118ee6a26c7cc0e2927563f3b64a004478e28ac9fce210a946f401968f5e3aa19d018b4c4c2e8b8fae91947adab9a0594bfd05971573fd5a741d5fefcd4fe1a3d44564e54559ecea13f3ea18c042ac323b3d360bf0c0f8d0c6462346980d7788ec71c4143107c1155cd861d413a647053fb7d989c29cafaf0b37b356630e7fc687c6537e27a7183fdf574f431c6e7f8eb05b132d41be26b4829a07e4369e7d0effff990f547ac320d3648d31be828eafe853fe24791d09d93043258444aed7f11a3f691eb2fb9bc719bc0cc1459812f764822c3af3b27a5fcf20377bf170d36f88e82a9e98f30754edaa0fc10acce34ae4064c5fa8eaad0588622aa3a135b358accecb04026183af2dcc699ca19ab0eea1cfab7ce045c040d027bd55368185bddaa90c6565cc2c6f443a1f6c7b844eddf56452648bdfa5918ded39d818632317292e01d57a9a8d4fe11efb01125a6e6e9f9699e3e31cfc73bbda455cd1306caad42c2491606fbd72a9e061bc9c2e86f1e57b50d68e82a57398a739876112339b491f88086b34e4e3ab1dd248997fbca777e50a673e8bf86d07e7793131358676210057cb14305c1177ddad10b30c28086d4444767489182fcd47e216ebe66fec284ec9fb3bbb35ff2c22eecc2aecb2ff7ae8f9341444c68383732d07072ced076235b435e4c750efdb2091a766a1b03a591e5a8f8acd3a9c689387d0a3b9552d5febef121a71287e8dce0a42227e4a8c89ffb502a7eb19f8e38d98a49583a82e1489d43bf7bf40634dc9f1a2c49d090b60efd151336ae599820eb1efe10777777bf1f423841c36dd5184408c9a2340638b57f04c40fbe59e9eed29ff9e28b2f66969f104078417e887068c82c5694463d97c4c6359b18e8649d595b0767c8e44c4ca448833fa0fd9daa21eb94f8f7a34033330383a0dabfc3360161986b7086a673e8efa440fbc319251db34b66130a447af2503a66697a10a563b6dbb97004e8063ce10c0c48a61723f90b73243e4d7fe7d01fa7408fe07c4dfc4afe5bc3b536040d49201b41fbfd081820a91d92a0acbc6049ed8fa3da4f6a0873c3297f2cb06a5c88c90c88d41f5d351033161a509634b8751095ba95c61250fab44970c2a201254a9f4a34a044a9456676a801e424e7679de450699c3ead132252fe57e78028a0e18c4c9fae6b07a823045fecd0b02c7af41d8e0ae2317d751cc6f9a6614122494a3833333353e7d7a139c49dcde5d7a3800e35d8171268c8383755fec53a7d92bc33e4a81daca18e8791d8b82af6f18ec74458a748ab419c93911dd0feee1c8d0433ee9c736211c3e60da16543e4b68fd11de334ce99c3b089c5d7aeecaf9f73f2e4aedf6eceb804ce592efbb9b9fb17663f9110dd31c758734c032bb7d13427ddbeeb0b7da8375ad860a5868c48501c72fa552348833f3df0ff40f268aaec8d28fdff27fd6793dba6b99a3b19ff07d25f9d0dc7184dffff8f11b131e86f3fbd90abf349197fe1a4f13b8fc3de3f935c6693691976455a37edfb47d13b1b6d3ef69af6658cd9641767ccd8f54d798258a37f0411e2b34f02152975a9d44d821a5a75d7a329f10b89e102d1200648b547f641bcccfb41838706b1893588693f7060d8fc1fe6363d4c4e89c5c561aa9a17ee144a57744557744579a831b3df2cc6f923d60454a952854b361803a4da23ce08a9dcd9c4f8313c9fdc691b8c311aecd0ff07528d1fdd9311091ad223dbf3cf492929a5edf6557b0f671792ae9f4ce011ce2afa4252bd68bdb88b6e5fb115f2c1f5f9b9663eb88624ceb2797df7f5956e94ae1752af2fe4caa359e447552cea878ef1f7e7c13705a052fdc398eaa157fddd3d2ecbd234e8cf123f2e4706ab49c31f350a817993c9e4bec12ed0af733ef6937bd63c927f17e8d554e40a47911d233a8c735d3c846f96a5a34f1c394a1c4c182805b4a3412ef1cd10ce6990bfc43acc467234c83faadbd97cb82c15108e1c3a96a276c496cd2aa0daff0db2aa96604a334062ed21dd0334d6c7fd7b6cdb18d8b665b7c0c65cef326f3eb3bbbbbbbbcbbcbbeb4ad8dcfd223dc76e6208180f68ffd6ed1de3fa0e361ed015d990be0b83bf11ec604a5d24d465b20355dd301ed0d055335289546e6e867c3ba02107f5c9e74e1068385da5ed38ea7ace7980beb99a4f1aa5a93ca6fb143595a35c89a67225be247eaed27ce20b364a5a2c7edc2d02db9999dc61f9e01078746af6510946f4d40ce3927facf21a025de18472507423aa20258d9239aa3e65532577a411b963441ae9987e24d92777bce743b9e34a1aec6d9036c8bb2b775cfef5a1ab78705017907d943bd208cfcad81bd9c7f762b80d4e6f1bc496d8b01cd00cca12dabbf6ae5d81f2fb6398164443b036866198b66dbe3977cf971f3ffb17da63bf6905a8d86fda566cd3364d03c255fb5ef4e029780083c9255708dabeb7efeda1d06df002afeee645a9a8297440e5ef123404ebf5a0a3e6b7691eb7d63c59601accb47f21b3320a50af0765a7004f5e1fb77167a37ffb4d5698ba7d0b84ebf6bdf07af062a7e0c15e520b4aec54edbf6ad9f69a767536daae54641fb2641f66331e93f18c77bfbeaefd3633b332ba66ef038f03649f6559966559966559f6dbd96c1fd860263f046bf633d9775ff673fb2ddb9e3f1a5fb5edf9f76d58d3b4dfb4ecebb12d276c2417905e80614e74a6822506029ba6651c98da765d97a44075f96bd8b2dddde6ae3260bbbbbbbbbbebbb3b272a3ee831fcb9fbba636df076f728a5740c7b678ecdee2ee375c5c6769743aa7dc0b94c0acd2a4b91522856590abd2a4ba1b2b2141a2b4ba13e3d40fddba5d01f2ea5d0ae3c02ca2fa5504e4aa15b39f6c4bceb86eeeed714ca72f73d8ee8c865264ac99befeeeeeec699188d541a1a7fa075d8dd700395d402196c661a868941db386f0d73153bf429e939904dca728302de6b9205422a132e23664dcb8e18a18897c7ea28c080020c5efd0630dc0086cbebea29c090020c17090c2aae0b2c8cfe511704571e0ba33f08cd508021bba16bd9a1b172fc5c5a4637a4c0fef236128ace06f6f10b3fecfde98f3a1bd8fbbb6024152d5e192e2d2b4adcf49189f999c94ca3ee468fd1c8a5a5648a994b314cec721a59b4da753384f40c130b6e5706f6fbb3550079e52a57c94496f26977830235be543989b1232eadae8858bcbca0e8381544a82427b3a8ecbbef546ab214b813af1a6ccd0be24780708245458c27800754ef8d91ef9d8dd780cc7a651b239fa580b16c8cfc96ff4d40c6d831c6187935ecfa21664df61be3d5846cc26bf47aa8f193034713abe8ed3033c3034d133e1e43a60919ff9ae8cdc103f5fa38c618b70cc51533ed3312e909126f2838913b7f21ebe0080d3056c1e887d1c4ae28671c95fdca544e712ac5442c8a577ca47e4e605794be7a56b9a378c53f0da6dc79d53f29e93fb59ab1d54e0dc1dc4daca050a1f841a66973aec466672c356d53c192b1b6f106dc8e22c80e0dedd00eedd0a8ee0b5914b3f8486da601c90554057532112c6661346049979b24f2879835da15ebe5556007eb071e425e2f2f070e1f7404f5e5f140e3f55063879919cd1b825493e407109b03d6bcad89e4b735b1b359d1c2cd2223b2f3fb96659a077a47de63c640f9c3e795b1cfcb897e64623c15a31f46d9c42ec975feda7b32acd22676c9d889a28c5757c5cc76d418558ee299b158c562152b00356415cb511dd8987e110815d11ae21ded0b4283216ed12e0cadb2101bd10ae72b0345dddfb42dd3443937dc40880e80d005160f157cf044074c2819d500c7cad836714109430c5943116660030b87253c416128620624f0026b8147896c758825a8ddcd82ae387868d4e6b0820f9a1084223fb042ab2666a1c6fff8609fb81a5fa64ff163f4c9255e27a0ae8336825a77567a724a39b729a7ecce66621826fd270fce91a1232dee6c624783ebae1298d82055934da1fdda0a68f6db4520fbac0aed6c68ded65c39a0e19cf2e3baa33167c8c77ee588a6a8cc81cf4cf6fd52c751daf7cb9d6f3fb0412984e6518f91fdbd687076472e2768085609ca29d48384262e238250e5fb9046613e3d2ba38594b01c49901b5979111f27d29a79020947b88cf0e9849004fdf8b45aa14cf59189e1e3a88e4857e4a733b2ea900429612d11f2697539a14cf5918921e325f7191a1e3f78d82168a5ec8f7c8ff25ff878cf27589ba33f1ceeef9f4307efae56479ff6ebdddd6fc33c1d387234d8bbc2a1233a8e1c3a643c870ef7665d4d6c0b43fb293737e7ccbfbc50fbebfa4874a4fd7e987dfff585999cb10be3cab4baf16edbd351a3b60fa663fc3b80a1e08abe82f803e330dc9561870ec686d070593bfc0937a66918b65d97b65dd7966ddb36b52d9bdba66513bbdc3d8e8139eef7c78ca021a93679c2dfdcd8a3939fe3dddde79d73e5ce52669641f247fa34b80a4972d5270f25d0933e79288124509f56eec81d9264f56cbc7dd36378c8e1187f38d8f7f7e8e79bcf2fe6cf27fb7b86e371aac19b063df36ca6fac4b51bfb74d4a0c1d160576075d33c76b44cf5c4373c84c5fa1d6fea53ffd504fa93844dc20cd661a4e482898fc518e36b1fc3185d732d6e8c32c618637f33e0cbd0eef6d1e1438c1c37536286e17aa2294167838e0df1a73e27a52760c1c4d819f0651a5ce168d2a4094bcf5797f9c921e3439fc29f1a2e7599f0e8d49056f781a3e6c472b02460414a4e95bf1941c3595f244e9ffabf7b248e64a208288dc27270b01ebf51613cd80ea6b3898eb0822a3b2398e87216867cf67aa8f0e85c9fc86761c8efb080b1a8588ea3b8281d235f8ace942a25952a6577a3aab21bd2536588f954f9712cd1132a3fd472581606b7547e8981da2f2fba30f833506995bf49aef2298ab64645aa34e2a40d46586d00420d77a89254a513364ca9214c951fb957728eb06282c2dfdd3f550b31babbfb35fee6eea69436edeeee9e91c9d1f3a397a0f2e9c0d1604b0968c8b1f4502058417ee01805512a85fc050fa730f3f6bafa3fe4cf6283ae69dae7af7de16aedf1f5d568d0bf418f6609b4dfbd4feeeffe3178a4d490aec4b0e22bd47dd3cad81a9d1dfbc6b0ac09588d39b1b931fdd826bd1a343c7cddcec68eca57d3f0d0a708f68033610c1ec24824064f500d4991b5b9bb6f8c33bef27335f6a2f6f2e82b9cbc4fcad3c9b67d8a75ebeeeef62682493d88fbc302342459c317c83005680d6c05355461c3e185900842a287b431132464504bb55b092b311e19411215f598ed7eba856dfb04e4aa3df61700dba27e39acdbb20e57aaee839f6d7bd23eccb2acb3de3e9b736ed97396fd66af79a190293b9b8c26aa2a3fdc7254b4fcc2ae0826346f5807ed8709209f44c284eabcf1ba22d4db94f4683facc3b68325c0b6aaf2371cd5d603f9a46e46d7950f6342a3a3ba1ca1da350bea93940ea54f1e451de0e57745ba9dce489f40ce7140f09f44a2d47970706674dd36d5a664ebc171d40654e586b335a91267eb8a31a19c26a409695234eee11eedbb9c4680cf18ce79721cb5519a33e7cbdf563c5fb05fe4610b7613a07f53396adb987eb911c1a5f6a6a2f1b5cb5942e7f7e7f4a93bc0cb4fa18486470ef0d967cf9f8fd811e9d3763a550e8093579713dbbb9c01446f1e8014715fc946acdcc7ca7d9bd732bca6d231da47f9001e2fe918f998c74ddae31f066a50765d8ea3b8c763e44f12fbe729e46f4a1ae53c1ea3e2ba510d375595ef3cdd0df7f854797d5d4e95cf895a319a71a4b06d67f3f25bd69a2d1ed2b766a96572e18580ba70e12531fd7efbad08a777366c7a9a668f6bb6ed967171dbb891c8568b884ef3ccd93c8da479e6cfe66924f2894501e1260f0847b54a3e26659445a0db60bc49fd35278a37c6b4a60f2515d387a3367d780d91d7f7f2897fd93b7dea9f320d5404e155443572e954d3875791abb3f9de04b2173ff36870690667fc5ec8d5343f98064d4fd31bb68c999e337943b225a7f850ed2fc9327d2b7bd945df7f8d836a229168665acbc4e2e571b00ed7cb6f8003f684b918c18ce668f4d835615c98b4392925b59ac7a7f409abadf9262f34c51b2ee2c4544c5d3857cea523a95c432e2257eabaa9d1a7f0fa1a5d0bec8a29eceb1a5c592b94c573e1d1d69cb1d5ea717d5f83226950beaacae6e1c178688b57f12b422eeaecf469c5cb8f3c71489fba2255462355e654498425b698f3695a73ceaf060fd727a34896118cc7512e5e7e6bcad0fff5309e6f2b2dd6a7060f8da4791cd53a1ca70c55f92dbe8ff5fb421054ec3dcf851a94d231293edcd6929ee9b592d67154f37ceb609f4f699e29b54b73f996979964f1a5d2fc648bc587b2155bbc6c11d1e9138b222412e977491f3d5383f223bde0f018f993d2160b15bf220ddd942191a8d5a76eca90887b93c9dbaa82e4f9e0e6e150c8960f2cf37c44975695dfa2e1902b34d15b6ff626c1d54b8354aedf22cbaf7cf4bf7ef36dfba687728fd3cefd9be14f9f7e117bc7963013d7939ae027380df5fac5e2af78ebc5066564b00df3628340b83c37fa4d7b14fe237f176f318f976c0b0b0fe95b3696183aeeb383692c329aa6844cc5de9dc7b66d9ce34f7fc3304dc6283f40f149841265e5a7898f48c49472cef5d7f3a0cf7ff9dc36aec5e3250d5e2fe328f6f198eb9f44a2574f1168d8388da44f427ebdcb5fdf44ba489f8cf409fb15ed99d527fa2d7fe5d4eb3d6c9d7a5d5f6cf07a170f636d5f38bb4f67e563f94252dd16c4588edac5fec22e0c7bea4e9f7e0b46b11516f71d2d5fc84fbf170d62df833f1e0d7e1568f0fa0e7b1117a54ff3af4b847dc82c66ad8c9b3e61ddef76effef9d0e0f534bdd2ddbc44dcc3e21e284b5ae1ae9ae4fcf4296422ccbafeb43262d6d6eb81f0bfdc775c11c7b56a55d72fdb6fbb3147e93657fb707f6aac8caedbff10a44ffedbdbd87efb5d28804bd46ddba8d46d6edbb287c4a7ae94ba4c94785237eee6948afde64da28fcc159bafbde6c73abf300415fb626b7b9ae626cb8889123e359ca9db87fb33d3a790eed0a7a7f91aff2447c58de1e7e636bfd0b435f753b76faed1e0f694f473afef6b60bffdf60bb35d4bb6ed6c5870cb85b1a39ef4f15ac1da53cb875dfaf0aa2baadb52f78615bcf9f290a300f04ffa75140e3ffa75970780c71bc3c21c5ea92a6567336a29bdbcf45e0e5da9eb66e3df520c81863c84613cc4541a9491a3c743ccdf0c0e5948e5d1f31053e913e939b2d0065bc07423180fe63792d7f2db965e76d53eb3c3fa6c93fd59a05d790c994c09168adf0b50d358084ac5bee5378e93f22746c126505cc52731284289ac1865fe34f1e9ba88612dd8b77c40b8c607b10f8685841a942fb12f0740b5e54b7f618e955ebc7789309248f48ee0f0301eced7e010ae0fd33063b10b7b2afdcb87b209ef432986ff503e7172f9509aa1ca11e93422bdfc96d28be7bde7e2ed82387844b08f8e7ef4246fa8f23725b644fd034c2d05c1f5e581c4daf241acd496962f7d40b8be7c617cec7bd120d8f2c13428392e4512947f087499e460495d26395052b78ee3183fba57ac91dff342ae5ec496d6ffddffe8d1c962fa6592032917e52167b1108e3ecd91fbaa699ca63d6fabc91b35d8e2dff3c155a84f5b77aa7cd217ced1175297ef63aab25a3c5e10fb921717e47ff1e682fc9ec72dc8ff1e5d90dfc51b2dc80fe3913686792fec69da06fb5a7c4b16da20912aff08cca764c714a524d27f08b6608ea58f4f1b25592f1f9f7bee6c58fcb30e2f2fff5b19fcf25decc97b392b0a2a03c5efa278ef05f370f060bcf8e2ad7052f2e20de8b65cd89037e9135663c90b4bfff2ecfdabeaf75f379164f1100f499664ad564371157370e2879d8aef1e49b0a08c44c454a441e74417344e5441a7e208faca914c2c2aa670641331473e1175641a2e22f21af2614c61a43e852f4f6a50f6f8c135be7c2990a0a9178f2babc565b57a7959bdbcbcbcbcacbc55145e3cef5ffe5d9a6f9071ca8be74b1a94ef79eed3608cffe2f5f0de07d7164c90ac5c160718009c62ca5100f89c4522e1f0a5603e960e0e8509203fecea0bba7867390adb18172e5e0ea5a82e5c54170ea57efd9cd7b0a0fc2a0b8575e02126807ce9822115b4aa14aa520d0b437ee859a8321ae9d346116caa081c23aacc794175f17d18917cefe2431e7a799a7e19a188a9988a3792eb8a718cdd03fb460d7adf36e87d8bef07577ff2a5408212e9d3bf84f914d8475f795f38e5c378bea463e4bbf0fca741f99fe7402db19b717d0ad983d4a0fc1f5c471ec5598e62a1cde56514e9d1fb58bd2f04417d79ef6950f254d287db431ac7eb9b06250fb5f86660f5e5f3260dca98ea13f6cef218f92d2fa37779675d2f5f38a5e9577821d715d827590dca7fd36f1f4a9664ad0c697a39e987b4aa50f1bb2a689a85176fbc88d3a0bc3a96a3de63e44f1a3fd317530dca177d18534df0b3faa4f13bb3641429b43218c8fcd256159e0f267921497e0a2fe46ef0583eb0eaf98823c9aaf25dbc70d41253a48de167f9e81752a622afe33c3a6a30ce1ae5d703f369d1347e600303032e0c5e1834baaed8ac38028d0d6ebe1c856d577a92a8b16d8c3146f9b10a71661f04a61ea8642dd655412d15cd0000002000a314000028100a070463d1603c9e0bb3f80114000d839e4a745a9b89c32cc7510a19648c3160c8000080008060044840007c2f9d51056e5634599f5b72acb5dc99baee6ec9bc6490ab4c9dd8e61060a620f196311adba79d2fcd24fc25212a55f10ea33403f91a090d1028b284cb2aba747e31c17f532e685972836cfe52f497218b2728aee28d6791af87f0f714ec7647dbc93d0e4f0ad20e785f4cd94406d4f5d3b3f1d7b48cf131f370e0735cc0a28837b13b8c121e287aba46a8bab1efaa208572ec62350f64eb3d8dfed23dcd851248af28ce0f4f7d47a240b648dbd6b132bc808cd5b9da67d5dc3d3846227803d4c2dfd06c890194dc9940e273158984678646eb9262f737f046211802d24ca9996163f030df7dd17710ee56d1498e9868f273cf005beae7f32201f90af8dfd867a5a503c8cdd84ff2eb68f958fe42e7a676c10ce940b6caf9bfd05a0cd72d76fde78cb31f8baed7c792e5a50976539526975a07c2b1d61cf09333b514df400205f0faa7f5f0800014aef6081a904dbb88a194c3e63087a16373dc66c408db3a5405dc445e6dd72e9b34ff98f39c3ac46cdb714922eb73f2bb59aca25261764aee5fb9256187a257c0ae1afc723a6cbcc240b243a24919d933c8c5dc716e62f82a272e68395d77ace4838b636680908f048a17602f730217aec1db7b7f7dedc26ca2ec4e76e370566dff1ca25df0f17e1eac9462efdd685c234311a32f4259acdd435996b604c67e83395d58b3235d9fe8becc4a3f6f5a47b95898ebbc3cbc31874a32ab2943851f7237e50f4a7f5835877c75518413e5b24f0590e5528111afa36875d8fa2314bfd84be064a55106e150185c327b7e7f0b94bcc26906c83632265a3b14654eb58094777bce4b8dde90d39250557de773df0ecf363c3fcc11ed543d907aac151d501e55f78962f63c2cf819e250ad28c31041613ab120df04b3448ddb8b6c13e3a7d3c5a8e54b30dfdabd0e8f0c44c0a051c7ef040db1c1d534e45ad9194d9be058afe1cc048eb0691979d8131471cfeb7bf8500e3a46d4e3d8b543ff952a96d4a053113f8596672627eb989d08670c11a633942c0f33bcbc8a0b6a390e412c1561ec8e194f4a17cd6831734dc60aa5fba6c869490a06b78d77c26bc071054aaab96881661045cdcb0744bd753819a2455445ba0133adaa64a0a529ab953fc7118550198ab4297971997b04767a0334a005891a846ba3c7f1a3b8d955d61a164e98312e6967dea3cb07aefdd47b953435b12b03669f7580667d361d7f9c6c2d4c44bec4af738e9d32d9181f0e084559673e402e25326b0b0f4ade32354a71e4d8272f24e7570b1193fc696105749ba70c4d240008c27d140a9f5a38a2993eade4287b6370eb46ccab79df54ec0e6d0ab0e8c36a5c599f06df6d32e7e5b9bc83797aef933bc8cc8b648fb74ff1d9117732534b632223a9c50baade78f285c1b9b8d7df97e90c7a10b21a1442f0062d04c9ecee65c2c7c1a5ad01b26b52fa560099a8199e64cb8f7d99d911e78c601f6432487f1c7be6e94158b29eee076d1de41c409e82d5195f429de739f1e27a73065e624cd4d7852b4b42ea85f5c4ed49ef6fb162ca3fe909d57c7362185ab44b7d2785ac29a3ad276a1581a04645f6ba47ad60bd2044e46f16138072688fb8c0a6b5530a19b713ccb8af327d61e4bc52fe0520238e06f300316f3aa4911a4e9e61c3a600660b6577677754430cf7301f0b97b3c9a6f4efa48bdb053dc609c8aacb6dfcf5be19032734486111490de101ff8611a6b75ca7e8ddb44a488899e3a53b85430e15bb605fe42d5b2ad0056ff6efd7ac0533df5c49b13df62add9fd1f09e7c6e78c0e2c8d03a8d081e85f6f5073b8c99020fd0d0b17df06253817eefcd9698b80d052caf0c56489d8d729b169586e906ffe8170c11925c21299ce3abba9f38d33c6844adf3d8ad45ba76bcaf2754f82ef8f5dda5edc584049a39cf1d5a1bcdabc1ea02c9e4d93db292c2da9382f36f096bf8dee98482c1d8c0953393cbed5be83487abcf1e5f13bc402840e98c7b7a8b41d2dad2afcbe6d88cafd725183a04cb6949266b7f314d02119c89db07f3db5b2c381b62b24d7b07aed6024332f1f26b52752e02c5e6262bc087d728062f142df0c13cc1096aa6dcbf2101da06ee58f4b7c5f63f9c9df2e3bc4cea9fd1459a46f5f285c4bc34bd54b8c434d7af3981d0d1eb0e769da4a1362179684f44d9c70f59ad06deb1d7e5db94b0f56ed5dd3277f681da1ce330bb9df88067c0f2885b07e54a596a791943475c1b634e659ab32612a8b204c6b16c8cb33011057c9491ab02ce4083fb43952d747efcfa36bac85f5b0c99b41e40b71667cf7bfef6041ec459e92a649ae742a6bcea678803c14753848a412b8e05c5358ffef9f99f70ded12f242751f1f1d8846644ba8a814486165cd221a84f8870b436a45b2abb80aa8ce3649d1ad3d8d5bdb5bef1704c17aa6bf5aac2beb449d06ba7b355970c01e7cc80037f856cff0a80b3cbc0071a5cfb57f295e7c7240a5a0aadcca002067dceff1656fc2f6ebceb1e1626c33c7f44b2cf43bdeec726775d53e4f17ef9b5b0a8d2aefd949099b9d0c056b451f3b8c3d468463e074a0241e52ff9104f2c90582e8a6880d7f18493fe6822fd9232d2fa4c4dee0c1d4013eefeaef0e33e20ef7bcbb62735dfc193d8f83dcf85cb665f0fb818019b11fa887d3972d3f8bb457fa561fe96f72b5ac0068b3914220c4eb927eec2da7e3e16c8c0a77f9e8c96615137a043346944a6b7e9d6217bd15aeb8b11c849acef96db1739783c1827d74d6efd8d0d36c508393dfa4154aac7c547f5da22d9b7e91ec2415da3a8088f80f815f0766950847c2f07e8d520aa7d695e2f17610fd84120b9c36a50941422f27cd882cc82351f68ab80d2e8f0710e30daeee4de7ebc43772541e67d308e5c13ea0f488089abd4280aaf2c9ec41316893ce91c872c48627048aa4868f3413a1baa6d4dc3804874f88e3566ddf49a7dfff137db2e0ae67d61d954d9e62adc1d58d3b3b869560ea62624c8aa389afcc0a3f41527106152b18c3e59c4bb0ed90fe9b8359028c89a802caaedf2ed371c3da853ac60750cb51d59190879058c95273307c4e05c103b48017780c57ef1c1cacb6f105d6325c16755d127f356ea0b20230335dd158c3ad19ab42ecc5712487ca180687c2f0c341c1184b9e621c1d3f6d2055e8159b922e2472e0d9265e6f5fe943c69614ace3cc670d70d48113bac07be4c0438594f048a38d0bb49b0cbe7ed0d7f503c53ca8c17c441343c2f410ab1ad5655bd380612e129a924e4b567f449572121ce74264492500222f28e7579de7fdb16cebcd908b52d8a69395012244a550386d65beaccc202a60c208e020cc42db0eb5b32a4a04c2b6a39c1af08bef110f6606791392dcb28a6e322cca85eba07f19eda617cbc44eaec8bdd8d9b5d4fc682605ce124c2d1a6f8a4db7fe7fb6564a870db054b98252556f73d41768a9445e2df8e0040a881e263763a1a80235ec7e9bb086b592034fd7186a9c009aa48e90547e4bb004b31a624e6cec708f44f9057da108ee90934c5972652fdd58d68192d3adf06a8909cacdf493e6c1c21dd149810b94331e16a87afbd798519c37d61974db59fa76c5c1d5d12821d91351af5ae6c0949cc3545b8aca38ef366aead5925dfb34e40833fcb623d9be545a03a0f18c081d6ce0294ef9c1d2c874b4af994330388c60f1e4158e900bc00c3ffb77b2d80c013091379e868dd9bfa32715c6bfee402256ee0503244e512e17f97d276caa77789e091a24d6af96dee771f5a35b0aea3ecb67135fadf42dbae7a99fe844089dc334bbdc1a178a92f0343af693c99ae8af2ca74c2ab162fac42c4aaacce146a6c905e17b855d0e33c02e591aff2773fd98b51719e793b8d3a53e04f5e446455f8af745e56df7359cbd5d945fc55812cbb2a988c54484f7741318b86d2cff07758432781253e5cb31d51b188b3bc8b376c44a3a459be18dafcd116b3976f68eeb24a403f4892847b8a4ee7c1ab7877e54120fa6f105957c1b43650eb33470a20ed87f5544081378a6295f32f7a6d4813e90758c6b454818b445efed278d5c9c6b8faf024c936ab8af30f896611f921a5b1cfc4d0938bf55410a9652d67c1538e675932c4bc4d4a6b472830de15a35e6ba72adcb6e5e27d2a6e95b90cf1b6b3134607914608ef32fd75d36c062c05b142f378136c0ac5c49ecfa47b10ce68e5979ad4fcea1fb168b7678662ecc28b735618de1fd8dd8aade87b15e34c2c4781ef8d7f3746e9b231bdb056eea34e06c4b958c27fc39b6551c0dc6c1a60151663eb6171b6c530dbcb9140f81c9d618e03ea6f4c032fa2b2f1fddef22b907f6ce2e1631d054e982fc1da5e1e0e6520fd7c882362d41c77631f0a430abfded8dec8ad479b1b6f8d9198374a02ec0fabb991f64d446125c1951d0b13f38ee762c79e547ce08c450fce0da21c4bdd9c53e3ea12171e0d2610520bf07e6d9b33683771a8fbb5361aa541f052fb1efa15b2ad05ea64fe29d716b3693859ee57bb55c4eba5c1e2f63eaafe840c70503376c7e7b49202ea0eb69dd1fd7ebb36e3d0f6da1d10069c7d9fa6c68a219069b5d4fbd9d6cf5e0f5baa7d4a886193dcf5d8cdde24f2262bd96ab0009f2f4df3e824a56f6e53b757eb4d4105f4000f20d3ccac8327d7483657df9051394fcef35b71e741c69dcd130c52fa5d2df6bf76fdbeaec6021b08a607d2b9896cac44ea35e930ac7292d02837bc49345c659e23e45a5e1e4a98a176e890cf42a2f7bad19fa4a5a6aa08a11f2eb43fe16dc6429e64f0fb2f742503937f0d654cda72f87ae72df7ba7b00be8ca907c71b68326497c5fceee1fadd64cfed1f240925b69ce5902a3812684d32202146a36fe65559fcf8cce07a3061d033bb0a54b71b1a7b05cabc2638db2c43eaf56921f47c33f9f064fc5d763a37ccc141a4e43e6440f9b69a9028f7f2713d344ea847d7b7de6786fc0c47afec14cafa4339d6542d3464f10230f513aae2401a7c45901ecf129bc050cd0f41137cb379af16a34135f191a88bcf3d8b7893af030e067f75c66a13194468f7379e5bc3f729a4a13a7ca7928d095a41a8221590a9cb196d67be18b88ab20505b96a0562c1292a404f0a6625cc0ee52f6e61fa838f46ce737a3eb3c575bf4cf594c714addf4108b4567b5e19f6b2ac8333909d40733400417a0c8efc88fc421d9d26dcd2ae806a9188734ea21efefc45558aee8e023d1b7b2e764712660e6852d8f60a8346a987ba322222e725050a30b8838494d9e8ad486216a686c12843038380e8c840f879289c9dac98c6bcf1c7cea3574c78d7f2a2029a33eab3fa70fdb2ba12fc2951f5c0e70637686c09bafb535ad580df4ee65f290a2c7b71e7833e6f90525c18b9296da0aee1e163b52f36db5eeeb01b1c748514629ca24479df7b95f609235682eec354470578518589add9bdee551520b828faaacb3ff52add9ac26faa7292f178b0ca3fdb7f36d2f490e15ee064a20df076f8e1008f80aaf4aa78e567fa6376ff56804a884d279fa98efe943b555f9a366eaafeaf50460fe81183b9a77fcb5ec3cff97ea7f472c63d28d8dd17d7ee5514a1714598b78352a80a50693577f822d1336268639e50be1b57f65fa15f98913ec1b105c4a54fa48311f7d7a2cba90b16c3347ae0f9dc3759480ac0961c3f9b060fdc4cd5e9db199e36ba3438bbad88f7483d8ce513551f867b448bd7d151ec614131293e3206c22eeaf84e0817f2e79e33a71351f03885bc82853535676c1da24d5f7006763c589eb156a3c9f777aa85ab0bf1529aebd65a48cb66e715453181fcfe8d094ef09233001fad51e6ce822cff691757f24b0bf125f92219a72e65862225c70875471e7438982454915ff866f3825f51f779a83641204390093435069c39bdff2239f4f0a9a1ce60752cdba94ef5085f96c5ed34dae364c72b086286ea6d0c8885b2a944236e2dd6d97a2834da5ad28f148ec22516f25d512560d5adbc305a128e9eedafde8060a6b93ed156cfe8e6f9d5ea8366c8c5fa2e8f07426b97b523dea0e85fce8998303308c1712600dfc8c1cb8680e2e9be2c648981f7426f112c7603cb65b70e313cf4b081dec33b8b3712077802d519827c695136cb9a781f6d75438832ad0721280ecf4c513ee92b0841c75388b90751a8d5099a0d7695399ea1a01a11a463ff0288f3bb9adf38c9c4d900a688dd7b9dbca041f215a0c1ae9623b450eed584bec723e7f9408385618221f8c260d57226f360a71eaf2c4dfd3630e5379872e55a0211280ccc1b820c1c82a184f915ee041177a74bf7af8ff862c77d46b37b2738cd7dd039a0e722ec065d0a9662dce7e92bc48b343a2621298c3dec904a03a1eaa59d43456ec55b1066d992e5c7e3e9c2396cdf76cbe6a68769d897f8a19b6a613278de8dd055eb97acdb0b58759dae5c700caec2f2b597b4919e17efe6f6b02e93ea3afdcbe884141977437ccf639de8a1b3e272af04b39b382e24dd67e17461013557474385db9cd6d324b51e00e19d110a08279449d1211dfc2b6d2323c91c97d831c4b1948a3324ffbc0d391c551e3499ca0c1218687ce84eae6e54b6f52a07803184dc40e84933ff7f0e4934898e69356432e46cf2d810664357a69581573e9997a1484e032b8c151230c355ca66c4668a096cd0dcbbabe54e0eb702df03452d603ecc1c8b223d16e84a8f15f274732652e640c9232341816c24f13657a2da87585a29ebb6382b762c3bd4222175e004fa841c093d386c8eb8d4a780109aac07ae36bfd155f93e801e8e74ec9fa78572c7712ca0040cf963816fdc87c1c442c0941ffb3a7f897d040132d4b91beee33dc977222fbd556571ecf50ca926a4d56efe769d397cd233700f1fa9f818fa5a3a59def569a9883d9435b11491fe5e56aaf23c087a23cf8e9c96d1c81840c46084b932d0010d0616a12b7e104ea63916ea22c6f7360e7fe2cca687cfc74d130ed161b3691c44d1fd80b7bd8e2e286419df544edf0a9c377bc187405ccaf4ede5ab045c602a2317934810ab02260d7343a37d2909a5e70d1e93b74ce0cf048fcb88ee6bc4033fe44eba50c9e2869034b2c01715293f6121a2ef984b3a9e197ddb81864bb7f5b340ebf28ada9da2d9d5760eb08d41496d370576a976199f6cd179e8630c9e342e0a446225f7703871ccd41a094ebe5da0ac50e0f14a06524ea04c2874b1110ab46fa985f4c618720d960251c7473a3bc60d283cac30f18921dadbef7594718695caa3eac23472b5dd7850704a9db8bfabbeaefc8c00cad1d225c5659074d00f1d33430ec0d1ab23f4f9f3ef2e4ff3bd0625bd736d054fb0a07098f16212ec43f9755d1f042df7e6526d5f004e163be9e5cdbcaf762ab83ec61861d34dcc6fa2ec82df9dcb7dce27d463d33c559f5182de994ec36e733fe007e8d468c44944ecd1a61607913724a11a460c832e2575bb0ab9dfc2151ada1654711d1ea4e23751f6d94708206020297e9dfc9117b2ce43c8c7e952fc5cd50cd3ccdfb259098fc5ef1e5c64d75ed03717ec1b59135afc5ac2d66fade5080f67ee77630e4972154fbdb02c462011741bbecb04122bb49da47aa01da49270fd37ddae2c1607d4ee7d5e63a2083f27a2da86078ca9e01d3b67239636f8b6e22ccec82343fd4809f0388f8747d1f7dfa143ccc8c38688b405eff02c7da4c6e375e26b3852131c1faf7f32c21a74d85c9a68d86bfe50a96e48c55e41073bc500ce16ed28f507fde744f42fd8ba5dfe44ed45975c79b9620a72f7f71de4c6ed6e08689d5f171b1c02787c9d190e5bb19ae41f9382ee46b9eb413f01b25f15e1ae3fcb8aae195f964887e220fc4a43d756e80599edead1ef8e30e267bc9ddfa8e46c53ab8878f0049d7c04cf543d05a60032dbe7fc3613f0b5d908399390d559ffe56c578e2e88ee6c16aa6303dc78b36dfdaa2ea1c92b6f7afbb1fbd154565490e644c29716cd14245c40bba1ec7a3927b77347b747f07dbdb799d9dbf903e895996b2a4baeb05addd18079188f70fefc3101015178e8928030ba173680e933152df037a06e16f10632b73f59e7fdf4aafaa4038e4c39ed074a84a9713a1b69af43ff649597e717e0bfbcc3fbad4e5c10f09f84af91fcbbcd35e0ff4479231114ffdb552e94879f59a04dc47639ada15cb9fd4cfda8af57a522a5970f01da6d3b1895be8d4616641d3735ce65112728f1f9955e6a9e24ef70093fc72f3283b66ffac09be15dc97520c9680f0018839866a26c5f83ca1a7a2f0697da190705d1813c2277efd0d621a7195bc42d9d1d54c035f12de752adcfb24824996bec71014369f77111c8c5171aecf288f843d9479969cc96b85cfb3a0f69e04daba750dadac888f89390d2b2277015aec8a842e1cb44ccfa9ac83c982854e7efa3901a80b91641dfee736812080a15db123d35fba4b0d2ee66e97d10f5e062af96dd455f79c63841fcf72aa85ad3a46a4bb96ebe60a8f2d54fe74da16af2e2e9ad6838478feacaa708a308794248ab66f2f1b7bdce98de130650be8f6dae3bc022b6210b0555a86259ed596e49e1d9f31c2230c2c0ceaaa9542a7aec0b1a1b5ce3736d38b30e2027b54f702a19848ef84814132efd7b973f6bc4381cf7085cd209c95e4f0d7713a4a5acd6fac0d574f7b9c7113e8fb3b01c237cbb007e61f12181496e792ccb9c4994db47200dcfd0fc3e1a05500d9c472601ea645072d6e7e1360b10be6f1565e5a398c9f12dc120652b929d0c562dadaabbd5d3c96f80977c86482f32b5b42361bf34941b30ca07e7658ca77d56f79435b430d390c67460d2b64239d2595172f45ccbece6f5091b3783b3f332047ff5111f1beba14d282d0c7cfc548723f75711c49e79dd1b01599d03819cdf3d20888f0c2c662fe2dba6e0214b29b0af4a3702c4dbbcd5c88a530b8c06aa6cc73aa06a0d7470d653c43d0bf3ef95862f9fcc0fbd1283c4f94aed61e9d8707c160bb0421b4802b1a1f993d62b7f88d0e98af64af17c1c0b50159f5e79ac7f6dac85561e9c5b71af8a1516c7a5ead6d37046fab9093f8d0152d6b02c7faa514d8559f505654e37e1edc550e43d82ecb3701f2753a531c6dc7ece2bf783891cee6a8d76879ad31736c2cfaf9a51c2029ce2075c37cf769441150ce1282da40c3a0b2688f09414a73f4f2de1dc74dd09681faf222f329f4c8b871f4d02556e11a20eb3eb1eebc96326b35fafa60b27b4cf0e75252432d19f5143b96f5ab980938c24398f0b2fdd3c7231ba73fe71d0340b399ea847089ed98b3b09838a820aa2e6c23aa9c28b1fb2cfa7c150010390a30214360ef32939b7a13d641e0719800d39bb6ff72ced2533b3fee322aa6c1dfa441a018646fe323e06a71ca2884909ee64a21f34a76002daa5dcb31e30e45338d055bb6cf367b65951a12a69f04ecc5095cc13b0f60c0ee1437001f175ef2fd5eb563a44150257b80ff2af10dbc915bde41fe04f7eaded96d6e3786211628f551288da64a0a5419f887e77028c6bd8a0c75fbe5367cefb2dfbb9ff0924ab2b2959947bad721147c94f6b52c2f552825cfecccd41e91142b913bba3dbfc31684a8811f76480651cf4684a5282f9a0c1b902c8f179f323e46617eec5fcb6381b751366d1a33d4c84bca12efc01e955f9c80c973f95ba4b85a9af3c11859dfad4e6a50e30f61ee1c794ca8a9aab6ecac8c663aa738de41c6ba744768fdf582ea8d6efbae43a7f898c5f90be3c98e4ebf28e24251fbfccb6cf273d85d274ee06f0c46027b48f239a58bd9e70e1b9270bda5a623683809a5df64e94f16710d0b8354deea5c3f81028763bffeda130d7a5a298e90838e53903d93f129a742eb3be99794b243abe6a84891a6f3e0fe4664c16fd051a15e5d5cf9a5e3e4b62d8af367f4e15d448bfe3894762f568d246f73ebc4745b11e5326e974bf51f35ad06efab1d09be7f608df6e7af2d65c7c392e1a53ebbeb89158c129ec814615241b88a1d399f8e4a3e826fbe77156318c86bfa94bdb4f553e911e20eee9a4e470ff14704ce341789e7f1d149300906c6a05edf425be19a61607267e4c1fe985f000db8774995b1f34f097d2b692b6b7e22f87a21982fc88fa9db4d1130e7940580fbf1475c18f5ad5aab2da4fd3031210a10658373b11c5e2ec6f16cf516a68c60a2a84e400e3c932f95151030999becccf81e1727f59a7925aa39428afb22e3daa68b82618c9ffde8a72dec83165a229abbb1af92bba80ee5de384f69d0ab493b5e3c35b79748314ac057a01a0f839f8214fb83f3950dffd092849f44b36319209c2ca61af4518df802a4d2a813e0a3e83f61479b6c7b0e67d5773d569a902a88323dcafe576aef4ca976b524d5151556279da178a73a625dc3812c9d7b8efff099858d625bd6110273516575be35ef72adbab12f0baaad8e93e2e199e66ea740864cc76b7d7f2a6f03fde53cadd888aa47222c9f431294096fd04775a35eab4f9b032b477d8f38139c009e8141a93fd2d157fa7720b8c941113c63b0e51688920e72ac46934221f88489fa32d287a9c986e4e967763547429a5b3e2137910c430aed04cd903f53a1842343ff5cc8a0e13e92abccccc605fafbbd9a4ade582613e9a2b1cc10052b19a54b8246829dbaa45ae0ab1cb1b706369a30724a682035628bcea06037e8aaf509d7c378dea29e7a2d43bfc913cb1be32590dbbeac296867a36a78bbec95e74880321a841f3f56635fdcd0ef7ffc360e82471a283985202f448a374a0aa31785b2922112df7b4c627fed9cea6bb990a05db7d7d8d6f8223f1cfa4d1a7080b7de3beb89d982b7f244c3122f9958c2b740a3aa3beba7772d79a79d8bc03b5e8c513692b831f6d61a6e9057732c27d34c5f98fd968cb823674d987795e7ed42aacb4ca5ba11afb7e930a26d932912f9cceea7ed1334e8562132d933540f73ecf0e6a3c3ef4c9cae303d218e82d21c14acd3842b0959a5508001a2cf8bd475f2d2e6c3de9f852addb9653513dce7fb895adc8cab072e2f587792918c884e01b70a47d4b9e6a8ff638b4c6909ad2a0b519e695eb434989925e120bc4e6988f351748aba592d2c11fe85b260d72856db35f2a42ca689d1d12c5474aec4d593667f2d2351046a3e20c840575da57a8e7d99f97520e0fda995128c32729e928a2706783b6ea746f4b355b798deacdd3353bc1884cf4f0184cec80359fd600aae2b73ab89b27abba1505b6d51c1b721e8d9b4f81bf5c42a377b0e341840fda8be131c016206a2618378cab5c420ff9ed9c109905143aa578a4c69404087c7cda98de09ea810be3e4e9a1ff1dd70f0c32438e0c17e4faef8295835de4067729841f0621138246226b6b4b38ad2707042fa09d003c16f2dcc9b77bea5f2a10e1b129ae7695720b58554a333193c70b4a100b90cde3902993f4856547cf655e7632c5b840a2e3ae12f4ea0a56f32421310ecbe1e0f1ed7c703cdde8042c0246995754d25ca8a116464108c98b10d8487c1873a24db4e6506c45afb88c5af09da3b82a7404e52580f7d83c075c0372aeb8250942206f9ab158f38c3f531d1cf9face70038da36d4da6db5a3799aef3dda088b488e8d159ca260284b800e520e2a0b209ecad1411be14fb43d86f61106e820db809f84f7599d22212289180a83c48e3a67f7b5ccc7de6aba5b6daa140ac5e50815a3d837652aaf7f2115b84e1faac44c806b82ec755a70e5381f58a4321b2c7b7b1a58f6c22cec718c4984ccd34d3144eaa92e85ca238ae3b7c95907508021433e416a20c8a3fb58df760476b02ee4dd1c01407b23d51b9dc9e379068f9f0881038c822d3ae31fc3361499069c396f92a336571aa66159c57f0f2e50356b6522bb612182bedb295c9eef1fbcd7db987a39da8a80dee4ee964f69b709b5d78f74ee19bf0d5ba7b61a61cffe0462b5a8dd5b1123082af915bf6111b0ea8215ddd962f3575ee7c001d6392d753941a93de749f8c63782100bbb35162b81b48053d174bbe96b36fcd832db8deebd5e600b0791f52cbc32ee3b723bda22dd0d104adb68759ab6e1d187dd9c1673556f30d342d87600b103634bec1e861b78c8a276d37bbacf97decaa7cec63961f4fdd7a6e60907e6e9f7e53989bbf419846a5a2382277bf2c08f99cbc796f899904bbebadd5797bcb1a263e033e6beabdad4c92c030ea39e44ed9a10485538137de0a0a5b5ba6fda444d6d4beae0acd58e1496f97d9ed812ac6f6dc89f128e5ab4198844b327a1684fe88d182dc2a10250edbea64382c71642258af5f2a70c250aac0a181696a1d6dc6974f8fbb7c45c188f43a5d23268cc356568a2b90479f611a8e5e043f5be9777bb84e66ce7ad00e9bb888e25382d950721ac982a065e97fd3a115ab1018824fcd9702c504a6b22f5124eb633baadcc58f7167927dcae96ade0e8fe3586c37425a04f4be9fde26bd9e2132093df2275e7834dafe21df54c624f2a1828cf44308e02cdb3145f6a38ab4e05bd4bbee8d7890a173ba481f0bed5ecb820990e25889e12efabc750cfd32f24913a63c6fa5899226928a53377ca2b7ed438e691f0db3cf342a3675102720d8678399c1cf9a05cfc92b2eef51a6ea7397470d971bb3e5ed7eb7a02d78d49ce27c43b5e93ec612b30fd569d952a2cb7537711e3a332a15833e96fa4212fb1dd9965f4574483cb7f28d030ae9919138976dc855672c19ece9efa2d309f5417aab6c922e8ba3451600f0d96f2afc8159c0f32ff0d6931ee86c5f5751269bc7287bc76c1a650c3b48c200d71903e74bb9defa3e53bf81e7eb7cbc9aaf836397c955e3850a186e7f0b6ab0be07fd0dcbf94a6f00bf13f16f61aa34ab6c87ba3ec6a0c3fa25a3b6eeefc3e19a99623f1b81bfcd087744ab7e3c26638c485789d487ad2cd898e679bbe0aeaf6013a9d4aff7d7bb6fd49f9bc2529b407d6478facd9d7e0fec0d8cf9c0a60f8be6a2013e3256f3f357c3620c6e35c1e69b9d87283158a8194a471118ee3259e20b63381ec45fe22d37a234554043633e0b6d222af2ab9a35a48a1b29dcf4edfe0e155b8c0250da7ba77624d0881bcc30dee663e1bee307ffe7ae9fc1b128204fca8d250cfd5a44c6e18e69d61984ae7b8d35cdf5893189cb00008b10692769bc9875832d68024210725d278f9406105d06e449dbcfa667a393268a94aa2cea1cdc544c0e894059a1a86b6af08a7254700c032cd71f85673d22728cd38d502aa0ffedeba2ce2f4ff4b803664fe413d41d51e743c62df7737603c5656d6848e88f49f9cc801658e5c62102368a63aa2a108e8c3fb98db355a5eedee94c75838cf0360cf9262674a06c4c814b5ead62bbe5131282f90fff6f62f4b90d320730254a0a360db745f19a4bba79f4be4e8213a33a563211169541cc12679646a23c5b2a7b26798098685e45f86cc18526117bb625e8aa3bec00b56240f821a562bc17d3abd9d9e7f4028862086a074ee332a1376180cf0b3be836d8eab3f7c0d48b63c9ab86b807533181888d03a14ec891f7ca014e0d0fe40d67b59801f2d7afc38c9ca454aa41abc1abeee40310087dfd2bda92104597bccb8e9e4212063dc64a81d7fbdc4c8c0af8133cc4abb4d27a41165d5ffcbfd5d615ce2c609b817c92bc242b8cc4f64234ad482444af04cfb8ab15ef420685f06657357107114e0439fac5f6495ff086f104241bc58ef8788e9afb752a4b82d8a627977108c75dea2cdb47275cda4e77c7022a00740e1b93e46e102554d37f16f9a1c421735830c05ed201c8ff1c4421b6188da9cd84c8c910b6309f24a2fa50448ea7fa4d6a9b3c9fc8a39db6dd24a50bb8fa9651decd4a7069a68d79c241fbdfb73516f4b7b642128183384511b16e2ee179494d60e95a2c29381b35c89109a8e363610ca03e93400e3f85caeae9efee3afcf4391934670a670a690bd13743299cc07446aa6e9f74620af819a15b108659db376f7b8349013db5dc8592aedef5d2b85ed6ab66c2959dfee10390aea6a49e36395380690b3aaaad958bfce3a321ae972f0a731204367bd8e69b8f8e815b93c85b1a1ea32c4b2d1891c199b6fc814e028e7fffa8faad2114507876a09bbf641cfd3b66af7e88e416bc3ee6cbb18151200ac425156b72f84671f1d50123d1fbc66b3f8a2e70200ed2894844b546047409926822ca79f1af4a9292fba164a8b19c34c2a3da7a43807f008eaefddd3254b7db2d48b33f4f9e9e47f6fd4dcd03b55d8a46093d474b13bfe43d92c7589bdf1a990e7e8b4b243133bef5e1b6022996a9a85f20a4ea24fccab6e522a9f7406139de5b67003e9f5bfc8a89d512f2dbdb3fa2160661599d3000b6bfce0a69fcd1224aefefe6313e2281b5081da9b21f3506869d1e5c2430cc3c69b98c5aa7f4694089efb030d57610dea7f4000328435c22733730c4599c9663f7671e453cf9d1f6ac1b5c2202cd57013f429df79aab7adfc2a8e82ce6b8587dbfc414e0056e73ebb7133d8eee195a5dc92d27c7a3e9a0bb9ad03d4ee8ac78758d4d4b4adbaaa5942ee2304333ab6d651b4e0e228be1583f3173a92f609a3c769f99d27b5d676196711dddf82bb4542d8f1a8c9e5c9a15445e15fdaee20341304a3d6bded31a1fbcbe74d261747ba5f831dd00f8707bac399e81c6da3fb0101f5741fa08a4c0e8721f0ba4d2177b8092d38f3c8cef56ea232b4c7ce8dd1908d6e063461e01a1f6cf0f88466a65f465e8285aaafbc304c7437e1d7f8b177aa10f7b2ccbc19a7b6d34021112fcd2e1c5a9e1020c1316e637921205583698b0388d11054117eb39ebd087b214410c6cd530aa4fbdceef1353ddff24018d7867c2d85121a6f3166a32e56d340225ae1685c7262a0cec70b790af447f8243cf80b0e064684ac092fc2c47aec0aba2c8b6d5a9c24c1db8ccf15d89aed47a7002a6a332439c47b6c17a5d829ff0a4e4d21e04563b2e07e8c7fc3b4b4dc7cbcace99e33e76972310136cf7a2f4b8cd42134e6aa45904b4388ea4313be9957c0134e1a4942fa482264659b948b5101ac371b061beebf531917cb892dcaf64c0cef28fd90218fba40a9eb68dbc39b8ccb9256f985706f40d4855249af220c8fddd80e404433feecd8fad33b8ef96def0a0eeb4546c6a55def1b65eda6e78cb0ad09a56dee02db9c5eef26873d854f6923fd81445a39e352ec74a17495b32ea4b1ba7edca3fbd8737fd6642fa34f2a977c13f97523766b852cdefd3e57be24b311796dfe7dae2bf61d86e34297c9efb0fd22e96da253c054682582f53da29cde6bd663a9b8a4564b5418bb344b5f38436c40d8a2570d4c571e472c57304e202e90c8e28bcc0c1dabcda7732426dc3ea34d3ab10f658180930fe066fa9edd46a096829803c56515a3ea2bb27e96a4975d89357b66ce4298b7e2d60f9317449fbff78416860f22965935101b14dffc41bffa31b39c5193a4060b432377461ea9250ed77018039790ccd1466b7015e34154f77485446de7a6ebdf414d57db28c1be1bedaa3c04523779da3d4f5ce7c7552face3998974590fbd581a6c7ae74705148520147c969c3181680166e59b18d07fb2098ad3a3ce89690548534bd747c7f741680e109257e27343a15be5e169b0a5f5c640515cd6c9563942835992a84a19c0360a2428d26bb23bed6792059cf8b9d3db9b010654e17666ca4573626f2fd11f4ef162ed51c72d4300029fac47d6dfce8c0c91a81f52865e8fcbb1232792303708203d68e63cb99a4873391a284301e4720da12ce9fbda4131f403ba5509ab6ad0e0302a7aa34de5fdb8538237000a00345524af5e248d5c844e6fb1834a4b7f4065f2ab48f79989c217b7f99c34c61a1d1cb2ec0308e74d7b11417ae180eed07f3c25dc52393867a97ec800fb63f6ef13eb8447ace3e656dd2a58ccafa7b97b145616cf1369776cd4cbed00efdc88f311919b8a1d00824f1a2d23671980d161ca969d1bf35d23417097a56a7a12c3b6277dfe804d27439dccaaa80a63b2b3a709009dd6402aa9723b000092a61fc4f070782e6e087c13e8c3e5a0a1677b9b8dc0b1e9acc59ab46552b7653c52f838ef05790c38ac3f7a36c5d8d994efb1047827fd62e45e0ee57868fe551546dd0504f236d72dc293c0370828bb2864f594a658155181ea85de9787f0ea1c5acd38d9d0e76b6b5c3c7c124479647aa6b0d37228b771d43313b32083f3e13308bb96f01791744170b6ee6b81dba85e05abf4bcb054c53cc6431671d73195a5b47464cde405dcc728a4d5454deffab733d6cc2a576113cfa6936b7665e49ed6ec34b00f531d89ac2a32ba8743c71980feecf9e25df3b08d6cd0a0628f03e655d9c288b9b03c09058033d3fddcdef39b473bc6b49a9d0839ccaad41270364c425563c3153c8fc2926714b9ccb4bdb0a7efc6e5cc031356f7998f660f196e9f85a45dc0b2071cbe30d0c5496f07c68835b2ad18e1b50f922c12139dbb72ebcee18bc1a5a435b02d861e7350036a93056ae266d172a7432435c82852e74b9bcdda916003aa03dda731051c240f81a9bc709b0dee28cbd27752a0d5b2add29747c1b82d0bc7aaa9cc14d41fd6a5b9466677df6c7bcb69c110c2c220e39919f63c974d4a006e7237cc5c0c3005864a6f57996a843253801ac5ac8d71701c2a335e8323c1b75b219f4d05f4ae26d69dd442adfee03e25547a53c95251bc6c289cddd88f1f2a474c84d1ec059b4c4f439fd0f5978efedb79b736975bb6a52096018f4e9b078a1dedc50c080504bac1a899cf741f381f520f8ae06e00b0420c59998e31dc8191a694c32a577b12bef529ab6deaa0174b58349f852b67d69ad947549aaa41fdd542b18e29fbd125ad1f0183873115264ebdd26ecee15a38d27b3b856ffdb0b124658e674e7d1b18ea53e756e82923057612a410613fea5dfd0f722fc099fede9290914c40cfff2de3efa30f3e1900f55062ce411abb572ddee6fcd346dfb4b061f8984f9903d2c2d40477f1bbefbc218f451035a0f041f1123aa4dbd38a7c84dccfb1423e4d5da182d3539cf3c9e94f43553c0da786762d5c0dd1135d9dcc9a525f06157be4fa3011a4d7ba303213eb352489301fc9b34fd5f12c3314b63b4e76bbb8a3f88d2b8a670081a9db137688d6bc6c662009bbee3cace7568ca4e6f0af4c6a7c69a899fa4f3fe8a6cce270468432831d6836a348ff767577c611c083cbf2f466bd7c18a2b3666afefed49a450087f903b5e0ada2c98abd2755e9e7c9e0b91c34c4f252c4e8a8514d58d0ed63391cabff9cc99c9c15ff1f754b56a394cb6f3e4ef84096a27a0c019663f48dac9b0e863650f2e1efcd6b4452860f9c821e1a3d79897fa9d6c6618be4c95517c42198bf77fbbd7817188161ec98fca697494f995301878752f1c17f357aa20902d66994c9b298ea703a39d556712fe1869ccbeb3cde66d1ce00f8a0abdf8140da477262a9fa546a9f92198f3e1a1f2e92418e5e621a7ef609f552334b76631506baa4c540dbede5a6a6cdfa4c14088d1fb86a2571d896ffcdcf4e80384b0eb5f4f0b2321edeb553cefca4dde2eb389977adb25f8c7ac1d8cd2abae1e466fa9b43de66d702e7d3bff0c6c30e0896cbd1ae9a9b3a2aed536ef4ec0bdfa690cfdfec0fa66a2217e56d0d2352c218a4a2b4f96a8107ee8cb18870a332fbf6cb31f2308dd7f0431058c34680394bdd1f3486b55754963c3066b024c08992a25688b2dec96545d36db8234574924e88f1c196af776a9dec302b8573865608b0daca80e25c44029fde815f543ef0d1f9bff0636a30cf72d62f4829e5dc6690c7c4d0a566360328bd853a14d6cfb1f8fe2f5d2a3c18c622bcf1bf9ef8966692886078e2dd025c766639f5750f661517ba7f373a227c12bf0c920bc4dee67595f055eb7d8355b9b7a6b8ff4fc7014336a5e10e1790a1d1db9f86694836d8440c94fe0439841b01daedbb9bb33eb7dbb51cfb315a15d8517fb6f4877148b3c5a92e543b6d28fbc831638c53ee644d480710f55fd033a3ac32fa97f87e40a1e97b7f299a173856e51cc990ff49b95ac80da5b623cffea28807c862837920e0ef79377e6860bf6f4392738e91b1603b1750b060c8772939565c6bdcfe9077ca153511ab28bba7f29ebbbc19c9f393f48270dc81ba68d5e2b23e4dee505d4d30e96dfe1f1ed02384765ce4e27168f3d58463e7974c807aef7aa897eea9871edcbf451a06fc771c5e28b25592fd2798c2197a1ef599c37d29e6572c5017f333aaff33a7178bda2b093c9c13556b362ad8e9dab37df53e3492925e6e3caa81b7fd07a62274bd3d70e192baf3b273402f76d732e1596de387abd82b0aae69e81e2e1cd46033cf138faa5ef6c632b7f26a213c86a652ae0b4a4e67a73f798a6cdff900cf18828db225481c8031c97fd5cd467ec2b2dead12f3cc66a4314f175bcd75a5debd1728da766ed36939ccce3276d5c615c3a22cda53a17310d7a3606a5b48db3d6e26090d76a138c1e67a27cead6ba6c905afa2fbe929b125ca3c416565c2e6ceac6b60724d02350176fc97718d1101673d01a6336d6e38c9f8b52714cc2524213d74c94b2ff7eed3851af1be683f11ecea6e05fe9c36789f4915c659bacb8120c4c32daa726639506c5b0cd23c8921669d0fae9010716e7d862e42df848e79f25018bbc2c7e73b5063ba7059f8d74a87bf57eb3b8a9e7ea31d195a54bddb6ba1b8e979f54ba29988fe93eec1607da50f198f4c328245c60d6c34140117c1861247a040e39c4eb9d582bb060a2884f4e66750a79d516382e9c644d6c26ebebc06fb62c817f73b0cb0e0ddd62776592bd4ade03c46855848cb19ccac8a747b6c14c701256e591e51f1935289def9756212dc0fa3ca265ed7997b45be745475004bf1b9fe68a674259580f8c86e64fa8fa0d01fa1e4bb239c492632727a5061ee65d8f21d2663909d3c6d21b8140bf121642c12839e6e12f8763afefd1badf81e14094f6861049d43c85847e9dfa4509600a61808bb76832cd4e70142c42b1781d3a0e39d9ed7662aa850d904811cb82fe9d68cc2cd02c1d42041990c958176d39ea82204fd06e6bc61ec2340f823f0e778c55ad40c2520985e1953509de311e6fa26e6eba209247f86ee5c57a1029a52e293d85e9d3b6f83d47eeff6778f21aaaaceff014f13a54befde39a6b7c9adadda285a8ebc9863e8a80086e59285536f0ab3834f88523a4adb697a5e0982c0f7e68af6e223c2a8343c0ad277c64c5c644561b46c59e126f3cb8a9d413257814def7d94abcc7e1d28423cf62407b58f174775fe98e8d4da8908c2420ab92fbe039c4fdf99623b313357faffbc36ac92d198e8ae29ed22ed29d326874d2ba448c162673b5897b645e62478d17d0574d0952599518abab3e46f8af2ce112f3240207fee34a7e5cb75e4da310bafb015adc297f57009f1ecd3915a98b9b5eb726a2030d8c99a592eb272b4100e792302f9339c39ed7c7d62718c96b959b7b14b35ea2d45edf1ea041a8124c5cc0735e53efdd2b2e8b4e9afceff953bc37139d87c645d8672c9d0a2e176df916d14b492a0b07d1f726409e69bcec0f8355ad6d79be2ec8e9559f9afcf48d688360d67e062f2e0922065437e4540042643568f448ecb38342d85cea515e6ce65ce00ce347c0a47267ebe8eeccdd4972a4707f3c5500114db3efc20d40322fe9c617159f31e497b0e9e6850a590dbaa8431b4e838fe9a70ee93c583e6c0763a6bdd9d330beb5c3c8f2b940b83462a8178233f0be533c20120edfca154417df3c3d1b3238e88fe8a0d71438f06631b85a894bc2c1215cc63d146682145dd07d9842e57286571efbb7e69126b6e00f96430baae0bf72ff9fb7ede072f32826744f4064884a43d9259fb0c9b8e05377c680327fac47a0048434374e5a365b12d26c988a45e3806be909382d234515506990b7145fbba2b4b9094715c7c455297d7d6b1c22f57b1d4d645e5f6324b12d5c05fbd6920182e97acc63e6cc001451d8753495f998a01d4d06f0043b78ed62f35ae13b52e17ccdc8e601fd3333867a4addc1eb4dbbec70793892fa7081291ebb55006bee9a2005849453b37e8c0dc77555281645a9d084b3d861c99278ec93b2a8eaed4d52ae31dff6cb7d81de834a3e3016b157759cbcf679df0d59d8b49c679bb2478ab6cb2460c283287f8bf44afbf8adfe53f86f1a76a5a713af8dc6cddf73fdd4fe0a038b0fd2792ad7f1120597647b5f456a4d2fd9ef71d79b0954cc3ee5a5d558b7a80ef937b57791b2e086e0f9358ea1012ad2e2410c2e8a8c19c3cfda8761dcf11f5329ac570d2ba7a0a34e60ed91f912699d551bea72a9110d5fbc8afcc54649a9896e18df2ae8cb55b532293ff06bb993c682295bf79e4505a7723f7846880d4cf51ad04f265ec6c1990746bb28deb667e5cd434488dc15a1b22748e8724e13c58e72be6288885db914c9c3fac41214975936bc75b1b080e1e40d8b489053e2422ba48af9ce415f9c28a2a8206429874c1b6cb4255be051b9f013b4e928a4d7ebd428d221605f92bb88d64a2f417dd85b1c154255dda2e074e6869138523b8331f261c128980ebc3cf6199236ee3b3b4c4c9b8168ba2de84c57ae39bff670fc2c09a6f28ddabcf02763f0990501ae20a5678ceba577bad7453a7b6e77d2018b29b4533520faaaaba128fd3c467b5562f6363aadfbdfd21deaac5c36d36cb1442816dd62cc9930cd2edd21a8e479b79d949a57de00413d6d834c7560f2621984f0ca548dc203817262aa60686a741ef362cbba4013d2aaaee0844b844f0c481becd807c6a3a0033b3e8652a903626b72ff83079b0e443d9bcb7db677d4707e9ee033a5a2a4e09f9a7aedb3b32498895262017be921e39156b08629a49d378c1ad16b10d891ca1cb31910d9e1e093c7ea4c8a456344770a4825b1367d782dc8bd9a17a20fc6d84530814a6378881d6e63983771ffe86246f8570df2a0808191c65f051b3e77f9ad92858e90c80edd4f838e603e1877aec24cf4a1d309b39878f3b6a3c58b066cccb78685baaf1e3781bcec2521f9cd5860fb5dae810c9c3d8417905fff80de3e572cc6920cd2cb8dc0e0877b81b6b8af6b4c3142fa9afb404516de310cc9777d85c52898cdcd319010cc506b3c3746fa7a43c2f59f4545f15c253464342cf2a85fd28ff1774688e72361337715f83777d53e887ce89d58a5be3e7f09c4779281f2c0246a65951d8eb96a11ee198834e575efa8ffbfc7e123920a725aaac51cbd238c94446edf751211508017284dfb8720dc5077a73961418132d4dc0572c5fc91f081cae5e5e2848aefa18b0ab97003eb1552bb6d9bc55dc8f3ff05a19bc13931465d50db0baa6a2058e8eb9718cce408348f865421d94d4e42a80d100606aac3a15c731e9589895f8e9d9707bfa321a347f1f8198ef27a4e8dafb679bd6305ad7045f67dc6989feb37453c2e1a2e69e8a41ccf6bd6aca780700e6c020903949d03d373b9dc84a9ecc6015d502a0838e36ae616f253aad0fde65864bc391ef736a6b522beaa6bb72de5618237d6ecfb2ffd1499b71ffc04d3ddda9f1578bbdbcea1309d2cdf39f1c5e9beaea8a21a2dbd315f589a321b6381da9384658294c4852711cc3d79dfdba6df5e1e5a39b997e0fb82b836296a572e92fac9de0f3c0f84766370c10cdb4c1bc010aa884b1e86479d30e9a94a19c24cf736b776895c551efa9b145f712ca47fe7071e72efa0f8ebbadd299b50c72c8c8568e1a96db689c11969e65e210e8461171a7911f338708fd49671788005032132b45b65d95ab47ac3367e19fa227e680384e77b9bab625ab627c0159a89842c561ad6ff910bfa464c6f4ff1b4d7c06dbc405b7e60a628dc43474830a6fd785ad95692eb4fad9938ce2006026f18bfb6c0178d8ed74c68f9709cc10e2c02109bb754f64971f5aee55381f72fe315044b95caee39b76fcbcc6a47849063d1f0ff5856d4420890e5e68cbe2fcbe15f4e6b31a88b842c5d8b9ca9a77cb873046da66f090978643b35a54d31ef35896e5355f840f99956a14325e8fdf1c91b6e1fe3b4f4e737638ea09a9135dbe2a0e786c161616b774e331220f48e4620aabf686834ee6868e3925052c33ef04eb8e47f2aa4ac4f5b4ffc96edf1769517df6909bccaee73f3484bd02290d593e38c11e2b4a9663437de85d850b48957f3cbea5cc4326aea0b78289201f4f8dd92a31afb65b2f67e3bc70d6cf9fde6870320d10662b9b07e36ad85bd93b468ecdcab55c476de504444b244b64111c781ad0825ab5757af6a62e6072e560f022130247966a31ef5a9a0915a5300f365e29f2eab824776e67a6a690a10e23982e5019ff5be7575cfd1a8a14dcecbfcbeb5eea75ade4c59e01b5205627df06e886b80dbd3d3b94967b3ee165149c7e1636f4f51154fd195203b279078110b89e5a39550cf5148ac79a42378546329a8bd6dd84761794592571bc64cb7bdc7eccd0aaea5f1794526434fadc0ff96bad622c92f6e2d951fb2b4fd8058fce2497271989f5bcc9a98bae417e4598a98a2f958614b3cb9b5e7a7c59c3505791e6ce5ef948fd195ab85c31fee812519965450d5b0b471fcd81911378e2711cd42f16ab9e38dca7cac51b2db5421c8833d5a891d4bd2103fce5096a95e8372bc8adcbca7b3ff82e6d665e88c14dd3b29da9aa7292b6addc7234754ba1f72b5d49e5cc5edd854a3d9a57b5505d4d596826b65ea62a42fb4b0b50bd932105f5a71d1a19105237eaee23645ff0e121bab6635c5c045a159adfd0f883004b09e152cc8feca5837c02baacb3bac4878adadb3ddad0853a50224c3076daa9fb96f8b3b48ad4648f2a21006c5532732932e10c5d58fccebfa80e6226a6749ddb8a17de0bbf28675156e2b57161ae4ac594ef58d43f7f221edb64fb3b9723d63b320b26af9875c1321a228fffe0b1db31bed3ac7501028bf5f7c0163a67363e8421b74559a4c32c85521235ca5e2ff2b2015bcf9d0210e3f02564a22362e8561eed487f5d482574146d0412ca635f5a684096f49184f9181b8131cab661b2dfeacac3c7df85a9c7dafd2a50901d3053f80e1cf17a113de67c2b1abd79b924adeff4831558ce167fb16fc81615bfa1764fd40944f75c9f730671e1cf7d05385fa0d0526dcecebb6fd7c5f695a7d1cbf522d594be07a6b53f13b8e5c7cd5b5b30daa0be8217685381f3d4872c036a74087c480c139089cd0b78d73cbdca8819771603c9ff49765de53a0b6d114e0fe626e4ae1bb43021e3075a876c1ebb1d5402d27e93090cc076a194fbb4ecafa69d5396a96e469784f73487ad758bd0591494ff7771179d7efdbd2e74b51a229eb45d929d5778707af1184eceacb3ad0bba905fe9fa9f53ce1273e4dc85644945c31833df1e571b93960c23c9c53d1d9caa80262e340adaf76bae26187e6f3559d2915849a81b9af8a3539d099e90b13b26317d942d3f4876a407e32aa244e00383800485cfb1ff224f039dddfdb668d9dee3b5c96162f63ad6efd30f0e44f03e8652a31b3d8296b927fe466959ec3c2e2b34635d05b50eb2fd9330729b87153962ec2dc3d833400fadcc708570a804e2a4da717604e6a6f53424b7b2fc6b081252ea91ec9b2a277a4124f208b71fd12026ce01c4e908cac440b7454fb532904388fba637d4ca45f9cf8669bb5d8e11c8cfe19a623601688b7f6fe6d92150fec951b80ffa2b6fb7b02a4bd995ea5e1376c21e94eac66082e50a42fb236a843967b0a79da5b6ce9b85b6b77bf73bef2eb2bf3734728cd2b010548668dccd48c9ee5b6ee16532c5c4526b8a26286b9509794d77cb9dfa4af98493f8a78535dd8a7cfa99e1cf1cda62c19ce026bd3f61813b796b95cced538c543b025a16e617526c118669fc5e2e34c139989a192fd130c653c74ada9641ac2fc24ffac25bd04516d5133c385bdb18427864ac284f7ea0e352ae1947733a6a9c0086c1b005527601d052dc0cfdd840a62c142b6d3f08447c3932e286b6724040523522630dec4bf960873efb513931cf1d883db529a9d802295dccc62385b92a7b3907793a52d502f83b1aeaa0414724811d50edff726a4d30a5fbb8351299952b4b3326ccc0094924d112a1181386c36955067e46e12e88412756c32ffe2a58a788cf8da162ca28e3114e8dcd0693ba16e3a43dbde04bbbfc3d105c78861bd96e7d5fc985f48c212babd94a946658ebb857e664cffc48ec77d3a3648ec28c780f551c6f9202741248bafbee1f1c883d88446218c670e7f7bea6cc9aa0b2c3207d5366766f2e4d404898558f71389541f06a6b8b0a000296b1c4ef6f26c0903ac2d14155c67fcd2a4fd90c943bf74d7fc11e1e1db9b0d769fd9ebc4e32f93bdc1e6759694f464e6683a3cd8ed16c13b56c81fe54042b0ffb722632be1da8b5ebb31a8ee042ea75f36900facc3e143c241d8c50023ebea7e0dfad52cbbd8dc5d061ff1af2c3ac0efce6294298319c92274833ee5d9dd72edd8194dd97b7abd4febefb93cb2bcbefb86a83376b79321fd05a7fa2001b9b0565e3bc0491d29074c59adda35365e31bb1cb1e2e0eb70a1c46f86e7d583742ae1d60df4b6451fb18170528e586b635c5aaa6991e2d07d9d3a80128f3d38335c081cb19cc609a81a13cddbbb44fd135063072fa35026189f80bacc32cd6efb71c039a8ab77c484db5dcfc7ebb139511c5e6c5644424be529341536acd300ab5510cddd1d36471aef6279eca02a01c0c4c41b46a8180f2c4d140a8c7adff686bbe8288352a1ffcd6c2b4c875e00a95b3732fd259efde7ce9fe131eedbb11f366576f1f68ac0ec7ca7f20c3b96bea4af8e199ec8c0b6825092536012791b446d63c7910a959cc14ca95b7e1f81c09af48ebb3e40fd52e4c088664cb51386dcbe90d3a280a716f1b3cf5585c3c82a14a8273b4c22c27536093d30fcbd0728eeeb7d9be80a21f0f2686804aec87661e99dc6fe01590aef5e810a6604f027c471fa8a46c02b451fa65945a60778fb1dd24d3bdc05c915456f4fb8c2bfeef5a4b9356ba231f0020214632265ed9a4ca6e68bfcae39be9ce60199f10c6b55361a9a2708840c3c4855c7f25abd6e6187f1f5e9bc246fa877bcb56452e6db867376cc5667cad6eeb84ded5b7ba8288150376349c46a06f8baaee57ab0e1bd6f6eaa1df9abe263b30cb3c7e1b744fdb8646bbef3bc31dd4560ee8e1a9a10fac44e1b15482b0fc273f22af07d6bbea8670fe5b3f593fab1b56870b4a5d8901ff0b6e7305599805103b919b1cade4c56e6dffe7da21b6ff4869f97d34b898f8c60b3ff9da28257b227c869a60a10a556e512342175b4f58fa4a8101fd2835f07d7e80e6f921bfd61397da7f1b5f0fc5f2cc976c1025e711fc92d707c2a91d5f9aa12a38f046e472e5c5b448b3ebe477003656999ebe7555f4068feceaa64cd55f22c275ba66ec38e52002b66f5a0d0c4ee8b94cdaa9a6c746f2076cac50604be7c230cb5d867d3757cab111deb05ed1c9144bbe2f1990263331820e2964ab0827e8b9aaa2797e74b1fc6a00835510ccd01c3b07d8d24df72fa90054258f20b764c3c24712796abf09ede4c66dd53392981a1e9516cf98253c9f9fc578e1806b1076386731ef151529988961dc0266b86ac16773ecea6bff64eb33c93d4aebb2d28c10cc7a83af43b0c9704c62a63641b1be5def597f4f15bf6478fe59e352eefa4dcdff2970371b1ee8246e3546eb77f4764f2f5a7a09e3d2403ac5d696ed30eed4827e1ee1e14db2f8bb972fc993709f0f63879b0bf45dc158e29c74dbfda0f0946b4287558677ef5a2a3dea05bb7e687980698a6e5629c31f0381957c529f2bc91d761358b3b1672e9474d2fc7e89c76dfacb2bf8f36e9f149602ad2d433e332eba93d630a5ea128188db80ebcc55c006e86d71eff8aa8c1e38150971465cad99c5123940a7a5c9be5531765e5d4368b02ef4ee9f173dd15f94e653edd0b208a033c6dec37298a9121efdaacfe4e896b6362f12e88ce77d482c442814439fde1caea88c0d39eb3c2573e018a8eba3779adf9c8641e63c1009c7f57652a706ae7aba373d8feea4bd4c2a4e3593a40ea159535c0b229754a338e69f163a8b187defdc84240f1a0e9c2ad63c54333b483c0c040c70c0c0eedf5e77a1e70240ba14902d79a855057d18b378f986fa90a810c1256988b53a04cf5b9a74e0ab5bf097ca295806e2162666590b842ad810fd374345b7a9cdfb6d92b5a49949574e549c83dd43219c05130ed98e356d428a0308a565cc7185a3dac1ea3df615da7eff637f1f62f6e72dae294fa9d0c499719431182d78e5f9784c3ca6196457d5eb3def0fdaa932759517a976f0f0e0ac04241c03aec895a22c6ddc1e37bebd1537fd45a1caee68e5dd59c551e4b6ad453ca17b92040637f79c3e74ccbca8c14d6c2a9c989157b95e0ac9c617f9dc9cf2589525b3de0f21ce12e9976a0ac6568d59eb5fc7d824d9b2855328aeb3f4468880019e3ba1c9c352ad47506118da5ce64b5e91f4d5f81baacbdfac3eb44f85657893cafc8c9669b93817d73aca887fae0cd14e2b87372a6e8b5464faae891c5212d102e58293177c4359aa2f6f92d2fa6e16254f36aab29609546cdf019731be11e554ba3de3390a545ed556fda788f92d93976895e170a30ad743a04b0ee04aa9d3ce543406f69de31bcdb4b42e4eaa1578a44a085e818dfda5940ef88d3d086a79d859baf5d18998f088a44510f095656f82192124f8030a13b520da9186363156f70cde1b65267f2068afdc22d2ba9e4f2116858c55b58b1ab47cd424b520869fd95e8ed87cc0c80abb57efa6ff078eb3bf33043adaa91c85efe3c3dfc3176d8535492005499491cd5f1baa9000d31afc7509c87c5cb5114721f4de152b64d43f68c3e5c83bee1b9328333a23bb3a766a65193f93d6dd40f23fbb3adaf2b08e1cb009b0881d1990d2c09ab6c5f87630daaf59c4ddde9d5c1d07f4f2905eeff24e9cc7ae37cf7c093ca3b56107e0f1bbbe8d3fd82bd4f452881d95b211b8654f3ea235380ebdec954dbc90e4436823a19cf134d8a649a2bd1a27144a2421f4ea1a0af3dea00cda7bc58aeef45ffceb1b2e6d81e2113a136771d90860a0cf870990b2e2337982ffb3d92b9fd379305e423a4836313c23e76ee21e3aa866a68f3697dc45115419746bda835f942175408fc3e09fb3ccb0dd2ca0196995290522814d02df4f578bc800774cc6b80610a3a7c53a7d85378a41eb246e8bca98990ff7f60c32d64c9c372dc224538a224e25e1ea7c85cb16c438500615f6ae3e5002c9cf343ada3d99a1327b38ce723e643c0fbdb534edb614480c3b9f9a75782f3976ae5db2ec2ce995a12cdd7e184d647912a15bbe7931088062bfb40131a2b30ce1deb0bd374822f83ae2ca4a3aa6f01563c8e96a180d4b2cddf65130418091f882a00004f277d1c11f34f6bc0ba6b6f734c0dcec8c3c22e740818b2efa26da1758785597312f7e6cf9f08891774aaa59a6af24aaaba816a23145edb362e56b73726b8267031210d100774dfafa27f8300540cef40fad748eb0fbc67dbf7fa84767eb57763e3db1c76cfee37ebd217d777b60e41b8f9fbd47565ae53fa20b65cd143c1ed8b05dc8b3379095c7c73a60e0d6dd3206c67f1e6dabfba3e446317328f0471376d686f954206ebc24a2ac7988351fac9e1b9e8cdf69d050605f7b41ea6ae13e47a89364e7a0dfbe4a03ff35c9e075759ae75685237b7eec213e45b934c60a98c84d3979c353723947133802933b82e98413e719e7930673c1b419cb3291583056c972980e8d538e31b42da9b4d2e4832a7761e5a4ed6fb47b94a506ce11e57c079d09668f15d06be6d0067d89a7921e03e0b9c5c5f8c107babcc24649170032356c8e9fed99db46287c2a945a2fab1e2872765a27be6280ee038418a3294d5d5274710d2bf2d3cd744fc7558e073d0ef9eb351f15ba494ce7f88f8433a019b7d4bdb131e309eaef129eb7e9cfedd19965c36ef3b303add486d2bceeacc0f3f8c0a409a02c2d8c380dd209257b87d9c37a767c75057efd4a58fd2c352e4f3d61c616a9268899e7ba5c66b78eae161dd52022d11f3cede7701be6d360a6871106a5cab04869f7c7ead40b711d40fd27247d47d2e3b544452f2bc57d0a2874ac672d37cec4d8f75a4ede71ea4e9b64ddacdb0f9a1e404e554cfc44bc92894d48cc0dda78024a06cc72330ae0260ae83a970fccd5ecdf0e118812222ffb7ebf10e3247fe6653a0d7dd063b6ef2619d06e2ed20245490bdd2591b25a487c89899d32cad3b732aa26885079a9df30965ca0b945b36acf5b964f45f8bd822354884d0304ce28499a70dc20fab89c442a2b131cf6fe33266d4a31c0b8d30faf9376665f632f8f71ec4e25e5637e006b9aaab385fe1aecd903b4dae19dec6ea0d93b467d25e7b25d56e4566edda8ff4bf572d27d67686d07282bdad6e4f8540978dc07aeb98f9479dd47bcbb3890631a0f33057212c16365a5a81ea8bae8f7a89db7a6c302ee81a3a8da20747d1526d288efdffd9eb10c2acf5f6b9b9f8fb36862c83f6f16d1b28cbac4f7ae5272705633fd03f33498514e6760ff32dcef1a85f9c37a582243751f30591c103006518ae25c7a6d0112f4a0d69f546172a5ee65583f14c1c74d787359d9c7419f53604d9fa3929989e6105789f1f255752820005ba586623296f3aa9c3a1e0d18cfec40b23a52a9d11f2021f327ce6da0087dc9819bd19e67cfd0fea8d8fbe5442d50eed5ce97cd3ebd56ed3813a2bac3668d05fda746ec2c8dad991471dec0b7d30a4344eb539bc700de052d2cfc0fcd47ca992d5b3f28688f45f2df15e9b293efdfe008b6336d342234a177f2c3dfb5c8b4781090f99490996532d658f64e0239b0010a2163e7cce3016932b30d8dbb0d8135b19b261c6a9359a58e8166a9f09616db506bc86d0184965e3640f533a4af4eb26bf6afbca890006844d63eb8e528c50412b92d87c4b8dbe49c94f7534f402c742ce548997c05a709b3a48312a636a0dd0e2c9a09849441506caa798c63e41a331866dbcaca449807d39c450debbc852d928fb7b2931255e53df4496bbc52d064618ecb642bd55e54d8f9b8e817559476febe42ee9ff65c6e9d98d778b01972a94e7534f6c5fca8913e3cfe3af718364353252d4148d9838ae6f69e5c59cbe5e05614bc6960b30142baefe9e76490199decc46eca160ad85b9d96ddf20b2ca546018e00d9a80c5d86045da7bc7f6349e6c388f738040f907fc0c4697294acdb7f7c01411bfc02f72dd236d99225cbf2a4344a6fa2d11d46a2866a54add624335c0a060c8d57c167a0fa373493c2d5a95fb2ba3d4ba5e6dff79050e502bba74c0c75543d146d9f80be2ffe9de44f4a2a2969951fd806aea6aaeb9ef0278de9cfb6c22be36b18ac5da8691ae05213bb062eaa43b0100adff51dfc0e712bfa07fc59f6e30f50756ee209413cef7604e1d815911c5ab5383ecceab74a7911a0d1df35b4d386411101f8a9e7b13853144f45cc23758aa943bb1d3db453d9fcd34bb609a1f028e1b00e50eea562ab613ebb6dc9cfb22bafc859d60ad6c836dc93ed17347ade25dcbdd394b1c0a46f1e9615f2d6ae234b53eb9304d626a298faf80f5e79f72af4b873526ebdc672be9a55dd7b4b7275febdc40edb307c1c719c73722d95d5d01941f8581d3e4de14c31232c2cdcfc152f6dc6152a5f27dd6944bef446d59dd462323796803af2a4331ecfb43a30b468a80f5059f31267c1687cbe50315059c6c106f4b0bbf01916ea0978cbe1501e7068e438526a7bfd0dc444565a0b00971547f83d9c8ffdbe773c2f21f7c68c877efcba7ed7c5e9af8af86e63bb95e547be5a2ae3b88c88c4154725ff9e3b51f91a2d77b756bcb9fb10979cee83d2866e18afce6e67e689e6eef9ae92a82d748f16a7012a3eb99ff7cf457997c07babea4b06f520a5d3e9e0d37f5fe96a25b3103e3cd6fd5623b86f09e4fb58976b61284b1d823d54e3449af933fc86fc52d71f7b293c5b416a1826ab595044adb356e11e9e77f2ff4bbc5f957e580c1670f4cf59c388e778d06c7c74079d609f2ba8f0ae6ef4474057cd3f0c7b568b4621cc411e2257d151fbdc19ad887ba65bacb586a4327edcf3c3a2181767192886f59f45b50857c027c9a709b663041231a650d48a9783ff339656951573833990e9c64b03c67733c2173dc7fc98b39cd1a2b4ccd49351f54d424c79a11cd146fd870e115b8949d9d486ac043be6306aeeda1ff3a87c66c8e133a5c7073b5333fc07b8f50974cae166c04004967b7f93d73d4bf9928342aba412142dcfefd1385731df822b6939a8ca894c313860a6c66d8c3ff85d7eecc88b7c84d1e15e3276865312d4ff3f86161ca4745a66485701a1c4d26c7aaa788de313f27c1c3118bddb14d8c3e8a873c284247339b7821f9b707fedc6cd76e1061b38f5b11c9c047a46dad36c8a5d3a877d0a161ec7048e09944f680b992af4aa220310ac2e5a7a0c78f7936e11448d01677f5973b508318466609177d6f2a22ba3354e6184b1404317a94419c53597316386dab74214eadabf9cced945a763d45333e5cb702d057bb6d9e07846d6a9c6755c6fc5713533ed4013829c4da717fad942af0c5039294113e9d9202545a10232e7f4efa3aff8bda4d67eb7bbe2fa1c1121eba58454e8bb99c4e7808d805363fb0a3bf2f69d4eab86eaea93de9588155512075ddb21aad4530512334cee73ffb5ef1f3d7bea2203f83f8eaa958064861d2fa0cce2f95a8cebfab6dc187e30f6331bd585b75729fc3d9a6182f46270915b7a55350177aa8e4a6386742235f028b2cf467ceb5b81efad3ae35e146ee72ade5c4b1d9fa3c9345c7df0dfb88272a4cb944b74951d16d95c2a088ec789f41f8f0f9bd9d744be0aa1855fc8b9e13f822ff1470c64d7a544df9eca5bb89126376c96a3197e23438eb8ed0d5e0e0d7e2d3ea15ca07ef61de8ca80a2900162b6a99790a5d0dd8d8a0d2efde3c6e30cf3a86923de2199d2ee34c5f7592d4975bf95abf6603fdd84c591ef716c03738e0ef4ff6f89ad2913ae440fa6c5a161fef60c6b23494f70ff006ca6ea78708767b3bca64700c2171347d50075fd89565116114231c523ca46eefa74771ca433a53085b4d7007c330062ee39d1f468f9d35afb391eeebaec2e768c81111561bcb82640117a92d00fb2262336b80b963c7bf2a0277eabcc58f8d7e1d6b33929329736233699ab8dcddbe9af8b16f048619962d7845259344ebedea84a097694f6c3057520aa6fb860b5624ecf687e9cb33bf9d96212ca054641d4cdaeffb3c6f74c8f67874475ccaf35ebe44a7fd664a55e207f22232b69409d6e3789e0aef5b5fc5459feb08a03875ca6f55d75a5255a62256512082bb2ee07488430975eaa8a86cb5d0e1d54088f97cb57a02767037c8ce217f0b9ddacded90528d1292dae5287270b9e1ddb8753006c350193d2ebb8fe1c2f7b9a103fecba7a8164c0220537a4345b88a6e6909c7c50ef8d7e1694d1ff484474e6c3a0e6a58d5c60de81dc8bf780bbc5f033602c1673db46de0a299955009937b5ce686db9273fd4bbd77c3c95406a0d2b90b45e2ba7b17f3d32742a301684d6c7b94689041dc96199dd7789d98c001a5a968dd15381b5b9676981195931c812d5a7a150313e78047d81e9989a0e95512d00c21e26e1d4c0064c9fd14d33bbaa8615d23049543f9dca4cb43d067cad208ac485ec121e305938077f0d9602f09b4cd9e39c824fe014233d91a5faa7fa3440b8a446ddfa5714c0157a979ad2fba1056c41b4da7a81634648c3cfb158ca10490a25e260b96d3f9c8c857e7220e781f2cb4201b76ef0c172691e25b70df7c79b811c2125d6e4aaa0189d980f34d8b8de673aa3e838d513da3f934ff85bb14b7e49f9ed4fa06a2f39a3cb959cba50a9a16ce8361c1339b4b501f063f218d30b0f27cca2ac2b66ae53dd7b972c6d7142d2be0923aa0e527cdb3de253657ea56ed44a0a20663d632e6d6c7633ac2ed80015bb4ffd931c9390da9a87c3a60f334f9cf7b6534b6a9f80b30da450e156857b6f45f2edd7832c29e60e60cb7040c6f863145da5912deb606ca1c76216a89fcc485233b7c4dbd6f8315524c6f7d2ac7d6a0bb395457f12a791f571a9b4b15e3afddbb661e21b5cf65fb0bf37e91fb768c8bcf98cb72aa1b0bd21fd8cbd0df7934a9886052a99e8d9eb9f68c31300edfed291905facd2e6b4c5d8a2297a6f654480034c3bde90815556d4b38af883ad7799d0adcbce05ee0164aa09e1635c3870aaec5f612858f33d913515b0dab5ae95d58410ae03c04cadd73d736b12ef65b21b828cefb41b59d9ef2f838ddc951885dff8453fe24894b8135d154ca63ceb3a1e9a2bedfcbc50f9fc220dbc76024ed5bda18cf088e2d2092faee12be84aad64207e7539d78eba2a89a1feffd794642b05b72c81f3a494524b3dd018b3a8ae1514a9792da5b13b8cb3167dfd946dca2262b313354776dfa2d2fd64829cf8df4c020c79f0885cd2c5cd4f20fe91f2aed6b44d09b9a6f6b7470961cfd11653fee84a65d86188a97a757a90f33892aeba46d02d9f0bd5d4658ecd8a1e2d3a8aa1a073af2cfd8887bfb2932dabd1d51d07f94f62da9d2fd0d2f1a207adacd8b4cd3279f0337b2f0ebfb3cb0bcba0c688ad7a8df98810c16b59377dfe8e4ff2b1004723a433baeba1686b2d750748ce8c9b3c94ffb07144524c698d3c90f09200776326b403fcabdddbc353870c4e5e83e8551d62ec632e1965e425970367b0de8bfe17f06d418f68717431b757397fa3a83fa5452866a1c0d8dae2095661bced14e135b0524b4a3b5516cee1b9e6da608f00ce9d37eff2806cae77c9a86b31a6663338842b2f038210417a18621fba875409a57eb1cf19266af46e69c69240c0a47a7cbbdddba49509a2cb2e6cda628825997e221c8e10249082dfb30e8742b893b0701a33ef5a2d45169e2d3c3e1c29206cbbd105e37d2877728d582257bcefdbab2e9bf39d811f3e9e4298a5810c59084c240a6083a924ca76805a39e5b2c7944bf7c812d5b9ef7a4d16bf71deb1fdccc5583ba07e5d8d81d6021b8930d82f666e93de8cb82b2b1ed1c9807acd408a5e868a80c32eea6882d7bbb2f07360f487d51d88cb334b576d7a826c667bf10092d3297c6f0254042686fbc61813e9524a55d67a850a9721573c0ea24022ee75d344fd2ff7212c9e98222c4e87c1f21e8f3fc0552da8cf5631e40ead704017f10984a3533ff019be0929c6e7fde15ae9a1c427b3b54e983cac16f6192370c5952492ceb081f20127d6869a58107c31d6fe55982064b6eb37a57043ef03c976ab2fa8e43c5887494b61585eb9d461690cfc9db84716d764575b254bc3559b7f53f24d695893e14f3223b96d9245f1ff27f95568b028406e490702314c5029a579a745c505a51493af908642f1c38aa151b37806ad1d1caa8ed16e05d21c1ef8a30369112f4d72028548e4e62af311445f4d39ddd29c2d783d89e3cbe8b04151b219d6a5bd494a1e19cfe214696ebff6385f26d2b898d1042c8267bef2df70e720729070907df01ba6c0dd0650e77f239745945da9b0274d912a0cbdc0066ec0d968fd165152b48a6cb36a6cb1c0e5d2605617918948f34593ea62edb5297b91b7c7cb0fc4b903459281bba6c05d065ae860e72e9202c2f6fa4c99a81d1651b802e732d37d60c967ff149534d491620690240972d0d5de658ba4c4a6179efb33374d97232749973b1d265155c4f9265479a688b2eab90ba2e93b8dbc9bfcb56b2e83297327750baac82a7ceb592265a2359e44fbaac425ad16512a7a2cb1c695a932e5b2e4597b9922e5fa3194ee2e68eb963e4da9142cae7fa8282466ee31177d95c4b5c3917eaba091204b644a08b04d7e99a09cac911ddc6dc670555ca47e69039604bb43741d0c941ad56b025866ee34c0bb228b035f664677878608b8f1656aa54dff40d6c89da6d9c61281f3b3a395040015ba23563b5c0b2b16aac532a751b63a92f00ad543c78c0961c247c3b3ab106b6dcc6b59eea0cea4db5a9354fdc802d51154510d04a06ae3a4df0f97656604bbc56b0455e01b2c863a71b601b408101cb2d6079cb088de76dd3b5922cf23986853b583e9b30bc46f242e6da8930e40b8cc9b3bbedb56a1ab3ebe68ac0f557f15e2b181c2f7fede41a707cc666b0ec28e10e1096360cc1c564098e6a2f30a60780216c0243d8936f808981e1b33659828bcf145b400cc2091f44f8f1e3c78f1f3f7efcf8f1e3870f1f3e7cf8f8beeffbbeeffbbeeff3e1c3870f1f353798c11ceedf628283edb948d28d1ff359436882b0ada6e10969c0f7228cd957428f428f7ed2493d3c9508c2d276673bdb032eca1738464b09ee64078a61be4123765d631c1ac0d1e2fc02cfd749bb786a6f081168024db935bd0e5d7bdbe158b6b4ad03ce17982e89c81cde4697b8d77c96e348a47b265913a34ba1cb969356cb5e58a66d21114e34777036425292c284a462c5094a0a0b955ffbe3ac85b6ed98e1026f3adaa32b714593286b39ae7280cb5127f6e84c064de6c69464a1e76e54c51e71472787035cce4ea72ee568938c4e9693e5d45aab0caf9586caf25a6badde6b85a97fadb55695d76aaadd6badb5ded75aaa28afb5d67af25a6fa82c5e6bad35e5b5be54d26badb59abc561bea8ad75a6b55f15a0550495e6bad75e4b5d65053bcd65a6bc96b75a9a3d75a6bc55e2b8cfac8a3561d01a8b5d65a5b6a9dafa257eeb5d65a5fd45a6bf5a14bd9ebeb3d00d45aeb4aada1d7babdd67a924d87dac2c50c30a6d20d2f3608a0061718016879010019566458a1a184c59b4106172b2d46aef25177575fa9ac4428dac9f7f3a17c271fc7228507e5448464f2d00a1524936eb591d891efa7fbbe4f4b6195a078483a5436aad809a79e4e586c82a3ab5bd8dcd999dfcf57bff9619de8e2386ed6cc364eedb8db38b356c89abdd5c6a1104f88be6e3b361d9b8dcc9527c94273608c9c386d92722621278f1e785bf9f679049499342ccfb30578fbdc0163bc6f9f336d9aa7d33c9d66cd69da40d1a519c00065264ee959862108c6a80869d344a17e504fa086a4bac482095066f2dcf02c9b1004c65c9d36cdefdbf9be4ffae0ed924797feed12075066febc3c4b1de0ed3207c69c7cbbd4d1a6b9da81b35dd67469c5b7cb1140194a63c3b32401de2e73c09814a036d1d329e824674ef2f4449750ae0065288e009e1b0b2b186302a44d14850a821282faf9ba94a2092843796a786e1f3c304605aa4df4fb723e9d8df4eded0228437f5c9e1b06787bdfc098916fd4e6c0dbaa75ecc09b2506285369603cc728a0803125aa36d5d36975023a0509e9128913a04cc509c0737c02deeab7c71e6daa2854e441014105c19bfcf6a80494a93c11066d798e4be0ed91078c197d7bb46953fdbe78f3a136d15f3c4713e0edb10450a6fe14d1a66aa1a0c10078865ac0db2900652c9a0863bb05ba847dfb0d186357aaed40b4c93a49164ac3333402de3e03ca583811063de4e162bce0ed2fda64a17ce8d2f5ed3260ccfc76af4ba1cbf03c03dede3d4bbcdd0594b17856604c7fbb6d93f54916faedb34bdcb7472863fd7cbb0c9b0edb0e9ea7162717279c28932551c2414953769a28148a27ca64a81b783e69c256ab6ff5ad3e4c3f7fa24c46f3f28329f67d73f5cdd53757345106fbb181e6244d180a75429d50279c2883f108000753ec8442a178a20c8653030fa6d76af5adbed51765301a17fa83e9e98aae3ebaa28932d70f0c9a93345d28d40975429d70a2ccc513001c4c2f7b42a178a2cc85d3c283a95dadbed5b7fa307dfd8932174dbc5ed41f4cedf7d5d557575f5dd14419fb03001a4c2d0a75429d50279c28637968c0c1f67442a12c9e286371a20c3c985aabd5677dd697f1f889329626c2985d971b67eb075fae2e5767e972d34b4f6486a893840c9d8b6ea56bd175591298de854a88c50945bf72b7af321a95158bd52aa3c1f42d4eb415dfcfc9b7e2fb7e307d9792a160289e130cb5024361281e4c7f4db014d809c331c14e29b0d3869d301c4c7f15176985d198ac52ac56180da65719b1d6f733f26d9ff5fd607a162516c985e219b950db85b23a140fa64fa9555e17ce75ba4ed70907d3a38ca8c8ae2e9acc6795b3b2ab8b06d39ff070136799b2df8ff57ddf0f97d59cd88d07a63cda43f1585c87e2c1f4d9b562d20dd51ec5f684f3933dd993d5e1609a850231da6443b258873c4041d88a33d83afdc098e06c934a20b0c5babcf28b025773abda09688ab77e152a4422f996eef28d15acdb661a59a7e53eb7cdc0de583744d6451bdb451d1d6b624dd4116d32dbd6c62036a409a659fa3bd64795822ad56575a0036f33b6776744dcc13ef4defaf6866e11116fdd04b61bedbec0967e76b19b6fc01d63bbd96e8e48e064989b9883a2b3b2633db3b49ee992f53ec9b0f560dfafd9ba5457abb2975d7985b89876ad1e9c04223feb76e36108ee76e3a1bb21b24e88f6ac171131d64dc044069c8d0908d1a5e8935f703fc3aecdd109d88a41e28d34bd344b3f86e5e180902c2137d87af4919a6d14d2ca5fe0bef5aca46197777e746d30dfd708eb224dfdd32cd62d6bc84e4381add360cbb2fad68998fd6359d83643765c7bd6bbd36ec4b64b3327eb22749430a3f0f141c26725cf1a3c63ecc7c7f70e4e585a4a70d99c87db0e14dbcb1ed2c6690fb396c0f5658f36c52021a4201c10a9239780312c904a4099de11614ccba3832c063010b1e70edab61fb6502773ba3423be56195fb427bb196fc50e4293cc812cf33ad70e9ef2c33d44bf6fba46c1ee8e72800bd291375dc26953a84b79eee0fa7a88e77ba7757a7409fbcc9a80311a0e91adcbddf6437c8ec7b619f12d25503fd1411d64491550ecd852a51203973b08ab6e0a5d86aefc691699832346816710ca91a650079ba525c74992fc3d38c7c00dd1aaf6a690f672a7264d9772a7f09c271803779ef8864081e74d505cee54af525d6a215d82aa860d5bc75a8e6b1d1210c9237bc81eedb9c092477b51feb437f3a4c1f33d69da9b52055be6bfc00d215f4407b58e9c72a64b43740735145da28131d6e7a507600cf6ec58867556bf57db8cee271ae8085cee1c3ce76ff07caf807ac89d2c798067779287fca9ff0a8ad4308f9e52c8574828dcb45ae3ccf78d0e6dddce770e8f2ecdcfd71b79a28e58735da92373240fd832658fee1d51462a0161cc4f29e4414840381e3ce712b0653e370bf07c6682032e4b15ee529657c11827604c0f21571787087edd7ee8c7f8eed651b57cc59a9e5148975ec81c393fbd93b879a9923fddb16716eaee6e1cb7383379a0d8b6370dd034b85d7ee89770d4e7d05e8443386b081cb2abddffac7914a45bae9bed8180a3a79c9527c198c6f53160ed645c1f6474e984763beca0017aa794d1257815d05e16584343b8c10ece39e19c73ce3967ad4ce480a6be5e46a5af27496b390ede138b33e9c1cdf88cc1073cf042b7e544977d092184f15167c88e95b8c967d0cacb43634b83198673ca19addd80c1b20230788878d865ecda332983e419a6e0afd78031f5a378513c172ff2106489df4e62a1a65d5eeca32bbaf9783b77332974b3c51b4c691d090506c3ee2e1ef40217430063620d8d3c30cd2e323694127e621879d00944d32507b447bd9f448a2fe0327c7c7c84d90fe4222597e0e81261e0a80361d0e7961a1b8ed7604cc3e078d2fd0d50ae81a8d35e0f1875268c3a325acb71d366ef12416de7b5474fd25472ea537dac77692870bdac1008ae9f9b0e55db76685cebb3185beb2a65ec3206b0ac157613a8bd7acf72a43961cb3400fd4998c0c109670f43af460aa6e03de9431867da83926b11901a20c1cd39e79c93d269436bad95564a29a5147e949e524a29ad95aa000743267276c0883bbf4b9f36270843267280706f11420cc7118e2b5c622ec8323fe77c77f0b3b065dea241bfacc0ccbb38007694214abb296d80f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f4f400c9ac9431429608c4850cce47ccc75a61c8c40d54386b8d240448863cd71064acb65ad5e080e15f60604c18a2801eed006429c1520438cacd87214140ed01c124245d9e283c6970d068d465a9c29f1554299f1e98e3ba2c6df090cd470b2b552a1442f9d8d1c949026b5a97fb84535f005aa97e3086c51dd852451104b4b256a7093edf4e854130b571c12e52c366b8150ccbe70cc3934c191b61c838ef34024402f4e25c829553d5052c9f5027cffc70bcc4709b3b4740134c039e670c18f03c6db080e7a90410a3f72518a0c9068de7b901053ccf10fcf03c4be0c34798004df1d4c3b38442029e6515663ccb2cc8680e07d014737878963cd8e1590a418767f9030117bd2f47004d317580677902033ccb23f0b38c410e1dba0234f54c019e7b0b04786e300ce0596e20c6459a80a646c93c774fcc73330187e78602cc73fff0c018edfd760134b58fe9b991283d370e6e786e1ebcf4260668ea201b9edb030278ee11d4f0dc2770c1de8f4e8026792359e4613c472702f01cafd0f2a233ef390661798e3d343cc72600f01c7f80fb510968929f64912bcf31272281a30b66e8c712409304b2efab45f4c07d8662805dc07d0a4089f20c5729d0092afd19d034776e9c3c439e01a878be01770beefc9267157d17d034579245ce4d87b60de8b26540b7800e08187cedd0e8b2554097b91fa0ca872eab5c363d74d926a0cbdc8cd36583e5657459c502f1d065bb4397391d7280b03c02baac226d3b9f0fed6ad8692308893961b3ecdaacb52a7b596bb32d1b69c7b0918665f24aefb2f63a66eb653dcff33cefba6ce3393327acb51666d676766636b5dd387301ecd608c206041e90799c344dc0e7dbf1bc1497e24e574d8e9e91f2937293df83808131f5f238c4a01bbde473f6ba659d11d1a45df2d895d85b7139d96da3d1244509c948a494dae852dcf12060600cf6f81823912496c414d124921e633cc9244509c948a457a494d2107df6ac3ddba016ca4ee98e68a3fac00d6083e972ca3a4bbb89edb0b63362e2ec38447076b9d50bab188661180c8661188661db85d50dc3b04b4a29a594524a29a594526627ac8b39b49a1aa9542a95aa1976c22a8ce6799ee7795a289465a16c544324954aa572d484b20ec0960d4018a71bc9826acff2ced9ec9476f124a23d7ba6a56accc0180c5bef0dc01888d3275823b59ab12727300ccbb0437b5dddc4326ba7d6c59a9803cb518361588d542a95b298a66118766d685d10da765fac86590dbb2c76e7afbaf5704cedc4ae2e882e5523081b36c36c86d979e5373fd2337d83757b8b88b887637a3d1f6f0726da931917d343ad2f2024832b39de44d263afb41767ede03cf4893ba28cbc36c200620291603817201c0063a0e4481d6187b20630a55dbc199259cf6c972ccaa1caad55b1c7ac8a29024908749a49793cf98aab28916ef2148f7f974a1e49461effa24ba3c7f8972e718f87d91e8f00195dca1eef03100eb88cbdd1b0d6c6682f0249538b182d204d2dba58d3d9db41c962b1f8098b9f28b1c2240c9950c20767534bb92a97d7fef77ede19fcbaf5d9bdaeddecdbd51ebadb456ee81cf7d11591dc91975c92a7b82537b9294eba265771495f7155bcef8a9fdc3eca8558e539744e8af57be39066b1541e73e46fc9a7749964a158275db696ca235e711dc1d9a758cf320618c57a0765293762162747f9dc68b0f8c9258b9f3c6b2da507163f790e9d7223224e790be9d59093e7d02a19d5fac6212744cc7921502e8b9b726d7b29976294ab83fdc98d43acafb0aee2f64c7bd649d64d6e9f6ee768cf7ac9eddb23b76d7ac76deeb6c86d5427d139cda375ba477bd6ebed9de669effb6d20dd4122d075a933ad3671cffebc4e9fcd0b2d767543cccb524a435ae0668431cd914cc17acc5ae504b6de42a8dc68d077a75a48ab22909496dc51d1253599f54c063491248bf50904d1a6d1a1655905c0317280088025ea2259ac0f00ca742731c345f60cd6c6c1d837ec1af690146c74b68b707d19b787ea7ccff7b447e1ebdbf5eb211b6c2f2fafbdfa006543821596c19badcaadcaad9a9112c8443d95e557234f2f565aa552759d5d71d1aacc86b63203cb9c59e8f9dad6d2479a52dc9241327329ba92ee094bd2c166d93aad6b96ac9bb1cf16cbb6ed1d3ac6611816c22e8285a00a23611876180cc3300cc330ccc54603d3300c13c1ae699bd675d857361ad8d665fb0b371a7dabc93b9f5d8add88e5f5d83fd8b5e235553d730ac1fdd643cb0bad5ec9d3d6658e4ebdf20808c33abd1247deb4b743daf44faf5a80ad2774e418a292d207c6487cc94b7e125fbf1ea18cfc220cebd7153a0e914cbbb61818661cf0b67ddb3691eddc26925d1198f281dff6185dcabec9e0ed38c0ed303046bbe7728ff46ddbb64de4dd4663eb607b22dbb6b974c91279e62e227255b6191c16d130ee6a91aebbbbbbbbbbbb5342d7467b960e68300d1832918314ce5ab4783b93b4a9f53c716f34647753a8ea99fe71d15cb4a883a4b79d0d956d46ec8c88987642c05553c1894c23653568b3f4d39ed52a284c9ace6e9176f4d4317360eb520cd0ba8402c66837459f28bad4565bb7a4902c83586bc283cba15beb3108d7656b83457fdb61081b889831481c82adf7e190f62c083b1bb00ba38f4ff4b9aeec17766529bf3e8cbd9f95b478e5f7cfbb8a8a25cf62a331df3265eb61765325a38f4fcf705cf4893e5d06a3a5485428abf822085bcf2f189aa28f9c575fd7652df60bb3f75cb2174d08b6feb2cd70816390f62c6b092e7bd1ea8da31b67eea44414c16109c016eb118030ac693d955bd52a14d263176b4cb619b28b36514737848932d0a5bd58b128134497e64fea95ca62b6555907fb67955d66d41ce8609386d58f2e3480bc124fab69170cce3848297de4d7dc0b0c8c81a579fad1b3cb084989c9e57180323258dee4caaf59aca7b8b0594a2e6c920b7be4c21e5dd82cdca562a371c5909fc875f91c7a969f756dbb4cb1cd087546442cd2e5d0b55f276d34ae6f9d1111b7aa3d2bb7cac72406b6bbae4bed57b7dd8889ed718860fbaa49ec570f38c9c3cf859082c4b02e3d977b24abad1da9bd64a3213b4de2589171a386472a4271c3d3ab1c3941768c361dea49361ab6db6c6ee24dbc91cff57286a6a63deba26d460dc168527a3f89c4719f25052e7b1651da7344028f361af67dd325edd6234e44894272e338ef461dedd968f2fb3e7bedb9af75b166eb42db8cecf65976a3cd8d3a7aa667604c69de3a690122917638e6b929e7a49384a38f1236742805d59d404a02f74308384013cc0c8973066aa6d63e307d76b1d65b891c0c03432678a8accdd1deb3c3c7183924395c717872b87288725862f1bee99b1982ae6f64b56cbda299a35a3bba744d9c899a497409eb24dae322ce24da25911c834421983ec71fbcf21c57f189c6e924308d36f7b4bb557145ef6e6e244456b5f1275661cea8523e7424c479f42ada703673c6763626279d745b985c9cbe7934bd1ee2f91a4897308847bfd1502439283a7167d47d4e9479d24499f07e965a7c9ea44bdde7495d52f17994afccbfe812f77997897dce92f679047469e4f332ba44f2791fbab4e2f34038a04b2b9fafd1a594cf07d126179f9f4097fe493add688ce69c47b98bdb379265e5a2fce4ae7cc53d39c95df1919b5dec8a70dcaf1bba752f15b7bebb2adee27617dd16f65e17b7719a4508c9423fa238854597544e9f437777062eaee2ce40089bd52b83acb7b82a1ebad776b963d8b32b62efe823575b71497eaffdc95df1957b7217570249160a9349dc2fba2acee2aa3ce5b2f8bda2a3dc94af5c94b7b8d2c595439a858e60a4498866996fd1cd775de6e66f9749f3a37b27d0debccab5d141b4379f726bb4378f721dd0defcc905e2fad0de3cc99531721190c38dd1debcc885797179e1adbc51a68aab01491337451f4f1d8dea086e8d433249115372faa882d88215c0924d5c22de803e8ae668ce91ada3519d236b91eec9e8f5a39bdc93d1e7ad94404672c75ef2c098d1e96513d0d43b5db21d841f1d28e4482634aa07d3873e0a7d34bae501e2eb99cd9c9934d30313671e314f30029b955c1c16c0f674fb81085ab719a387224ee8a3c78d86b5a16b1482315ccc28b31787080efdba9cfd68746b3f7a0ecd5d888d88f8ea1ae8e606c3a8eb212636e08c98184704c297090eb83c6720aef31479ba04371ad1761f7dee2871237a157dea60085ec190091e3438b35a8a518f2028a163034c1f03227088e0eb382c8031ee196747b73a8c469d06032e8eb67376bbe5b66e05c71770a3d7a7b8111731f175c933fa1c8d4613c83ebb720361fad9c99921d636472f57dedc80db04044cdf40f4063800d8c44834ad393367a28dece4a88b36cfd146b37e3888730301d11e688a3002893b1ad327308d558850c0f4f3393201539ba63551d432bb7ce37326e21c6d60ccc583c437b26ffae6ba6ee8badb75b5eb66d7c5ae7b5dd75ed7ba6ebd2ebdae1bd72874082113303ceca9d5ba015eb4ed908d6823231954a1accc344e7b4fed98e4ce8bd5381228fae8341bdd24301de54662768d73a3c365995b0b5a8031dce9255097229e3ada444a82ce991c35330450e625c2a01739dd4eb592081a08e8068823917e201e3ed8c390091e289cc18630ced011dc04327ba469ceccdc703ea99d3933fafc8430064a5384a259e8696c0e4e87dc893b3ca0af4839dae468836393e078907a600ac48369a748712021daa3a28b6edc717782341085c21bf227483f9c909dcff37e126d208a455db4a90227da5a747bc814b8dc374098be6fba84d32818133a7d230163383041004df2a603b0341365640f9d16e4a000d3a3482072b1f9a15e54459648645d23963522b2aeeb44746bf42c13dd21989e083a0a8928004d339c5e881b304674fa95145c82335c6d38c355dc015be84777862e1e0159e86528a971b1e11c6d4e3225d4e56983e90a965d9e2dc0cfa3879ec52b70248f30e0222582bb240fdd88136d88a038471b922edab44757f0c8c5f1024e74eb3006e21691a88889b9df105df4f96beb41f429127dce9987107911119ff4b082b76fc7acec314f6f208ce981e92b77fb92d061eaade53812a9c2e03c03ce3eafe8f6078bba1b2b98c3dc15c171ee802df62298bba1a010e6ee1664c3dcd57234ccdd4ce6c83077b1d5bd782ecc5ddb371673d782c2c2dcada98ab94b7950ccdd196b26e6aebc214362ae5b812df633e22c721762d8cd86812dfd0d77cf8c03ee935e36dca7248fb322b85f309d2b5634c1c13a7dde1110c21080cceebfd088fd44f7909ea4f91f1d04c190091acc701832810410b6e8ed4a083961d6227bc5180288a7064e28bd6181198bc065172cb21e4370823149c412e01953806774c194f2320a314528edd1f9789a9576b08a48edd1e03873a5542a2a701cb78df87c3b9e6731ef9299d466965dcbbe3d24a576911136356a33fa8dd26bd8e586655996456e6256669ee7799ea7b2d65a6bb5edca306dbb32ecc2b0aec636312b33cff3bccdd33c9589c546484a52602636458946b28d60bf346dcbb22ccbb22ccbb2cc66d961961d26cbb22ccbb22cdbb22dcbb26dd3b46f5d8d2ceb82d06c6033ce283f1feb99e7799ee75d33ceb85149e72595df7a9897b74364b782b021e9dcaeecd92581b075f9433eb18d7011b332f37c3ccff354d65a6baddd6e31acc5c030e380354d44fb4813496987ad3d87d61ea34bd73519ac1d07a86dd7344dd3344dd3b491a669da88d34635469c66336b6d66a386bc9d613e1e36e9a4129bd84c494cea20b167d793a69a74a8b4eb584a93a0543403000000025316000030100c864442a1440ac354740f1400116f8e4a6858349647d324c84218468c618410000000000000000466ac060050c945002ef2b4dbd0cd57278556bd877d212ab2ced019d3f0c979469a2c9e100492e1a2b8bab158122f36d3231d534d0d9ecabf491ffafab4c3be4dab3f20e7f8e9652f19ee87067ae7664a8acf7780141890481526769befd8187e677d4cee8e4a847fb8d99ee226010566c061283b1acdaaf26c6cff183aadd804d8c2fb6de6884901cb5314500f3060555055675abeb630836a8804f574f994a3021b652b078a0f0381c39e26260fb5a527f9b85daabd603ddba00b8f391120cd542b0dab4b8e062fb98342581b460a5f4d2a7fc64478eb02b23098b3dd4f1ac4e0a1325823e2b151838f78a8d4504a3c626b305d15b70b3c647193e649ff2598e3acadd3e63a237c5bd509f7c1cbe729b853511d19d9c12c3c1b3bfccf26d9fdbceb3cfd2f282dea29c879d55210a0967fd97286e40026d8d97f7402aafee1285da2e2df079b6bfdfa1162e52b603465bc8241bd5276ad48e0b366309547302bff3d1dd30b7526fe3b0cf961a96409101507ec251169c0f50ce70771c90d19374e32a5d311ff34769d39af53147e8023fb02703603d075c245ef3cd532038785458ddf27a16f9eaac7f3f53493ce382b33f40ef2c859e792139435425807d4d04506246076f9c8305d6b9d906c0440f1ea3e9c44905b44871227dbc6460d9a9d7238957e1581c25dd69b48267ea733aad9caf397111e7bd9214c7a72209efaa3fc96a34cadb4b56733a601aed33a493b1bc8d1d348f4af7af9029c146b9c1221e66e2822748a997d95baebb7d61633ca918612c82710f737de3e641a6559b1f07965cce1ba00f4d9348d04d2fcc7ddf051ce83fee2555f3fdcdacfede2d64e3859b36e69a2a19d528089219954ed5f51f7ebeca54aee690d9a23484054a5490a807d07c73645cbd82a9c6126ffe80a614f7d76905f8f32360e7bea4e31c2c2a1a689f6b7341a0001e1f423b2358552ad464618b7b7b04eb8c8604489413c4b7b593fc3204aee60f88b88d9c0e5ca9c7d882210fbdfc688919f88840cf4b0e9a0ccb269b2ab373aea790a522deaf601bb99c0e5346e72d382708daeb6ea9f67c0776b0951e9d9b031c91a07a47162dde11fc1526656a46e31e380911be86269a61b0adf654c44a0c3f1810ae7fb1b93fe829bd56dcbd3bf46d91d3ce7853505309a8bf040111429bcb89c9718f851172687bf72a8c8efd77ee65966d47d8a93930533154c6072484100ea6a080b68a0bc4c50bb0828e83d5fd0515ff4c10eb6713f2089f8af6c67ee2e98f3ea6e39f6a1603eff3c55fe923b9859cdc89f3515be379566d58b778f151c9b02c4ac87598956ef20244d55712b9611ac5003545519ec99b0b4ce211f742d3b531fb97476cdc272ce1a592f4017f07d90ea4834df0d28d8ca4ff38fa688d9c053a112e31df5a45bf721d19da7305cbfd518ebadbd5d746e43166486e9f02a03d46db966e73219e0c198be1e0d13082529ebfd9e5c444a2bc7681d8a24cc1a38d82999c3cdd1c80a548ae77c5dc16847f804692be1816cf4ba9272e1eddd560934e6c903686201d88cf1bbedc55965c1b58879786bd6cdedf1c51534cc5b36e363434154ad4e16a0a8cef2adf4b0bb93c2f9de7a36e079111eb6b2eda4a160f5c56969218328fa2c86e0b377b392a03b02a07351bb12db022d0b640134282201ee4481d133a66137c4e0e0c2b1a53f203e506c7080f99f78154fc5e00540f5987c6cd282253f9790698c08109dbc64820feef17b3080355da3e380ac79c00ec09b53a645303af0e6aa4d38e9cdc4e78cfc1d0c15a0639067ba240c73cc7b0e61d1d920f6956a9eefb6715f6231ea5edb9b712a11215ce725c2a727963c375ac7dc381fe297b8185712530c5b3b86053d2f7fee26ac89662ac7955068b55cee479be234e6269c726dd402011615a99d78cae783ea17391264e054ef743f7def448a1a341b8aa3879b719f5b90bc91154b00333b7a8a6ef7ce8702203ffbcd35e63de10bdd30fec07f00374a92d8b220c4d99b2c62778eafa817db25e429dcc717ca4fcfdff4ad35f2554e918f03e6888228bf6c2173c9e10057113a985e8748959baa9a2387fec120582e7731a2e14bdc5cc561fcf0ca21275a7b00b21092c7971d328a2f5151c033a49b06c6a66e235c48817e44568c4b20191ac8c6969b277826c791a1073c239873d05f10b0446dc8bd82cd18d5b93c14b55180774f5cab78aff520c2c8e2020bb52247756ba9ffbea9a245edf35e0d8fa513ed22909191aae3f659ca236595e96b4bbe3c7faa3987fdfa22ddba713c45a3b6b4329e5bfc5a8f30b7db392b60c697588cb7c88a280c39c68699154babb7a71bf33f291502d26ab8cc1dd45ad3a4c7034c25b68c6c63f2639ca7bf020a7c756876d393cb84b16ba31b56f66884be36c151fe5988de1589843bec0f76ac7967b691004eb74cb78a0033797b72050a620a433c7b005f82059680f29806dc82ef2d11627ce2092dd5f88a3271e93f62ddf75174db036f788ff2bfbfc7bb7ed07bd1944492a9a3293e4138523f1df9d978a9a9c1f10f142fa37b57ef30962c4b7309fa96a6737ad88d1866919ba671746fd858d1c9e03f5f694ac3ec1f645ab06d4150cb7d64f4368a2e700a6228451550952a9e75097a6db5c0ad1ae2bd961674423c6ac71e072660f9461d44160c023dfa112a99e06f1380209c9541386d3742c8748142a4e83b8630ed1087b0e9204434d1398930da618a30e9648b68d16118e16671ded608e20638825810d52ed50b12f38ac4c0365055ef3ddaf4656accd6336a1325a16fdec0c54f1011789c94dd8693eb59c5a511b77dcff33d22783642fdab1078e93cdcb34424019780feeef7d77e2d2f7335855644cdba82a612e8af58a5c932b140a6aa7b9616f028018d576e65b8055a42fb0efc01500cc2d2c653d9c6fa1ef6e1f1014a891e1863d6fed3e2489a4aa7ad6dc7b2a9a74b74ae03aa97d1568f7335370cb8dc714bd697e3a32ee360cb5fcda054bfa682c110f89c0a6776aa616fe33e882b9267cd27370d446b443a5d3d102d4c185d4e557a03fd50891bc9477411bccf4ba2deb76a9d46deeeae780d47d476db25a7e1cc85a9442404c284ea03b6255254358fc785c9cbb01ef6b99795e28130cb06a877cfd4d3fd3647eee0bfbfbb1e7c637a6059e870aeaf030d0dca998c6566ecfb113dd113ebbe3dd2ff0c0caaa1f3d9b8c7dc9311cf93d9767150661c6f4d859dbf10dd7e5c207e2f00b1b458337f55ff64305dad5c4fa3bb5b45e6a28cd026dc7e0401290339c6467496f3abf45d53e0a384b1ab04f18c4ba65d6ed62e738878383404e4f53af709449220ee59b676cbcad81344178c5ad1cd88a46536f6f344bf52a8ebf1d5cd337ae85beed1edabcb1523c9f8d666dbe3186cf19dd5d4bfd9577c418bab34d21ead94c8abe5d41817fb15c369ef932c0481538ab882885e0c220123833fc1a7d9f48b69d5ad26f05608ae902e902bbbb1e6a28829419d63e46df176198b8b2bc29bcbd9db838f8fc2907a5be2cfc67b6ae32d5331dbe255956523a5d652df993444f383696d92c62b91ed686d817d24fd7cff605bb12d818fb3357add6d3fe42f59be4884dca07199ee0382736daed2cd994bc65fb8bad410f4f1278cdfc791010c5d6b0cebfea01ff687712be401465ed1dba1160236cc9cee6455546335b080a49a59ea5a52ad064bc07577a875d521e2d4238e0b331f0509ab6be71b1e3c3983a41bb12cd8216049a3b915f0d48a5caa5ba6d96206e6be56be722cd5a1cc1bf4d042ba58b93929c0e439d1406713d2e8ec24529ef0273c12b81012743c9c47d363c391f0edd8e2cd01a1b71c98c5abb2ea25878ceccb9f8e3cbe05688839da081a3be9511cb627420fc89133d08beb38ff9aeb684480e1e98c141439e2c1afaf814f9a4e5ef1fc35567c08b89e4ff38173fe962b4c43b8b04c99c7661fe4c5488b98a842475e260cdceca8a1aa9b4666b5db8fec58342f694b653c0e143d9a20bc487665654ee946d3596a435e7aede421a16ea210a29d68b6323af0713b76b22edf6e0dbd4e7961777a18837862465a0e827afee1b49a3d91d742e62570f4db741aeac9c20140d1eb68fe67848d4b6ed7a89bafb5936c49719430dc38d9188d04f9c8beb2eaff8a69f9ccc88bd3a8aee7d45be05533e9e98469dc371c97dae7d841dcf81b0d36074574536d64ec80d914ba825a3180f8170f4fe240fe5a25b52145d36f8d56abf64af0a2e7c265fbdde051bc69043a78d5c428433a656d564892ec56297b92fdf6419ed775f2ca7d7a1db71f4c982edc7e7bd183de58dd789fce106d88424155855dd284b21bca1375a743b77a9915a74688fa0c4753cda8a14f837a0ee8e8f95aad8c4eca7f27d57e8a58cbb6e7472db764ba3e29b4bf7001360cae51bc1af5f297d3dccf42e993b21e76d0a0a515ce7e56831d23dc944c25b0f96612db61c2854919529e25cac7c65c5ba8d9099ebe613ae912e92cdac266d22798bf09d89e3ede74b17c9f3ca76f7292d8020dbefc53149641ec4148f2502733e3e164fb50b4ac2c0ccdf09910cf2b69f8f252196001ba33ccc8a4091388c88da41f4a7da30a4a64e46feb65c963681e83010ca541bb4164b11f8e376bf82c31aceb48aff84995a2a2ba97af667398e616aa58c254ae997265fee00c41ca69828e57a8a7722db7d6e9c527205d4a9e4a380ee5fde078be9d2cf83302e6a5c7f81401470f88ec343c878bc560c1349e4826fedb95ffd5f39b7b94b9e2cbe7107c73de795086348bb20b357c61f4bca1f783ee4717b7893aa68d7f5f8c6a39de900b98989644f813af1f521271ac52d4f28fbc771862b8844b4f8232be28cbba3bd656a0142d482e2f9b60061e2ccd9704b8e44554c8f681484a5410041b2e99e9f8f62ecb824b1c09002938c5be07eb630b2fe2854be29315bc243369943e552d4c60349bc59b15512969482bcd6967ddbfdaad06a926e6becc9b1226343f0ff4803fd64be71317c36412b94856490f4c1a1cffb3509a821172cd04025570e7141015d02290e498b992236b8b0aea8f4a0c49fc50c4814b500b0180fb032b5247eec7663e2046b3782772dd311aa59d22e9efa75371c847cd255f91311a5a4f1a94df6e4edaa62ef8bcfac8178b6079c751a98419c67dda38efe94e44a6460f578110ced8c0aa28da1cdc2bcba3caa51c513ce7128ecd8f0db0bed1b71efb6e4c9509e88bd712e394a6a2234b9e3a2d09ffd282ee4b80c5085cc1543c1ec35f83f6c4fb82db4ae2d419b82d177920ac3a4d2cf9a9789206630f589351b06d31bd034666cf4081c42cf937454fa3510cbf15e603d5dec78c5dfa351391d5f5e565b42b34c131553007c489961c0f514240b08855e2540cd3aaa84475733ae56d2a81dd45719c9661dd41d4ac5e8e250e23a2423e62d208b8ef0fa990876076bd1ac986401c604e0236636788804a60cce845612022f677382b8bb9ee9ad397e1633e15e7f2aa6984dfafa0a11b232c38e986a3e844e1d28af19216b6250ea2a7e8bf7216bbd30ae0de0ecb4fb76d761d85b35b92a4616ba1cb3a46b54c741408dad82d54c812f33e7205153242168b4278cf9780e155027d7267afb80a293db15186cecbedec06b7e8bb3b46314c11380fa55548b1571aa8c802462d270c55a17d45bdfdf70ede4a986b0e3b286393a02b906085805ccd3699dff8fe3e19e39d0799202529bfcd6aaa1599415c7d41b12036790d8f4db41759a0dced6916b04238220665277773428217e737ac90bf30a3de9e2fb9e145d721c6be484f22d69299195a0fef0c2436f924ffd5022d54d67f694e3b8d690e251040b8dea35e7c8bfb0752e218dc39c037687373187dfa037e3a3723ff64836afc6a64ac1e9447a50cf4be5fa77899494fd29d76d5d0ff4991687c14055be7de433beff35af77b4f6b345deaffb1ec3e2b71ea30c747e4c8a76cf79e48ee27ca40993a7e7a9c7b4618cb4f933e4502d52305cb741cb4983b55ea56d72a33b11a498bca3ada7e49a91281245c339407cff76eb6b31c80149fa4a0d6515b150f17dc7cc395aa2c53c598b9639459886456d522c8dd2104ddded6a79692aa1045397ee1b5c8c13b7e94cc26c92630cac79b4515eba514b18fb0ceab23ca25dc080b4d65be810086633207c4e1936507b8b120a2bdb2e05e7dae6acc4554d9a23343df972494576611af114c08c2e28a62bf70fad5b5ebb85e76409d9cc3b6ab940f8103fa524e342e0be2f863c0ede86055b8c3ce7244731fa7b3f259543f0b48362baf705c9ad20c74498da55ffbc7268ee8a2c552074bad62737cf244e6242d3fe6f5a5394dc932c430861d81c78ddc17f89cd8301cb343b670b132834f327d6a1843278ebd518a95b4dbc26b63140a8e44a528b52f2a5bc181d0143b3ba74dcdf88b702f1c4c6ea2f1cd2ae772e1ac649053b964d6b1ae75d6c4be05f35a25b137b81b0a36f52f8d344c0389be313b12439069ddbc659216dbd540447df5b47c16991c00e37432ca241975cd6474e7016facf182b8906b4c5575a5fac5654d4dcfccb1cfad6261496ececf85004e2ccb442876ed3851b2918d480ec1212df4da0c69b0d6be0e0e36f02dd3d59a3ea92b6c9399231a4e59f4003c94f58d0f834dc5911e000e196a6d070a9a8b6a0fa483c6237888b33abfeed7194ed6c72adbee45b0168d25ad34c41659e79586c94a919a356e8bf8e89aafb06d1f2a3976e7755fe985a0f3fada55cec614d3f89bbc0b56cc89bb4d234faf3b4bce22aaf2939118db0cda9f1fb569bc5a7e22cabb6fb86e4eae2322372eae1d612e7ed4a051261d20ac93458db259518bba5b7e3385c216472e96fc8d31b7e34d84c0062be3eb69d49ea8fd11443e1a4ef0b78064e2a3ed71d2384e9c7f2660935ae8b70eafd69275d81c2da7c676e75a4c3f3550200b860cc1b0ecf65be808d0aaa2833706443e78dc38d3ef39f9b6d569c318db5cedc7626058ab5f1e1a513c41857568020504c5c42b49e10e08c4807df04db86e8be7e79da6df68de55cbf68153ddd68d9e8790382b319e8eeee4499d98383fa049629ab44200fbb5732388b92994a7716bc68f44c0074c28884618039ba292c32231e713de0969ccc33b173408f8eec9f058484cfe067cc54bd7809c567870b2425b40ad01c14e4060d8107566d1be3eb4c581387e6257061a4038a3c5c8af54c39293cb02d212617089a71b5d90b212c61cf7e73227e1f7c4532e2c82aec214070eb7c6069e08275cf479104c582b6c956e32ca327a29a87af780e8a6176a3700a0a68479bc948b5bc0843a81ea54a28bf6e351cf5399dc928a78a02d2117390491bcdb3cc9fbdfd81268bd7fbd56f2e6d5ecc85184c3381798b304afa04f8d69f38a638391e0c236f59aa8e88f292b9fcde2413cbaebce32ca70091c61252c2cd7ce4eb56bab295dc609a2740532ba24fa166d907ade1eb6006cdd5368f004b519fe5607f0a8e7fbafab70cd7a3e8021580f8b96b4ee6dd9c70f2f54b57efcb3a2d86ee58934810fdd460abc8f34979ad6515bea9ab2243c534d5c8a9ddbfe36b421b28a0e520bcb1211ded602478d1ad02eef3d2c2ad97d8f5050b34f60a12a79136e40b4e6612cc19538d0cac91e1917197d9cb4c2baca2474fa28100c15b234e80692f84f2d6ee590d8421f871cf82126da4d9192c0c5285c2da85fed32732a7c010199c180eeaa0bcd8aefeab325558fc5a343cf4980922bbc68b157b870a595e3e9faffef2d486189e94491d7b32c2e6d363f190084aa84cb0bc861fa80ce3a284a20659e446357c744a6e268d074eee28b0a7f06e009baab61e85e5407bfb8a143d10e48b6ad21768b583a6f08838095c66c09d8c8cd812a2edaa549e8fbe833cf1c5bca6cb2887df5aced6959eb69d8e4a7449e2c427625cc5e7c888184a92e7cdd215bbe1002739205fe137c5218396f45c8451f189babdbf771f35ac8cd2f62b38f8b61183a7814b417f40bc6ab89026ccbb4131d93cc7140497e7dee4d0f5628fb71cccf3e8e0b80988719b8ef617032a66af195173c7fdcf98aaf1927860bee8d3039794b5b5431984e65df1ac67bd6b08cac73a1ecd04b704243941f0be8f346354197c0851f909348a084d7d7e1aea909b67ddb4f7161b4436e92ed94b94c5a3e25a996536451b219dbcc44938fdd7b7ab4ea44fbc96b7c2aa5182d5371f3d3f72ff4311741fd78690962f908e145d877c75b615765c0477bc7f77dbbc9aad83dd0890a2e235d1c8c046927ded1d0e963dbb845159076a4462b043dd84a62a1fc0086d99987a51b6c47553f375cb9a51f12f24504b4f8788d35c3db92a51aeedd8238130698c33e0eea000fd1f2b4f0306e7276ec97a4559ecb565591caa258b49db4415a88425673f8b082fea3e255dee8e6f59c57e318d9d565cbd5a65a6879d68214e4cc56b8f967ec4672d1449cb37582afa5efef77a18989c0f66e212127e5a2b568d36b417560bda09df5d970825dd8596bd19f69c55997371d75e2bf547bff0b0f619a81fe6e84054767bcb5bf06e86093f67260e7c4877767e80b558bd7244490a7e18e2ace38c76aacc9c78c8e5012faa68eafe7fabb2325633936997607fd2532ad7639326237fbdf9174c2a7ba91e0f500cd14381e8c3577bcda97c01daeda43c0b4ff336cf831c7465d110e1cd9ed9384240eb0e0c98c8c286e932878931259ee7e92b2ea47a4c2710f27d611bb0302ba181f13f0370d584bb8f1596299c73328927ee2c86f507e5832c40219dd0fc4ce26263202d56726c3dfc85345129a6287e4e503f968d46d3d10e92498c83dd6eda20752943b1869f20b0443b0ed316221b27812f37c5ae0d242e1fbd53705f2447dc0df559fba87401798e76852684f40f71ee4900e57d81ed6096ed44106d20bc428ff7ec509be0fca633d5ccd3104daa5571076ca12700a75ba00e1a0db0a05e80939b191a015d06db848aadd65b9cd7d5fc19374c490b24154e3805689efb36aa706ff398036ec9766f2874a8b37d27dcf494192d531bc6bde8bb59d52d942944dea9c3a0881d832fa9b0724ab36278da5c6ce54cc7aa6676f53353afe59c9113a9315af139a7d81a5d8132302e3794ef922b09feba73702c3c21e0417c56adbc53ab0cc5b07fdbeca1a83f3547e44434bc3fe9832c76334d0cbb042ba98a3dce1d4c528178643c4d9cf80f030d2872231d3f3a046c35fa1bfb0b4703c5c3680550abd7e93e49f0dd7bad0128375c110d9a746e3048e4166845963531b236adebb950abf05cc9d5c289c2697890a4d1ee81d00ce73617a627b53e85e6d56566315a9c3ba7e661f6c19a73352aa0a5eca9852062447089a5fe23d2e13e888e7fa4b60d9b5563965a51a9cc7edf45b743cd29ecba4e3e4734999b4ef89f34e8d21cd6fe4a26f682b533a055cba38714096c308a18fbb4c4f8a81dcd8a2e35f433c009091039001da6abce7701e99d81a2a635c1a290e612188fa03331dc52b2dfdc40b3754f2cc0782abcdb9893623851e24886e99bdc150a5e0656046c35e05ad3197f9e567c8bc2441824bf5fd5ccb012291a03632aa0f18e4b76e339d60ba6f46aee480c4c97ae0b509f286d18a67268c02d956720364c52171315b081ad20120a394e7134a83abd557c4a8f31c81f1581fef31b62617b4cce47535ace3f784e2edadd4951f55f207688e29c4414199875760de003f27da4cf03d2d0ca85b2fd22050e8e086c8061ac51005b18bdb4634cf7aedb0222a08fd42152ee9d722e2c62ff466dbc06d233170c962bb275c0418fdb23fa79bb0c0a51dff7f50f95a38c380ca4d181ea58eb20711331e079d4c76c5e72c521c3e7283fbf86db6ecc6dfdaf9d37cb15b2d43e8469334b46f9f9f6dd58456e0c3d19921779e830133d8072d53a63c0f90a90bd369322ca7d15a43871a585be1e3d6448d2346d2cd6d3f371ad16cc04ea71521773c9aa7ab03b270b7bd65f612882fb33ed0da6cd696b2416e52e0de6ee04dcfd2fd124a5b9c4197799fbc2b44e91c1e96b3cb783156316fad335db38e0f0cd0d93712297666d6fb4e6f37318d3da610f60bd84059002ee49372d95a13cf1415e1b5a503ce7efca82a6e481e54be36c53f621a614b4c9d01cfd506ec189daaea575cafc88481c3f531c65ffd539d98e66d29669034ab660cabdca0c6f679e843da0da8339a91d84683f181f371fc48dc2670327d0f9d2e89dec7f2e44635c7385539596a49c5cbb27195ace48d0ae82a719b75a5c7edf7706c4cc602f519e9d1a158666caab9b5d4f37092a8134b270127618a452034587ca3ba7281df4c36068c527673106b4195681e59c01e2b03981574b03c8655398a06736291926d2add1ae1a2ce675c7a782cd6cd578a9827a016a4fc30d6c03c0a60ef17a4573676242c11e957f5aaf16242b5f88bc28639bc6d2d3aca1b0cb507d82dbad86ca049b27b218617c4d40569be2063194caeae07de424acf236cfb2bec32a5d0f45386b61d0ad19801241662bb9f9f964681ec420ef9607a2060fe0cd46a2d30e56d5cb6f87e107dae01b7112490a2bfc0c71591b3cffb6425adb1a783ea319f6e497f4727440b42b9776b8a3672f45dba1556eac63bf120ce60df5e29d448591e4f8c243e83e5efa7b87b0a320706d62ae08cea3f0d481f9e24ad8228e1523b4a1a1e6e02c50a17879df3c76b0ffdebead0efa521029dad262fedee0c28d384119bc1e136804fc24bbc5afdbcd3633c6732ca0baf68c515c6de24c6c5b5b75169ceb2611c3d29234e8a9767d1e7dec2c27f214470372ce390998d276f847348da60f07a31d5df5459437d6a79cfa5035ff780cd41fd1a6f26de444c001b64fee29e9d70486b058774f27b19ee820c7e153255d3375893de3c234572201c080d9511a553a77981bf61e6317e8fa487834a00fb7b56aa2f1b989a49f3f1ce6b9f9bcdd0265be2fcdd918317662d2a5f123f22217e602e5c9cf2f699fcffc82159f519f7d5e21e50ce405c7f2d13c508741f52d90859a3ad1f3855814bcac826ee0781ba64372ec0accc995d6000d5acf38109f08054b244de8296ddc76831256767e19054321ce9fae319edeccce1e7e282ec2616bbf162ea7317b3fc91dbc4631f86cfdda50b46e7657f5bb72ae946eea868b30c7be9f662fc405cf24796c958cb9f91ca2515875937b4b8c07b749b879adc06ae7824e16416f422ba8982a2a053ecb343967698d521a1abcf02a002a22e45ea01b4c9bfc1c9e0a84568d8017615def0a084c048e82601920c254914a836817226b8b72ba4dd577bbf80ef56e7bd257d42c3851a407bbcc4e1d0beee03d0a80806caa7ff9c211a568ea6daa9adfe8ea19761c384d24078b1206b08044b35f0baeef2160ca56530264f780dcc9f93e68df056628a34dcd02f4f62e2667f09b696081cc36605391838896cac176536cdd640533f28c526eed4390a50f504360bd9611fc58dc01dc13c8080f3bf914fb12dc140fa1cf692c1e90c628af5dfc6312e016c23902a06d22658f5116b1d40f3ee1dda6a4edb1c56546143ca3a55b3c436a6b9e24be80629e04d730ec3294e39cac01043e6d8a8f8a15a72125cccbb8f3521e5b129b0d06ed81ec4f2745d88fe77d1b39c6527288325bf3406c460c8e36d034a4ef104e92fc420fc25c9c071ffaea6fd6b6ff22eaffdee5bbd1d5239e2312d460d4c25b4a1ce12b032136417e951ee6da885bcdad3a3cc843019fd6c6ff8bf5d73afc5959e6dac68769718c2a97b7d0b6ed8fae37f4464ce2a4d562ff4a1de910b7687da968af45e658a2be267a0e7aabd314e5ae74a4c64a1c36c7564814744646f68f4ec6758a161bfbcf072041c36e81a2898a5cf6a6c0ae3214a20a88f6be38b9edcb39cb7ae2ed53cac1c176028044f8240d47ead17d0cf132a9f85410293c71f4e8e75e99c948f506293f54ccb78509c66856846e685e31098ef24bf7b0a627938f394635e32727e1cb49960866991351f1b1f07733291be289e790973e11eb244b1cb80e3df41024feeb63abb0cd89b7532afca1c0512de4f6d91d4dc23c8c9ebf118f343fc45afcc462f8049f370a225af8a13fafc5a4ddca9fdca2bf751a71245cb24994ef83c533956f4486657b210eba2533c90043b2653a4d99afe8b34808bc325a42571679a56a38d9f605d10cfe72351cbf2d7c76302884194e662c59a63ec002a6e7560799c29455d69b5030fd9d172a26a90f22841d8ab716ce21d8a84db4354d137e59caa969ec068af2d3037d8e677bc65a5c51c610e8a3f1543298686cf669786f733809a341b94ea4f2d33e70680573111800248b4eac4f939d19c49a1e4e65c8e256d23fb222287c1a4c5f99dca865d2f650752704f2810332009d35970647d59ae020debd1665ae028df540abf9ae85d903e5ccbf202d9643b09a206bd56359c5e14eb35e565fe258e86279a0809de5427b4c1309bcc5ee0391e087a08d12b448f3789cf4d46080b6e2a6727f4e404ef0e11a3b124a483b2afaa5fee84a09c36b99bed8b495e31ca4cacb91ca6bf231fbf95134fc2222782f2e94ae344dd862bf18e7a380de823db7790fbe7d814d8208d1043af735c412733a12d1a5f373cd6feb1ad30662a8f76628c389a50ab80611cf868b23c33e35a4ee4f5f2567cae712dd3492a831b38cc651db2f2282238f3baaa71085ee3e5f1bc9e8707f44b226cd3cbe0ed9aa31c2047a68159bf7b0db3109c66dfe1bea86ff1345e8d68059f55664b7d65a71198721006470b10c3d1f284793414776467bf4ef8602f51e7048b2b91c5d96f6333f8625cc33cabba63d202a50c9097d0adc4d352bedfe6ae01b4c42394923fedc1af71d9e715b4bc9e6a220c1b0548eff0ac5209da2c81498a86e8cc658693701e8827bb1b351ad7c4d7949c0b2965bf85e270cc2e985ac5c11ffb413536a136c22427838e1982975c0642e7428751645675a64514a9726cb6f4236a78c14c7dacb49f30d999a1adae4898a19908497e0546f0b61815975198287482ee58e68fae240260dd82709e0c3d56e6704e56984f55d50f93b47eede8af250dcdc06efe12fb2abc56cbf6fa5facb8861c90998c6c3574b8fc656cdb1d4d9aa6d11fc092acea762bf37068fb5f5258f890131f111a28b42b74abff690474a8c30d8dc7afd5869d17b9f08dd0dbba487a99ddf5a1a60275719b835c6032917eaffdf3e10ce1dd2213abc490d560f73ee1c2fe61e7ce0d561b1c5f60005a72c484c8edc807213d4815befc6cc3efa1d4418bf6d0e90f3027a1113a1d499c0ae8c2cfa7f424eb4ca1125e48c2213ec151a490873ec9fb13fe16caa633243633ce8fd3ee62c4d11ba48fc4724d79651b09650ac3fd48e2bbfbdadf4dd0381fd375fb406c96f6986c06b65e1a62f9f66e67ca903dba265e90898448c8a4d3f77b63cf1b73a14744502e11812cdf7628820e66f79f1cf4fcac6df9ba7fc6fac68748c8c12aa3160e3585675837d86208e88d47fabdc21df80f0031696b0fbfa76de1061633b7d94e6a825c4681bbed0bd22cce2f404b2f53037dec6900059f4374d2f3be690c91aed9fe5681987f277c4de22f3ac46d9145df13c0faee65e79cb9503597c4bb9d346c7ff5b2286a6ed9b23eb12e7cd948a4a4c619ae86739d540a13c4bee0d608fc61dab0793f1b59e9e2ef2b5aae37bc092ca755bca6e7e8fe78599dce4f8ef011d7ea733c9fb0be8ac714b1acecd436544eeaf783431c74212c04275ce450251d71a793bbc852401e84b94029ab7cfb874cde3e9d6ccd5efee20eb5b2cd99bc39471c7b1a18a84e98f058a70722b7af6ca6708af116ce5e267658e5d09a396e6ca71a018a601b4682e603d8c93b425641f577fce9266c9faf1b33c30bbbfcbe7846ca2abc4401636235123b0a9cb380dc81a8a05b0f9fef238b297f1c74411b5a21aa2ace48c1781138a5de5435ebb611aee293a85ae9693296aac42ff962defdb4237c855cd5518d54c9624c0a38ab44cf310828a82f6ff5f27eafc493b64c15c8c733f210ea87f066f571442a7ffe1ab9937e1a0ea558fe91e3db047dfa10e2727f6cb79d54f6eb1c27f5e0197cf80b48d2457034dc025466b8829a86f31afd1b08518f9ed0bcc50a4b2a4577577b1e5850aa042151739d3843047f9fa459bd0b48f258452de69f5a14db4ed0f80234ef803fd35a669d445d1695c898ad2a9e11303e2398f5829ce966ddd9a0b45ce1f132f38f1299eb4bb9c3deb7a60ed07ee29ecc8c22d795ac389f0d9bb477e807b4b2c58d5b9f44c55da828d317c2f7bf75b898c584ff4617e98a40a20ea44862c4e6738c8ed8098d858d07f1d8b7726980002dcc7781bc7074573afd598d51204a673b91289f24748ee3de369aa099d43d3b004c62254ab60e3f779d80e876220d9b4a3aa4810c2f0e3b6ac4c48b882dcf02a94ee814b430f47477bbe2414f9add5e0116db4bcfdea397d9b8c994df1953e4bff15308469eefeb5df61e0efa9206da41d35bfe5dc02f83af08872ef4adf6c4d60f49ed556c5377a629dcd04390df554d1d7ee6f85e93705fd1684c0dd8251af5e33e9f9e76945452214071dd52eb63cf266aed9ede57b2fc8fc106fd7bd37063cd5e109558f179f380c7b1f84f86ceca8b2fdeff17fc155e4a2242f2aff6113a76e364d92cac7f395b5bef28e06aec3f50c4afc29e5717a44c3c11e177dd94a0bef8f8481595354f151900ab8a7225f5c495802695e20a68eee06d877129f2a3fcb6947a59d194f4cf49a74ea39ba9f3f871a270e67a67aa39ea084016c4276cecfd3fd1ff463fd107dabbe0f88f606ba6142b48b5d831c392accc2950862d984508523c8491d06c05f0312b1ba8dca6c123c8d4426de4a6dbe329d295ad5a68fad4ea436d34427cd36ad2660d90be70d887bc0ab2d06fd6324cb8f4a64e6052f324150b0524471a31b624089691991e36b256137c4114fe861e5cc02328c4e2ea23870e5b853c01edef21e1688119a0661d8b000cd842c20e777d5c46416312f3b2fd57bc61a79d03f5218179703ce69e2c422676301b94d7662e73b5b72e95e27fc0c1555e3f959011c8e840c82d143bba66aafb462b6fe91a3721a78de2daefa68a5736d9cab73b34a11174d14470a57193b48b654da7d0a720801421dda01d9dc82f063f1f7363565705d88732408a16adb4dce493d9f95da3343cfd9ca8b466d0fcd60e37138622f590fb7142bdc7b713fd377dea045d83e62b73860378cc9c7132902268928e7db82093ff8ee9713a626a8b3d244f88df2436f45d6903acf783cda90ff700e03a8fdc663249e28047106dc540a9410a4b9f525f52caa9ef20c075428848bf2b1ce5fd3e6de92eada9db861a35f259c595d455b51a890bd11841ec5fa558156d2e09867909b667ff69ecbc9c1834c919e267dc88920340bdd1194fbeff55767d34cee04f639976e3ffc96271a645ee4c1fc690021c75c3f47e59d28a8dcf78ad3fe188a128a10a9ee07a1431b31c32141c40f61d4890c46843762fc4ccf9aa5320b0f00a7c65237fb19dbc515078aea0e47358483e0f616b2f8716f4b91353dd04ef0a45f9d163f3cfc883c21353c5be2c599d6bc3bd01c90e04b47386482ca6844559ee5ff7d1368426da28889640325b2ef62a3e02db28966f4541bca264a4127c04a1368e80d05ca9d90ad61f7155dcd54cae416ca88fba68031c0d42f880288034645612af2e65a851d80bb07a9ba13804675e3123a7826421ddda4b908994ddd69968b0d810015ef73038e30f612beafa4b05224a08fc68bb5ee1b46884197ec463c3f75b713f50afb9fe1e5b05481ffb04bc61c403d0639f806f7031407aec07c01b2e06901efe016bbfbdaefc25f7e757ec2efd3faf627fe9fdf115bf4bff0fab985fa2fef0ee7b216a3fd2b778292b02ee9e12daa154f0ba513b49213fe7a86d0585be20b59080eece3f5aab1f0b52cdee4a2305c10d3f2f8114050dc6ef77fec1dbc8d73e4beab74734fa82fe3b90cc7c403e741ead1d88864427e03f67a7f78ab2769fc2744554df95b6aae03d159d316e6915516ba9d44d83f62bc87b8e54c9834b6d1f2b9db496f6c3ab6e702d1dc0552acf093da15bb5e52959cb9de3790294dd0c738a2d2c8f6867ba80e5d43d36196c9c0f83b176c33ec388ec4ba2d36ea62b70be61a475ca19bb156e3cd04e90f852c8fbfcefffbad46cf0e940d1464b2162e97f8d93a55a5fbaa1067658294f4bc1ea88d13bfff07f556a4afc38e03423a562b17f77922f70159233d803fe08ac423c29c579382a88dafbfffe674daa84f86c60a9252542b49be01d43ce0fff2f494d8937e0fcce2718c748b11fc4af091df845bb248f83980edca5c88ef9a83108fb84bd24fe66e66af1b32552fae428d32d928bd97f4c460d0e516cba582c2d8aa540adbf0a3157f984990c9826b3046a570b8cf1495827cb01780f28b58b1254482f238dfeebbdb9cb47ec42e25de6d43fe91e8dadd216295e688fa897a52241096d60baa56b439dad702aa1adbfb8da1999b0159f6e248e1dadf3825a9fd0a4c488248c5fe31ca5cde945c2f20a99565aa501f928ab75b1722c3c6e56c4f0a0ee031c5968142dee5a0886ed0bd8cfe9b7a06195dbe2d9690c9dd9e764dd427ab9687b1022e66f606f5869882b032f0aeff4273b1180bd077a687ecffc6906bf00493016ce91b7b306e243bc79fa49b41d8614ff84393d34a9f0032451420cf6648c2be2a17d891a78595d7eea974ab08421390addc272a43e914f8e299cb54896c4a091d100b0a1566748db8972a5c874385a52a2cf2c0703e628c59f6d91130b441b4edbe03df9c0797d218316232594b27475f80631ed421b706386ea4b5aeacbd4ad1e0a6c982d8bd7518e33cc3a72e77e5056533ce8a50371c697c1c6014a353a7777768f03d832128017b539d346d9b6da7babf483ad69e87a5e78ae6da95ac75c7b2b701473e8d554c7feda17b8fe12a2bc1d482bcb873ceeea10a378b668b2c90d800c2684fb7265ce8c3558093f14cd9fb3bbdbe1ba24ce02a08010c05e9da2d7bb05eb17b667a1e71b12f9fa4c41fb1702c01f8f12985d88ca2282969bdc7743c48d8f861feab2f0672d00977c57fd3b6dbde1c0917540d3c3dbdfbd5d50e1bbf72e269e49377661e453fca1ff2ea54458ef69ddb7b7d912e9157e02bbab0b67e0208b486621f20dab9250c3892067937fea8ffdb01763cbb2666e39da0683b052159b0dec5b38c23aa74ef523fd6fcedad56e95eff0a3f07c0e14e60ccfa19941003423cbb5516059fca68cd0cab7f69e281b4baeb2504afeb2b6bbf1d6cf0c2a17245a06365847efdf9cbc3f14c675060db1a9aa79ade99b1d5aa0b360bc351b9220aee030059493dcdd897521290450e735a74332bbc2f2ed71cffa01f29c6e1027f04afd873c6f901557c7db48250da50538d7ca42edba7ab64292d6a4b00d5fc32a8a6e01d5099d32fb7eab1c3e535ced91780c8d401a9273da3ec746eb785bc9265f093ed8ce53aa53003542afc666836d732d9d76ab406ac81e03fdbe06c9a2c44ca99b0d4a938d0ac3b7e62799dafed8885f85dc4350f0db0c27b9b478c09885b2814ff8563962911fd21acdb48837efac463691b84fbd52969fcbdf67eac13eb1378905cebf0a9e648df5a2dbfa28580424bda078aaa5a8c9ce7260015aa0f6b65095c642982397b2546fbdf9b0d8109915da64a02cf534f9fa6dfc04fae5e98b182fbfd8062b7ae9717850b3e9fe637a0268fa44471a3d47b7b4a0972d3b83b4d305080ed6dfb923964b6c5691b4560e7aedba7cdcd01570502eab53357d7f8f8b60fa4d50853fc419f3e9a666d195154d3801b743945773d4fc6dba093188591730b6b86a071891e883669b93de2c6d5a0854ab31e5d5f935cd0a4824d624cf401c2d5f347da58e6bafb414094b8fcc5b65c8361388505ddcf39fec695487da29ee52323513cc4211804348e6ceda8de2042d2bcd6be68559bf324b342ce9881f855df33fa0ce49d194dcc94a91124399949c0bab0e553a616d90365b2349ab91a0285be54abad37ef24100511302844a2c150b9a1f879867129d22dbe2761a5651e0c611bd70153f80757331b62036324681988818053191630a6344c64e8c35500fbd7a17d513580fc67a1fdfb7ce58ffea457affc7e5fd2bf692eeffb878ff8b5fd2c97563712fbcbd58daeb878c8f9542056010fe715a9dc1e28c8187e851df68af1a5973953f05661d77912dc61370d817294837d6dcb85b5aa5f6b9635e83aad1fc87bea5c01cb4329003f6bbeea0737865a21a032a737f181eec784cc7a702d8d43050a15fda4cad6da50961c3e44506ae216f52f2839019bcea4074dc585c337ca8c1db2f3ceccccecc8f1fa1aef4c9d87f7023ba829799a0467cb5c9ec219a9e4d34a0a5733290a43337d07fb47a5fe9df3270a0d0c31169fd840429293ee725353b51bac92c1a138e98cb0c5569036f21e0f8fdaaa196df6c8994983a07820ad1e021d615bea13d03f7692db4fbf18bd5b2406a0f02d57caf722d40defc4eef8cd83549d54c9e18a82907120b8ed96899cd73319aea921a0f67f829d659df21aa266bab8a88008bd4221812bbe347960903e1c3836a6106a41b6f692031cdf026d951489d62c58bfcf4c8161af066ca393785a11fb3786604357a6b118c16c00cb553c2ebb0ea3a42834306cee5be3d2a89501ddd99b2d8fb0803c08012d8efa791d32e4754d5f10b35d0308a9c724f6251a609acb1d2732c402f08008ae5712d43e0552fa262886357c1a1cb1e74a1a2baee29eb8c63497a1ed775aadbd88f42794f194bba4893758cfae2414790e2aeff8a360d18432ba8d8b88856ecd35b000e62cfed1db1a950178bcefa0b1c1afbb01549a0f5317b66fe4a88743722b719ed852bf4d85bf4bc109f720e10fc4803dec737a0fdfd05dadb5fa0fd7d4880dadacf5e2791170ef20d685f9f80f7f00b607fbf01e11e631f99089c9dbcf7029a507e66e328e9e1d61263bdcf1ec8ca5ebd479f8861fd70983a70b59bbee56df93b436c329cdca998ae80015c78fbbfb3c77222d1f8f47a5d0e7b8df841a9fdd9271d6e872a5cc5eacc4673ab12b6a2a1a343c48a678304ddc72623e585b0de3141e7cd74c0ac390bf552d3d1143bdcdb5ef4b62db42fae34c3c3f1bbfedbba3d40bb7dc735c707281fb8f2bfa6c97c03f2357ac9af6870de026d254df22b34dc37415b4297fc154d8f1bd02ed0257f4d93f906e46bf4925fd1e0bc05da4a9ae45768b86f82b6842ef92b9a1e37a05da04bfe9a26f30d085fa84cfafba84be62b2a0f3319210af7ee7eec70d8846d08a318cd47a25fd5e8dcb59af5070b08a2a6e37e36a15eb93485ca6fca82cf3d3aa373ac8d536129c7e8c3df062d15fcd74edeb73293de5b57d8a5f6c72ade2eb13f56717689fd6915b34bec4fab989df90344e5e545976b8218336d781fca5e87905c13cad1b4c8c2f89919f2a72c6b189ddca241027dcad4f4870e02b1f8863892d0c13fec42841d369b204ee01b17ca9aac68e3b669e6fb525ee4c76c79bc8ff5898cf495b0b9e8b4a1ac4c09feb17338e5584c94049c6b95aea7ec4c87ac1694f0516537245a3632ee316d88a6ea16523ba44f4087723731c3d2e329f726612e2e27d1448d303a8486542b191ccec7137b03f892c7cfd5b145a023b0a3a9cf18c87e7bca263cc5a7ad8a80c84d03cd671767ac1803c7980eafcf4cd8585ee24906cd6e84d64fa5615e8aa87893e980b2330d12fc9a4c01755f96934d1108b9c182e23d2907e25b430e31b7341aa13b3a34369209f25e347191d7443328c15e00667f74e6c6ce18f0cf2df3684236da85a447789b2d579a08d1113f42be06a2bfba1cb73660d681213d160635b16653bac25d878eb0d700b0888e337f455a94e82cd375cb268684f057d3df01f3803017ddcc75d00dac19b7d43f942887f3235e0b21f455c62e63b1e7a55c60b43774df4957f25d015374549e2548081d4fd9b50603672b08b4eb224bce720e2493aeab7a21fef6c2222f78b5f7efde672cb7158ed7c96a3615595dec7279f167e5395e36d9e6f73f56dc3305df28165ddcc5367d4a08fda71f9db077be4256b56107deb3cef674b4ce6693c9c9fceab7c98f1f3b2fbce978239bbd75d287fc3cbded797c1101ce6ea71f19c865d7802876a7bdaa88d8f652119dd5baa9a2002e30f6a8981fb90158b8b2f4fb02b5f48fbb1f20ff84a3b95e9061f4c706078b62ff7c612a788f2685baf0717c799e7827d25063479862c72d069fe0509ed8833f8832ee79f8856cd16c850e9671a65c62c4cd31ac63a4f8aef77c2e75bddeb97adbd6863f33ee49f45ab4c63ba6d284aa9dde4546ce90a026dfe331243a382def27812b632c33c9cf1c1bcdebdf13a713004ced5d75a66ce25510f1cee0009f1ef5433b6a5bdf6a2258f897276db1b739192185ffeecde4a3742e0fa0ea8099690996ac31ed15b3ef6f11f1bc2cebc5908e08b05ed9472cb47e25555a91ecca046abf30a705ec5d7f091adc956c612820a338b826da1e001c9145df079aaa6f6dfddd21770b52d1b26f8da72f170e10269c3d66d9fddd054fb57174b37cdde234594acc1c8592f09f4492e43928632337265083bdf79799690d5d9fe7c2a74fd9d3f318c818aeb5a9e4994346d24394a3253381458e8079ebf347356501130c5a28915e4d1d7ef543279c9be0be9e48df59475d26b09dce01ab656bec5e7f408181616f5407e366bf3abed893b1548ed080c7d8fff10657f144674a855961a772c2a57d49e9afb582d3e8e53ef5f221549f2b35a074acda3c6d48690a2600611f15102c2577ba0210d7510f9984129bb94a4ee13677bd9ee54f308139b371118c4859e0b3be7a7c398e55e96c96fbbe2af42117f68c99e3ba94715e07f7c0a9cd278a61f8352a4e644c8ce0ebdac615553912331de6d36af941e6323c88479a09db56c9ed27d9a365fc71118b11502ad3a2c5a825acd4d791af8371c930635633434bf8a4ddf2abec0d8610a36cc0ebbd990d4f31a537aa5af05fd7f138822559acd942c842f7db6938efc87e201f033668dd13018e6886c9e92b2413af2d82dfb335c8ae4993c57cf0465d4746134d04d5d94e7ab694c12de03dc37f81cb0c4a030881ca1af17a962247e1d62aed1c63a56cb6aa7daf353d822411742d2964dd7fb4847a35312e60e4611240e9e38b0ae7679a8341531683df767537c8ef6ef68c32a79111fa83589daebb30df42e19c0a53114b3471db27016aab76326681475cec6016ea96e522ce3f149326b74b0f0104e502ca08ee665b40d6554d079930d6741a0c486f6c9f63f75cd30faed5dfa40bb69c023e260baee07a6b9880e8e0de1f226cf9c642e3c35081774749772ee0d7c71dd016844ba3e21939fc9dc5f113d55e07b7b666d3c8a41bd97b6fb9b79429a51438067806590637aea8fc8c15a1f2878b45c5321e98fcf8f479f543107e508289124af86ffedb672e93039abde997a4a3868dea39f424c25c7ed973a41a3ccb3cf3f72cdc2199238c7df0aa9bac7cb84fa8ee3c7686ebe693ee0d5570d134d1e5a2edf7b5db77030ab55f48e92efff6ddd0e0f6f26bd7d7400d7a8e0fe4f8c092cfbd19b8cdfc48dad01e69ea5436147db8243bd329d91952e949a4e7bcb0f4851c75baad51674d911577bcaf26ff62637893db77b41d51d4837ed447ae8a3d3d1915b4a7532d57ad7cdc724add59879dd81375a2ce919322a326aafc2c3a34eac49dc83ab2b2a4552bdfbfb890077193250d02895ce468635807cca4c3f6dea98d443bc33d7fec6267ba25d1b085db7bcfe6f1c05f333779999306d9bd02e91afad1174e0556c597c3f010101104957f391a51d9a68985e17fe21545188b2a33e148b167877acfabf2f34b219d0abda772142a226f78db7a3a8504f326ee6a909d49655fe2a4fda853d9ff0bca859ec2ae2e69b9d1bfa05cd89b34904bfe6c08fb80af77bdd8c81a658f6d9b6318f6d2b7edb96e9f0efedbb771111b75914e6dcd5c7ae6ec370d32db3418fd6d6a18abefb6beedb699c43e1e1bb3df12c3acfd3fb2ca83d7ff9719e1931adde3506634d8bd3f17756a7b7e36e223be51e3b9cd647a1cbd79d9779e0d3334b8e1006a96657cf3b35b31c778d67ef906cae90b9f05f5dbf6295f0c2f000bb33dcadb9e6501757b189e92bad108778aba3da9571dd36f70930f63b3018627bff4bd6ccc16c4caf7e003cdca4b6f6ecf5b6fdb17fac05af9651b56be95df3cec5bf1dc1f876f10589a950f9906207fe6019175c59b7585d0aafed1fb9538d28753cf38c1165c6cb105175b6cb105174b58021296a8ca8ddca56d1f1b23b948dc2eede3e8fd3c2e7729e4405dd5a6527e1f8755a95851e5873562765d01248e64fafd6e67509c39efa6c715c56b92e735c6e8eea677d3bbc9e4421e9465414366a0f8281f3293ba916a307d6c750ae581766665307dd4818bdf4ae824ec0dea425aa5d243495edbcc8d25520d5c4a8a0a4aeb686736e274aaf4ed6d25f1306be9771063163bc3037523ec0da73b53a2a6e71e8543c970404b1d173235ecd7174f287516f0a196fe9b1536ab592bfe7297ff3a8af398091793289e682209879a1ed76635cbab974a26520da577194aa592d7ce631f262f878879a9c59162609f82a564de6a390a4a8b7e212ba1caefd287adc9bf66f5e04c6f3918d17dbde52d8f383dcf42e9705e0df7fe91a5d8982896860d4c6f7a2e762a1e0ff1549437c5ca5244b13496b410ca054995eff25c76031af26647dc91e988368b25091a7aebc52e57abd5da18f932bacee39ae2b98f7bf4220d23dfc80e8f9b6069c82f799eb331de424328a85c58314495fec3175d22e59095f4f56bb9155ba59df1ead2158548a2ceb21892a60f9b8b6afa52483598de5f516865307df14dd3e5f22fe41c16114a08e771ed7268707a5c51a68c7cc6e121a47cc93925cf2b97f5ec52d881ca7d2db4312f25b47cbf6251b41abaeb6b8c1aba2bccde3f5e18d3a77ca6277d47dc7714361255964c261e6235fd0ea66afa7e9fe4c51a4935a07cd124a5e97393bbc9d43cadd5d4a12c54cfb74c2cd6f624afabc96b16cfc6c856dba0d56a75500b610a94922a7f073974f097077deeea140704e5ddc47513a6af79b8c52d6e71ab59dcd74054c6556e848561d124cc2ea81755ba15a2102b5c1eb431f2252907e9596040a50ed247e2ca4ef8c8f4b9abc17518eedd036222915c8b2a513e0f6a50724f105a4ddfac22553e8b75040aaa7c3741952e57e5d030f2bb69e472b2af23b9d2cebb224b3d1a94df75e5243bb37d39b42f08cbf8459f52c7c0e2f625fe56f71cdff1b02f661d71aa6c81057769911103c50263e5a49282424d2552c76dda7c6e6eac05cf859f5e6bde91ffcdd39ef33617afe5dd7379163ceff8c66f6eda1bc755fff23b87d4c5e9b3f3e7dca3bb772c782ee848f6a2728b59f076a80047aa81858fbfb1f01163e123f6bce342c7233a3565781bbbc4eda5ec31c982c73b2e1ef3708fc748d88705c68ac7400dca3f79dcc463578341424344dc796cc447eca46dbc16d230f2a7b3ce10f59f8dd3476d94437f83dd9dd7ed99cd99615a966933c37808ebb0241355a7533a9d5ade61d6ceac0cf38bb371e4fcee9f3db339334ccb326d6698dbb4340c255b20610b246c117baf9b4368285f3a501d0d84c88c65856df343f9e84764fabe6efb3a9d7923a4869247eac81d998412214b0bd6616404a0734f2586b704049646c6d4825850b3692d27278765357966cf44327d603a18757e9395e3aa9944cb899f9683ddc823cc460e79f2a50d69af1b5749a22e729556e4309a4da7b42bb42036a5052d288de62ca21e5792004a3004e80840aa918fedd0192f74d3eb564676bc8ed560f3d8a0ea170d692e205709add40c3502a9b9503d901b564d1e6f0c3769ee85cebd96cad1e8dc935137ef88ca4bef880c19df046a06d018557a47543e7eb3009d7b2c95cb32ac26a548839d01a010b302c51e87ffc058292bcd9582a34e695b57a373ef545f42a62e86142b24928e59b54f8b31050d5372725c858272346de80d2a0547be34970ba9a1e6120263090d53723056c5be70ca1e15a95249598191806e124143390445c23e96957ccdb5335d0c232396154b8c2296957c49a156a960da2a48478845d463e4d312d2802611cb4a126939aeea763a1e6dd521d172ba241aab5ba2e5744d349f2e486b75421a5026a3d399590ba926fb345736a7ec368d3b4057da3a89a02e24ec4bc9e96a90692e2da8552a3add4eab5856cdb2e2a148505d926e49abf6735fd835a9cd02d405b1b83a214d68e5aa1351c3f49f8c744e4ea8909e21b5595647b0b4568a00d51523b53f6471d54e3192d20229074bc5bed3508c213001d358aa8a9752a461fa5d20d5685f4a4e0fa8f6d8632f2bf751a9655b023af74a557a475a3eb6bc6cd22a18dfdfe2b1ace6cb9b2b1f231b32f2255f289eda3bb57f55c38fe1c922154f1e799dcbeb5e0e235ff235d4016d4cfff4ba9cae48b7f23a2355d8d46e774cd66ddce889503628d7d1563ced75f2b421520e54edbe4e47e53b1aa4e4744375eb8c3a269ca0f6f7775cec0d2d8769f4b3186995caf7b3ac543c0d00a41af969aeee0af3fb3ba2aea853b2537167785ad5ed344c7f50909010119191937e174839566a5c7d5be6abcacfc9a75eb7e5b44ae5cfe94052cd7c90a42356ed0540d2b152b9afd31901953943b59f03493174a6c9dff86584a89cdaaf496f7a19cbaab9ca2c373af7340574ee4d6e019d7b59adddee8c0b35955264bc4003066f46912980010e5003012eabba00e880e6034a5b40098efbf0a56e78d2342c6af2b34e88a7e9fee3b86ec68c7a24d12053b5dfedbb4e7a2cbb26c92053e367dacba891dfc6b20588cf7930b600f131efc434226bbf7d5d83fbd1e8b3621106cc1d5b3c3d4eb22ccbb22ccbb22ccbb22ccbb22ccbb22ccbb22ccbb22ccb32ec67d6cf39a118866118d771dc478f7bcc0b5f2a462b36491f768dbb375e9846062a86a13c9755816e832942305269737b29e539e55b0ce4c87e3ef8c2371c00a2a8e92b7d5dc317520e07dd5194fac62e851da83b788ddf8e1cd0f8e1b61adc0e8703e18afd78699181d6ec69cdbefd62838e1581a98464df12d8af12eabc3e6a28ff07aa4aace321e0682a04c7719b227f914c0ed5f5e6102ab118638c7348763abde6eca68e8bcbd01cc2ed10dadd1b61a211f573080db11dca5fe8a2c385a270f3bbc0104208539802d68486eb9273528a42fdcff678b334fac39800842c547ef5c4b02cfbedf8366c78c4de194547d00eb640e4641bcbcbcb524a29a594d279654bacd41203e6b1a8fc1d60d4205c8fdc4c1aedc369c3f638ba46a77880ff2814c5c1e36f39efe683e02734dab711113be591bca0d355429600c2fbfdedc664bfdecc6cfc9381567f2fec804d0de2853f5eaa7bd863fb88c716c3324a33897dd6e0c68dcf34fb73a598a2faf02c7971fbb21f7f69f877b8aa65bf9607c8c73e02fef1e3407c7fece3c01237c477ec39e02fbf965d9a28d0f02b93eafe48e1277aee717713c1a11a942e279b17ac7685b0ce0494865581bb8346953f43837207015665e300557e47040db7b5c355281411344455f9d8d71243f74defbc49aae91a945cf78e19862aa9cac740a784b48a85d50d9dda1f23aeba4243429865c48b1a6ed1ea6735855cc6421b5562445655d6ae3a828648346044985483f6d873ddcf39b0df1e8763ff35d31efbe6927468df919ba7e1be16ec976646c3c86fc19e2bf6810dca9543560aba3f37c8a9d807c16a3f33ce148212ba659687a4edc36122f3c70b139fa170425005126bdc2635bebca1c19823e6b031b107173494a9c00f1de253606fb8300dff6476c67b5da2b750e34b1c8c88162f40e2a946c59ee9c660157cba580e1b83f5c08286b462df3a605f015761ff83027b0307a681cdc7501846310cc39e9b1ee378e1c0010b6a178831c4686393557fb934fc675733393fc8ac7263fcb150033566cf4357ed8b1bb30127e5883546d94e38be60983f86f5b27364676f991d33b8bb7b16831ad217308e94cc8dd3a0fbca48b764ff35be6bf916f94bc3f5ca55ddf6b5c4cf590da2eafe183d31bd8dfec5154ee8ec668cba3f5f0051a3f378ce6ad07ffb81b2a620a446ed0af4695063bc01659cc67112999939c618a30ee3304e17abfb7025e0dc334c468f913a814dd153f7678950ed77a1eecf922475bbbb518beaba066b4c2f88f95a8cf3b7f6e003cd9cdffce8f9174e0ed8d4fee9612f5f24b69772355831de61561320ac544cb33f37e061244574761ac43e09f69890ac688a16ab533054ecb9e52aa6c19e5d9d5a9590e9b3c4a8aa60d8304fa7f607084215a3c1de3b7a4fa7425f39924ef113aaaf5ce53798e3c419602f21a34ef563f1b196f87593daae6faf811ac4686caed8cf14ad0a43f58e1dd44150ec33ece325d40a1af6cb7558a71fa712a02e144d60edb46a694e95073ab19342a8fc1a0dc69ab830f15d6a9c4103ca2829d74f9817bbb8717b59c7617abbb918dda5afaf73ffd21d28b1315237c9158ad4702527c9158670e2c889a155f518c1d875ca874e0474c3d93518a46b40b119b7533ec45fd2d66ab01fc9c6cdb5c5df6952c4438e1b6b10c95babf6c72fd3d1866843b42143e690690433b38eadfedcb14586afc6af5f7624d504e9ed9a9777b99f4f757ba8f15bfad0ebbb8b3297b1e0410e0f6e769a40518b70a67d7107abf4a21c405d120d5b95df6e4c24751d0c9322d73048d774356cf54152f7a70a271555f7a70aa1caa418b2274fc28e9f3bb987f9101d55337d880d720dd993274f9e48964ef6c4798c526258d631efee3233efeeb2a671dbe6eeee5d477277f752a9c499ba6904dd654adddd1d05254545e574621ec0ce224837a03e9b4f830cbe9c60aae3d0f54150921afeab53c2413040311b3301e08d0de4211fb6918009862dbf06bdc120a04e42d5399446750738d842096ca36e8b638cdfb28c6871a32a563aa8a288e3806e757faa3062abb801014b9541c3807256c8a1a626acfc986841e4d4580821082651b40c9834e10465a9fbc3a405486042821e2640b810b4abfb0324851350aeee0f1013420084458c4041a8511569368a62940f01f4442b0124834e0288045d033aebfe0011e9163d7de143a02422f701256511040a238a3602153cbd032a8ec4f054978a20b2ba3f5490808a225a0d320cc33e1a838ec04a50a495e00b207c2e812243d5fd5912832548286989400bff0abab9099beee6eef61370fbd212811e78092c1aece50bc1344b48207bf94cb35fcb0b45343dbc5044b3ad80bed7fdf1e2c7695d13133dae9e56dd9f9e9e98ba3f3d20a8146565c89808ba3f3d40d4f8eb30dc32fd025536c331fe0468fce623d112c3be25a494d2a3cbe718a38cedddcd930323ccdc1d021aa3a4f244390c9b736a9a46aa89cf6ddbc671cc35dd735dc7dff177a6e748a41ad273a512f65b439f3375d144bb8d349f43e92611ba1e374562d9d4b694dddde5985432519418258d2bc7751e574e6ee56467f2b8d26e12a1fc1c0a69078e07af2735c83ed725c9e083195999237e080a13429d482319bf2f873ac5ad7648c7553dd4e3aa18bfef3eae52f97dcf7115ea97e5bb0a0bf617b1a93e1ae2429cd8ec3751abdcc6f7dbd541fd6aa11e729d8defaa953f3d90c3b4e977fbf516c60aa9eb52ba53373bf752aaf48eb490a814da91af940f278a4c6bb371184dd3865c5c8cdd3af736468769eeb1e631d675ee754a91941c4d4697795cddf3ad498a0b35060b865c451d861f5574d40d9d3c1929b1ced4b9176b96916a66a6699aabdb3d59515e07e4721819dfc269f0889cae48178591f695e7ecdcd09597c308354ccb5736b96d9abef67671df644dbaaafc534ba19d7b5c2d7927a25391d191139c99e29392e3303dac9591949da982d24deff43a099d884e4527a386e93fc2735258293a2939614a4e57f734a482dab83a5795ce3dd264b50c08fea350527ee1e491c16cb01bf9924345a8d7c6745dd775425a2cd8df48826a83328e8a5e42444374a0eacca66469416d8ddb8282fc0bdbc82855dabe44aae9bec4cd215cc3cdc73c2e05635901636def7244e5b97659e1ba3be3e29ea9ba564674e4153c8f72ae85165ae828ad5ecd86611206741ffb3af7502ad739b1e15d07d6507369da1cd25c9a6bbea64e833b2c9e1ef99a5a4c24f2258f64917cb5265f2c46fa6bb47f928e203f8ee65048c0a24059829c8c18dd22c3a507a0121367d5fd16777769911103c50263e5e452fa8e08e175c67c409b3ffb8176f7d749e6cf2ceecf6fe3675f0ce2753fc61823dd985d26fc3829399df6c6c6f88e318d1bfda1ec2ae51799c67e7cd73666b7e38cfc4dc9ad458cb13fc8fca1f1f7475799638cb1ab43e0ba9bc147f5ecee6e1b0d6ec7eeaed1df5e70bba9de95372422a47797aaa0fccbfbdddd6d450bccdc464d5499f9bb894d037d9db75d0fb5ebe40d15b5c77fb8c97a9c642ca34c87285b096539dddd5a90707a9ce8e4947ca2777777777777c7e6ee80346541609b29b87dd9ce5b9f27ed09d44683fd32cf63675cfc7967e47344980a4b546e870d33c48086322d1836a61f2b426536186a3800869dd1b135fb7eceebc10307ad0ab4e3e1aa24346caf6b100712d01db2d7d11b0efdaafdb7b50ddbb88e808a5a433e2f1b9f9b568ecbe75be0e603e3f0674ffbcddbc1852012abd887a220a021dd3e4079e030b4403f3eaf568f4ed197cf5105c2c10b6ac832861d7b41436c59c2babe9056a07463b335e9063f97450852770a5d5a46a8fed1a360fde003d57f80457da188a69b084faa851623ea08092dc6183da6c5aafd1d63f4e2c7638c31468f9d7a690d8944a8d7fd690227072f58829452ca8e316ed749e02496852ea97046c5917d3d1ca67f9e424aeb17ce9a1edd6b638c182986af3a48198b9430186576b22502174c56455afc3044118d1b55ff5fa12494a0a8fdabe40ab5bf9bd41fd5a9f722a4e862ca957500b57f955851fbb549bb1590c48d0b6a1084050f129a8ec29107babb87a0dd898a1abe24b1a9fe717a9255f5244ea8aec409b0c609238a28c1149290850a180a545822b351c3ee0b2a7e50475e9024c300010a202880a8ddeeee6e3483ea5d757777f7169e10aadd4eaa1b5d517dabeeeefe037555a4e1aac485daa627420c515f602302215cd0430222ac1620518ddcfc3cd1447581cb6128cac7073935a4af1d1189c0c1086480831434c007383f3d48d2440f6aacfbd3039f1afe1594a06cc38e067b8fc0feda0fee4cfc7e9855ed6857026a6751fbbb520a68fc91818de9dfe12a0d304c7f179105086a3f03c1c9f855c0478393091aceca8b82e24e34d0ce90ba2ba580cabaef3894ba38f2562fa9fe19b36c4c5576dbd424ddea250f581aecebc18355daefbfb04afbd849c3788abf21fecbaaf9792905d4eb51e5b131febb43c83929b56123b264cb39bbd9c6c6a6f2fc07842b8f8d61cdc962230d3a6b63fc995818ff28504fd026fc3522ca3abc6a70b268c82c1b95d5ad11b5ff6482fadb585f5f20315069c38cce475e2769d0417fffe8ceefde409c92d945b61365b22ccac85a50fef07fa4f0b1c18e4c1032bbcc1c82b983b3003b0df7a4505e0d462201f5b1332cb5bf023be3b5bb3bdc27d49640b6e53112ee69d5f5e130fdcd1d5a8a738498019477447bca81eb79fbbdecf73e8aee17ce0ffcfefd08e61dd1fed42aed5b7bf94d16d0e58f25e0f6654b5dd0fefd9091547e46d263a7327ff4a6b7df23077e1f9d32557ec6e11cd68f1c185566de1a6f2749dd1aa296664b82f6472712ece343e0b865d6fe7607f3a70b9a5bb045cb3fe7949e8f0667f021bf1ed2f321df47b78f0673e891838fde1e3e6cd8d160dfa03101ce49515bd403ee39a45dca971f60e597da1fc19a190c36d8ccccccfcd2a04b6587e9de8cc821bae97cdb0ae8760eab0a3205336806cd293119df012da339e14d7ceaa3f8f3af4f8df3b2645f42a486d493e05afcf7b4a86fba80cef93e3078e9acb3dd7f99193d63468907dd6446679d4d1910b461430a2fc2c9235ffe72ce89cd29e363534e89c9084efefe25424cdf82395a652ca10bd437b1f9631bccc3300cc3f886bb6d84dc604ed3cf37ed836d3ad5feaace2ddf20f18d9d61d999583d8aea7e45757ea2eb82c6e71e540e9dca9c48b8949b5403447ef61c8661518822222caee49e9e4e21e9d4fee4c0497553f5e721366a158300879320d9a94e440df955dd470748d490895ad57fbd396fee1296a4ce2ffc9a838f1f0dbaf628d73c94c3f86f49d0f8d18904a52f2b3426801cb0e365078e1d3e3b58b2dc1d381ce083c3013b70ec001fc70c3244384286f9893f3bf3fa6783dc97527ecc92254b7e1eccfb36744afab7ab988617eca136748a39b4e13c5fb1883935920566a79a144394fedad2e882548969dac603a669df9cdf8239668d75871e6a5c71fbc201a1f1c349833f7922039ad8a8d42d1646410a118d000000009314000028100a078462d168240d1459f40314800d809c4472549b4bc324c9519032c818030c000000000000204034180e008e7550c1213828a81ce8d819bbddb2257e300bde7bfac3c0964cf2ca1a8f42b0bdbd68e5835e62df8ca06b8701ee45c21d1cfe7f1abbc9c1145a18563e79210411346bc7414f3f40592eca68bf5af840f21435c7ed337ce952b4bb2667084a29359287a4f3fbe567d631e234af15dc2b79a240f9b64c9d225e0c3cc532f23edf8600c308ab788ecaae496471831f67b92bc5dcdfaed32120800f93f2076a9671f59b6bd96ac1207635bfaecb0e623f08cf3959a2f22548b82f3362df8fd7df631490ab2da57dbde1f621b5ec7a468ca648e36a635848333b06278f6341b24c80a672cd649ad63da5c934d1707ada02c41e221223447af3fb4ee15efde710e9f779f0cb222f7d9e4c858b615eb6776596aa0bc4773eaa655fd3dfc0af72cf3e9487b1014926c2e12278a96230a03f05229a6129006d37e3685524fdbbc5af702a58b5341cdf6a262523985a80f2785ea9597b816ecce51b08173eb13ff3c0183ecf5d3cd5c681d1d55130633bcac44464b4ba7238d2e2c754efb6534cf3db5915573c07623285854f8a05ed893e8c73e20347332a4a6f6de09f276685715a9aecf0edc642edfc1bd90e841790fd49f478733284d04d05790285011ef1e88c04cf68888fdd07795d403f3c2153069ac84ba39792968ad721429af5bfec9610caebd4009d6255f09bc909387ce04f95a254197acfe183a8c2c2071464bb65a34b9c197b846145c698e1e301c9885c69844f1ebaec647c21eee2ce6610f7d21278e7cd0258018e1ef62550e7cc020a1a333ab4bf9c196314208b361635cac7670ad1ebde6d9172e98c7c73ce54b09a5bf414278b6665e5d53c8739c71a1750d1129b1853e7c49d652d4117d06624ffb60d1e10e98824fb4ae13314771a3d3ad6f5486c978ff39ce9829fe12aa8a5171a25c9af3c95bfadde035b932923c2f01257a27abe1c17c417c664b373a65d4c0c07a233c72e93f64d9c391f0ca4ef9186700805c4eacc764a96b43358a9c9635aab614cfe57d6309a9e3a33b0bfd00ed1cd0e228f7bbb828665cea1e807164e3c872d7f0569c1ee870386f77dd31eb97529c1b97294bb0ea4620e17fc7776276b58914ad65a44a31fb9e105eaefee0db2aa243096de309b6fc63267df7f3d3907a562bec040a7853d0731384564c89e88b1943a77d121568dce8a6e2ed46887840d0997f01b5b8056664084dfac2ffe0a97585e92931a1cde7c2e26e931bc147c17748fb06e059e4c0fa29153aac39b8afc36da2171b04ec71f70d999effcebf2a8717661b5a3fd1cf54ae1f2043ca4ff22d39c2ed85ed604759c946d880896b092276ab84b7d0c787e701c7940535a810bb562c13c553c7511b5be76214ded605aea0b8a472279569f419b7ce4b127320eea4e0b214248d1bdc823c5a69f2259fbd0609d8a31f374e1d1a622b633fdfe924f5fe76840b47ac0323f298e5caecc864aa0e188bee449588652699a560895eb5435f0473307b73be57044c3d3dbe49b06229c0b330bfe958ddc670e4ade679ba444e34a0521e953c3e5148644ce26dea1345d2f6656659ce340da165e9d70eb25f7e1d88088f32703ea25489cf5467b8c37668827109514d178cbe58d4b84b79c88672ecb3dd861cf8318691cd570349d643b29c3aa7cacd610b257c85ff8cf5de0fa5a031d85107aa9aa768c61cc0f19ccb2a9667da856e65f20d07275411d3496a5bb0700a29fdb53023014c5b1b7a826b0b748d6640cc6eb2df8c14e27e01e979d85d210bc235040ba3bde75ed081f0689c01df587e346827d66f0d80c9184a85d90203671e4a0ef2047a523285820be748301442f0dbd73d7378040a09b350322c24bcbb8d84d1724d5fad0dcf8f61a4592bd0235a422128a914aa54e512b7a2c641535e4459c0dcc166f2df0809a3d0f5bc3d60b5d2f3a782b713a2e569f2cc2ad673ec34cc61ad0d95c2dfabf23ef46785ab9a9986af267c90abc21b75b6543731ce6bcbaa74aae850a6bfa2f03256acd507215d7e58178c6718a1009300c5f008a3af1dd7faa0362edef2bb77e2c09c8ece14bcfbd7ca2a96286f65d54a1eaac33fa675054a994844746dfc497d2e71ce34b92c531828170c0c4f2999069991de8f36c0920ff516c7d538769e0f67cbacb62863d340f27ab228270c526753c97303a774e3c95b7ed8ff2d765679fc1fde9122377325a273001cb32725eaa32ddb138bc455aa1040dcc260bc3ce26f73868bc6fd90f24eb77c06b761d1451288a978c43fbd42cb6fa33f64cb54e2fcef43f11c39d6bebcf02905f03d0075666331ef4dd196eea38dc6a4fbf14ac8d5f3d4dae7eb14e6f170c4aa5a574733bea90ba300846fb8f77652a0f78282080d1da544284b27b0fd7cbaddfd00f9ba8fe12877213a02dd70051b068a1f1e554082b8cfdb3c45533aa3c191a2bad7b54c1ae2c0a77af7cb1a359bdb25792684d18d68fa21e141993859ef3d851dec88a7c88f477abe3fbcc8e0857c01734dd27e83b0c5a0f325c0112e18061f2ac53cd2ae14b50e433e8cc6df0c01aa6ae37326866cc2aaade568b2efc62709807786464af494e531a61293702fc78ecf495bdd0a3bb6802b77009f8b850134040a3ace5b4541b5458011b84d6c8e5a029d98848c3ddd058bb8c256bdc46fc8c8c1eaaa68c5c2bd333ea28d2c4633067d33e41fc0f2272d230fd3a27acf3da5dc8bd1e824eb2b296407b94c63ce1253eb82e45271db8e8419c61068f1fd4cac657330cfa294988e5a5781d44f635aa165f89b114a1bde67fb8c1842428086164a29d980219880deabed9ac57f3265180886ac3b5a6b44fafc6c75ecc9313b2b1d506196232aa78d59b683d141012f1fa9113b3380a2d2c1d56bc75722a2e2599dfab1511d5dcf429fbc8b49dbd6f9306cc1581a509866946afec263b8c22e0e087422726e84d3708e3c86ebfd8aac802d7179bd6caa7d86086e6abc4649a882a3e78a3d94964a6cc8562830911136ad1d5c89bf75784932d824976f83c222cd8a9d2e82259dc3fc9c6a22447be0505bc96cd41b735c27899e55a93697109b3eadb23a7a5e8ab5ce1419aa101a7bf884197a918fdb74b069fd7631d55abfcba2df4d64c8f8dd8369d76c49743ac06c9496dd1f47b962e95a4b6366c82623d96eb81053cb24afdd06f0bfc091b33b8d6436d44630162602e60578eb7b9c00e48c1c6180f5cbd6c870dad1efe85a8192551ba653c2d39885e3eba06a46d4d3085d34a9aa7809e685c7a7203381689ae895c93ebacffe1af3ce3586e391861b7ff6a5955c2d65fd37c15ae3cec9fd3ca19be764562e3c5e40a676bf1909ac567e71812be714fc2533943145e7d84b411d4e6af598e490a92312aed362e32253690b34167386103c304bf45a3a3e80e26d02d9c776c3e231dc35db685d79cdf0315d4843ae9a18fe88a4669b61c882c484b28b65f23a45d73af79c9518476e3886ddf492e7943b7ded0e7c134a5296e630134b1e0492f3bf837eac02298bde0f400378185e33cfc9a2887ba63dd6018d92c7eab7c5ffac4f4a08778a3dfa5613c12ed7954fec3aaa8d29ea49ac835c8b1dad456711dcf96ff2a4823db9449eaf5d47a2a44a030a2845bf4332b14bb78824bb4551e1b8ffbea249f503954235ffca5b209f3898ff226099ce585187704680d986e9841f23fcfbc5d788314ac5628ee714154a3536647fcd3120c87e3df4d709bb8755aa33bac549de404d582f4844be36a15bb34f532a861c91c24efd220a654b4821600f314fc3834bbe1d94f873f78297daeb4818653a38df5c334df2e49ed8ffa8ea180dc4e5b39c1ad49e5d3e4bfaef386a703b581a7c0265bf28b3c0536f6517ebe5483c8aceade15c0407c2e626f519c9ce160a4d7e7bea9f8b73d347dc2a1d4ee7290044c261ff73381255a9c8ab86c76bfa1a5335697e09046a024600c0c5be72d08fd324b1df323f34a0b3213286093c6c3af4ff1e16b3e65e033e8ef780c3510cb1df98c3f184dc0e9189eddb6ba19a4f52db58e827afe788de6e8a4ced51c427698fe33e43ca08d00ab90d9549ab5c0a4a1dcd9b2faf214c2cbb30b0170f1de8d535d4f14401eff118a47fb083117f7089ccd7c1ae555259e2725dbad1aef30722c4c12ff61e56f956a4ba970fcfcada26e19ef0f01d66458b41bd757589dd0674e4537a14b603c42dc635330a09a9497a5181272145142b5075f7842137c2abad0c20b674d9e75ad8c9fee3264ea131ab893e8110faa1053eaa53a0ea381444490a682bb19808f0c92d7b7e5dd1ba2d1b83a466482a0062f8d82a177b0d9c1d9e8c54b15c14284c54200586aef61b07a42521872fe42d366df264125323464579610c9fef5af34d22c45e3132fa2f9a7b000a2e61ef884d47d94f035e3c458be62c70b17042dc762b24a72bd0382abb1a5a615df1a1510087185ecc07c8e24714029df9358870b73fca1379f1fe4e171c47bde3a7302bcabe5afbb0480f36dc53483b24d70b76d262d79a49fc5d6bb100ac16f7ef77453334ce0a84f319382e80f9c4b0b321e539ec12e92e2792de6ae3fc4471e8ba0c07914dda789f34f011ed4e8d6fd4dea5e6f05070f798101a7237d09f0d4002698f507a942714491c20227883a943e08e1c0a5bf897c478ba38f5ee9b38cc8f2d20102e2bb49b10e1e481afc3fe94e1c1883a27af45c6cadae6338fd74633c89bef49c768f281b07585b762b49462c45c4342c163939b3665542255b26bde78faac7825d5ac0db5015126966b9dc0b67a2d74eed66191e647a201ae69d83f16ba4b503527a5a901614528a4db50260829aba72d40e3c41d36c49078494b0171603670580d881e3d6d2ca1059df8f8020ba9ef80b6764ec6a1f74f0126b21ece5b537a4472bf5d022b8a758e9d59c244666b1f049f1e24b906b15234997c1a36690548aa432528f2b50200295047c8f223afc4697228e73dff7bd2842c41788ce498b3cf3e2e6726ccb6cb4d96a4d8436deccf02757071c5a162dbb707b26e7a10e02b0628a37cb776e40439e233238b640a5e43d3483285b1376398fc990e7f83994b3d7d663c8661b22534e0b40f3bf8906d1f473c792bb1009ebf17bfe59a08007de648b650e2690b4abce39ad0b6ff86e637a30428a68e91d8447eec0f53f6411b251f2763b05040f87f9c30cd630e83976cfdceb9d90af9de680881e26403c142f0efd941f9bced930eedae7688c8399de6be8a8384f36f63473e6354b61ca38ffa8747d6ca2a9525f4a4341afeff79d6e1188ac8b79f91d075aed7c5b4ec8e21d042353672c5e120b309ade504fbb83029b3e58877a924346ef312d22dc661f62d157e25561ade5357e0e3f334d50ba0817a14711447f83d11f1810f87ca0e0c5b6233f98c8b3e4e3cbc47128a65c54bb1bde1432b4ce76c95f9b2444c637a521291735a135061f86ca48e7c466a17bdd0f7ff63b6bb7fd74aa0b2ecc5950dc0db0cbb0d34612d251b052e68708e466ba31736de461d1da9b8364bc69a0caba6d6491cbfc835d898ff6fe6ba558810a7d134b47b13f1d36072772eddf3e94e230b502707a9e65ab70cff17a553247a5010d8ce0f33b9208f167e9adbe42d1fdc7e09835098e837c6655343e3b3f2c99294cf8048bf587c52d14d4861f9641d88cec39c10b21a42a6de8af12826d5f71a8df0e3ca12b658cbc0fb579b1052461b153f14148a339759fa403ebd2428120ba7280cc8bd960c3ac7767bb8987182c619d688c51a8d995e2343cd26fd10a30fd282bc98cf788a296fa98e702669c9d130f239bb46111681ad5481853a8243f289d15e6582ccca09eadf96ac62cf4e13d55310a008fdb2d1674f3584e73219488bbd89bf1722e3c3342ae374c2461c3d2037ba56fe80ec68ca78362448ec625dc1123fcea9982450435b3a1103f77eb858c86965ed76ad69f8a5c5f1d6bdb0263fb3f4a5f9174aa3272aad2f8d82958c0351102d12045d0601b2b8c68df1cff5ad3ea5295200554b65b82c4454f4ba706d16a102502a91e45786f236d2f04b5280b828eb5ea454dee3350c7629932fcd609e2d3eb13441b4e9708d9ccfc5e4f4021e5bba6f9951f6d66a20de992e7eb8230124bcddec3acd3b53cd8ddbb67d3262aa09a488fc154f511baa126bfdb01dcadc1f80c665208b2949b145daf8857c64ac075f08c8c12db71ed7646d0ccff92564ad7363df5e8c9f1f8ea9b444d1ae77ce38a9811d4f182c57b2885f40e05cccac93a01824bb01e303d80c631a4b37509d9f03fe1b9c24205d4b8a777750475b23b45187ef10b050e6405f175933d0c0aa9e2c8d1acb2a48c65cc901f900507e06e2249804b593b415b3f419901d79dfef3c6d2422f30b7634b0e36602719203a76ddfed0ec728156ba349cb2dd5d3621736a27e0efb599550c188e72395601cd899391c6be909e3700da902b942d8381627e560ba8abdd466d8c0f9e3ab5d6ee29db10fef38ce091d999958e203be91b441ebd4d0688b358743e18b78251700ae39ba034c26fabd13764c08a4bdb2ff449e483f1ebdd38c9bd0fd7bb21736831e218f65e28818c4f126b1f1451f133cf22a2efb121f38416eaa6d8f50071064d142bc300042031aa2818d979a68c092d62f32c42892383068ce685de5f43730a9cbe33513684b6a2cdc52ed702769f4eb4402509f98e2ef847a896e38a167d29f2b6b85c189c101d87121da5fe5a325ca9873bd0ad6801cbec09db8d8ecc6d1a8f1761de52df6eefd98d8af58a2715fb4ecf8d45d0cef5199c937d3d154acad1ac100ff41f459f3a8615566f840288597a9f2e96004e79d776c7a2485141d92bbce0471c2ce8fc77be40b46f594d3eb446d5ee2ae23cebf7655a603b129374e00d2cb87aaf756df33c02d3817867010d9bc92191f25a8deb612737a195951c115a596b2cc2b8052f5cb3b7706e9eb0c6ebc5f8636c513d88107409ac388f3a24628f5e396b4691e18140766012145c98a22221d53d238d7da30da84699a544e98db704517c66eea54eebac5943563f20756390ece448a20dcd61c420e9ae42116e1463c856f86610ee547ce99c72a227aa9168f3268cded6653efc86618fb4135dd0299d7afb8a890e00644655860f3724134269150f55d3a967f332196254414f856bb5c06635a25bcce443d920aeca1d1775ca68e57ed63ca48a09602d6941b1a4f4b7dc5a89fd4f46889d33bcd8353dc8e9464078268d47750acb3a826f092919d70ed97c8968038486c9e2c734264c0da9ffe1b83015ae67fcdefe38f9150a21d577cb23c4c3d40bf692b3ed65009350965b6aa8dad51fff51bfba4533f7569837b737614b263501a02897a4968cbb441da9e6bd3df7563671dc238ce493e089b48417cfc2a16e4314ad2d8a237ede199dfd5698900f7b64103cd0e8d3400a34fd3c4fd9c48ad053316f131a2fbba339ae39f3174c51c0c098a5851579b698513ca6db497f86966b4eab53870122ec8cec2c9d351121aa3fcb3c5147d589c4c94e5cc7f3a381c346120acbf9dcaa2992d03938bd0d9d2694bf781ca122564c6b1e00cff8e6b510144d6f470912a7724f7f2d421b2d31720c0554641413c2465d1ac034425c93ab52e72d8850feef83c5d428310e72507390e3f6382e2d481389e232f90de72c219cf778c117d2c97996e1bc966b83247321449e13821023fcd44015a5f8716652a9612115d8592ba010a7ff62e6ca091dbcf1210e652f7907399d4bb1a9ee5d46361e2ce4dc6bc8a0d7cea6390d14c0ba6c32adeeb228109d3011fc605296f0a93c6b04c6ec7c6b8066c5016ad70e26e599d0c6745c295fc6c2cfe2869c29ea9c6a035474140b400061ef2bf88d98dca4733178f72e426001ba4bf761894f6b997d1979dabddfa89fe359c9c7d9a95293c747586868fdd6e3984860b0beec5ee4aa85b9be002f3a46dd1a7ce69ed25fecc09b735943a835fa22972eaa801b139131bab0fe6824296378ebcd6fbd99fa36adebc4d513b704fd263a08a3f00e2a4aa75355ceec6387b07f431e915e4eab4522e04d68537b94154053e03560e1cecea4305a6ced2c8782db9eacc98c7f07ef4a702906fb8457429c2b071ad8d598963c369cf655225ba2e7a17b87afd01c10e6e67cb6150d3a67764d1dd8fdf207b0f6dc8666bb610a376fc17a7884767480d63f28699d2406c01866d0604489fa6b2f188c783fcf98a6c9382b158dd2c6877daa9690bf85d00e71d50d65f31216c9d4c6640cf9250f96f6dc43647e90ab33eb4bad8005c7965822572724d5b6f94d680177f9e597ea9df3d0e893c645fa6f907b027c80c2574967fe29545c193da01c8a0a3bff8ab13d3ebd0cda9e9e5d58f8d29dada931fad47ef1fc47839824634afc1644a345f03c51010732df28109e5852e7f8282152f2709c6f7de5b5cb465490acb91c08fd1596259c743c56719e73511773ec1a63e0023aab8d60d7db98ed2d15940d9f98b171ce576e9ba9c52bdcf98ac405bb6cd1f8d108f3ebc53674818970c50a8df35d2d312fcc6bbca0ecb8cd4b3d8e485f78043c7add26dd25097270e7ea0d55c81fdbd2798621080d6068d851afea264c81c259504b04a66b7ec0ddb4801523cda96865acf5c51b97343f37f826afe5f5cc9130d30fca0eb867c040f7a0e48af804c449881720089fa00614f655a2978d04327d9a5e97880522c7a9fe1f44ec0ad50b1f3d600e54498c9d2b6573dfe403be1e2c230782a1fd7ecbf008aa57c6b3c36c1f8ed37448ffad11260fd102c12c014723ae6fa2881220cc4183d3ebcb8e2d6fa11d515b2832dd248c4c79de156c21ba18793a34bc795e19beaf506383455e9f6a43ba92dface4a73441eb0434e38a756ddfc60ec572f8d6e57165f68377193dd7c40e1457d751c0a43fc12431f4b001a1575395c76a095f4880f54149aa5d2bf33589245831ef1efc61a9afa04ec072a65150e7dc1675935ffc7e3d19cd0a88b92fd198e2c3f4f7166e63ba490275db3e0fc446f237b7d23e010ec8801eb003839158a2657543471ff9bd20252a31572c50a4370e6e5ec63d44898d6253e1fa10ff92f380889b01e7f73eaacfca9f44238f36b98cac286f8cc837241b87a69bfd477c804cc9424b349e432150ce3d5d0815e7cd0e82768672d3e2b52820bf6cc79bd96736f97195e0152bd2dbae8110ce9decf52566d87baa06dd23f639dbe7988383fdfde71c782df0d8699c044302b8274683d30d11a2e4462ea138fc49f326b4a0f1f340110ade96a347370fc4fb0ecd420cd0811dba5a1f29ffe89842c1c4f602668ca7164ac2e83a7eba80ced458f6bf2c571c9148df042c2ba9ef46f9840d7e48f34a5413f24b9f3aa3f02bc3f2d4ba39b0edf19bc50893755e7facd7fb1aa2c882c9afc89cf333a711030fb73682ba9ad4f2a08cb700c1f6315045d68b8d023fa200c0efd62f9d33fb0fc738f06b0c1d80960479e3e00f0a556a4183fc57cd4636f61f08b67d335dc5cd64fbfa28b2c985131b8c8d548378ea0bf6c0b47d0fb8fe9a69ebe4f4f0eb970d923f497209c68a6c639268a496d60a5c3a172466be82a46374b90ee2929abf8e779adbd73446ccfa5fd3f9c6f18fb1fb9f05295dcaf706779e1622712c273e35d0b1cdb7082eb63a3ab88211afd51e1286a463ab1125b33330f5407d64464bb9580acdce7e8ca58b59cf2917afc35a8be8829934a9188e6dc3cb4561f2e769a132409d7f921340268a24c19a5338a7554504153b022e71ddc946af4dfff63e4b0d72636488e6f91198d6f7f3ee00bd5525d2817eee231442489e89f2936972a69dbac6d89ba1d8ade84d44b167b130059178d59d53cde754c73a0c1d2785910c90ad1c4ffcb618ea33e4b778cb6ec3d7cba68babd1b45326323623e267f2c5a405f23b09cd09d156b79f6181a7ef3014b69cf1705f2fb12a5c9c6cd92a8010b84effdd52789deee373cba101960a507f0d36c9b8d0e7216d940d64438d919315fa3312fa2d5b963241207876986dccda3cefdc8c191eb07b8fed24f3bd7d7b0f5b7a7d373ae394bd20400611211aea3c4752265ec31a0603546ca65ae32cd5fdb600c0ecd5c056cd919563f0547439123797ca797816cfeed5a019f9297dbc08284cb41aa35ec3a299c0ca5c2156ba427067b7d9f147bbd14aeca49a90c078add2e69acd3ac46076e0e1d0165073c4f92a74f6f27755a15f53af33e72fea9815112031df1bcef4aa978c4b6edc5bc1536d5ceba58feb74147942b7138d96aca4f0525516f85afe6f155c39b824f0e00ae4055e409b430f2bcc6fc455dccf776182f2803ecca64390377629f76dd7ce2acfa815ba458afbfebb8822c84dd783ff7bd31aa50cce27e4c1d32817f73658e500455645c136bb054cb23c4d9f94a002808b6612d2f35afcf4e6091101f06b1b8ce6f6dc06089bf0abb97349697baec6b784598cf9a4a40dff3ae7dabab8ffc853c1a7b0d6da9efbceeb0c1fd85be611fe4dc315269c3d338f39710f67cf994a18d3e429386c7b8a3e1d911a2536ed049f9369342b2f798a4b255f811452ad3b558491e5f40d2cb6e9c4b026f8a946da49bd0bd5c06874c508034616a4007c31e1aef56398292887d716aaa1af550acd321653559fd86836288598af17486f560da16dc821f4d995ade621f566b0e0ebed8094d53608533b6068787d8b62c9777eddd6c976fe24a53ea48987220951558c7da4e5f9c8c9d0794c217cd5e8c991ecd5c72eea4b29a2773ad0a8ebf047a903ee35c20c4c1ae309ea65c91c4bb6fc8818a220332cc57bc6a6908bfa29b5c22f7e1599fe7894c09c5142efdde1010fceca628620338eb29b388ce44f8eefc6eccf04f6561aea6bf56033c5e39dc2e31bb129d31e4e69fa7e8ab45473a15b86efb71b806cee62d0cdd42a1279f027285312f9ef453dda1c06e8866939a89dc56566ebdc5fe3084723554e89afea903e4d6b79c016514d780d9b0f0b8d1d51edd406802f51176b3fbca1c2f0e9dd0dcc84e75a52f562913d0a8b63939a7a756b146a449bf17b78963bd0ee3fa3aed62470abd8fb211bfd4369d487b9059eb9aebbf20c61564142ab091395da951ac3784b57aa52ecc1197cf25f2e1c1b2e49ded0a46236b631b3e1edeeb09d70b94e46993a2cf79d0753105c45c5df1900278705c1a063f3fe6c0a016d9e7c5bcd09ba684711166e764c9a43c136ecc90f9af10d241afbf3f7408b0eb6f8e3b5b51c647a3171bb24108fdfb6238dea13bac759c8df2233f4c8a8222ef2afc5e49444dee67eaa0efd7eae862904475ea4558588ed0486752d98402992b128c0fdcdb535cfbece150f7bc570123e9f84f20380d69ad2b34de0d55d0a2c059700d2c0173112c9a03a7c91bcb0031a6841ef0231e88dc04bc6ffeafa7a0e8b9871613230cc420583aa37094b987ac4cf3eeb0490287e1f8f708165aa7e8c8d4cbf9c195980181bb50c42e39b21937131285fb6545ee161014b38a9f224d9053fae3de53d75a44fbb418d8d65ea08567b7acccaa63c179ce71f561b36febb4f3499b3106e97fa79c444ef3e92d064c31b63b479a963b228be266c066faaa65ea512228f53e0735568ccaea0773e565439dd8fcb49841d543ec7f90192e7d34ac24e4708b6ba56f0f5ab2c11abd88db8b176e6fbb2742dd8bad191fd8383753b0298abb53252877b6d2d2ead57ad352777de67a24a3b3edd23b908a567e3d43c2c56cccdaae32f558f884a01d5e7886af99fe64fc834c844cbd8ce74ef716997cc531235e08e8c3471953e90073e8954616feae6c92d44946e3000131fe74b0bec96b6c6d08678285f882074a6281abd7195dcdc16bcdfb96637908e8ee4b4d7e1c171bf83e9833820b7d1ba8b917a89dbe313115d04a6f0e9d0f1fff85804fad979d836856cfe731f5e085ddc4b5b57b93b15cbeac8a5380e2ae9df6470b1a98c11b1159d63c6dc7aa61598f6afb1a9cfd9086578ec1adeb2d1f2d43dc3862ba511bc7a5459cb2392b1fca9d471e983bd28e2cec9e1b8240f63491ff609c57f7c25c0cca3e5d9d065352759c03bde531e9e8530364a14078f526e724b98caa67fd32f89cad7f6644291076e148da0d59067fdf0d59f1a0a08d94704a61502fdaf16a9cad2627f02ea3bd5cd3cdd9a3ce8e94151f36319e96500a2325c88d5300241d908909623bd2346984a97cc905c2cfde79a6cbe4a3873193885e7ae618d82f31b50fa72135c8f1f61407fc3fea34c082589052ebe54908c63da09b4d1e2e674f038e3b2c53a563d5501a9090d71b5d323f1e61289ad4e0e30aff5b423e6909ef9e687fc110886c1e118389a1f0432f1bc8db82c7183f3e49c5873d1aa721bf9e1ddd61c306b8de40594c325089864f128b5f029db1055986b4bd9de4a7f4834a5d3630a497901817dbfac889b69e934b8d08ad39843c07cadb68a577890e53c605b90fdeef549501b0d16bc5e6d3c0b3d1edcdb4c78ae4a746e7e84a1ad1f892b7996767b4375ba17d8c29a680f846d626e5f322a70fa02c3fecd79f72233ca4f7184e5f890f54a49d056656b2fa9f20c1a706e01cc7c507667e379fdcc23edccd735dd41d7f88e51ffa51d3dd6983dcfef1e76847b67ac620d6eb727b03af048fa53e0146d4c93831c4ba83390907b07384d46ad53568356b565380484b98b925198e220cfd662a3c3a4ae826c3ed9bc66cb50a543cf96eae21d609d34dbaed10b71e6ac10ed43511840ba07cea6ae951cc11252fd038138134bc8172093f9c0da8966c30ae810d1b14c92222bdefc357e76084896b563639248d1f6fd2493f7131c5adce13f1e56040b37579df6da5e1a3243d9224b47c3a08126b94e4c79f015885b288f1fd81e41a519d7f2dd97c526d44614a3962ca0869a501c830a7c8e043e00ad50fa1d820721b3793b5f9d33818de2be08a6f8c9ed0ca3da3c4d6eaabdc873501cc49639e77545ba6eee7ee337315ee840ad9109fa883032988a822291a5f3cc48249b563898e11a89cc6c388571b50a337f19cf6ad2faa02eab6a5482f0ce772bbf1ffc2a57456c045cf5206b11ef416d08aefd7c3b70b1aee21c52e9c1218327cf18009f255acdd0eb077910e2bced328b9425174cdc9a81f169733f7ad8d4460302a28637ebaf2ca663c0ba734c7c428859609c784e9355b17959f30245c72e124c9d71062d67d118fec5f7fedda7dd2547ba83c0ba0bb88d80a6494432cb5021f7d07019984e4141dcb7ed7ce400cfede431cb9931419d93a1f0d606efde99d929db314728685642e761477ae863eacb915e894f2a3f6d7607644b17200975817af4b23fd1b20d9923df7430371c9979f87a82feac8794eb131222c166f4737998a867166ec765d0fe77eb4703ed1b6202722590f02dfd4412e7ca3301be029d42054385bc7a7eb84ac049f4e125165ba537f0b5f9c4064958bba579b0a75068251bc52625dca42fa6044bf32ebcf68344b22b1e6a8af933ddcc593cdcb4b94b774d3fdac6521dc565af2b94ede2744cab848bb3f02278f9c77ff0a609ea98e970302d42a482441e12c7cbe33ba1f2c2a4e2a4e016d80a2c3e1940f109e0b6dd1bfed61927d655a1aff83ee4285563db7c104f7c8191c4721d5cc8490c6fb77b6eb26775dba189ff8730a60909500447278a35efeb97f6185a4da739baf166e134de5a6140d478b034c38016520311edac89d10fdd13f77e6f7f3b72e513d21dbdbea242dd015e3b08fdfece6ede32346a00b5ae3811237073c838d8b21a080c502b65233cb547e8c99f58376e05bf1f42c997d9fd904725f0dac325a69fae5ca4ac70b215ed64d4bc706dc29b0ae8e498280e4a2b4d09c7cc88afeae8685244864c6523f4d98e94ae241ebe81e427071e519a0513de945790231162a8f0bfd2acbb0bb9a83669a493676439e82cea6af08e1d153db8ad6c94a2ff639cb71d85ceaa12b1a079ce6040d5e21778bc5925f6e36d391319da0b33396185832a29a2c6dcd94b08c32bd141c801007f33310c296c969c4ec8c46b153e74a06c93ea1dd201652188e7407b5a8040c7b371808e3210ac10f05f86bca2f4dd8b065099e4291c950437a0d8dde5920e4765a6144e4dde602a95d82a8dd017dd54994312845ed5e689e9f6bd190a1f76dc7cc468254ff64976c0ba6d01f4b9f113f57fb5cd48c713d6be7c5f945b00ccd6adae184066e040926f2cb0e504bf0985702b4177629d2e45493e040939470dcaec27b2cf15203bc79f3902ed405675d5c6a7524900c10293f9fba92f24dbaa8e99e83c2ef23ccaeefb2bbdb5f231a5cfa8f640597da255322ca53ae57fd00fe85b188e5a508e00916f50ec7afe930b6c5eae6e18fa2cfb98db3e02ea0f5432e051bb4eab3a91ce3f87fc98aca4ae023822ecbad8bccc9b2eec2701490dfad96f1b6fb1d361ff1a7ed6022e6830123605affcaac8cee828379bfee511e36cee0cdb003ac553c4d10b3bbe23bc2f95fd89f3f85bf9d80572ed53569da93f6e76d81bf2ae4952b21bf1b65ae88aa621383734f30e23365e577446a5d20055832949230f8b3302a088888e94a92bc2e1bac4de2b1938fbc4fe78c6f5f0228c08e367532a698f2e6237393b096058275bbaa5605940a2346ed824fada9a68daed565dbbc59d1509869bdbe2bf6a3e1b4b8529892aeb042cb99c7b3f4589cad0aa36fac5617ad43943cd68b55b8d77421c92ad06588c0d4492d64569d019d85eb8b7cf6f74a38bb93f882dceb5fe63871df50cb1cad480a8c8860d87c0bb2ca32e689b118151f544df225be5353aa1de14d24c96536194076924e7218934183900a80627fbe9d9fe7f499718bfc4bbcc2bba843431f2c0de6c2eb13bff6e8e0cb7f6bdec7c38fcf4ca0667691c29435928d3e0b6b5c1332d79680abbdf832698a67a1b23fd74a1216842db6bc44429c928ec71ee2dc7929ea4246622574c43ae8b4ee0168a819b3e62ac7e15f974c97a7ad09be45d7465f43289e032e0304b64076dc3e4414b472da59768af9a83dee48635d19f00ccd44766b7a3f1807b7782bf9f3b60d43ae61c55ad7e82d01e93c7b96b32587ceb71141fa7c0752fcc424b391b8e7f678771be300691026bebc513c47b26ff9218d994780f401d21dc038d1efafdff810a4e627c2e976bd403baa342706083340d13046edccfcb85b41dcaab01c706e95e7c835abb75305dd387451c1ce258a3a1be1b59ad287b5c9e444f1f365a85260e98693fec4bfaa95d230f0b6130a01f9929bd5cdbfa0326ba426cdd0e10c96ddf88dee8eede5d1cc5243ab0aa98b15eefa4d28b45ea51ccf28d12fdc30c536e9225458cfa2cb8a4d8fa937029b1c587e4aec5ca27c52dc4949f9abb42ec67e54cbcd6fec467fd263ad677c26f7d133feb3381b5f61396d51ecedc3ed4d19c14eef6277b8b7d4bc99fe1addc17b0ca13dfd6f39e1d6db58fd761af7e315f1b62c97a20d9a003de94c84e4dbe86cdf784f841e6c46304142444104085723ec08f0d6be06c0ba03f0fd22d06549c817b6cdf8eed05bd0610840aee09e464526e2f858ecbf7138706558cf0698432d9235e2d51013eb31f9ad51171111de0eb557ff09d8968690b2331fa5b98f883790ff70d2d1fcd410617e9693754629d5662b99bec04bcc472bea59950ac8da1efa16f07d845572145615fb21f5a2a5483020db3df268aaae8368e2ec9f6b4aa3cb8ad7144c0c67d31ac7debd521864164097237faea396533e2244ade3acedb39ce19c2a0f682c42e687aac79d9ff4e30071835390065c3518b4293970045880441530377f352faa36d25077b4650530a4b1bd453d8001d93b3927af095c30448899782f6ab87c3ed572cdc22d6097f00c9b134db28acdc61927a79fcd2137f3f25f4b403216768e27d24dbe77e1036a9d744b81bd06172c76ab8492de38c1568901d7852857c410c479e0332d15cf4bc366f1c7e1b66e337b0d91bd854193951002e19b2bbdb97178adf807f30521be07da1b1ac415979978c4d10b9711f6faf8ec85a2c055ada88a198e161829ca6d4edd362edbe8c50225a53c24bbb88aa677dccd400acc8b4d0b7e9a44c118bda93b0a81de468d03478ec0f2149f6a859317bd4fe770ed7a86765b4c688acc82988f3d767de3701e976975766c044015354efcd5342188b6488691d6dd1681631ec761c3ce9374861666518908b106acc3ff1300952d0b416522bf275d6fcdb12cc8b486bcd7ff4f1fee0f368a22cb013f91ad70eebb5a89cf82fee015c2c1b7facc1e86bf8eee2d516529ae67a7e4f0b2452a092b441d9a9ceff83dd168a649fc1a5459c59bc168009405d06f18538ffdc2918b0ef406cd8e1e1a63060c72e406acc44044e5580d409d944f5808dfb69806c87a7a90fd800c3145bfd0cc5fc144e4aca07ec8a83d675d05f1df84f409d09acbe4e6a1b20a88fec91d1070a3ebe1bb3700fd41dda0476476c1c24e0d147aec3428b467c89127e1f35119b185680179b93152b2703228bc135345519fcba11a7abe099325348a8173e1c91ffc20c19eef901692dd166adb9013b6d8128d8a6a341927c49065b6d86c876054770a2f55467e91df664421576a81702e1b9a6ffae545110acbb8808b73c262e3b03d2c41c3b1014611e032ccad58d3562747468ffdd054bdca0833e180df214e283086806d1a2715850061a7e320a6109b8a4f853935930be8a4eefeacc2a4c7ff0fa5cdf9752884e7fc3164aa6719920c66e5034db3ed678a57a91d355538a838d00194fac617818e051ddaa179867e528cdda73285e616235f7f727814c06b37ade05391a9f1ae3c5cebb6c21c8550e2eb9582e43706c4d49c482a82bbb22244525609e2ffb4bd00f0423c01bd709f9233e70114c3f922db37a5957db64d6763d2d281280ddf0c5882c54849f361129bc8f429e64b318b4407c3c810dbec7426ede59a2b2b63dd4b7e945860bdccb85fc0980aa214e9ceb69a62cbf143483dea9c81afc2b33e4a6a9c53b6232440406b055c8d1ba2be47a1acf3f7c15720faa78782b51cb4baa90378c16bb784e08f4a8a4b07155adf3badf411baca9cdbfa7fac1fff7b74a9e623f89824d39189c3306c3703b73e3a7ff3ab7b44649013fef3ed2bb229ca010e93c34ab8ba722c178301ae01a2560c5d573f573927a2e33bb57d7031722fdc2335d4ee7a032dadd9cc206b6e6ed293c699b2261fd85d961f60c60c74a7c6cb31644c6432a80c9fa92c7870da145708d165792e77d9f50793992f8ce8dc635ad62a37ef91fef8e655a376d5c3047ba89eea57d9773ccd446b2a3c3544a65998cadb9b8c2e207ea8a78d047d65e6efb17a89d1aea5deba05261b1159149e273968fd12862ef7b25efb43509d43a1801984cd10284e50a43da82a660b8d2804b1bfab92515924677771d03d70bbf1439f643dbde489f5bc11431d9751e46bf0abdd54870c63e965b2aafbcb2ce9a14ccf2cd703c7d8d9a9aeb64c22289a0c4b1ca4db8276c5918d4fa83c9de5014a6b9b812605e9d05a2aa9c19286e37a041412af2e244c58368e411cea200b8f8f1086590e5e56e5634dc207c6e9d4baa0ac6a2af362c72c7f0bb2d8bcb5e37a8e3176fd46594e67494e93c7aed4844be381316edff3d2e57cd884385a165bc771597f95e79ad5ccd1bf28c310181ea9b9a7339ea541ca42a3fd191fc2f10dd2d4feb1c40bbc7d64ee5a6770edee30268e8acb6c91b137bc631769ebf38c89b81fc5dd29c4200f209603f0bd53e317101e51fce820d671363a55d8c112d82c68f590c83c8e2bb717425390fcec42e26580d9028ec4561008cc34cd4b130fce25e6fa923d7533cf3548407cb2489d514f610c8076f40a429fadfde5ad95f3cd3832df15302d47328a71fc40f0832f459b53d6da8ea94b8407b6039984f45ebf6c015ac4be68c454d93c801b3585a00b241a5fd68ce9c7db9c7d2dd395e97e24d169d9d2a4af86734298a06d62bce107737512070c7f0776c5266225ac852474f684a8819755d940cf8cb62da4644c4f43da286f7c4a2d401ce332c9016d07dd4c1f56ef58456594b016ef817385570368398a44edcfb3101ee6b5c27bf5ecb5904de5fd80ef0e46b3da4aabf5959882b74f0387627abb72232e94db24545725a6cbc50dd948b82da26ba628598d55c822863ffe50ea7882aa9e1b21231415c0e5fe261cbeba62aa918081659a022eaacb63614c7fd754577c75320e092614af74d892c5f44480541e712415490bdb99730ef54a2168921446e35085ecfa037a083806e1d2674e02b02f8f2e88daedee537f0abf051e3c3c007a596b81981e6c11d94169d8527c1ebc2ddec9f58c037725ad93542d8d473cb92d635adc42927ed6d5dfa9cd1a04dc758e93cb091318a21eca19b635e7b9017336c614a09ee815f9a741e90d713b090446ab54da34b0e0a3599d2604644a396c4adac5f5f860dbb6c958953966d30ccdd4f009bba3a10b308f5a68c85d7ca1efb94416f7c83629761ebb6df3d943ff4c1ade00df0186665bd7ac9fe2c53d7f08c38b154ec562ca892b521622aaa9384a9d175fb320ffb6945665f66635e3c84db562ee0a2f458bb1fb651ca8b924c5902f16ce29c67cd6a85e5e98e96960bcbfdda2367bb96d3afb5b1da08f22e9b7cf2e47f46776f902e6150b394afaad82d93a31ed6518938942f1587776f3a01dd99eb8f3832afecbba4c4d2f357cc7aa80e351f95632f9ac559d3a441e8bbcc51955cff475a3892bf55f0af9524672e6dec163e48b429425d988d3765ac0f524deb6ccf06a18fe7ac44225c49e2850e3856a7c79d7975998ec807d229f831c773009d959200a8d0b59d77ce90e241dd4b7420deb01287f1a5c2a68f84dfbcdb888fedae194b3a6efb9fe3240dc6581ab27c3caf2b6880704202eafad6735d1e499229f901a1af1ac30109edaa625dc05f237c6a85bec67551d1e550241603fea4e3f9dec855a4489525dec3a3753841b77fbf9f24e7dddaec1ddf8670639ce0e7f4c8c655cc7a736ee0c2323fa6406a0b86423a76ed365875f2b5fbbb681b43d193b8d0fb704959a46669f6b80550e393f76bbd7fddc937c5fd5a61ad2dc6cecf5aeae6a039312c5ce7ea87da34a77401a9026cd139691956ab7682cac8c1212bd37a9b070433a46ef3b62e6af9769a0e0ff3edbc216459ff9ef5ba677f2986b171cddf1d3a22185952383c68d0bbc7591025591d8531780527b585c7d1f541145cef6e2ea009999a3f58653bc2b598baf14338a2e9dda00a03af7512cad177b358433b1b758df6e41f3550df490d9be1fe791411114bc8fab979907ee31c70b3e6897abee9287ed393f3627c87005a4c8dd4c09e4be359a4722f736f18f92276e94155e87b4890460b31d75570e0a10b1b712fa5118715ced2773c6fab63718f89244360e3c9d0bdacd0e89155ab95a8604f56ea48a67f2feec26c2dade7e6f8f68b8b5b6d9b9f538042634b9c068bab9e9824047e61f0a7c65ff894fc88f4e00382bd6a8a1d0163e336604b9e73939a4a2f793aabd51f5f678f3508fc05a6c9110bcb495926b350dd31e1fd2ad740cb8ddc5160f05c548d45656abc0d5ed8a0a8443c1b22073df34046d935f9e040d11abe4a0d4c803b04d19a1d7916e7178fc8f0f27dd8a3c4dc37da8128dbdd9294f27dd9e147ae62f83527fc58cbd65572734a97716fd8932640032c7fd5c1abf2dd493aeca87346d162ecc2a121b486f5124f74eea1175f2f11e6e3d9051d72d76761826467df20a302be8cea2adc87244127569e87fe509b6d86625ea0f42579e30ebc613366c23fc5b86582855cef1f29fad2226fece119f025c2a709420bd3802b8428b95dca6a79b7670672dc31fd1b2ee007e96514d7cfd0f74d74ef85f4aaa1e00b6694958a22e717f153e9420178a50f8c635a8a2fd00718dbbd14b86de38833ea7f6857a840f75ed89e8c3fc179cec76935ca97af64573898c09f109fa38174388b8bafb66a02117bbe8d327afb217c9dcd7217ddc4237f822485474d00dfbb5debb7614a050bfb63cb123e1e9fa4e0344b85ec28766316516cbdf82fc1d483c4f07b6c9c7e20c4f7eff77400caeb25d06646e3de0f157646cbf0268f0e22a2fda1bd5763f1315e99d8345201fcecf50d45676b7aa4b459c58a71671aae2c1ede3b8eb395c3b1c09fc8b335cf8f7591d7d9e7d2de75fb783681cfed77b04cf793311911e08c9a21554dda07a60a482797eabce4ad38456d1e11557a6961dbdbfff3e8a841e143e502dcd6bfd24a4d7fe97192d9993a3df5fdfc6e35c460379523e9bf2b98fc5047b93cda22671461a19e3ffd0d5b5678b34d4b59149ce2a59b440b1d89b7c111675ddf68e702f31f6e731457d81f079921e4cffc9bb660b565a92de5dcb79973143f1583ec7a50187203c2a06f02f93d915d362df25c0b475162c451dfaf29b8967fb12005ae7dabc411a05b937d442e5b1ec1b6509e404783120a086222a71260a4d8eff8d20b25f0a901bed2f45a59f8e0ea3db0c0df10f87d3cf738eac916f562f23fd25a98e76384926796fed339af542ddc27a8013da47f88dea6277251d52a803065794746c41f15d213e59828d3abff3265f745e6451e4c03bafe3a023834a1a12c46776f3504d2056f0abbba64a6568512bd95e57e1cadfe67b4dfcd6c91bbbb7a2f508bd0ca98b39809361e3ba918551e2b2aa6f18d41c57867c4dd98653c1c48f83e1e6bce26882b9684d2ddc00e19abedb90a7347a8c9e9d5f76cdb454e49aa9ca06b7837a02f53c7d10cfa311aa356d1882a25df5415e4b860bae1029de75a56ccc9e4d0fd17b503387620624f15d229b9f4c6c7df828e53c799831297a099fbc3a779bcb16c7aec6ef79fc019a0dc167bca67909be1e031c4106f2824ead828237740e860aacd0dda66bac833550c009236c69b2d82663376ed366460c75287d12396ccb59b58ecac4ea172f0c0d43c47b7ae1d08f31a9ba8979fa8fb7f17fa6074909f0cb75650ca1fe9ef7d308132711fd7da0dd06e31599ad46f2782fec9426908154e47b8e66567978bb92b96c38339ce8547584b4237e46f69da2e091a42277319863e4379b7ebf931e9a9b31942a0e2d19050f8b80953135c1f1ce15170360a6345caa806d5fd22e49f88211c5ff4d9afaf8330035a0865657c8d8b2e42626bacf87bd7ed8b9a351dbeb391930407c25b00ec79cd8d1c8eed10cd55e0874708aa874f8bad03788abd25e0a4628703d88bd56896d4a0eff3f3f8672ab305975c121e94ac25fc3ec7a82573ea826734134d80df9895a9fb89087b29c40be02e8958b6e88e2a4691989b8ce92087044969e7a34667a1a8db1f58dd2aa69ab6a2be720e9163a179c61dde0e940fc47745372e6c6c255f4149d5f4dddb8008de70779da9e0a1d5789dd97ddb825e8107d5c8bcaa29e62a1bacda0a147637401fdf21fd769fbda8411afcb46f7124162376c0dac575e3e2211a860ee3e977f778f26b3e89450ec85d6b07b21f2925bd594e9eebe86838b19de987faf25ce601bf1dede291a5ec882c5f6b063c4bebc32216c13ff341e9ec1ee425e3561916178e3100d597a46b98aced87481141800c368c24c6bd16098bc50652dae3c0a31285a9037858ffc0ff634bf2e914c8b4c532568189050f868481b4acc01b54bf4ba62a82c6d5bc6a8c1c0f79575334b1e25ba7edcd4e50a24db520b85caaa59958595b5b8598553c3ff6bcdc416d2489141e26a120e37adf91babd5921b5210c83a102d888676b7b3a6df2f1aee4903212dc13cfce8c0c7aca2805ced29ae968432d5a26c0076930e04bae3279146729699f2c908b31824ecc07199020e02d8ea4f325f1e8523614e88b8a6ab4c6e6ff79c7f40a8078b19e543af1db1dadc9fea51ea3a7ff62447f2bbd6b9b374395862d8e19f719861a99d09df3ab1e157ffead90bf6584f36a7ce6d4450ff72b5a9a4ebb851fa07be437c4c7f0be23582981979efe085b7186bc46feb42fba1984d0dd1df198d213afec93a8537c86beb89e8686427135beb289aef8711d086009a89b2c066814909c0858aac9797a9a1ecf6000241b984392491209585f8fa3a929c948dd12b92672b19bd496ee6783ddc034f09cf3c98f6ff3e0dccd8955eee51d6bd623151e2066f983d7448a895f105c6e1fbc74f586d178ff27d466a1df33f92c1d37b22a869182110a7852025978739bcd18c23ee36cedde897ab34be020cece7985b7ecb088873684241f66499bf213729aea9c4d02187cf35f6252eda976d90daf7841576c1ff94bca93c5395f25edf73a04a30e8788a6bb2cc819dbd88b8dd6b6f2cf62d2b692c338e75c817113f49b849c3502c87d7198dff100826d5adc0cf57407780dcec17841d6e91d8fba455d438cedc20f4e92be9fa88cba175d2c3b58b20bd7c4cb2e4e98cfc164c974cd7e6b68164ae4c400882d484544ff419321343822e4aa68bb11d647de8fb44ec5f4cdcd75e06acc5475a409da2271c69aa06cdc8b4b340b4809494fb5881f39641a45a590ef4e939a048d8f002b7300b17ea914427e9a2c02e78cec2d043ff5dcc5c26256e71dfd4123d918f9ffb451bb67afb6b46367827c51eb53e25d994cd3a59c6929e167e4f93f2685b48ca55679c375c505e9df0d563673c818c8935650213ec2273a62792e1c4146d862618e1a42c08d10119082feff8ace3101475b3e32b23717ebfa51afc38cc0737264eee55f4f1417ba76a2672ae1525065e47e3732f5f4cdea775c9fea615c6cc2c847a18458d4df84c0ce6502fda61f11a72f9332c0e6c428cf43b92260fee29d20c0522027a81f6ac82799642587e0bf834ef510e157a8294d73bf861f332001f295fc1ba4407fa0836250f36179079c1e34dbbb67072cd80ba5129722fcf86411dd87dd71d63e18969c4a372bbb1925f8abe9288ff593e069607291166958192a91a44f918dcc6fe7f61b567cf888873b8dcb0e79d3ed354f1a6b0ae94bf9547f7039877b2cc11f73fb84cde5a4da43e75f98850a2c7021965ea3db29902d6b91b459ba251f8f0c3b990761d22396b9014cf231cf60688623de622e253a5119387bf688b49fd10e7e8f26afeb062e526e65162d66c7b7ac62670c7732fb0504ca3cd95017d2dd1c2429b53adbb7e321aa426e25ab706efab1aa9a3da705c804d15b1dd1ece9176a0e99fff7631b87dc860ae56426a1bd23c1661f8bf220233147deb50b3e144014608c58549c5b66e076edda5e1d52d92f3edcc1ffff39d630f570f3d82ad2f361871d95fefa3af278a529321568479ed21989533c372b908cf50da2564eec91a99d1148e90318c4acaaabacfd500b00ef1beaf57eda26665bf9115acacb247264576a03dd60c481ce93a943bf1f07806803db0bd42cd3d3cf597eab12272e6b1e84e5f3e810455a4b03a451879ee765e0bd3e350c5727518503a7c0b92b7579d568112f7ff106cd8409802b1c1c28da751a602569a8748f388d054d38b8d9370528efb88121199199d9df4fb6c6dbb9b7d70734a852bd4f639c236980dcdae34fd6c25d9519ea133b45b664e2f9f341757fd2033bb7dee0c186230d9d17195b857fe3754afbd3f9dcaa0738b105731f4f1f2dac82d28d013ae0d9720a89c1ebad44345f40d6140527e3885b5986913a73f424e668fba7929fa7924da2e91a266d266cae4f432d167e9f701d40f2c00f6c821f82057e448e46a5d50dc555db631afcd135a860488e97bd50fcc7d7b256183f14c2fd179427ede00e878138887fbbf8391b34e8671fa77cddb76de0f3d97300ba21bc5aa441152fe4b76370e0d5ed682f64a31ffd7916b669ca392e1fc023fd4512f16930aaf2c04d779ef5fcc3840a146d8668d032cc91e07d5862fed95cb6d6e1e856159cc35054a376a620e392107a116f6caf2853d26d23909bab2a6e72a3bee9836793d736b17f0e53f34400e1357e48418e3f268f301101d98067ed3a79b67389b5897408c7ed397909b7600b66b2dd0a0cc33ce172cf7f0f946bc455bcfdd5e772f51eda76ff6572afc2bbdf1a7c8d210154d302fae935625820d8594d07d5c7c64798dc6c085988df646cc030e94022de03595b2935ebfafa18b7777e1e8da7890042407a06b2bec70dd7879ec020c228af3abc836d1842f8986b01716d22dacd131e2d13db5aacb5dd6dcb2da54c29a56d06f105fb052ec593649cd080214a5945464a8ca902c34a8a150b3a8d244823c96924052006f7a418a0b392202bc959493839d13909534420ca2863151ec2c1ba27e6414012c7e8037477cf21c9915ea4a29430aac42a306862ac42435363938a31134386cce4828c191fa58c58668e5230bc286515273352a24c159a9a17dcbb9022e3c426c68d7b1752649cbc70e36e45c6c98c57c1e05d48f12419272a0f0697e249324e68c010a5ac222325c654816125c58a059d4612a491e434920210837b520cd059499095e4ac249c1c8f4f44185552be059c9c1aad2ea4581180006ab45c8a5ba9d18a12baac029d868b08a34a4b062b32cc6065061aacd0e0edb98083bf3d1c77116241b71bb53ddb438f52916c996c83c964332f526d04a3897a49c7b0e8180c9a1e6a180d4d8d4daa8d0809d5bc8831d344fa154386cc3216bea2c45764ccd8607fb4c1ae584ada82f277b21658136429190c4f366bd204d6c95233485ec44734352fb8c4b89962d6b2248b47474746543c71f482ec6683c106db5ab0ae9e6d42c866dc475a3c713463f62a188e7cb6c1a6345942a6249369813d21537930b88c8a254a4ba6d113473464307432a221192a8e6231a72236c2c20886d5d106bb028a6cc5da98c8eb654488c689610188210810a52b31446629f1a094f48375f2a1b48493e347474f74f8ec02bcba97c2d96039355a4753cc36d89428d6d5b2964991c964530b2db096f5122d565a96ba253a590e9d4c00271c45b265a946ab09199375b52c754e1c4d232a28bba4d7507ab6c136d876c46de051aa216b4597ad1e8b97b92b1e4519d213e80e8c5351abd592a16d52291966e0981968d8edc806eb64b26e8976c529473be2110daf17b0bc9a48bf8e38c22606005c68d08d48e2100c0683c160b383a5dc2509b05ce38b46b54d431c63c0aeeec5a6dab533e2040c602d5857bf5a88ca1d91664f1ef17201b72eb439bbdbb35e7560aa6ab6a77ba41528774f4ff30d3dbc2407ac41ce1e581da89080eb6c184a5c0d6a50a869ea0f1599136e6f7a65c4e19c45a9cd59878ab191a9a1a1344935388a18e9cad2524d77c4339ed9d8c490918a316366460737229140f8d582ca20c0c4a4c7326765c1b2d8cc1434372f6c742a6222268275afd493d49217a7228ec56c6200c045c68c8e87a200a09b28a034e61473b6ac9e51acab5f526a77af7ef202eb48fde250bb114c68f60bc9d0d09317ba9bee04ab0b610c83a5aa96847a328dd00e888f5d7ae145fc6205a0f3a17e71887bcde0b5510420864d071d473bec40eab13af180d3e57470fef4ca676bd8d9b1814796430c271ce42ebdd438c44a68ad682616281ba1353a2336757d98db43d615855090ead75c42cdbad7ec84634249426598a1f3a17b2dabbb21eb9a331454a1a428733694850cddbc02fdbad70c73b5ddcb352bc469734ac08c1a89b0a0fc5f1c7a2f4aa566a0a169b0c13606d0cda0f6d0b2faa310ebea5edbbd6a50fb9505e5ffba57ede7066013c306e53e43464b4c85457733c1b9bb57c0bdf60af797bbbbbbb31494db9978c17ed8509ad5dddded4501637b438694f1a5831ac498b3bbfb0792dcdd734882dd04ae06a51d4abd04e61474eb861615faedb2d1faf16e76d4175402262d85564adeaca480fd80765d2650a8a0ae5eaa6ea0783d61a5a378e8eeeeeedd0968fb0d34bdde31eeeeee3539aa7bdf05eaecd552e80319757f53ce9a2b77d948004d75aff5036f0e4d9d6153d7d5c18042bf14bb707ab56346f46698c4134eacf374d7c18f0834a0070240ee1648724740121cd232012a3a5091b177c04c2bed8ec900edaf87da058edbe1a43555f7ebd7929daae52c67f99c526082fda71450c7c24f45a9b9ab6e571048f58f1edb7bd0d1238e8d2fa5d7ffab1154c8a3390bb03927b2e0022184eedd4738259c229d49a060437a84202443865832040c882526b818426c23ba493cd87a278d1e9cbca4b5b305260802c968498a2dc4aedc98a240bfd4471953087f606104265b3c010b4330610b1acc9db488391858010418b000ca910d8ed0027c1b1042788214f356f80f7f0561c798a040db79fa87b0bbbbbbbbbb7b647979797979779777779777779789134eb8fbbcc1134eb4bedeb43fbb774241f47ee61bcdfcad2b400821430821840c216466f8b0a350b34bb34b61384cc117bb52c6194d4a778fd96597f91208b375528b28b5174d4aa3c9995c3aae839168e6a70e35a3a8137577874628a3baa84e0e65819ab9c316e9cef1eecb06e35968db3a1fe4cd912f56cea498b039eeee2f9c42e8ee1d4011721028fe07786c4f9fc7668aa6f8f34ddb4398ed4d9b07c475dda7ba9749bda8e89bbe53d1dfcaaf4a3df826d3b7a83e9fcea4a47bd39f4e3822ac31aa8f13105f3e3727a570ca3ffdb7fa405085bf3d10f71f900abd10c0a8bc410f88fb6f6edccfdf1eaa268f43f68a7ea0799a8781a1f1661e0606fc175f24f54564e46f457deab9df9ea7e59f64ea85aac88c0c4af5f9d493d7274e35b91855ca59addaf8260e76a71cd35d41886c17b2f4c0fc1021ad67bd6fbe69fbef138ecdcb211f9e1a207368156a1ddcbc182268cd02666d4d2d4ae8fd0c72696a04a5bc5af9d4c5a9fe40f13f20ec85004685aed2344dd3340f487ef4a013517706e2eaad0714ffe3f930beeafb76277b40d22b9a1fbd77d776d7acfd5e8f46387e1e403ce66ffd82ea57d4831225dbcf96257499109a55a9fd313ecc6eb61ad09d55c6523ff6138ef81f70f9409a7b218051b9fff8a5d4fef3d34bedfda5fbc93d20ce2bfae1f4a7d75e326065e03ffd9e7c5a52ceea166f57866f9ff014d4a7fa5377a14edee95127faa86f39a13c9ebebd160f75c261eb2ece17df832a6c1d095dddd398942ac6b3e91511b46601f2f9e5ac3b83dbb30a6efb8d66fe1714ab5f8f9d559cbada036dff01a90cb4596a91ccaf5a8707fc150a8542a1501ecd2603ba40d073969603cec71e841f3fac309e0764faed35c701555fd7fde93be66316705369c37c90a01e18f8dce6c47779d4cbbb3c8752a1fe45858a15a55aa9705c54d46b51c947edce2a0fa0edbfd3c3fcd6e903e3c17c91a01e18afc8ccc77840dbc377a8327d976553cdc87842307a60bc1f601e265635ef03806a0867e951021fa6a3f7a4f2c378ebac5542e5e72968bf7b1f0303f331cb5f0466534562be084c8ce7a55cba43e2d65d6c738343635a7665a84b6b4caa2e8ccfa77640a6ffe687c06b11fcaddb10ff20413dfe502502ffb89fef271c3e26e01eed351f12a4872c495c71852db6c0852c3dfe45827adc2b225ff33c20d39b543745f1a5aa07ee19b2597a8460f444ef077fe8feb0887b414c3320e20741b8200927887ae017f12fe2a5620fb1e310f007f845228cefacb9a2f007ed8b48cd934afaa1f7ddd4651776e91af60a22f52f16486aff36df3005a9575b619037ac82fb21f2b55df95be5774bf9ab829edc95d261c7ac05ee624c693a05e38c115206fa1277f91267b1c37cc889d6e8a881a852ca6c3772d651eb3810bb92b23a7e6457b208faf991ca0f8b4104410411f5063780410451fb397720a0030144651f7297d450f2371391f4b82bb208ead2251b492367f14f2218e54c36912d8919c92322a3d812996c2267f2487a942ea58cf2793aba8c2e647281940ec1902811ac68088634a9514c794bfe38359513450d463804b5083dd46604eb8cf606fb33bf8c42bbe4911cda1b4842fdbab28425a9f64b2479e42e0e0b1189d419914947e4121279a508ed9544c861b2082affdb8cb82bbdea6d28cad49da92f6abf2ca2f2459d43ee3275423ee42c36cd17985ec1ee7a45a5e953271cf15f70646952a554331d6dd76614a511f4a34ff4a273186c887ed461ccf4cbbf1939ab7d93aa22ee4daa213e5eafcdc85d0e33525198f7cd108d8c2a55b4887e3646357ed7e87d17a8d073554ddd541346d3306c97c386aa2ca20eeb6201a802378b817971a12d2d54dddf60407bd63aa70d42817c057f28ffd40f9bbb87e41b40ce6671e7dc9a1c827e29df1bacea1a4293cc08932c76b78c45294410bb1ab87b90d97aec9d7dc0ad3e45a516bfd32b9df8ee6ec39b2a151608fd216fce50ca067ebfb637ae80041249922041b22d45f898403112677c0dcc9011c3a6860646eac58c4c0ccc8b0b6d419d3aceb44ded055c732edb98d0272db26e13494ca99bc34204d086ac4008380802109260c216881c890110b32b8a72807402ee420926a01862b2c0dbdd1d42f686bbbb703ac3dd8df0c5b9922bb9922bb9922b29790c52815420154805528154626419b7e9040edae056ab861dbff17f9c55924d8cfe039eadb98431c25de9bb59f4ec20dcddeacab8b989632a5c8732d2b58ec974ea8cf4f4f0a094f4c387d2924c3a3aa2825d9d4c76f4c4c98d11bae8e225c593649ca83c180241827a52ce822d674108df5538380bca2a3cbd807e7ba46347eb7c313ac4f8df406fc269bffdf31fc0af7942b6e79f9e10253f4236f5cef2efd4ef7057cdfee4a1d90ba264bd1ffee905d99ee707e16faf66837ae6a605855efc9ff995a7e10be99f2f4489f47eb4e71732bf7f53d5ac57133d07f4cfffe99fde0fbff64234afe55b16b4bf051b5ac1adbba02bc1316be4d7e67014da1cfed813c43d787309b8bdf9342217cfc7313e72f1128f75f7734d68ab22ac573cc4441c0326ea23d08f634d5a8747c6440ee0898206ceb339dc13e8c731d9a49bc562b126d08f63da9176b1114d888f20a92e24b1b4eb47b31c0b916e1673648394e4384bd5c6950f56a8117547e05cd64819bbbbbbbbbb5bc69deeba3c71f4f4017742d09a8e95bf8623662abb5c605362df42d95962326556bf458a444ca250a9df56d1b921ca141d1b959f752a3fbf8d8d1b9c9d6d5299b64e0bbf8490524619977291a6498189289254187599880256b996ada657ad5c737373ffa4ccbfa7c95b15bad3ea150ec87422a1ee15d5fcb464c992254b4f540929417cf941b4975ecd03e4cf9f9e10cda3aea4a6874f3e719db54596faa5bc091c87b355abd134f93c36ccaabf8f20ed725915ee38b40eadfef05505929f88ac78554dda689df6a1ba09ea5743ed56edae387a37bdf22f9aff6eb34447043993f9482e824cca5a099944472c5db492c4dee0cd611eb81462ae55b338491112493cf281324241bf9d1981dd08b92bbea649d56a6733199d40bf9d7d521693baa51b2199bbe2fbca2394314a70bbb45030c018c0a2f667605dd089fab98060599bd35444a12e1375995081a4fa68423f6ed2849fb40ef3151fbd6a2a8e54c845c834b9a3025bc3df35cf070aa6ea1efb6c4e13f463a179848c67ced4b73896e288d9152ddc348b7142c00480dacb6dbaf0b8abb523e351795c835faa3a0a31b94412b58e2ca28f48a2bdbf0e77c9f707e22e7ae555adb2999352a97d8b52f7943b9704fab110914cd23af05d1a710ba50c95034eab1f4435a1b33a0e73ee8d75ad364d9563737058b94b01ccf277277c07a0a2fafb32e16b5d41a27e7497aa9fe05bfabbf6ef54556e3e6d53a070ad142905c1031e18e1421276d0458e50c4ca90c9acba4ca66c1105090b553195c6c04076777718bf7aeb2ea51110f290a990476cf76d4a804a94a66d631429e5461ed563bb7b40294a1991f03b7b30b6bb4bb75a376294bc3760125a1209898ed1cd07ad459458fdde0a1aeb3289928329a2dc8088fa7d94213a26518eb83cc252bb252548e11f1cca5ac1074f02660448c435238eaa7c973a4aaa317ecc3fbbd211158e9c50bf6f25c1cd284c2944915a025b6922184dba478a0d71a4c4155982682241ac520c80a04270a823747f356e617597184256d9fbe1753787570677776fe725b8bb3bbf3b4729b0ad707777776e247777776778857323addcdddd9d1b29e6a6e5eeeeceedeeeccdeeeeceefcedd2e05f614778682af40981257ac20a221618111b1425219a50658c3944532498183262c522c66458471135420126156ac561d7f74159d145d157bc42d6108437b64854916a1f4d87929c2490b7aec4cb9b999f2c3bd8a98d6f9015706abe0254803207ee0252b5ad36b0e191c4891833a25157ba4a6fc881c7fc4283236a3155b113d62aa7fd78e313c85ebd30edcbb6bdd3e9f3c772d4895f45adea492cb2dc79da6fa3e9887f029945fcbbf3ce71d8dcbc7007d406acbcbd75a5e9337705ea557adab26f32be3c5f8f0635e7e54a11ee2f02c2f0f04e57ced5f3e46f5c1783dfc5fe07f8007275fa40704ffd36666e06bfff2f2b5f87226fe4bf480a65734f37046b5372efd2defa2fa7af87f20a8b67ca6d73c7942a97278fd82aaff49f54120155090ea6f52f1f00faa5b13549b99f1d659dac7e9e5802f1b005f7b97daf3f44b6b51b88f3ed2254f41fd3f9fda114618bb7f9d7a2967adc7ceed52b8a58107bf5c9a27743e67a99ff65b0e0d88877f0ef99af705d54f7a45a622a1ef31793d2881afa46b725458638c310419f8822a07b4fac381d889e0e0c3d93a3cfcb5a7a8a72f2f2f2f2f2f2613cd525d9e630a5d9e83757395d7d927efe3364ed5c36753f9d43e2580b3d48d337d9f43ebf84b87d0a507217487be64e505dfd3cf75c7b3037358e849af4883373b6e034d5d265a48692b3ca3b806ff67aafbbb3da08e6202d02095dbdf87930bada5fac318213325aab223b2a880a7949cc9a857497ac5a69851aff8a5d44c466e8ab5ce6a71685b87ebdc7e40bf0920205157759bf8811295f3ce34b41f54d7fbf88b42714846dd9a10f989010b858f7291eb534a097cc29182826ab0cde1d71e72b1db7e6f8851370fca3687ff5b55647a9349654a42a7c9e83319558e4695e3504bac083f41827e8204b11397524619dda7e64408f2ff89ee0fbd20f083f8079d604e4a53a9ffd56aeeea47d2eb4524868411242f2122a323664d845eafd7eb63abd729091448901e3ce8384adaa1f5d39a7571aa418fd69994a6be551b090af187dedce86d0f37f79b86a0cdfdc4a7125405832afc7e541efb3dba0a7fb9c627abf6cb353e18ff7b7426219a026e6f705aa766015ce35fb99842ed5abc84db9b9ddcaa8fcecde199334654f6d33add8cfba7753ce0f1349deedaeee91ded3273b73b84a621facd6e85b3daa9847e36db667a13c731d7cd3699a0c9e46d62d3cea0f81fe9062a901c81ee5a2142fd5a66755b64753d1a24d016598de20fe3642d6a1ca3f6f139c272ac142a7b33fa983e93f0a37f66b0a1225a3c2cd9a18a0134ed7b2d499783e802babf312882a51a7fa78c461894a9cb640b47fc30c96aee335380fbca526a9aa64108fda18c30080b5b53903ba49452d334a9ade70158a3f7231661c5fddddcdcdc7fd35bc8ea47f917ba803233ffc321fab5765a367ab7d70a16b6c03b7577377a1fbff45e6440f9e70721845e842c30e122c47fe58e317aff37beaf5af5ea791aa7b2c73dcb4d98025a12a93dac31c68efda359dc4dd8a8aa4387e79c83281dd1d33416026ee01967bf2646c8cccccccccc112ef316498fdaf48af7278c0732054468de4fb3fa7bb0604e4a53a9ffd58af7f5eaf956350544f4f75beba331915e09091959b2c49122846046312416691ec18ee94cd14f09b1100bcd28f4e319cff8194aebb417a4573c5cf921dbf13ca8dfce568624a5c4769fb5acf63edd302b1090eabfde38b4600234825d3b92b829e7d4a626b7d61deef2e1010a23f48a36dfbc9d97ba4cb2f0aa500b06b82875777777777777777777f70edddd3b9a87d3cd5f89b8803e5a3822bf7f7b624d8c707777777777f723f4dddfdd5dd6acedd9d0ab95727fb7865eedee7631c5e49814dcc6d7f2f97919d1415645873be5211bdc7be5ef01faedf88e57a47d7b385eea86c61071c1bd8326af9e6dcf47fbede1ebd5b343af985f4c2486041b596224424446fc32421f409afc98ccfc6d120f3d5aa73d1d7ae5aee9fdbc0d4aa833680458802e82a8df7305b42447707bd339c026adf22aa5dc0186a4c76cb1f020dba775be950ea39f6ede953f07315c477591f63cee72e6baa71a264e1728e0580b5c444cb0d3335f68f6cc0208ad7ae67fa71a84767ae67f2d740d00dd3bea2ce8156dcff9c95fcaf6ee9e7336aa486b69ab56f1a86e7018a2373791082d954ac99f968d9d1652abb5b384845464f27197c99b379c6aea61acab029b4aed8d13fd91bf0325543f945055e9f0416a355c24d82ba4cd93de97aa744e4a53a97ff9f5c0018da7056854a8517a3b36870b0a63e5a6ea6b49d5e753a54af3668f568d1e9d75ce84f473ef2a214a7efa394f883fc7390b71a821ca4539234c457715b7e7e938638c73ced89c0741891099af3d11d36fbf271f0eead8e12cf89b6aaa92e09b6e40df4bf50afe8401f56fef08856b9ee0ff70d1c78f24411808f350654dc61dbc640786aaad53a916097dcff47e348b1d40bb5ef1f3b7475ed16c6f7a3b367cf42bd32738ad5bae80c6a07e8bb433cd2b724d2f35577be354fb71e20f20bdea8f9e8f9d6d5bd0f9db330d4d1374559dcdaa1fd50495f55bf9540d87ffe7537bb42a4ca5229456e158c9b172fcca2b5ba9b667aa967ba6ca359b2eb647017d7b38ee504354bef6205857ccb2f87700ad4e7cf8db431b2e54f8316c97ae03b6673e777201adc0ee781d7b034685ace56253bdb360a38ab6e7e9cd0b9c08a8148d5a6952c9680602001401f315000018100a874342a15818a6999eec011400106f88406c54389606034190e4280aa2288a10638c010600430c41868a864a00cf0f5a0a3349fbbcdb4d5a6e806b8ed81a4ef68b40c89b55bf3749ec8288431a22d3ef808ecdbd238f992f973f1972bfdf31d531d1655bae4d8e8d574dfbeb4540f69a3f76bb130570dae5b097f0fd4392517fef156f176e0d6388886ae47b375b0208175479754de717d81783f8a6e0be701737ab92642e1c183319e6f0199649a6e5b30ad025e2974ad03500e122ccd5a67c8a298c31df1ff41ef6ee14d9abd2a9a99822fa8b84886330e961e26b51e740b1e292a24b4af35995912bb81e58a70acb32b5e1d378f683fd0ea27c1cfdad7834c041605e269a5b84b6d3ae9cf2b6bd0e18dcf13b0913c315913ec7b309b70dffda05034db9ab9ab5d9fa7b822841de2e7699b94e3b3ca76ae6a352405b427e9fcc33b7fe5dcd3c69e6f7974d3407c66b3994cfa89a2dffe73595d3b544333eba540ce9276384eb50165148162f0f569ea6ab249ee0cd5f3da01c8aa7039833d1f25f65672e11a69908b0f52c86553c706595247f68066dfbccc4070d217c558c485a4e973b55db003e3cf8737e7142cf81007d3402b1183b54b2a38c948f0ca07541c161bf411f50f7a865184966c8108f32eb5a227fcd333e1d68f76fcf1824290e91fb8c1efa50d21f5ce15d10e55f081299d7115632ca04753d8a724964c5ae73934ecb92008e1d9794c6318577ade4334040d21101e0046a41c0610140a7cc6e5dcb5769650ac36512f5ba87163c1e7f49b7fbbace045f668bfb2616db24566d37d92b166505b0f9572c1e0a919e6b54e104cb049b879e9f6d84e0daaa178d0aa05eba4a590ecbc7e7e7a81c0e929401788066fb797869fdd20fe77070adcc8d3118c8ad7645249cf874c54f9eead36b69d7a301cbf0a2b43db634a1df54aec4b44e0831e0e7d57aca92c49b2490e9982298a4c9389b38bb47e5bbc90541306c82165f5a9880d46fd839ea3aedaeba8ae879064320de18d5ac2f451514ef003e29919cd010888fbd1297defac5b312c600919dcfd540d928e597ede4e8e18544776deb34586f274f64d476b2c95527df18c882e76ab550a7c1374feeba824030eaf5fc4bfb5dc4ca6680532b76c0162073c297c74bef58c3f2264f262d3b900f29f0005eecc114b7035267fb2c3c4fcb509bfab4fd1b0ac3650bc0d776f7e0dcc9bb6bf79370042f9b3c5777d1023f78b817edef469904cf81959f9073c7bbb02c04225ea6a1e37522e12a0d2a21269e3538da01629dc3ba7de5e62fd358b1720504cc5469f81c9f9879143c05ac6df49c9175483b3527be22458079d79049d8232dce29b973e382540e903eba5a462ad9e5a21749c691fde857780225a3bbfaf2ca406d685c64f64dd706daecafa0a98dba44d416a3182eca3d4ca546ce90587e93e8aaf01e4353cf49ebe9297647dc8063f36506b6895ccf664d178010999c1382346967e7a8f2d61b15fc8ec4e39e5d83a596c54ac9e947628099e79818ee4abd45032c7c5caf31cec046f278c94ad8189af8b2b3659403f13716950ff3516f5e91783070b088b808fdb9a6e6fa4ed992d080b77aac478827a172202ce53e2e5313d5dd21f2a78edf7f9c904099338c6fefdd1ceea242e8241b27d1bb5f33a04a684650203da28550a6537307ed596f2449f1de326754bf74ae4ee386809a3e5954720ddadcbf652850bd3af307d41a162dc18c67fc0762bb4c89fff53729145810f119c3b2ad520836a14eaeec6e2a1f44f72483bb0b48f5e4f478029cdb6e7a069894ecb4a30e79d3c0b3bc9f83b1f80673a17762b935e4b60cb9b421e3f1f6e8ce1adb5c49debe47e306e211412a0a57371854ecfd9ef440d5c570ae016aa037dc2bfc0c81c459df5855265e044c812c02f444f4ec0676c3d4806cc763d668eccc87447b487bc3615ee64d3e0571c1b367d07ce4431fca71e21eea00d496d4ba3a3fb0d3048665a8272b40d7c3ca6006d192470efe20c7d8a07328f79d650052cbe9510a347b0aac1ff3e7b22e1ef82ee37e996a31bf78e502913dffd05a10ee03c6d49d88271e8df601b9fcdc25e85be025772b1eafdbc5367010c011f2214c425145f976a2fbbf2d0aadcddd0609fc77eecb9ed130e6eecc6391be29686b359892c36d6196f33ae7f3c7c64db05d25a9ec4e419712ddfe606da2fbe135af8946840cbaf71cdfe9b2facef8bf667aaef924da95f9bb975212094559a8844b37c1782bb431501aba15f013298b58193434ab62f9ca0e26aa43429d1285d57fb027b25dd06c573526d886251038bdcd1d14cb872e75228028d767915a897ffe127a330e95f6e4506ff590ac894b56392464035c31d8f1cb74c51b6076ab4f0346f3759fa1d0fd9426209a1887ff6b25f415517364db1284fcf42482d06d30334a0662c490b84e22223e5efe6941d457226892559094e40fcbe6458e27074460761e2684d63016fc8ee6efbc3a3c70feef45fe16ff9a1cd16b1e656be0e2b90cd58e605e50cd61368bf44af7e6aab62e84e16d583d2493cecebff470e05a91e8acb35fc867ca9ea8addf2c77ee3bcf3812a1e0c3a3863c0e2991a6abf7f9ffeffa63bdb79658f4a77c315e908777bd1612248124d708899e989106fb0464b9480a318a8144dee1697f8b9c2ff24320298e1687b22da357079b02628ba030ef0c7564e37682b93f8be32499d9f6d05a117764bbcc8d45077ff07cffe37449b060ff2ffb632e80230e60e7ea075acb7fcc4808d9e0ecd5de0d622a10e7e063cbb572c21a4aae71eacef55b56dbaeda7fc18567200997c720c30c005ffe62d04ae9ab37134e9d54fe9e8a632499172c9bd5131486770932d38f5b1004e9ee1ef52a456b446b23d82e709fa6db51a2f116c88b8eac61f7ae09884459a50982ee05c27d6dac0d5a5d3a4a566e2122cfc41acb876c3226ed2a151a8d46101f79f958506975ad393f4854be9bd7a900c647de668fcb6e848f76dc9304ab19f0ab4b685f76feee97e4f55612b276fe2a9ace8da7b3447aaaf5b0f223392814b13720a1ad8bf51e3466a0628d62c7e915ccf57bf650866eb56c59da4758a3c56c451cda6d2c4285e17b16934a5988808730de4462c6700f51696f1ecf34756944e18107382457092f8e35f0d6ca0e54c554be5d9bba35b879b413e96639b818e506fda61cb260aa357504f421a156732c1872cf683c430cbd5c4ebf7815bf1b51d5becf274e09d83d9f0f70f27eb44a1bd3d82597ebe18b45ae861bf54e64d54c2c1e4c06f756640a1b0087987661af99a31e54fabf19fe4d1a2946e018c7f73d0f3f3e1e8a9d47234842d84b916cbd2126364d23b5d0ab9909e1530c252dcf8d6f2acb2b317777d0efbe70b5bd642e7e1a6d8ffc65164bc6202f4113ea56c8b55b785f4fce64755ae94a48c87b5747e4c704085d92a6e36643ea6de8efd2ae5dde9431a047724ebca938ecb803306467204754072e945b8b020131ade5fcca80a3aaef8929d0bdde0010d02c267f155d6c282424e790d66f85fbbc72194c7b862def1acc433b84831a619b1846de879c1d2105c4d17202a8d6dc371e908095fe4266289c8328b64b0c78f2cebb231d4fae3b635e78a365d596604d928bd8be465c464d86f8210fd0fed88bdff010943002e25c150184c39572c7e4e7bbfdaeba068b81a2ddedd5e111ce1482ac4dc17b49d6eba5c3bba736c1d88a104ffc840abf75a0d195740b44166687c6e35a8d5688be3b6170b8a0102fed2b34ec2110dcff710812a4fd5e7333a28130e46ad56ba596de6f4bb149720a373e93c04af9c758b991a10180dd7818f5aa91f81504fa67328ab07e67c8f9e5aeaabc2f8fb982f5e862ed46a87a7b0dc4fb1bde476c5dab3da1a15f95b0eafcede8c49ba62b1735051647f4d0d794ce4c8c45b2272f778ab2461bb472465da4e0413f0fda432ffe9f09e5e88fc4bca070332cdc14e2104dadf2b3d948d28f08a21930bf90c4d4d8d2501b674b352b2f114ebc9b733319d4b9fc348ff6c8335340ad11d75e5024c8d141fe59d0f0c0040fcb4aa9e2ba2eb456691cbcd6d3e2cd3b3f9080e8b3d9774f4da708fdddb94d7b48707d43e5321c2f631d4d1eb7ceb5472c98215405addc30c06de03c6af91279825b11176b2d269a2ed0b8676fe5d2950349b85444343d52d23f8adc62b0aa301fb815b62786082842c92584f8ce1d8a140ffb63a24b523368a1a5ed05dd648ac351300bd928290cb641d2c5c7f886f04090bec8ade68aab4886407de4116f03657ef5b4ce53a54b90209aa739abf41dc1af062b130a263e300e88fc1924e67ceb15709e1dd0773927a3842967c5df8e2db77094182742c4b06ab945693c8172e1b555711080f5fd54de7d2ec45d35379daecbfa2cc8e060ac11b740ec437a0ca317a271835acb645958f25b076db4d2d05772e0702b0b26cac5836453dada2630cedf507b8d0b6ef03af30b20b6cb626b505b55fda9d1b07001984b0a923645ac94724b714fc4562c0fbe559cb41d429d10196d3ca5a58822d8fae543113f0a99a6ba2a608172a9e9f6df1bf061aa5b29c50ac52629e75be433a670c4dbce751df2567700767f414f2e08172eb8731192e8ec070095495ca1503b72a0ad42c9cb91c38e44bd48c8730a1dae4d869d40da02008d39524eecad427069624e09d5cf06e551a9510feeade400cd21006acc0d900594031c759d09855fb9e43664f64ac4c0ae6e89d088e962c15fb59b950c4f2711023afd1e0fd206b0ab2672c223c33dd554e28c474411c62f4a6b557b918c3be3abbd8f9b9e2dd4834709224f0c97f00b092721bd4e87ed2034bac741a89a22aeda76592cd670beefb52b0cb8bd1631f058055d900a34ff11c6d4b805ee8e1f50197473c7cab13ecf72e897413170759de17b834fa752a4c9a248f001ad7728138fa1f77b4129d6550c961221341ca1ebd2ba59959b8dde342436a69a454bf56be1c92f5bb10784093ff490ee293ea7a9673a88f87408dffbd72d70ca97bc17f4db839a05a783d8a916fc49b7ff8512b14f33d47b5bace085ccc51bd44d4d2dca0bebf1cec0c7e8205e53de74350c4c00d5068388aae9820c4c25cb2ec093699a6cf3dfc7a75d18a31c3324edc285b10050d3b643ba8958f2533204255b10a3ceaa5fc2c22e28783f787bc6306113866737000340903a144d0c10264edc861330444a32fb11238b18c29227ae6a0930824e56c0646aa028771e3ea3e51e075c31865c927935d335fdbe9509d3693db805713285cbb158dca6e417e8f47bdd82b590456aee4af56ae12fca1df6bcb9e94d34a26733cee62227e3f1970305777aca9d8407d4b6938e4c49c97c4d3f773e9237542164a84221adb7fdfd2882fa40ea3baf755e54ecff56beee29f2f7e97914059e7123b1a31fbb8ea191918c9fbf9a960e662b8b318ae7ac7a4281d4861d8580d6fbb2b9eef538b9e63d407682f5546c7221434313db71d9b6f60f07f2e199aa8f0765381958efe22a031fef2c04c81990740a028a24d600e8af37e89281fa5490b3fe3763378702cce9ed66ccd6d38ff1d5011086d18ecabd24a0af80d063a86c8dbb7cd27f6124c2640d016944831100d6815c24300e44ff7909417408d260cd434a14e9a6ff604b74a00279f9a94b04682ab701814701fb3484b008d0fb967788e2975a5334038c87e5d8dd56cc71d48e40e9082b289f01b234df53f48540b8304c44cd51ee6ee2b08c3f7740cee833ac98892d629821ba959c07fde5323082a9aee250973cbba19b0f08148ac0a66cc6de3c320d7cf4665331797c5bc9c00f0a256d7d1e2cb5681aad34c278349f72b3eb70d462759566edf444029cfc403f07fd302b6dfacf871fe9acb68148e926dc02a4da435628f84a369c0990dcf622dee34446965b7d89c9911321dd74fa57eff101d81015913d1d4c4f8eda1068ad305b6e100ed5e64ba734c5921c03a5f809b50a9b8647e7e264733f1f0b1aaec4f6e93f7bbc731c990a168edb31f1ada8d030583246f929ba1569067e8adc6b00cc7edc90a3accbd8731f16d920af8e373132c786c4a9e180bf36504a938ee4c06b973625678d260a3dcf2dc3c60f5bd9add4ffa16256858c118b3de9d8e2a2c348226c71dd03c0427ad794e3e564d6ffceae91a069c7dc825041ee292f50f7eabb0de2c33d5ce06969528bc0622037b729f8c60959474cd932d83d74b09c1b8d132efabbf319f4606ad4810f3bd43e80e7cb919eaf6566518bcc805a2ee2c2d0a0474b402a25e1922f3bd6fa910dc6ca2776e809a278676aad846cf4c90e08ca6da96ab1dd11927382216ceb8a50612e0a58cc28aba17aca514b71e63080047bdf5c05b1f4c08d90a9ab6d58f6cb6298b90d3b85f67163957376d9cba13d9d0e7b5ea16b1a2981dcf54c6596316e128aaf10fe0041d0ca023e98a22013b3b8dda1febffb902fe46e65f8ac52eacb0b051a20d7cb1657308f49ec6b2128f914332e257e8ede2e4f36c4e42f974480fe0434dad9da99403a25da99d1bf679d26c29f6a05a5f963b6e4c2a21672d8b240c47c787642e296dbefe8458a06552047c3da15331cb9ba1c6ad32871b0791254b6cfef44e4272598ce41ea5254197ba926f6d91508cd84612347596a7422a0ff2b61a54fbcc6e0bc22ca561d8a66e1267a48195cc065f8a14fa76c11c96e64c58a3587bce015d70d6ec2911a7c12a2173bcced0d629a065d77055a5fb24e67ce04b671741fa61e95f1f26797f63bb156da0fa3e1169a7d04b2df9c184bda28f52683d4da2323b0a1f3e9e05ca2ab4dcf29323f3567ff7ed5ceb0ab0e250c59b24202b38e808235ac095786dbfefbb62e97a5203e62cb55a404065e0e2a02164aaebd73d7b2e95ba1ab42c97e433031e600c71daefba372bd0d88879d89e82f83b27d2387645539114cf95e681d4e737a6ccb511f0735365e5cdc97bff394cbc978e915526f4730939b049637881018e91d20a1d96e9bb11f778a0a2b7762a7f4d9552f5af1a9508a10a777ad089407f0a6a8d730a1aca5fd9f5c9039875b4b8e7fc2b9ca403b88489db8d56bc0a4484285a7d013feeceae253a0d6998c3499ba4040263b0051ef0b977c3130cfbc243770423e95032b09591c08f290d325d51f3959b813a79b8dbf6cbe8056a54551fee1aa00d46b7e5502699f60872f612207f9bde167b7724516e56e78d927d60f4416cf0d10238a64fa9130343c97dba8483bc956a726e23487b261ca60a3475d17be3f59b01b31ca5912acf670f7acf45a59531db81fff114b32685899322eddd9827d5b4128f96d858e39dc8af1751e6daf473cf8a0d687e5a18f4f886eb3d7788e2ce4e0879e3341e7eccd0a3d5d83537309bf75b71a7a43d7ecece3a344d86db7620870f4cc563162f2061533b536c6952931dbf2de7a3ecee66a501ed50c2af8069c692d3bbf8599a3bbcc9d06c0e3e3c598796cc464445c476c96287c571ef649ae6c83fb02d0fcc93eeddd4fa7adb5ba169ce6380762be2f2b8d9376921d56c563ed701c4191613e15afc4c2e96cba17f572bc8037bf061dc05b9ad27b1330d77c5815c8f081cf97d60d4ad969b279430ffe62a3abb979cb214a55a3724329fb57dea95de5a3ae334cbb57220106de715e596af8667c6daa2da280c5bb35b32d35b676273833215e142c77751b14aa124e063cede84a32ae012563a3ee9743008bb2a4a9fc1750e19b22d83b37809edb437b32b9dd8ef8f30834df3cbb702b8d198bee3b482b60f7fa23b8c497832c66dccb67263831c8ad21b91da3cdeb9660b560a29c35c62c6d37abe8b12877ec48b8c77f266c140d66c535bd5c1ed6a5b7798c26b427d445090462b207ad0a52e0ebc17b5ce2f84ca58334d1743c226a401b33257553122c58c7f37779a7736a412bbf5d6857d0faa2bd95f13f459f979bd6560f6e4f8338d278212cd1e92e5f2ce179471463665a69b82197286299553ee8ed459a2a2172ff0741c1e46c01ffe2be13d17b12670c43f5c7cd6bd15c8e89d36efe8d6983aa65604afb8738d6e45d12000faf187b3cde0ad78af0e81deeda0703d4b2848895bc4dd26797c09b14bcc6f1c800b66a1a55fbd4ac49005bc914f9612667b43e6efb8714cbc47ef9144196c1d50624ec7b1d583573e8dc3a3f840429b8564a4e4e9fff6a612d8fd4ce3b8b91b117707b53f389d48b0d45830e833b58d2357925b0b00b4d42473ce131949abec5af0d2f3a11b51f6dd41025c3e517eaaf7047c12ecd74c7319e3c2e0c67d5a122e607050f2359aa43911ebeb146ad92f00f0999eac56b1362853cdd5920b4c707d7f08ebd2aaa287f7749c3acd24aed11692ebd2bf4702630d41a88f12f0293e43dd2ccee952aed194e054835f3fb1dc7e38af261f105ffbb65a9cfedcbc04f1c9edb79933a297b625e0589fd689ba01dba39c731245b89f9b01d3f433def367bd692ca3aebf6a5732c7485891a7de1f88975286f9383ff130c85f72ac5052e001a20b05de7cb6dbcaab2ee8433b0235dcf5e18609580cde21f63969785542507b6a720eb7d56116bd2a84440bba4f9520b4dab63053a67188332487a9fb0030c902ec507798cb483c380eb9b9e919290b2d14ae90cff513aa90271591957f992f3c4c618d3402c5ba78689706034422ce257e1b8bd31903f3569064786965f8a413512bd1f76feb79589846aca191a09e2df7c34835dd9ef4f1e81c02b747ba5d8c09f914b1d0a3645407007155a13b0838482ea88c23dd1ea49c239105400a3ca0c84a77840a8d792ee14f0f73345f9877c00728a800c79373630d15a17d117035d49209f1177a8848d9bb2166bde31a75639ee81872312dedde395b1dbf5ea88f7850842c0931bc0d668363f7dba8c2f40ad3b19eab23bf6cfe9ff115edada72aea1481ef5ed61e45907237bf8e92949372a04c4e660bbd086eba98ac3613274d378f9568e6673442ea28ee43e3c3c2d029ccd6ff04896ddb1ac1bf0b6913a1a77ba28d4a7a2b864fbc00e5eb2a04313f2abda442b3f2b61c94d4a197a975b9618f3eb4db65e14db42663d7cc892f0c20085449c152a15b7440f4ae3c0504112dfb0fb46f8fb99953d83180762e4af95a7e53a46b839d48369892daef7d442b072adba070ef18b9a2b65f558778c7e5923dd030cee0df36add1688517f8185ed0badbc6b2b7ea09db340a698494ba1519775bc61739e3376af65a57251e833ddfc583c2fae6d28d7a2c9947afa28f4dc5bece456c8ea0c32603846aa7a900f87475c3d4af588a2c3f4597db71495b55d623fe6c9c3cbcac4e10500dde3f9fd50d9bea63ac8ca50f95f0a65efbb494e17c3154c3add2a86fe3e73755dc32cb41de767ddca298598bebc2698dfe3c0844f1164a8b78c5483f7c35e971357ee45bc2894ab337914e28eec454b0f7ebe6c2d5ba9954278aed4a499bd283f0fc3a90a993c15cb64d01ad3b0ff55142e31c06f0ba122f185c6bb469f7c9b7d205d7154a56372a5b0c81e2a16feb611cf473fcacb9427a87672ea34a1a8f351c3298147e45d8027e961d5f248385c4da7bcea504b7b146b53fffeb30e5a4ca264c618b11b2d7395df641845c458a3e8f9411718e46c267e2bcc48904389f3a5ead8401a2ff2574c5d4418c218273348c6c342a9e7ff00390b8cf20d39c51c9c267f422accea9b68df70506f885d41c8480fbf3fce016e3d52a1fac5e1bf3f9313411fcda8461f6b08096eda12a55f6daf45fa518011691004463666a73c9404f53f261d49cc8ae3464f8e592020f602d338ae14d74fd9520f444e50fa25e00941386645c7a65fe8cc5dbaccde24ffce416115b792f6ede38018f62661de1f540c596e9c73b9117b7bb30e77dbad97cb7d0a9fd87f85da3a5815fea321dd24e7877274dee1f1bd70a163156af9987b088e066316151c3eb8360062030a7c54b4eb5419e368b922946e149698da2dc3f4f4d8cb31170cb9b849932a36cf728b5c2333d0e065755d80509de6c196863d861fffc405593931eb9876d043ab931af176c9b21a31cc9855c09d88694f001e91dd8f72df74f4da4e1d730be5606f67d042c0e50c3e42dcab438c0eccd65647da9fb9f8e6330cf7341bb8cee46fef0fe0dc74bc57eabd15bd67e2e18644603da7475500f3270237b1cd8c7adbaf0070bfff0f00e443efe6abc11fe89bc1700d2a89391af57de418a4b00fb42db743816f75fbbf3059ff92bc7db76cf6aad1640100fd4ea75830b830a33725f9bd7497a24ae0c90391b3bef76c4d44cd63febf61a23ab142c62a06601e5faef1fff5cd9fe0052bb0d6a0e5d7b4023322f937d5881b3e57401e1203c698322cc4a33cc15facd3fc3f54db360cfa8b81477d9d2b58788f562819df8e0511c937e2b2c0772bdffc627d47249677e6e9b5d3fec3adb826be353ea0e1f1dcaf9bdde3121641dbebee1906f59e03f621442454be46bb41d98d9bfa68563a6b5b472c806360c97170e5998e2bd5298efe600918fbb34e3304f88819abd233e5113361202c6b0991167ff54e7582d3368d0f4c522cb9606dbfaba86efd9a0493af6c11d6260aa7ae4b639e55f001bae3961b153665131f17ab142be927104b0f8708045841fe167305c47d24fdf89540624cb5748d09be51e96a932d78f9810d075fbcd474ec4e95800f640dab3a21c2102a6e9f5e82d8da2bad983971ae4a49f1f5e8e678156dd804cafd34decdd50a432086f534ed88fb109a9680bf5b8a56184f00a11729b3aa56ba8910aa018346a11bb199fad4372f741aac45c3f6d90c4554953cd174b74fd76beddba222a4a070fc122d745350c22d760c6b81fa4a56941507b16543db68f866a6031333bdb96b1f6d6019228ac9212981df4c298ab717b126b5324df038593291345ccaa7033190c1caabe02b0e34f70af91bae219135fd74a5c295591783d246ac366b85613f5cf7f362167c7341832627ed0c354e7ee0bd4065e48c5a3a9c50598feabd22952860e4348162168d0e97c3f5fa0e4da0d19d13f95be195d32562eb4fef6bcb6ff374ea745f7e3b81a3f1743cb6abb8fcc795bcb47ac04d308c136c677ffb80fc356968f6b764ea910b3962511753be3983f5c15302930d888add42b00bcd35c80eec6f1b8955ba51f53acf9ce0e711800a02405c579ce34bd6a9849c26cfb66c3eb768d0f6a54e0531c39f4b77e9dc1341cad988204e4b5ac981f67d25e73e55eef6ffc83d69a05f65d2c7c226ad370ad9acecab629dda60b01bdaf085465da07d68e1e8635cba5ea9d871824b3cedb40dd50969f69bb86ad6c762aa340ffb9662eb6a10775a55e1c30020d029a6d60f8684c7befb439f8c4a6590d9e20d25132de64ab8c819995ab01442d18cbdcc3284dc8684401816b1158251997e6b021f45386edbdb7ca3454ee339a339322517112b3fb0357d083c16f7d33d86e571524c8e72c9cccb8a586ec9f5471b5ae43121accec89e9b7dca9fc433ae853b16f0b7b39f485eb0b5c465bf960699a30821c16f35ad86352460dd52048388609a795a9c9d3d1fd9c946c874ec48866c93a38d5fc91e8fe0ada95f71cc49bcc235c49cc279b4967e333d3ea9b7d8bebff3b887ed4f856137bdc4f4dd81ff25bc669426e44899c85d170fc7448b8970d74863f10d89286f724cf5dc28d33bd6ea049e133ab06c567759583cd7846542697eb404bd5e9de71d1b0eb5186986a2cd44c34ab1d85c9752327aacea7a62d3b37568dd1b960a5aa895a709f11f3fcf60833339e66920d6cc0188bf0f62db6789e7e2d097ce29e7c094208e13aaf459cbecb9e364010b137c8f71154f560600459154db8f71358ef384ef18b1805132886300109b812028ea007487b841d470b29a9d8c4184ada0f9b474d5aa1f91a03ed0b63d9357555629a9d962e4bdc1ff70358acf3826ad913038f348a7d9286b4edb2565eccf48eee2575fca5c0fcd9832adde3d14a0ef928df6c0f2e5694f706ec8d9eff4ecfd78ed90edddf95b6d9b8add16c95540c37012b9261929e3ce4bd2b4f7ad69e08e60909657781de90dd004230f026d19dd3e646245604086e92380e7f7255f253c79639087f4cc1c2e33a8327c690f83d4e30f0c5f038ef9c73bfc4366a6a90f1e0b52653983c52f6582c74a066ddb6f8f23fee42d541f5b151ba11b6ae3b5cabf144bd99635609d290d77682f71712bc7d810851a7a1c3a1a70c13cff7c9c0b8e75475455316e9d3975e81af45d31f402ae1dca41e5ef7c58ba5429483cc11403e998221186a271572d721eb7640543351354aaa44c790e7739a8ed47fd57e34f0192afe0f7ce688a4b3c4e69ca8d88b6ad66b5d64a603a7f8ff3342d0a4345d249e882f83ebd518cfad362784dd7b0ea4240c0a55654b461cb61ef1a89cfbce01bf5c98860aa66432294ea8421f10920c03606f3df059c7a2b95c1793ccce386c620e0d8c72828933d5602cdd352a8e309c00252e76ee00e8453358a74f488b94ac57675198a8e15788b18d71b68553e09b5d3206e7a7c66debe5b4ee4a4b786833ccfa78c9d5f2d869ca3c1c85a127c24273f7080f2b7f70b116071deb1ca93ccee456e627314b50ae73d37b408841a2f7ecb89989eafb0a70255f86f20ade281e984ef75757f94c3a15232f7d93eee2588192be6e6f04efaad2743c902015dae76390edc91a4338ba8f5a23815ef3a16aae8e01d9055848aa3a95a68945b86cdaee8b5629c346e37c7eb60b0241422fc080deb99d7a2a8ceb8ec9f637d843f6193b8459939e0be853825e68e60147103eedfa50fb2e4c65c8c260aef282c90cf83954727b9a74144079c00d93e07b0e495b78eb686ffefee68eb8c45eb1b9030c464482c0df93d4d7e30ac474fba9c31b1f14302777af59a3163c57377602b33f94ba326b5bcb9f38f42f1eaf582f9c45058ff1b31bbf18965e9061ee504352d289ecd63398d861a4f484acad5291617718f2954e6ed9af85884e997315a094be03fa7861410c70b2364faac81b8fc72f42f016e6ff4ce8d11cd7cfdb9ad5e1d42b47f2aee5d979b70159f69daec4385452f92c3245e4db9947beed4c655744ea796dd60405f7cf1df9e6e17d901e5ae289ef74bb54ab054aeec54e45c9d7418c76a40911e1851fa025289c4f099a3d9ef71a72356d081fd94d8bf21f6f8b40cd3696af790d1ed537f02da9a8401a792a168cd7f508f4c2e1a50d55290dd97deb7e32be895bfbdba998a90e5baec8b9892f80dc84a7db6a84e3ee8658315a783c9a2e97837a30b290950ebb7b289f3c53a6234f7516d0ad7e244e6608e7097871653c21a085378888d479fd39002463061574352dcc8d550b42adbb1546d813405ef9df1a2877ca6ada4d613afbedb72e6d755eb5b870bbe67c0eb92bcddc05b735ff061a3e3f3d239ddb5d17878b7c9a9ea8a618172042eabbb08034f4c1d6b94326c198f401232d05f4f5e8c5326534c829b56c02cde3c3aa5f4aed10c1c519195b3a6a98a236d18b01b690baa8849c48f9b8c4fae9c2178415e39a1b5e3f83f25434f90c791f57a1bb4a6477fe28014e8e010457b192816d2a26196c4a72b161615e99cc22acf7cd8829a7bec1121975f06c569c6a1200cab156c3fab6e991aeedf4f962fd5fe2e51c75850b655693179c8c6c7d8393eded6876e397bcf9dfd020b7ba423acaa906e7eaeaa07571644b131faf3b3d9fe6fbf20993af02ae786e720305f2f84e6f819be91ab38ea5ddf1d5e14f689d2bb81848a862d955b1c17c2f4b4658d9899f079ec12191d67fb3fb63f4c5880e99f9969ad8fff3853802d4b432f4a48acd36fe43949ef78510c4c09f1b5ca8dfd35ff0561d0f41fba433f41d4d6948fd718d724424e9553336215f604c10d113a443bde645a9292ad10bb4f251f2ce9d791f87a324cba1686835299fb5b0593527d2b40725b98f8ff418fcb084d24de94db4f2d53f062e348733f492ee9e40447a0036e24fa6c38fca7b5124e5a5052259e92409527e71e4e0ffb895ee8a6b95ccf328b0c885f2ddf0f97ebbe9da528f41bc75fe904622b76c2ca90121c18cf5bd18cc66a97d0e7a9f29f2c2b572afea0c1409153e38d27aaf7766c2c2daa4de4a735e49351c6eac21c913ba3baf5053b1dc8ad2679d7d58ce6ffc5cbded787d10e4507a8cd38e7a95f9c16bae26c68edaecc1870b83b77f4c98bae4336f1513ab4733dd28c053fed640dd8d8fce3a4e58552456f3129357dc8fcd5714f2e280b301a4030f1e5860f4ee2cc9778267f25d8ff8bf4d00e3c6710548e8fc2408c537a6826f5a59a1071b73b7a686c441afa858dc54c0b851e5a3efeb8d046d73c63a67564f53d3f8c9d140c79173046fe6b924907642706164ce20cef5c3e78b002852fd33b681b8cded5054031651916d6f884d669854f8f2d279b1219c237c8d4926e85b1324bdde962e6725753da57b96307f433028d9d297edba3c8c1a79ca343b1ccb8e99902746ba78b437374c6a2765ec5519ea24ba373923b59c09b4bd574ef8a4b1ffa3e3d985725ae79b5ce7da099b54a09cd7e6c90e7a106e66e1a42750cb84cc68f41754b6460db6ee3703165bb6c0c839b54b64eaf8c19db5b21d9c1268c8ab28e09e9614b3b0af73613e29bb4849ad221ca3a244cc76c3452dfeb3efc812f49c8ea17a516481528ac5ab2cf0294cbea407159be401c1f7acc0241fb443707d716333dde56f1e62c434b3916b62c88c6f7b31dcedc5c925f26331eb4d1e7373179faaaba4cf9d8a3da5dc9078a82bc18e34970aa887ee3e4cc01882f69867942e5c67b8025b4f1b65d5fc1c82cdc552c0c4da173242252742c8e4185f15b8beee2d4c484724fcd70c8a261dc84704962d66d5e3c2d28c2c284c156eb865dce48c209bd6b863fcc43359fe4a465d55498250a3175ffae567e690bc5a8107514e2c5d780f8f962f3acd3968c0256fd2603d3fc44b28fedd8e5ccafc8cb02e35915828dd3801d63860530b7d2ec4baec44a38f7235c77f3a061f26e356b0378c066ea1a313f052bb09a36b11183fba1a2d1a97b278c0317b01cbb170f5c0f76c041709731fb94d239d2e0132909aa11e10b71a029df398ab85231ab9226421f4970e906ae5cbcd186ea2693e2f03713a4a3d1a6f8dbe4f23ebbbab8af03cfdb60b3444a31f7e201360dc351cd8bdc7cbaa7e226c0888ee6ae716f2a4ef7147507e101adbc6cabe28754ac702b11c9bc64cb80d00295af731686da20eb222c06c32f7b85db74985bc0fb441a9fd73b9d5e513ea70764e05995a72c49992b0038abedfc3dd08b4c8151b8b8318e1e0c28004685aa0d50557c03bd15769fd14983cc016ac9c27ea2523c6c388be5e99152b06d7e59df9bfdee8b92b83fc14ded25a6b8e7d83254773849831c3b7fe283f35966ccf6f9ce55e19ef89b960106a7e6c75c28952626b1fcb87a4fb01a5cd6d139967089bcb7a297c7b9ee2952588b9f734b28b4a185244913c59dfa82c7e7ee7f30f955fda8e661819a25686ce829fc2885db5730eef27a127a1085d534a1dce4e415940c42840ede0bebca366c8ebff4303b20c094daee45fc247e3db565d6f7120e87c5e25ec0fbe3c97dfad2097f1457ecea6331c9aa2ea883b476d4bd809332948ed9bc22b35a9aadd73e5a1661d090a22b8525a951e813ab4604e6f4cf2ecc534bd500cffe27d064c565309b05e02e7cefc5cc0ced7ed968c43f47c0095c9a1bedb7ac0352ff3878c993f8343fa011533ad2deafd5e33b1a3070b05f05ba7ec4d4e5fe1d0ff6aca173708da0c4e254cec1d38b7622946aa8ad2bfb732042d6b11e285a9ef044b56616a10f1597aef3123edbf60405e29eb7c9ebc227c8406b9fb084c70fc881613c7c261646d40ed847ad52433c7e632fb67c1cab67aa48620355168301bcf6dd7c5858e0440bbd5427513360cbc62f10161b4468c7ec7a10ab4d44c396e784019ff305a025cab167701d447fd71c7a94e908073dbfae86a39ee35df73dbe6ee7581cde64e939a2a3fb3f6064f41ab6ed6ccb77a23abee4f1727cccaaf885d27dc6c3c2a0e7cfda4b915986b4366aa97bfa879fe1311944c85d3047afeaf5662b390dea8e6149167dac81a0f106def27ed4682e9b6150895b4451103bc0b06aa32fee61a76715bd9818a61835dd910033d62915e3e7ad424da79c9d3215416ccc116227f975727578f2e28aeb55a60621d80d981611f2527a8cb0d9c0010380ae348b1f77e6d3b11e3e5cf9311be4edef7ea787caefae4e6d2a63938aa16a5e2deae608646e0c85e832af45e1940deb9070fcec6b95fa8e1f0b1d76e4519b927e178f7164ff91ac2c98e0904dcad3be303626f6a2f08bd58d32e624b0448aa921280d8ec2db0bbe05799c48545b2ccf34f5c2d8257be3e28d446363bfb1155d6c7f52b896e1a74c32545ba1edbc055659c8d7d772bd0dd66ec6613d34c0b38a44f954ff6a929d58d2bcdfbc878ea72355d824e0b0f1923b1ed2a2054095022b572e3972942357ee73e79823a7dc73e79c630e6ee69deec8915b6ee40cf9b07e4c70e7deda13b1828b12faa97698c471bf2e12c1bce388bdf6377086337ae46cd09c48ff42851723f852a0c857d518b56a67d2e212a5e7d0a658af934b6a4ad077974eee3469fd35223b2703743ab993e4813f019d410ebc93b8b11a524af0957d3654f311c0b83c40c7d5a487a5281364919936fc2090a6ef19249048f1323efe223dc02ac074ef5f1183cef6c712f4d129492877a5ab4751c1d2a88075c40bec85cfec691dffde9eaf820d8c2f5e7ea5a5b5384447e348f005b485fdc49b0d890607b7ebf4326c0e0f6bf3ebea610558e3fc314eb62d247b5bbd81d24b51c1958e2bc63168643298149e78f005d92a17a8e517e09af22e1946ecc500913a4b5b1f896ee8c91221dd8edff76ed9c36bf06e007e8ea32b7f9880b6a0cbb8010568e662465058bda374f7a3b4132081df35d2d0ab236c5c42a18e8bc41369529d380ce6d4ca8afd7c5dcdcb57bed59564b53064b5a953dd77a441558df2a3f2557a0fff538d5168ecc90d359901b1e9c416013e2ce2a6c0dff71bd16b1903030e29b5253b30c80508da290185f7f4a1e46002ce30da4aaf1fca9d66e9bb0752df0d6316b6057c19f90c232b282b34a6f88dfb2fc1c6b83066e95696d593b42c29764588706bfa9de36c5e34f8a38c3d5d365a37f5a72b0ea3ad3a99fcf24683e259e2c3aefcbd59b0dc5f5d28131198da5239b1c605d8b10b64b57492630690ab0fbf82c552c258a6b0411e57cfae3fd5653455d1abee15b126894b3a801792ed570fbf23bbb19142b9c7de367b885723e6120d985a0e09580f9d761bae61f9fa3a0c706b2ee19e4534c3ded16162ac793baff020c7412a9517fcd4adc95b2863e530d9c4b6f081a22df46b49844cee6bf1c14c7d8c6093962d45046b6e759aadb19ba2c26620ca31c03378149f13a16dd7039506ee20116854793885887b2a3de8695de6f6eb3fd09e05ce2b6cef27f519700fdf249a8f061edf035c52947f33e40c637581e343cf9c09773b6b50f78575411773d6192b9fafbba342fae2bd75e6365803a8ff5b1d2e1807adf56b0a8f75b5fba2ae8e7c5fc44da2be4eeba2da6bdf2bd0621ac94f1dfe0b88618c08d2a341c3fe37910b22273731346a6c441bf7e530c26c2ce671e761c22d61d7e9dd0bb08e99039a6b825997d716747d13a5322158841d7ba92628f1997f6f0e814560bf450142c37982eb41070ed3f5d85f5c49617e992558b2907ee84b6ce44c336dc92a37d4694051f9899e152bbc774aa401b7d19e1986f2bb4f11040e72acbf6b380e0ef9d6b6d2a6d13103cb699eac51f5f1d5e3f809b4fa2f76513bcf3bc67fcf63dd076ff36667353a22b8375dcee5e18444339ef372d3a3289003105256eb2f32de9700a14510ef8da904e510310acad8490e24dd07fb139768db7d0191726b1f98ff8997f396d3d6df34f821e4bf0c18525b529a8f4414fed31740f81ae086e3800d5f1ea0e73f1b0b11839f6c5fda54e5e1803d106b2a28c638e503e338f937a9915b92a3ff8e6457a21fc1ba3d401eebbbd05b7e673b644fae69d1d38b96fe9f16e47048402cca33b1608ca8f875a88362d847b066def004b848c0a94b7956a00e83bad40ef9af355009083a714d8dcf435d4c5358a65bdcd880302b4ea8022f892c607b8b586de79c2ee589a02770193963c475a431c06e18ceb1639467c9c948ce1e699307b72c7a5a4106877652b3f85fdf9e3b4c0ef96b7329e54137a3f27a2949c12db9a79c64060bdfc1995bd2f7eb735e7b0638fd501e4e340527773f4728819b545bdaa01cbcdeff94684e3d6f3d0057cae33aa83fa9c291fc2ef6f2777b78f80a6f75230a2e9ca82ff981f288c4f48718def9b3d0a4f5cca0100b97c8845861929e6d79ee0242bafdbd343198a93044f6920708b92a953fcc6cf86461378637dcf7865aac198f2d71127b791b7094750ce0d0653cf336685635a50a4e6df3afb06c01f9b409fba1220ffaf675164f3c65c158a05e8e178f6a4f038e9a9bccf4698874c95a435118733b0d95fdb6c376a4527734208e199c15aee8dda2629750a0d1b806520b32a698c99e5f9f0b55ddc26ecf97aedc2c8461d8a2911ebf82dc44223a147c0075739398e6c2f69cd57c2e2c8512e7fc4f1e1987894483388e630a947bb8aeeaaa3a9ba687cd4349ac86238c97b58a05212481d1be5931cc5b55b1aa54efb7429e8483a3b18152ba60c937971c607f180be110d5ed7bb4786fd83648083e3d69708ddd52bee389e27e80686347e3e445ccf884d87d1ee5b0fee4afd2614320061cb748aea9f7bce0eaee2e55581dd1843f44ef260e3f1afe2b5f59e826b7cbcea976559218ad1feec3ae260059c68a988078cb917d9a040971e1d22573265b52bbcb69a2076bba2ff793316645e817f29d9729a9ddac72e59a59ca006b2e633a09908b157b0ef906962d56a8d01bc7108d09ae13c8ae64da03a42c19418ac187104fe3e0f135bf14b3f2ad91f2f7a5f53a377a6b63798922716c270ac428b33cdc95a7b1f19f53a536a45c9d65986058aa55f8fbf717e7c0d7d8b19e3b2dc317455621ce7d7774f256a671a3d27ee8da5d20e307e764695c8817c6728fee0f1948d6fa0b2c4e9f916e8a544fa1fe9f47bfbd8b05f742fa2d3a30fdd682a318950c51770c32a5c727d8a7079cbe0421781f109c1171b698787f0c054a7e60990d554f468841e277b1cc6d7910846105976d88b1d75f0506a733a2a86f5f8111f38cf21a04d19a41e28e7bb2640e61cdde210c41ce2fb698cb16116747c31d0fc5a359f77bc526dc0a51a0cddaa3ffacd38d506e955484e844ecc3ffe0f43c2e1613ef2d0cdf6e7d3b48754561ee855ae3818435575702d3509735d950cb2889063dfed12b35c025c1e4360f93d019a3e78fcc2e58614611fd8de2f138cb446a3cf7e8bc3d7663493f01a3677cef8e75c8596d330fa0ad38babc0d8564c21cf9c0edf1844eb3f181070bd7d3a3e7e7fb09a50359f0e245e493f57bf2bbc925cb3caf7fddd76acc5e52594194f31edb4bc2e7e07ba050308fe9282d5a114a5f1b9d6191e652883da23fefe8600924f98f389328c548d893f45c8dabc2659c473bbc128ca3a97cdb0271556c0c1ade8f92bd0c4411ac76e2296b5842112e46112df9b9737d1bc8427829f1d89958f32f1efd5f478708091638c26f99a5526b338e6750d08a1997688ca82f17202f4875f9a78ea729cf81a7d2dc9697e9c4448a503dd7783c68121e17a453bf8c802fd29d49af0d3f6d175af892a253b9477363378f18acc498f3e3b19c348e9944de61f1ff8a2f9df4c0881c636963f01ea66e9e8324acde33c9e6bba8daae4b7d8f65cc3c84703bba1e40c00d2005ced5653f11c1c4403b8d77ce2d1185010a88bd461ce3be815fa0458891b79773d915ce250c90ab254f0b84aada52ee70bcbe9828ed202bb499a1c06968e8a2ce5659b1a375f87f2d038431b09a8168aa28900125a0811e115317101723f796e801a5080f4460e54fa53faf1734ac78592f1d3d20b72c52d4e0372b0587396ec9e920d59d7a666a40144b189f4f018d7605aebf6232856aeb88e8ac593b0ca2cab38f325c0391cd14e0f4762050642779eaa0100bb2a88a72e6f6f9e89f805095b06f5951297670b1af0a52dd6abdf0aa70664d883f3fef35bda1a3977b353eaf10583fc767f041c952e42b1475d7e852f91e5ffdeda1467dfe848d598a7bd377c147cf517e3f4dfb4703847c4028d89068db95ba620c024a55362c8dcd2d38672e9bbd8d27b78c9b9cfed8baaba35255f0227c732960c0802be6356e8003fcc5c552ffc71009e71be2a441100f75cb5b14f6933b5c759f631423ce871a9997697c29f25786f00351b525e7518a29e1968d006287bce3c87f86e4f53b313db48201c701bb585120277ec6308b1853c601e07cad4941bc438c35bc284a6f8a3981949cf0bcfe2667fe52bbd3144eff6d2f42336c872cc92eef36bc91ac18891105eb3a12ed2ea735d8907998669a72999a957308e04ae7c6d7a36386398687a623096606826105064106aba628d6725c19c0d87a09c2b0d85ffee61832ac5b3e8723baf46a412c818b2b7c338bd1380a684c89ee66010af47d1141ba51c11f0300d1374652bde91f06898ad8b0535f586cf29061bcebea49d50588b51cb0b1c88de8e78338410b7827c4200365341dea7890d4e9a13474b178551fe2c48b1413832c0f6850a94f4ba260e5e06075f7a3a815c51df7fb9e526c054d1b96e184cce92d4bb68e588b6ec8fb6d9703b66b2efd36a9e1bc66abecf13af6941c37c0f578dd2d42785bee86b0295661cbd25456765ae48f78a44d5f5145092da7f084f093596f389711882cf6f57d2e492c8c88228b69c3e1ccf016a69ced5b9efa61024af97a1adef68553d2b0113d1849ab04f421708792d1f162f14dd4970518f79405df1a4e51d7b2c7873c3800dc65fb752c2211203b3465755f4629a6a3c4866bbaefd673936ff49069000b4054d8f524a9fe17cefc17f4a779762885da7a3e30a7dec2f2ce4cfd5593f3dda9f2e92191a1874d08d99e1d4d8b70e68360d7f823d494eac4c6f0d245990960d1e302e182a53ab9c6f7be5bd41cce58113a55ff02588f7a51a4f1c6eb9bd9ad7e8a5256a4f15ff0162af4d0a5961b3e1a93478327cd11eb0f15d548de1d6b084da4342fced9c60af77c51ea85af07f55401385559149e99555ede2f321c74ace7d02205fd449d20230a13e93f8e57e1c22243a4285f12ccf964070000b862b42027138b0d6fcec83258d8fe7fd42043b44fee7ba04a7910b5b27fd686c52966474024e42d725f250490620a49bc49e4103e19d558fbcdcc630700bc57edb0472a69ed21f225e4420ce73dd29309b61efd515056354ae6539f0f5e9062c5a7cead44f5c7ae556820eb972048b3463b381973c9609918e39af2e5796ca7ed9e7cd6846c6d558e05eb02093ae48e3d01015238f63088655d6e82e93b49af27eb1c6979c3b81470b32caa3066c628e9476f508c77f2c81a5df0fa8699a6cd3205b0d4b376f02083c10ca02c07632dbdaf72ef1e6ce7b3cf421321b4319332fdecca32899993d5ad4f853471d32565cee8e4a0e192a6c6e8fd0f064a0539d0a3d382b20594799c2ff8120067964ccefab9d96f2fb16716e3d017c8fe9915a3440987b73a6bd07a916f0437c92afa5b7e8eeec35cff3075842bd094b129dc32605da838e89b27bde3829794ebbb188292a1915a1f13bdf629f64181444c10720b87dedcd328c3dd2793ec188a0692bb4d116e791f9e75c1a104a6e0a432b37a5a6b562fd378281c86bc8b30aa13c446a262e22d6fe1ef4392f69d4741a48448b5e92ca9653be408c341698b46a63811912ee8ccbfb22c7fa8a6ae452e565f133d02844809de47b8a696ac8d338954639c3ed3f2ccf99116b96048e66c9c9406b2648209676ac0c64a3d083da645b7c240cf39d2c4bb40af39f91d7a72b6da58b98ebe14faaae842d2ea9a9cd23f154a41221b0e6ede667f1976f5ec4adff870352cf8eb056f87dcd0a0b7e2b10942c3644a934b5da8699d342052627868f273dd634c4e002fd268e9a7cc432c446280135310d1a0822c709bde391254e75ce6c380951beee6273f448692c20b5222389a3867e8e4bd9ba44a654054133099ec036d08959babe91fa74aea85569caf9a454053a664ce25bc37b1339c041e00034f905211744e4cd56e3e5fa8ff44fe96b891081c5b67d2d4aaed4a165d4f58bf867f2094b69bf7dbd508a49041aae9f77e0dd556d80b99c78e4a8e14d673733b1385dba6dad4a4ee2a311cbef06f4961530661f78f31f129fb1cb5c0a72f33cbcb1b4c97dc1dbfb6b459a59ca30c43f0b3a4d5bd5f78c228a4f813ca23e6184c99465c47fe4e9c373d997125d21e0317013090105d69795b07b64c8dff6265f3010daccff529e6fc3805049882296ce66d73cdcdac6b584f22622bc752cc50317927d2d98d2a66c62bd2975d2fc402a2632e63c705090c917758d52cd2bae47f402c6df85d42b4b004181f2f067f228dc92b573454ea1ab519366bf93ffaee56b9a6b3d6028d4ef5d7209ca709f232c09d666509ee3368617bfdfbf5eb6a92c58e9fe4705d8992b2acc4b572b9cc147eb8bb422521c90173874c6d7f86ee530b039dc375decb8a19a3e3233d985cc10ac5431cc60c88fd535176899409d7e11f01ec1832e212f0f9f6dfd8166112d4d07e43c32e6aab14d82987bf089eef3c0f435c5a7d62084d8d89d8365218f129546c04592af4d206ca76d0a1c6122894eab8a048e9a89baab0affa8c7d15905494b55872a6dcec42652a680fa85985f53c8f8d58ae3fdcb56f05d0cbc6651236c7f00bad0b66382b57965574ba327902cf6c15ccecad2c7c9064b570cf26b77fb66e0e80e7d42a30b6b00c83f7216804866c6536883ac4dbf43cc2a1376f1cd62f0b0ecec3e96da3c4cf4500086445b6b29e4edcae1c2d5eee8f39f46c6502963dcf617477406a651c2ef7efade3677ee5178cbc95fdc8120b0841ab228a077249fb9a0f0c59c45bf365b242c8fdba564351e25ffb52c0804b004aece92ecd7fd4bdfab3645d8666df5deac7724b905ee3b9ae6ad17e77e378f9db54737eb70430e4de1db247668930377f0c61228e8b6ebbf2c876b99948fb25a394e4c24e1786c63fca54062bb717a03a31add7c0dc84e102894614078462316a4f946ac241cd755b13841772137e2345b3213e4fc9e717f238509c8ab319fb54034328a21d6536b444d2302ee072848b95401699bbe64f614b862a1c9212b5cd3c07876032476336c2ce0bc71cc22baa0a142c59fd0c190a9aaa7c230b3c10c5a9e79233849ebadba80075e07181294f037188f42239e2a1454bca0e3a29bb89138a03b49505ed2bc9df88c87787c12f6031498911cf0891ce884b430de953d7bd8b96702f7311f37067338e4714a32c2632904b58ff65378836d2e3517b2003a27957cd571f1d9ab3a4870f9954bf8690380b12ee0039a2f926c793f3269b7664c97f5a0e6f3e33480203af0ca92580e7ad987b60a767e419c2cfc1646048407744ff64499763a36be4889f025740b103eadeee56bb5a49902805172f44ae143414d25d0915ce55f41e1cc9fcc7dbd81a116d7ff4344e7902440a04fa0173995b3054b24a070d97901918a7b0b5ff4a36add26cf4dc50c3f676d34439ca428c6f92796e6e31446352d3c17c7448c5a85de725563008c230e81c470f46ea18d58347e8a388e6d15ce37b65ac0cf1e83cfa9290bdf7de724b296592297c09ae096e0948bc6412c30b2d36d8135f30418170b16cc9a19381083502127046a79f1eb61ea30e091db41e0e06386435206d453d96861ead8b293dae1a7abaa0d2c3ab8b2c7c70d910d4c5161e5c312c79a1c30e32347971821d5c4884bc1022816b06212f64e0e392c147c5852a2606aa4e02152b20a2e2092ca8c001153c48a9906c60c4469d7ffa7d2ea2a2868fde91076d0c6d0c6d0ced47fbd1a098b3f3417d7a7b43e84eed6fc583bf7d87bf3f23f4eb1752f7801ff99cfef6d4eb2df57c30103e53f10e7fc7b3d36966d229c237acdbc0083066308431314a01dffca04ed805fcc4d3c0a7b7e13cc2db09c65bef4225045f1f38079e5bdafa6cea56fcaa24c1e01dacc46a792bc65bd78cee456976c69bf96464dc25e3ad80549771998f87a32cb9eab7923ee31209f35640647856f29340bbaa633ef3c923c9b22ef3f1441a6638e208170f0c97069c1752b89c647ec4b54d2eba7898063734b102170f0ca723979393c350c33882cb4976e3099790bcf931f4447232491fd4928b738f87ae62236b1deba17ffa45930dc5c536ee437f86e286add47de81ebb66a7f36305e3d5b14f1a4996f5ce874b87e88fb4d4888802bda54154e8adcf1904bec1fc7bebd34ab7ae5b17b73eaf300e75950f95f4f596e667176fb16f22c57ca1457dea0b511fca264f2af10d7905b3ac5ba62cde6a01f34922c9b2ddf70f379c48561245e11b1b49c438515545f785578ab751bc75a54c8cfb03e58789f9e44e85ea336ca589c474613c6c21d994427df30b559806c58d5d04501ebeb80d6f0536689dbf07ea63416a35b83df4d65b086ca106ad773f79eb272617e5f2eddcaf83bcedb7c939e3b4b3dbb9f4b60a66659dc43e1e274030af5e3f1eec892f9878598f2e25e8e562d70c3209497039b1284ffbd8c5a39fb74b0d5a9faf06ada33ed9d4a0b58e25b1f92159d6512f5e289b8afc90d6adcb175a946516f56ce96d33bde59c7134af7924cdb21eda905b9a65c7601cd6087cc37a088013934b3ff4f9a19f98dcf8ad7913896fc826c9b2ae525d6bede973a141eb451a8c6058b72ea44e9372dbb9ad739fdcd2a095dd4e675d2bbaa16c7aeb13495a7bef447aebad6423c0573eb30db6fd86a45ea7a601832dc618fd86630ad5e7a4990d26931b9dede7af79e669be4908c4afcf9d038ebc538d8dd09f4d36e7bb644e07fb41ef084e8e987b8320e6353d7d7afbfd090466f137004b12b3f8b1ea326d23a3d84ca1d2648a04e2623438ba2f2d003aa20b26485880a0810450b0d8e0032c2f2e9ab8e881b275cbee8eb65b76b77cbe5127a573b6eceeaa83e876774b29e527a59452deefeee62159dc3da7f76c654b296decbea9d4e32725fbcffbdddddddd9beac9c5be8b92524e8f7c83a5942d41d97c34278da00e2d19106a4d819d76da89d569b14a95ecb493469fd32ad9692756e917d362952a558ad95929f605ad95624ad356aa64a79d5f7c31ad929d7662957e312d56a9d2849901b3dd72d6cc358fb3229ff5b89f4d7985a4556236ce6931a7b26212b39b56e92c82553ae5151cadd56612b39b4667ddb42c93d259afb0189df20a4c6276d33aaee3b24ec77a26b36c5a168bc92bac8e752b334d6276d32a9d9b96c562954e7985ed172dccf2c86318666ba599dba8a20caf2d7b808f0d84b7c7fd21f53594d1185b34c608f4c7cf31cc2dad2f4dd3366e02bd8a2c09d1aa6bdd4ebff58deb4ef207528703b061c3e21d7109c838d65f3f2b34f95131a02515a83ddad7cf17462adf1d5f3f5c73be79a7d3a9897b8e0e1dde31959adb30f6ec97f28ef88a38ae65226a104a83b1a8591d774418308e76fb4d71826ff4c7a10c8b1b375a3b2a619d5232efb436ec1cdd46bfd14647950f99c828c8921629d8628c3dcf5b96b0784c8ae59e2ae0e9120ab210026d1900012f9db350826ffa627156b99128fe45d9a32c7a583fa7b8d1bd2646f12127841d08f0530832f879e5ebf57afdccee3e52830d6c6852c30b867082c8d5d3c2bebbbbb924d74619533f6b6cc41a3ecc71c2cfa2293498d343bec258ba0f598b8d0f790b8d19c6243fe7929f45247d1893f8199f1c4d2a3ffda7dbab72f08a2a7eba8e1c1e3fb010c24f5f21c80f3f5d4811a09feec2154e5e4040a2c70a1f2cb0f8e1c11110108c8296fcf428d42d9672458c9f4188f244634471e79c5789876fef396710c290d245b737005660f916b2451a86613fd88204580f98b21f8c81434502b25620c130cca7edc19064517973ad3001d2911545f050c58f154cf44085911551f8500592153fd0818a2615175bf47432d0a1075034961e50f1a1c3a0075828d103303ef42a9066983520e9f06003b6d0e2890d9b2aa6d04208cb76ea3ce438f40c73cda3b66dd8e6393d396e7693f39c3e751e4beee339e2f2094ad69cb3d21e6e90152a30b523b1e596ca6d98cd6a1016b835bdd65a6b9d1608c279ad2b6855dbaa56533a240fc9aa1d1037aed0adea15e64548905a6b759817c6991e7b26b1714de8e2f3d5b7db2dea533639f9d63b54ef2179237dce23be3693af5d82af4456b22ae79dbb6455efbc56ae3bfd5c945fef7ca08163e016f57a7dd60a74fa91236f8a84aaebb5faad8ef2aa771492aceac5a1223fe44d5ca2c264b52fb4d967bf2569edbd3f4e9ed35be7c3cdc2383f55c6a5ea724a16eae339e28a2fc9aa3f92559d7a3c0d56efbc082459b50be28671e9abb7472cddaa610d2ddd0a794b5ce2e1e9d2a757b7351887ba8b4fa6835cc0e6ccbdb59cd35b96f9fc6631599574cf1b36ae3901ddee5612a82e5d05eaabe8ad24207d93bead5468dfbc3d6e95427c16562c7c3fffca25bd958bf356ae4d5a2c277a3f2c66310c6326166cddb79200e6989fbe179c00e9be950bf31756f15bfd38f904d875f2ce4fdf0b3c4e54e8be17303ff9e95b45cffc88eb052027ef3c7af7f138891f90ceb38f67f3ce79383ff91117bbd8659d5d5bec745a60c147fce9136057e62de854ff91454739bbacb78a8e39bb2890153057e1e4d8f78213209877fec22abae6d64fae42e7a8ef05ec5b494073ebabf8a9a0b95da99039e69963de39955be6d948164b9695ecea3c766598952c2924b4b3a7135b04a58cddf1ca738705d1932db2440bc410e470da31767781c94708a1d0dddddddddddddd16eb36e211bf135c0798036cb9902c82a6a419191db115cda85b47dd0a35246d8a4605886f213e837c831e71438d4823d28aa4a6a46427e5aa37e76767e053a3026dac80811c4d4536b2d2f9eae18948723a296ec84c458cd0a8ac55a952d3e706534ee92ce53c41f64c010171bd81748b63b0bd9d59f22687593da9e5c9608745389e8f730bf0c12837b4a04dc8481e7a9359d4338f8653ccc5ae87ea432329e4b0518409e49962c82903396851850e33f8f6ab72d0a6d311f9c70c316270832a682084510d29d09205e5c36d61fefcb9212b492993a618c0873670b0a200497c927091430c6c985eaf970d1a1360b400063f2cb15403972c420c2295c648ab0f53df3435df36541fe6e821f2c10884281a011837f8dc80a5080728be7574778f2124a3bbbb2d4331c64bc7ba5bf5ddddddadc3862856f28fae2243119c646185122b3881ab51f0ddad447f3788e57ab8212b09b941bad51e5df1722f532ec8f1d26d910d4f5ec55c184b48493d7a90549c5fc84bb2842a6a90b4db167c77110d527c17d5a082977ea518482f635e4a292513171fd2d444b9e26d910c44df4533087dbb172131c177dba8c3e86a2f2a49b0279032a51dea5585f753aa219b250975c9a0072b7a1d4188e953830842baa210d12735740c885c31306a167f686f134a88988a62c8410f335071d1096da9a265de9094040749423491e48207b7505939bad263e5db6792f933977cfb11acd03c4bd9620424bc9ea56081799672042c5fd43454d424544465cb1445efcf453b60e233a508f491c6c82939e5945386a93934e79c5f123f9f0435d83f3434568056aba319339464c81852a988666698646484626296522924189824a39797211717a57b9b50a8a3d309a8eb84386e69db82348d28cb8cac65c2f23b55907ea70a9567fee18616899188888a8ca6141124370ea554c90f2ba2c18ed895aa446da84a15a9a752a9538e72a8460d56a25ab46db1bee416231c118e6ef9c68cba15b1a16e51a66fc7863028dda274099b821d3d96a5061bc3f2ed25380dafe1cd50c33dc61a5ec36bad51c3a327bf1ab1060daf4183c6952fe1c3901a6c1d1a1f6645c90d2d145528bd253a2a0a3bc8e8a85ba145a2a2e5db2d52b7421a64a55bdd0ab1a1bf1277f0b76356baf5c3382c34c44f851887b125d8d0946fc7a06045f4cd7461455812b548cb37c55287bea17cfb8e1525dd6a229e9fc6dbb1a2c4ca8f951f2b4bbad54c9e7fe5ed58596205c80ad0946e35d0f3cff07692a61c1d59e9569fe0f965783b495694949e74ab87787e95b793f46468084ab75a88e79ff17692a010112561e9562f797e196f27094b125312535212dd6a133c7f8cb793944492509250d2956e7510cf9ff27692ae242d252d2551e95697e0f961bc9d242a494849484945ddea9fe77ff176928a928c928c9e74ab81787e176fa7ca93a1212bddea1f9eff7a3b55ac282969e956fbf0fc286fa78a96a6a629dd6a25cf7ff276aa4c393a5ad2adeee1f93b6fa7ca1220a024bad53c3c3fe7ed54494248e84ab77a87af726569a9886eb5cff36bde4e95228282a074ab49f0fc99b753050a115151b75a87e7b7de4e952223232cddea1c9e1ff376aa606162daa942a55b9de4ab5069907fa70a12e3743b5590f8067f4e1721c1f4215db24cb3e93b88524a29ad186318f530afdd4bfaa7a720ddf985d1e8e7e270c3d9337b64101292781ad42d96828422e8d0abe86f3c17bd943ca54d5d0a91e7a38d13e001f4f287b60d378c3fdd43bf0ef21e7953c3dbf9bbf1af16d1b349ded4f8ea8f643512245fcfa5413fa7115c6c08e3e9c20d6243742a49d2e3d48b1bce9ed9236f6eb37ebac53d9ed168062021514ccc3e817863f947dcd135a8b6f8761e8ca3fab0f8768e5ce5914817cc561c2e383b1d2ae58e19c303d808c574c4349a9347b7ba0692be612b40a87c4b26275bac4c4c0ec1dc5af67ec06c10f330629f571f7293d63a7fab9de8d37ea1740fc4233f9d53350d5e3b5b1097b8ec714ea6926e61f61107f3fa16298d9c9c4c29a54e25ddb266323b1c78c6198d603955bc327afc6e836dfdde066ff3bc74cb5dcbdd4fd2f0329bd6441cd19be6e36456bddf6ee5c7ad97ef266237bde5e46a1867737621455c9037dc45856c64820dcdaf87f23852e0e41ce7d1c59d38afc1ba2217c0d51d90e93a7d35cc807271de2ec62af7311720ab35ca6b3e831844893d9888870e1d363620e85e6520ad6fb323cbd3566b041dc322c6284472132824f6cca086e31772d177748e5f0bf1e5c720ccda1a7779138986e21787ac0872a2e10450c7511830ecc0c112442e27d2a97757c594938b2c555eae96134a103f2f177729f4cfcf86db7256e98e355bf45142346549123f11ab54e9227131157da2c72931c69f2b6e187ba66d92799622060faf448b603baf915bb66ddaa6653176de4db18a6918949e79ce1c4f06a5d39048f7c702cfcf2627cf9137a7cfc686688c227ca8b242f486f68d712eca4f528c60f4283f1961e8c36b04218fdb699ee6e9f485457e1a5dfff07e27efee695928c2b47e6191477d61911fd25eb98fbb14dac3225fc3fba72fec0ee767643ee72afac5a1bbead17235bd67294400e34fb1cec9825c8186eb6fe5f455e00689930d555d3ca77dab35e45c88707ff2ce67f53a77f190584a518e6128df22d773c8c9519ed32ede0c2ebe613d79f0f767b7ed6be272aa365c7f203f36d9f9405d37c2797b9b9f7c4ce7be21dc60e7a37dfb647c94578f08f728a7def4563e866c4e9dbfbd558fe9dfca471dc279751d94cbb76a67179066c5d58f186298d0d468566e752f265d30b26830a6f8fe98f80da308524a29b169a9ad169357d6847cc44208420e3aecc00a1a38410587307eb049b7965a8bd9b6a08d0e1fec2f6de101082fb23802881bc078bdb49460cb603a0a52d25001a5c9161d4cb1431397ec11bc94524a29852ecd54758bdf8b0083085124114a1c81084c9040841f3629e5ec3e819bc66bf0cc21a59c577677730d4a29634a4a668ee299c5d9f3ecef2f6ce15d98e69c73e69832c66843a9dca49492ea9073e698363d3b4a29419a06995b35c6a89a924e19a594f7e308c68d744e2bd9450925a5943230a7a0d24ae79c53c32a9d99d56854aa99759cad744ba269de69ce59edd3dc6a1f379859ebd8f466e658866db7729ad69daec4b2a9a14e95a24e49b44f93e2466dba90691e332dfb429ec77c62d68b3d1fadd52b9d33beecac5485a5e9a72a88684cbb1ca7666264a68d3ed9a7c59e7f7539903d299a54a752bdb8c0c850c998416356cb836b401baf30b28bfb42bb619fd552302fa997eede53879a81612b9a1266d52c76eae4a9d341d3c18dbed588e495032c439d3a9dfa5dd965a0dbe205d9a37f08cd741a1a536644c80c60b3f6403dd9d823c720ec212b451a2a967191b5ac4e0633dfb6d97281331e8e46a5da380ef5c51dd231dfb41b94b3f390372767192e35a00dd4c95fa12afb620cf29c474ecb3ee330aec35258776fe534286eedf8c471874c71cea813873afd882f0d0737faa6510633e7ec035f9dc18c33117cf568b58ff94696d958396bdf512de934f44e272a7d7c35939e395fa83ec2755703d5b5c902c4c64aafd7ab0657749b200c81a82342cf690838d8c15738f594074fdd52bf59c4c84204f34d9412f4ea964754f3d2c6173678e9577ec1c54ba6327d44855aa14964da4fb742baf4ad842e11e21b34dd0a291038d9ba4d8e13b8ab51c9dd701f05a2d34e6ec7b64c7b5377e5233cf2dab7da78d3aa7b0de6980dd7e2cd90b0da96b9b66d5a87016404942dd340afb1516444cf6fae6158a743bdad8bcafa10cd370f35e77cfb3888eb74953900492b1931858b8c98f232dffe230806fa060977940226df4ea46f588b50932499469bcab7cfc9c98e866f443f61dbbe269c6b5a6b396ce40df7d18e8ce56856db1951aee6d4b9351d39a634c8cfa98f1edabc2c10d105469a525111413f9842454520a11577c4778115cb24e7c79139468ecc95525a63addc54e9ca9bf87ac55783ed42ee6b42c1b88a6ac36b3021825092850b1d6481454fe104144ee4807e446cbed65a6b6d0209eca24eed77db0918e8e0290ec20d6a7cb045134db53a41433b61c30e423720c2c50bacd892841c4e1045efa048a80917d473911012bf3d170901318e7c1fa117d36f1967c30688e5398554515c8e02ba2a7ea8af007c3395505f18fff34e68302acd9869c2149237ed03bafb08a1bc7af5f6e9167b2ad4b493522aa594df74cf693e75b7bbb7bba7fa82f2e8f55b2f8c3e4e3f7ba07ea6fac317fa573de453971f7f93534e22361a179af0b67daced9bf66956bb75eb73da185ceb34f57293f2e993e96da6654c803e0af15c7402a5df64b7337f36189be73cad7ac8103ccaadcf2b5ab4b838aa73949647f9756289f56945e796ca5b475d611d55340495bf7f7d837149c5b8a04ea71a1b28cffe8c93cb8ff9d69da6b380ea1ce59dbcf828eb931fe54d6714ea73eb75d6b9ae07caca9e514249b7c2eb2fdede3fdd1a72ddc5dbdba777601c14ca5ffc7a305efcae7b00ca5d5c1c857217fffbe285d74feee20db98ef2adf3d139cab5aec7fd50dfa6e2c6f8cd515e2ff15a49b3da5fbcf629c28d1f4e2520a179a55b4b8c63bda716286f7f80ca519e8c4fa95ba81ed355346e43949fbc7d06756b08caad77d6f988500871e5bbce6dd703e5765aa1eeadc758eb26b8ece5669cdceb98db26c2fdf5d048a33cfbb4f381faeb9b8b57ff0447cf5c3c170d71e5b71537c3821bc6a7e166567031a76124fe10ac047ac2fe14bef02edff52a46532574e412e6693668bdfea90b697cd83ee17da40f53e18f0f89c47c7c69afde8d275c9287a388c1096870c180f54471fd8d275cf5cba94535882104170c18163e7051af1f0f1b61290a820b062c490817fdb81110dad89aab9863475c2e592a50c79cd6950ad631b75f75186a18477051c7beca5d6bafa451f18df6ea5d20d44a1e9e810eae98c205037db9a81f7135d808681f6eec294487c32bda3be78c36d84e4e708372c62a36db2deeee96cd8fc51665b3654eb24de6c9b38bae74767377335b619c50c686a231aa60a3b2093f1ac236270ca4bcc186c3ad01cc1bb905669e952c6e174c06c6f26ab5d54ecccb98557d002ea0ad32eac4e817f946c3a085dbcb26ad469431046d01d2f283c5e775a4c4b78d418a97870561f9e9117ab57c81c65be9b9e28305d3f2bde5d542f4c38e6ad4d0aa0d9b6c25b7dd62a500fe69e8466f90c592d2b7bc78d2d90d0589887843a76f73763a4d6a9a25dd752e17ba8c33dadc29a59473e9b28777092168cdaf4fc6feb21f5cf690bee69cda4b878d5f1fbd3fb64f2196e263636dbbb5defa255991718ebe97a15ff2067b4956741bdaabc25e1f1dfb42f0c37e452564f8188314ddcbe382b0fcf4c453e7832ab197bce1a8342bba959e2b3e1f63048a31ca8f3ba2f2fae893e544bd7a36be1ca79a65b3b8ec3c6ccfb3c936a8822dfa16652c0a6209cb7c9682b4f421419ddd669c4b8ff34dca107cc96599cb53e69ccea9095ca17cba8cd389821bb20e665c306a327ad67351104b7e93e1118c893e13b96341f5d10569edbd5bcc8c2a6646f5d2b1bab84419e38556f544282472c2b7c79537c3b330b82be9f2fbe18264518f2fc9a2f70b89a4fe445d5bc1cc07aabcc1eb2acf3c95bbf070431074717171661777d9e1662ee3ad665cc6631ce5ad661ce5f137ce935eede18660538e4fc1387fa111fa391aa46ee35be4409a823981496ee6d263083eed317281070957a592f0c85b2fc6a537447aad6e6de79d6fbed36d7ee4392f9ccfb9f4c2201f1be46438773b443e942e8fbcf488c8f80c107154e7a211557961ea339ff15ad041b90f198ff97264ca83f1fec50b794a0bf34a4751d5142179033ee91b76511d09c535dfbe0db4b6288824cf549e8b4a30f45b731dd86d94524a29a59452efb66ec529944e14dc301a45242222510e1b118971520d52aa7d4d6638fde2930685e4cd8c2f0249a158d414978437cb0d23d253af513cf520dd923e836e086e94e37ce3baaddbbe958fcd35dfd93ace6bdfbc762967d0056dd89c90c3a35bf65b619f524ccb6c0154a94f8fd23967a45c270bec73b9a80441fc2b4ca7b188bcb997e98b5c04d25c3a085c9031bc744addd9525a99d8b343dc15f5cdf9e8f572ade8f78373cd79b02246ba655dba0bddf2a65d41886449e9da0aead7f9705d609cc938aad6f4ed4ae77ba5944e575966a594524a29a5949e596c856ec9fb530159443aa041e99a265d4a14748437f40bc471e65b0d786ff5f9d5b51c3736926593a36f4e526ef42d9bb2a6bdc1b6f996d916f9d9cc1f3e195de9f4830889d2a7f7f385ebdd3a414266aa2ebdfe6e5badc52c56c1db9d4ee41b92ea74e639f226fb6c6ccf3f65a1a4645fb1c64aa7d7a8744a1b504a29a59c734e29a59452365766c64eda133ce79cccd8ac93ce9e93e39c45dce81fb83c65fedce85c0f37fa9c178816b4606e410b2322369dc8cd52ea2cd56089383966ac324d8c8a6fa29173d2873148d12842616431a024d8896118162520810ac2b0e1aa9e8b7e7e50e5bae0e0670913b48335d8074ae991ade5ca782efa2941fd89e1c7fdc8c1a61a9b9a83cac61bef74b7d11175ccf86407a8167777774751714cbdfc21cb4b209c78e9352aeeee2628dfdddd0d80a21fa4bc94fed9205a7ee8eef67ce8820a6ffed19cc5371192be677c7777b3d251d7e8749a001f724a967c90c14b2fe112010c8fc6094a92e8618a974e731b0c2631453dd8b0b21d8510034977e76065003354178a1b9ae841075a88e1248bab8f284209babb3d707f3e16c3b78c4ea75bc05255d1cd803ce0f0d2653a1da99221a6d3992903bcdc6187215e7aaad391aa18e4c8085a60c50c5f2c8183121d828a00c545c195825d3e537600d3e9b4df306a38a9e8bcf6536195be5c7913b9140d098650c0b7db4b82a46f57f93cf976179750f8a8e00634e0808719909a8c51041725cee7ea40c506a82149fcd870c316465c616484183cc8d0a826162aa9e2be533435367204cddd8a1e696430d8ce47da97c3c4e55f6a0eb090b8839660086f80db7e212dc208dfbe35c732ca53f59c7ecee1e186bc64bdb125219977467da812fac3379600416930beac1038279c13cec9e6c42634c3dd6adb84a46fb21715cbb464b758a46a8d64d01318cb0b88f1d05ef9948736c8da7b552a19f7d4e703c67ced03f3d27113bad17364d5002bfd90e849da4da05d312e939249c9c8f88c8c8ccf78ca5b015179ca55a919991f669441d6deab52b983a0cd698823405f1d882a9d71ba2d877d21fb60c438deb7db29dd92dc0a084cca61fc88ebc55b0179f1188ff97862b694179bbc7e4956ca65bed8b4b29e72198ff15640663cc667be8ef956d665be060a92ac5ed94f02ed8af198af7dbe06e286d6c872192ae67a7bd6e9b83877cbe54379fc31de745d8f8b4939caf380fd6cf35006598f6b3026282828a80523d733c611dd066dbed9a0cd066dd16362529d806fef3cfe8409885ec84a16c663d78bc7ae93d7d59fe851181912a1a71d2e9669de16d3320cd3b40c3bf9dcd01a3d52b7aa5ba46fb747dd6ac188b546d252c1a84f83d3653d0bf3e298e701fb5606d90661bc76c9a020a38c8b6e8d64832ab79f85f1f84d603e1e185c2f9f9135aa35cedcaec164e39a90127d4776131e48df6435cddd3c05fcae1ca3330eab3d8e9bacb5d6ea1e7764cf2d8359a096e58654683e198a9f8a6f0871ebd7c4faf45075dae186aaef7e1a449388aa6e35467de8cf120a242991115b9e9d61a8c4ba9b11e552b73bd4ef379b25fdf64dbcd13c7a93cc69f6cd66d5764aa373bd0eda7ab64f39a56bba3ebd4844a5d323910c4f78fe620cdab8a613e34eeadab8c63dd249b471cdc6be35d7314ef41955c90ded4fcd33ab79b7c1a9ddf036386dfce95745e335e046975c50874a7b1aef96e693bbe537ecca68bc92cd8872ede6a14af3bc50738ab9f59ce6cfbc236f3d2337441c94ba4acef68e6f4426ca62c3386c3366a73144a7317cd481121b31d1019e5d4701425577f2f0e4ec8c691ae639dd792817cc394b80639e02187489f2eded39e28eecc38938daaf14a82f8a3e816fb487ad6f8f26b815d858e33e166212548c5377e88838dcea88a1cc361d475fbdb8e4c5eb883b5060220ae360149890c237f8439c6f9f5ae6f633fbcde9759dd5df50315a6de6e387439d39abf1b2037c23cb6498e086366c6cec3254376b1b6fd8b5833f0c4009ae506687f4f04381092206f9e3870213458c833f94ab1e7642d930e79ab0c6d157dfb8ab029936a5b1091598cad4e4c9246a92c5c92708071afb4a6a490b0b0b50fa4e35d1a6349a20b484c68e149881a40222593834a50677240ce6f6b19d48534d345400458922befd88680692d1dbe8b23e264689e48de676f3ed9b81640444fb661c495675eb748b1c0560bd5000af5983a806918c79f10dcc635e8f45d64ea1075e23e21b9846f49853fb7ad9f046acd594b42b0d5a6a2d66958e60b2184d35cd486db19e6ab29a9276a55b3d03694bea4a6aa95bf1f314966ef537847aa396525abac59f031aac393aa267d3a33d8b611c0591c56a65c00bab184619fb563e680ea24ae714c08b4e296b104dd91df39258b7a3d2e29af098d3cd470c35a28f9f4d7f391aac9b86c43843a2b77ba92d7e542ddd708636e3e8555c5c546c39a9d71eca876f54cf91d1e34729314eeaaba396ae10e36c5ffd3e49f930ce8cb6c445f9308e0c1f694a5f7dc33819427ca33afde2861469674bc184c73eb6c79e8d06ab47cfa6bd1c0d7233c7181f2590706c1b363a788a0d9b1c3a723a1ac45da540e3f9ad5283338e1aac33a834f8012171d418f7bdb0c2d7a9b0b9f6bda0f9f6e5344ac98b797d8d79c52009faea313d31d563a0f40d658a49d22d2e22a227e605f4b58f5cf0614cd05721226cf061cc93afae30c6e7ab6716d39494ba15ce5862ea568852faea3546e9c187f40a151f522c5f79f021cd8714e9abe649d794661ccda0d22d9452835e6b1c112009afce926f6aa41e06a065d3a0d7ba0083d265702b88ea02dc5a31285dd5e04fc491e3a534e1a547a348a56fb257113d47615cd22daec1cbe7e550c75483970b3e8c5382c2f8e4a55bac763dfa2be6c22b6ef960503a8f7679f3e3747a69e5630c7c43faf4e28b6f48dfa2dc62a4d4fef4b28f4d381adcae1e4351e5890f1b791365882c10302864012fa537c982c89b7649dfbc7609d1fc48e7c375eb921e8384b2bbb9267fc41fc902e2be08e45a5c1235155c1d3629b8db8b715c30c10de3cf07758b31979d2a5a1ae48f11094f3f97262ecc330d92f0f3394d7d1a6ca2da5d120dc1cb34f600397517e44de637d6e9d015a261fcc93c7ad6378eccf2d4a43da75dd16357e6d9e8902c5af3360dd2fec02ee9b60b5149cc272fd96816051ba4366cc006e910463022bd00cca90b29426dd8481665e622f2460a611ce7ad5229a7575d7a4434a21c0d521b361ab469ba11b4d1374438210d522b6ec8484ebd027d737d322a36aeb92ebed9ad5d3c7655eda5b399cdac96699bdbcd374a3b9d262fbe9d32d73223f37f7e73fb829edf7450e091a3e34fe8d610ebdbe648ae352207e59a53476173946fce7d61111e97ebf15cbf924563c64037f3950a7dbddd611ce67bc1c52333cec91da539ca5bf9d03ef3ec1b72fab4e7b721f71999bfad329f9fa1f0e2adb28f5d9305d77e390d1a712bbbaec72eee22807d1cddba6e71857ed270b691c618ad8d98b5297a82324f98935aebb1c058ecb9d1c71a7161fc07cc66a5f5422314bb8f6598d30c87cd3604f3ea1bbf78dbbc710f2df5f98546e6ab3c1e39495c150a3c1a6ce2ce1ded7cf078a2ab06560328e8743a9d3c36a901e3eed5353f9f1e81e40d007c7a0c92379ecf1a9f2a55781f8542c9c8f098989899989998984e4746860c196fbe8c167a604bafc30dce95d7b80a34eef90a48096e829bf0f16c603011b94af023ae6c8b2ef6c497644df73c17246bf6308effcc5cf376310e3323e35386ab9c7a2aaaa294ca90e1aa192a95ab64784e5316588673a723e3e3a1fa723a9d998cca7826e3dc3de065c69b2fe3ad7c64435e3cf3123c9e127c051e1a1e44b27e705e0874631cc601f0ad5490345c3abbbe6fa542bbe7def74209de9e719ee3c2c34d31bbec7063fcb3cda20ee31784f9e687798e7cb19f440b330efd14badeed52a838f8c6f41a9bc75b0e0a3cbac52eb3bcad390d4eb734bceb81f9f61b827dbf9de086387e7a68f393c653ad3c3fc2d590dcd0e6a7e3601c7ea1edc84cc730a93e96c88ad0521191911293962d538e86ba15d61ea12750823eb4437ca386c886b317d471020a291551518ab344445388b8cb596bab8f0e1b1353a090fa50a318a51aa8e42c3835410b159a190c0000011315002028100a06c522913828a049b2a61f14000b819c447c52194bc328877118a40c328610420821840011111a1ada0800eabf0b587452a3d57fcd761f90d5581ca5c09b2f05b9feff04410a527db580f3519dbf20b4811e14a5f946b6b2815998787627714b4045ce4595e497d1711099dc36750c2d83f99558238e25f303848df0cda5200864258c30c845c3182377545621175d1a1031cacef25331cd9c525b0eec4692a29f64db29f6fd5e1264c10b108b752a19a2743e19b2bb79c2040ae6fb9f037139bec034dcb1cab191f7abbbcb310cbcabe055eac84de9c7d9aeb8cce12703adeacbd216852dfe0b5a928f653cd69f95c93e193d7d6ae8800f143aaa3ffe16e2c67a5302a517d1d77950f2b7d8ab43811ac8e40d608d0cebc5a9dc07e8f3f10986bcc6bdc2a563fd58c20195533a12efeb4f383727ea1069528566f4daef93727ea2313f2919f47482fcfd3c2c9460ca1999e7d3d779409e2c667bce53d91fd374f0b10daa798dbd583f2bba41c8dde42ba077212b5d978e4e8fb6b53c0cbd0dbd6aa2a98295988dd57bae458a36bd18467b366d62de3d832b497d9b4b123b80bece93d2d071731e6c54b2c22c86990c0203e4c77509fa752f9c9aaeb9ddf3df88a5661822edc100c46a97993e6c9c812bbdaeb7d5b3fe59d0b66bc9fbece54992c50fbd14f3f38453a2aa2b51ae6d452920b032039b193487e97716201616f300a1018755c872d3f434fc95042284eb806970be26943372b5140cfd37223dfa342c50847ceccd0bdbde336f5906bf91ca5c14343cf3fb0213ad26853e607a6483fdcc2195135912904566f371dbdb11049e07441cb4195005f5477aadf5e878ab020d86a1d3f9f77e365e5386a25354f9ee13f7dca94c2b87a60b3bb800cc0597a42607f0cebfce000d9cbc05bec6975e8e29a3f9fb2aad7b687f9e223389960ba20ef1b57bfe41a77ce512866590541d207484bf7f36f443e5113b984c069f32b4eb23409d705290507b5e05e9633000ea75e5735116403d081cdfcba25cfe152a35a0f80f1fb00e700083d02c7dce3349c9200cf831ed4773da647ee7d9b3ec36a068f4092007256b20e2db469a7b26feca3582474a429c6930064baa506505d797f337ef04610e8b5df62d04e770b79385ae227b10bd8e82fdc7176e10437142592090ca2aaa70311148e9a34715b2c4c830355687a0215402fc366a955970451e43f5b2d19c8e6e908d1c316caa522c5a7cb441abc6b271aa37ea84cc6777200484d721d2b3d536eab3d894a36819ac8c950125169c4103ec08d5d8d65d8c04dba0ad38a7b8c88ed7850da9a48153233f9d9aa57228d895e9e7a4b8b82e270487a30d92f3ab5f3c1f50bb00b45e45b637c3c64e08c9015e7d62d3b34271f438c42bc31d56973f7ae209e10fa5e138f31836022bd3ce756d40c683713801390eee37ac2a70ed391d4d56764202fcfec1e3f78656fc795b92a04117b405b5fcafb27c1d14b704cc1eadde4385d741a5d4d308f66f880bae207321f61aaafbb310fbf234a9b3569be529386e5a5d19e40d332aaa783c8c6b5436d2af424a1cd55500fff77a549ad190c79511402a1535961070115462496547225ee0946ae0bf0b9cbd22a43d76628d60e6f16338d668a3a708e7fc2be874147a160960aafb6c87792b3ba0da0058c3bc272475777995c11006b2fa82c6369e34b8f77a17ad2a6f774f0a1b58014154cfc2acfdbb1acb17f0ff451a7b8a112f91228175fd94b1698ca0e9b08ec2212e4e62278b5548f57be3dfe296e306e8beb7c9081d7e61ad3559f88261c7000f4a10c36238636bc830d28c425583d0eb8c6cb17968313a373fc8cf3435ba2a912c62518b74c7020dd505734d0d86060a8201a0aec8be566dcb5276faa8d7181ce14f05352ce07f823a21c49392c6015c7d720a4ccde1601ee3010308195566b6eb5fef84668b9985e9f2859625434f5f20a2092f8653351a8ebe5e8964e633e723e5f2da71a583e3a1db4167bdd00489710948517c647a13a54b926944831386d016219038001707385b5561a9d576b378fb3bc2a0884fcd7409a80af7dc78c7eddd95071ff5e5869be0ba91821a6fe5f7d7547187c368a71d230f5bf202541e271724d68372e6d3a635e2a4ef79bbcc869fbd1a30934cc86736437d356a9fe33e17420342eea30a5b60303c029c524529ff88fb65a2893e3523ade0a137f7e85460010fc6510e9cc118a5d86e86729a7bd6d44ca1fcf732015b95167c0fe30bf4ebaf086aae32e58043a6b5b6a4558fcbe2ccc3c44690c52be7b0852a5827c8f7660961d4bee0d83dd1d85e2c1afcb044136f09d0652d42fb2efa1ebbbfa743fc1132ecbeaabd9fa877551ce25e6450c04debe32d4eb46b397ba105ca6f2dbca0fd76cb2848160196e53b6aa8ff408440aa2b7249959e14bf4e2531c779d61acbd286feb5a2008539953fc9248a7b5b02881f18340b7612c01440cca668ed525cd7ba241c83fa3b58f64305690e1fe88561ab9ff5186a2f9812d9fb38c53bda9a357a4a0112670d48ae6bf5fc35e082e9ea6582dbe8451626db16d55c9b1d00ecf912c885238a5212e4fc5e3b5389c536f015c92090d43f0166ac1e28742a69487f6a53ffc2f0b1f94abf235254878b65b80ccba00c1d9c87bea0a6ca6a62f464ec618f52096b0e165abae874a5c0c2fc18b9c62dd498ca42101462c6c9ed5fa945a2721489182c9b0555f7ca6d521dcad16372d8e67e91efb443696d311d6dd4dc430f139f10294d483325a96952dc0c17311cd6819274543e46198d0afa2cb8896080a15651329889175f8a23dc4c14c4b67a2dd76565461e8dc5f1c4c659acddc4ca538ed5227f16ba045864206a1b7ec158e5357567e3263a5bd616a6950e3a3d6d8905c4460ce80ca1d18e017b39630f27c0ccb36799c476c854ed3c226f56ca6c0f9d27f8251080fd6ee801d6dd1492c767aafdc9579b0999dc3cbf2e493c0c3693561f0a1e2d60778a05e8021df17f3cd6c51c89b7edf70fbf8eda409b942bf96449ecec91d4d4e2d2da0fa3039653dec035a11b3b80208ddf4143942157f0cc93dd1b7e6b4bd938eee5e7fa959fe5a7cc32356ff2e32fc4c658c0f90f7a1233873bfd346518dc520f03614a32c69059429acc1805f758e4b4818aad5cb88ff02e53e90de17522b1481861b36f2943d22e5789480676b63fcf8d1d20fdb9fe3c98e405e82001cced257103c62acb20e5e68e2b51052d1b8e8a64a8e81a78007521e16d198d24b109e392c47e384ba415549aa3f9a6cb69146cf304e79052f4c7edd778b6808e2bd4c95baa358a775ace79c341d34c30449b3896943da7b1a7b46f52df8684def96f97422267d20119a38198f21c3eefd689980f73a5fc1f6d7c211c343bc3c6ec1dea7343c9d7ea6d25c60c4518287e4e02b5323dc8e9ef930c80d47fb8b8ec880e22fef4ac9fddbe38a7789d392fb94e95cc111e19995e6872432c731a28398fe54ba8f40d570e40710f45fd9771acf92f4491129da92a0f1dd24c4f486da3e4df2f5cf912c74712264772889aff811576c3765501ca52b98378bf562267e9d5ba907b2f67f78fe2c09d687d95e7226a3f845656191ab47c744f1329b3d9cc88ba4a96e408c8974f1ba1c0f91490be674af280f0f1b3ce622527cd5475285ef25a1c0544fa57a4bc96a792eb97e91c4843dd5b825283772efc0915c102103113d05562e051e3cc96cc4eccee050315f0291b5a72739a684f44cf85eeb246709c36882fc5385c7caa3ab57164deb832e7b98c864b6618d11d7795a926f1eb4ddd670bd4d7bab5d1bf887cf490e03b691346409f44fe1174ab16570330a1491ae793937b57887f2face18d43e9bdda605d208c6e0beec3bfb62f4cd3cc510636364d0ba58e11e8671fd4bc4010050d8442aaaa4f577851445df73a0289d5a7618f4a830fbb9b1ab9d94df48c96469a9e65126bea514e04aba6b6ea89e556184c849921ce4dbd1a2708e15390126d064befc757dd01b3d0c3976ad903cb9bc8b00f31c3d9606fe6b73a8dd92a679add1559809b1a5c9c99ff3e1de25a844afc8f2dc4ad730a5ba098b019b19c248af532da2ec7cc3c6a5bea65d500ab81cfce22a06a4bc14e4f47e4a2725053617e5995c37e37b7f4f3d367a3bbc73e5bc62952a5022cbc48c369d8dcbe4285e28877c1f9f746f3f159fbda00a9982b3fa86761cc20d95bde85a032853fb1bc933fa15014ab0e7e4d6f4bccf8f764ebbaf971a723f8508d56aabce587df0fc51d29646193b7b1d5b49dd8366014d34a00db349b8f5fdafb8f185e28e55542afc165e07bc70206a407f878e0e8ec158cf26700cefdf52af1947ad2b1aa4da55a627ef8a9b1427f6c138082488cca8b8f19fefd6edc1d420b3a0c1e16967a359e990be07e742c5be599be63ab653a644545405357bdb4989b1196f1c2dedf242edae4e57d535ecdea26d681955a344f47cc2cf68942e8adfba522184a4b8efcf3099b4f47934d9b45b85c9b82123782b2ad0a34eee3341854b507c38e279370d8449550282f961d36d1def9c49e3b7060d9eeb54e44372dbcd10df3afa9c2b25b8f661e92ab6dbd3025ea9b2cec4b50dc0488ab703857988814e0d80297d168e3ad3c055380061378d55ea5991dc00d4aab8f244555f9e4c1d2e54c4e5c14760f13b5c84b41aa77cc78903381a690fbbb70bfbede1538206824e3440bd0bf5bdcb245823d67314ab226915f70efc91c74433509a49c343f35bc96bae4ef3ac83d8fa97346401b51219ea0013bf5ac9d713fa240d86cb85e89f4babe84a3150c500e085ed8f4d90173cb4f95480dc06f8bd14cd3809318fa6b9e8b0462079e0f68d0ecda62170cd500b1fa68271abf4db9524916434cb917f63571d2ab234fde50b111f6de6bdb7a169dd4689220903a2a7912189aa8b43c36fbf2e2f01a94c1ec8a735b464c684da87e68ecc87141965179da8d9d50bdb56f9a8a90cb6ede44e23899d7cb205f6b2e55dc6b280399b8fab952419c54d0135bbde287ac5ba2cdfd3402bda3c59a2a44625a6af2c4354f1d1eeb6ff5a04796bf12167cc2eccf90b648197e3c94c9003d8e228078cd422b9bee09890a3a73da6ad494943890080ed27954f24f82d18128e5e05d1317378e71a27e79cf42a6f8cd1b2188fa379b5065185bc6d4657ff4d665046fd77280d327742be1b52c5e8a19e53c0124e5ac1926e2910f19cde993a56c6505d62c1826c0443ef1e3f409f0d417ca8364ea32df80b3e086fec9f8f42d4884635b70cb294b6147cc6a3fa58f66ea00972da86ea5738c0df3c317bf673b51b52fd0935a5fa916af67bc2e2b931a929323649f8c21ef4abe9fcb664ca5605aa362cc60155d8ca9d050ce7599d07c3f944608812be581e04385bc30be5926320a1daa6bca7f2c47021378774f2f8e35e69d16d222336a5a442bffb896b1385c39fc9d300f6f3caeda473e7551a3fe78b47f6149f88b0b4fb816566cfae6212e148b12c63479d14fa4433b851ddd9994df2388c359c694f2ade3e84fffd7e1a64db030ab46ebd0b109dc32d3e19b823ebe22433933ff28475e4045939f13b88a90825228e11d45cbd8038e6f3ae285d7bab8146d7dcabb8a47c16b0ef53514aa2b434ec1a9715e3eeb2aa259bdbfe4ecdf9efc5b2e84987dc34db9f13eee16edfecb3bbbc92b5fe0656be8dd81e3ba24aad097eef5ba64b81be026c0749ad35ea94b9879179dc5a30b484f93573eec541d5e22d79571c4d217b5873673781e1d53cbb5c4028d761b6eda7bf362595e3512ecf1d7f705c42b1c4dafbefd5d27cf63e95eb4f9efbf46134a1535cf2501493152ec2d9a9062e1460243a0cfe9b7dddcde5993f7f4da74ecdf553a650d381ae4ec123b9ec788caf6512636efc8fa2de368e89ead916e947c9eda3836d7c9a10a673e9eeeac488e22861374f09fd479ab7cd789fcfbc3334f24ccb6c0d18f664f70e142ad6f4796b77bf8c8999c11969c5e9122c73c72b15efff2277d2bef2cd61dd448b0536c7cb555205411ffdabbe395c75097dc448ceb84963c6a8706f4709ae7a8173d62df09ad5fef1a30d413f560f416f88a658c8226b6f0ada16b040d82d8054ecf2126f85071e122c3f21a41aeef670f4479b03c0aff28aa280d61c2b84e8cf363e8f7f2c224c801257277452a3dd807c0ebcfc21fa74953aa3baaa9150a8f7124efb1867e6cd3226327eeb5a09a9733401cf556cc065140b40a2add563398f3208cae539e43bf1f590c0d2bb90d02164762451a60a66d4fe506263c47f4bcb0542b1cedb7e43c37fe87afb744b599103669373ae6bd7e9174e8347ac2d833567efa4660236afc4a9f6f3bf555173cc340fc6e98afcfe3ad2ce573a7db6abb8794227b1e368e7cf7c57068b80ebc3c3454c01215337c5ecc1cdef42ee3e15e96d4d3ad151b03f85d3435f01e2c32bce3a336e0530dc1c42b5e56545719e4e54a8e175bb54a01650a91d6822c45c3175f81b5c233e3635abd8ced4766ff1f77eea1efcb250c8da07928e3a094181b9b18654fc28dd7432d52e161ecb6e256b8f39e42d21dbc1fc3235c99251916323fff01623e480fe1063d364242f5925250145424cb85fe8bc9e1c0d445b1faca854eff9ca0401190898d1bb11737d873ef4346fc2d9009719075ebbb23e564238962ce091ef4ddbeb12f325c8f47be10804caf2e89f292bd7b88a5b3b3bbcb91aaeebd4e712bc9be5ca40c8905aee23ba58fa9971db33b7b456d6d97903751789c67f7f13cb0e5499a6bf20b3b56ac12cc76e5f7f904f324e78fef53f86d8dde88328199cd367073eec7f4a134cab178dfe0a7073aa5186e18b747557095678a20b265efc18aedaecf92192feaa680ec2ddef445276f1ab739ad2f969076cb8991e2130aa95dd54a086551834fe0ae028471871e8a80b7098809f4d2ace59b9127a3229ac1ec47367ab86f6077b73825621407afa38654088ec96e094e5c4d23f75230acf286801d16b714e22e236d74a5eab811018ed5fa4946e3b2eac30599ba49b9054f02782311379d59924930a0b1847a3bb7f5d400e699260287382048db9e2fe8d86dc1edae15b6702202dd7abdee883c0b8a5ebbf4b0c8236a6f47992f3f4a69ebc6091c09df7f2c92208ddac22a4747a5f827c182d23db07a09612393d70009fb119a7058c60787521f6582b7a4bd3460cc7d9f81e066450c03dda60f9ec7c60c8744b4e9611e9d250f01b2d200627c99404615f8e4426d756d55571f8f4bda3b849b1d3cb96bddb8f9de753cf00071f5039a0b60d4161d3f3fe63cd4319c63895a91ae372cc0f88a03e1a16f3ecf56804e92aef51bf611a48ffff1a437a55fb4ca510e5ab28121992c45ef09a92352b49559728f4219e334e8093d98a0a55b9d05c565cc276e54260ea9256c925529693d02706911e040f318c63bca08d93b7a795433bc913ad424838cf7b08c5080e3df0dbcba1fe3be538b3cbb3216a80e2f44a12f45ccb8981d6f1043b5b67f977a984e22388c23ecbac6e8d5d90e214422802158d6d97e320e24cb5ca6c3f848f1a0548a9e4a41dbb8d6717f734215728a2f49b896b8d25c8fab468dfe3f0bd9031f1b9a2312c8735f02750fdb0d72f390e0a8adc36a7ff07113b09a67878395f0033e45a56da2c843ccc9229523748421ba4d1abfd541b82daa5f732137c2b56eb45d835ce813b43ea5710c9c2b65ae0effbc8ca2f9cc63575f1e7eec0d53b87e4e7004758c86c023faec99e833185f7abe5fb6c5e2b8f5fd200800c31bcfed8d3dfdea68bf0975c5dc71d0f816eea1429cbf1e43130636a76c02e3d0768defb0a6a6c39952015e897cfd016f70b02bad2fa0fdad4177ae74866ac4b5497fdba4d28b1a25818ab3c536ad419a279e6d942babf89a548e7a81b2b135e3f1cb9a7da4d977828dbdca5db846e028080bc657ef434d674d69dee6f513994f5f8a3ed3bb885e8d06e9f8821e2f8833ed900471600e25d461f0cdf510adb5695114878284a3269b004e2500520ef5a878d6dfccd0416cebc7448ce56275b04fbfbbba8df264f4ec3e8cf40a4aba367c566f4ca6ace2adc35790a9aa6cd938d6b6509f5ea16a3ce7624393327d314e304a444a70e6314a13f2c9b528187735956e40f0051ab3731efd97567a351216312bd70f50e4a37fcad875dae9d79dd426cc86ae9dce92c4fe9039622673d61c91b81a048e4544c5e60e140986a523cc52e912697ed930c1e6e17140f45da2c22fca5115f814bc2a773b81aa13697797c3e5983b63af7426d2b04b4fdcfff6bd4037caf5b911f13eec5dcc6601d5d9aeeb7a3ce8dd9570a40f1a5ffde184808e0851109894c02b74229e0593d2bfcf287c095455e17b96e90d1d028f062b8008a7816b76c8cf9e67a65d888059b289e2540d7be3d413c9c9958c919e0204e16bdd162363f417b69729124f9e68bdbdc6d7ff7114a53aeaa6fb2af43e1429f760df0418158ec072d21c25af4f3460a58a04c668d065fd31a4b813885573444057c49d14f6f6c3979d99cd9a442d49b49b264ab9b2acbb1f80afde5bf6de2743f6638c43a36b62e5cc25e2e37f7cc40885f1a85b2f7d9208ee121575ca20ed5326666fa877e7eaa793bda6a25beac4c07695d2462422761da23148bcf3749d3dcadcf1c5fe583c790550bc10169979e722f0563d61aedc1f36ae845a2f7547c44859676709f3ca9223c0399e8fc6a9fb6dbf3d4166ca9f7165e1ea9f11e3b99d48828f8f07336de822eb85b7de65e384b1b9c6742565cbc851afc8812b7143efa2be5b6aa0e52140e7486958e0339496176d6561bf65535744fa85ed5375de3178299ced7e2caa7d56435aa9941ae661ae58a3645d7a50f4ba5497d2ce7a43e636a473a17ad88e275ccc52bd1eab4355b52449c37040a82a3b9ea63ae76f0748607352ea112ed9ab923d8278ccf691f5662b3b62d2c4423ba8e7afa5cf6010623064b79864d93e84406d4c0665162d3646e1dfb3a83f51304819d1896498a0712bbbc05375c9e7f62c159c4fe42c5c7b4fb781103a0430807a82022c2b3657cd78b93bec851df9787c1e117e27cb735cf490ea4bdfcd943344b5a9a8bc03bdecd3cda1666d8156bb3cce8557b21df9992bdb28f951affcb2baa7b38371207fc802c0ed5d2bc628ed1df37a3d8ee75444ff7f5b042dfa26cbcca5997c89389e380ec7ae06cdc61d1e168d0084056b2e595293ac269a31f2da7450e0fb4ffa02bf64e0357b740d0e30aeb24da51d1368d3f2e37e2cdde6b53666694716c3ae6d0d9ffc5fd9f7086c86d02cb4353c83192bed43162ecdbe02515733e87fb3186cdc2840ff231eedf680bdcd9eaf48f12b1471f8d3a9cf61c9d59fa223f1253d69f9272bf37d4c74e52ac781e27e598855b721cf0a821763bfc59f7f3758295ede640a750523192472ce6a7bcbe564bd9a9be8e021c45cb7744d709ec1173d2394e180dc5bd72ea61ded6196da612781c460715c45eaa63a690430aea5521410c65ae9219944019f95a42119b4e419d3bc6306c6d82ffd91d1471a472e8e0a59bd8c55d1cb71c210ffd3bee7374ae5390567ff784eca88646655fee648b2a29854b457958c6278076ca61729dec3cdeb70f7adfa8d8cb24a6c469cbc611778a89dd6fcb24be3723bf4850b5a50178824fb3e1ecfea3a6d4b2f28bec0142074aa3ebfc39a87d3a6f2a384b56371fafc15ae071e353f652dd3a35e6fa0518ae132399eb1d00f702423e58f6ad957e8eb57318dfcbf8b6806d44efcacb73c4ebf49f313420251db831d20cbcb8b943f7ef56f40ce13a183ba9ac4db0ac2adcafbc09d653cf58c1a607a65cf8a741abdfc241c0e515bde89ec5823321cbc58d889ea83567cd841d1ca8e802d3a48a0aa3dd5c7febd284db99338bb28aae62bad9c299fca9aa2a3b606d0b3b8d1259e43121632461b6d49159fa3c36442f0ef109e3d1a2062b0c2e87d9248409334af6c008736c075594827760e4011779fb4bb6f7500263bf3ab632947a334a96600765e04a706e7e42c50c211c71427f599764df815acadee008045baafb546f26758a73261ac088a0658a977042bd74658bf5170223e9836b1d6bcf92fdad9f68ac7a7b06ca9350c1a06bcc30ea4c0de023ef073f03e8ba75739ed3363eb62dd1b12beac06969b5e3c8ce60a1622362b6002f4cb228b6848d4287f2b89a5e22826b2ce21d7ffac047be89ef1f4ae2ba988fb71a991f04562542f0c4ae5adf53b27cbda99ef81b56cb1b83a86376638b461fda113db65374e0e018dcad699a6afc1e1f4327ed17b4f0fd98dede331d4090f21defe0fdc8f25615a63a8d8c0de204ae871e37c575ab3d49ffe0cda64f5df1b589ffc3dc2231deca60bd5f8db666ebb637b0d1a02524c23fe6e7071524569fd04e04fc0bbe42a24fe4f78d1b89d8321df91fcd6e3d42a42b2648ab1a48d9e0f5d6e1baae9a0b85c75f744b1a92f521b630b3422fa7136ac4d113ace750b4d25ae1bb7b973651ccffa7756a4db08fe6d3411aee4a6d74442d9048e4d65f3bf033b171a846b466caa986a139e246f425a797c98218971f04c2ca0feaf16b5f3174934b39c98d3aa10ba155701ffa7082619756ef69065261828b6058b2130ba874e5574c1d44977b3be283364e3cb50bc66f58851868e100365ad39295e7dffe7a6d1b35eb688158ed1d42e71ba3c95ab93ead02486d50d3371d9ce91eb423668f739ab05a94f0a3dd75b55e51758c9c6b620c3800a641b73f9badd32985ce39716d8c7c0cb0607da069fc115848e503a2f02ab537f04b28c169bc302c3fa6db524d27270fdfa68263ac610d464a6543c9dec3f52f059d6bfb043bd00193455a0d1e555f6bf4b3149d02e6689cad68061d9ff39456f121dcf2bfb41d8bd6dff4c028f7847646b4bc2b0bdfea39b3f543a9b879f46e9609085b8668ed73d128be70e6708adf051fdbb6fa8e78a31441d12760055ff64b76f471542e05831d240fc378eb76c251669cfba85b3d52ec43df85f44daeb76cd360e539e184af50e55fcf245a888a252fe5ddb14643d49b04b09c022e23c5e9fbcbbc5c090e0bfe7d347bb806d1624d4ddf6a437d29b6a00214e7e4b862ad3a53b53738bbeee12e9779950e9b46054493f435711eb48e1ee6cba6d6bfcce0f526418a1e28c567e63e49f48e534fff132556528677d8c2139205c0e29d458a27181ebe8ffdb56691e06af54e3af93904263d4e799517d503ef06c32d62175c827aa5be33fc2b80b2486e439ec6659378ae16a55001a868fb5bdcb4b3331b9f1e015dbd4c184f9a0943a957de45ddbff1b2d63f55497f2383904be571d05bcdc7c446ad609d652885babee3785165259a25a0db1a1bd002946c4dc5f44017011ffa514eea41265441674d0895ed0cd5047b46f10f20c3a6008d1f1539d94174f57a3c9fac627c662dec54b2014f9bfa8f5e4a724812cecc60052b79638323bd19c1ecc03e931e3404bc2ff9bf0ff109c1b0199817faef621e9a95f32c6d4ac069d15a693c3065f2e1d08bfa7e9b2f1138b82ea07bc3e83e6b3964191396070218d53202e22ec11edcd3170f6e0ad75a4e7a126c5e419975d49d3d1270de8630a0a7b22dabbff7b44d6388658e589c91d877e8793f5c322dc3086ce66ac7cba958eef065bad090e032eee47b1e06c2b7f421e4772ae3c1386506a0cb032ebc5a8a84c6b63d2a5b5a4fd491641e7217d785d4c7d1f9de55576025443ba96b25054e7d94c38f1c82bb09005b3b6861a31014133ebeebcbf6e7cd5daed9260e8c07e4587af02df58186c40596a8d36377b159df7c1efd89a14b07f836ae485088b170301575a7869848d734ff9cc5b448a6baf7188f0344ab44a38f396f88bec47efec20d30441f1e20fd5ef66b703ba8127f5bfe15397be80b399c908bb1b53eb347546d351f69d0ef4b61da9019bd4d7c79983d8215bbba6e2b0a4f483636b98be600c525e63b3f2c739ee4010f8a0d9fc27b39dcfffb5c8f20ac453fe8bac101487ddd13544bd2b970a7ae34a9115a8d1cb2aa6dfbee5bbc85ea37decfb583c3ddb1d8a02169ce5af2de814e182431e502c0d9978dcd6a39da7748927a46ca2b85cb383929f2438fe4d440a211ecf35bb86823c42d46e8617e4a3d6c9c1111811c48e17925deb6e4f595a89c809d881f9b632e225a9654dd8bbc8fc64e03a96f96e3961b856351f724240a7c9f269ea04f4c1ee7531d32f5ffb5c16fb8bb55972d37e3debd3f6c09d2fdfb670391cd1a46e8884648e04842e27624ad09798200bc17c266d7457230cc865a4685e60f752225dd32ce14408fb422cf1770b3632ba118ba9a8383352134f45dab40baf5cd1191368064a74fba05e432ad262a96832825a6c7d8bd0c395e41e45df1e5237d25d8d1992ec18f105953f7670dcc33aa207a3bd08f6f42f82164d78d259791a694d2effa2b80e83d45f9e140f720a05b882606f6045306e7692879b35a92529b79a5dde8c75f078e746432ffd679eec0f3af8761e7e4396ed809832a8ba90ab5aedcae22337135bbb09ee26d073a28c644b1a0854ff9f73164f2df7b2709eac14220f19d3a9aa525a81686e712e219baa3481d3154e70a0dfa2c7c6a455a3eebc6702bdcdfa6b32317409fe5c8ffb44effbbd325b21ebf67f2ee148dd8ce1b74e431a5da696e73cf69def288cfb62417a5bbdd25b9e269fab1eca7737344a4e06a46bcb6a164646025148b3eef6478b34dc887c41baf81d024d5d0fab6e61bae0ca7cacc729a028c1961819d1fe3775dbd1ddb94f0778bb00e82e46c5c4f8c29229f44ed8c5f8e88b48022cb6b2edd127dc4e6e7c82ec233abd7065fdc882338ea78302d1b98b5b4dd138f668af65a1038ca486819a488adfbdb67ce0677b3a3d173626daab9b9191bbda2b03f60397a2bec0826c0a4a44369676abd3ace106e02b0d9f3b1a2047faa13d5b2fe0963c58218da8ad039051bfce685b9bed8ec49940744975ac36fade312283da2747957e160e9777df430db7781cf85b65a707d1c4a195397cc5a1c1de00e17d51baaa471e6700203b8ee6749b810f8d41761f87ea385fd885ad8c5f48db5d76cbdb26ab5912639b11fadf686063c66479bc1188d324079c8f79d8db79bc07a51afbb5148779330961ac72a86a1601f4c8815d85eed50e8863059969b3c0746af3f03709c2de2d8d729857205cb3f6a7c54df5f6f781355ff45661452ba36c8a04675101e2d466afd880a86ddde2d53cab53cb51dc354fe54eced39eec7ec03fcdf3320fc7e11fbf4d283476c50fb1f79f8495ce8b803bb10ace06d454b61d0e140da6b34eaf55f6550d6bc096a8555793ba1420759021c4e65c3d80768e80bbdfd492ef15181229176fc4c961be62f200a58faac3c596b04163a74bc278b7fbcc409d921228ca40c05309cad2e613a8020f66616e9db076637bf6c5c5929289b9fe2699ab86f0b740efced391d52b0a7d6e40318b1d423b6c2cca08e6bce5f574982d8ec0a6fac045f884c4ff5e2ecd083f1e1955c4994eddf19b1167749f70b15911a69835fb039872f047aa0c9afd52984f541f015fd51680f51265202b47a10f7c895ad600c00b17c5b6a067ab55e07476e7c6b55c8a146f3b80fe216b410bcf68c70acf27e03b0c23bcd5e523b1e962397667e4325dcadf0cd18c3b7e339fe55e8a6d8157b8796134774679fa539aa3da053009b211cddddca966611ed418ca98db20e9ac51936985ed8f23dc5551e3139a03fe87ede910370be43d79642ad34cdbc7cfd93aaccc73a710cd1dcafeaa3f3b3688311049699f0ff901f5f04d22474accbb90421107b38d36765d4e86a849cdc97982ad5449ee60d57718befdc8f1904682568d1c05551a1c9a79d8067ec42cf55a6214c70834c500daea62109a247005d65bcfa86cb91b65d33b4432fe182367ec331fb6d10755eea7b548164bc6d6b2b4260afdd56b75856963f4f7a1d593a5e2ef9580b5c4cf00d82cffd80c311fa1342f9ea1779a466994dbd0f4efad96d2ce204d0838ddbce533b94041c3992c4676969c2d2c06716ae93880c2b7258742e33792a67e7d75494f9f69b399cdf5ab1fc485b57d05c07438315d1501d393ba5fa0bf071f533e480698aa54b7a209a672b4b1806dfdfd30188f431849a2ee84bdd1ad892b761b30719b25098e5379e4316bfdbd127a6da0e471fed7f1c002be44722c5b9489b7512838c1d5af0597b3ed33f4d614a7588de6364b0d634b262e40ab1f4504ca927ef9708041e62f5119690b5512749b0982c16c46ffa2a9903854f3b8aa561e6e86aafa52b95989dd95e6ed5390860439c16177be46ab5a9b8ce948b137e25bd8c92201add408dae29b19bed69eee967bbbe26b8df6d814cfbfab38d072bf510f05b7a707819c900e523f4f8eacd45edecada9b3dc9d423bf59fbaafb90a1874effce389677c2c5e6880ae579eb82aff8040cfb68609755dc7668a82ac114c9d646e673027b8755f7dd87a4aa507c40a7d4ad81da522360c77de0dcc5c252a98c7aacc654f1452fc75b9363909fea03c8bdfe542ff6f89aa4714d67c5565115e08e91f9b0a6f9c03ddbba50a79a8b0d0ca1b75b737e25a88fb78b29f2dc8f73c6000f8b71daa5a6aabf8907b37b85cbe2d1533424de57ea49b1fc475d06215907280da0605713200f79031293b05739d88aa401c3c8db13796814449f05f00b20d93a7df3e6e8b725627d7c6d342a617f08c899a2ab538ff5a0f88126da426041fe9d569c2fccf6cd272e87d2543a43932e868a8dfffae7415383d303ecd4475f0295413de1d9a0ccd7ec590a9d52dbfdcc6a3fa50e0cae8dddb6fcd05139aeafc88f4f1751301d0359fa2ec2b7ae0a6ad99ca6562e338b1d247a46c2e206a637f852a37ced4dc8681485ab30068895023181fe482804bd53080e9cc1df158409adbbeb0143c58dd413c5be40b873f76e0d3769c4bf920d008e77c3b37d1df31f7161228387336923cc83cc9f0c3f7cf6fe9f8c9f0d376980b2521c4789153bf97e39e3beb9a54923e022a196fdddfce6f0d6960d14411df82c2215004dafbd349623f11c4530a373dc5a3403629e96b6ed7bb6aca9a011ab51706b5d458f3333929eb36b52b819e3f6be565ed648a3bb0dbab8000a860a0459f8631512f2d1c21fe36ed4c356aa2ba7aa3726d95964ab3a2fc645143488bf8781c9e6a65ccf006450127ae8bedcff4bb1556fa0d73ed05d8fdb6fcabf8e6dc75f53615e6134fd6cbb197a0c158285e2c5a6bc626c798baa4440bff858f0b33879f996f62cd809197031748e817bdae0efc9ff65f48709f6856312c32086d8c5d51b6d3a5c15302f2cc7db83ff22d836563f5219a38676e8ad831c1f0a463f8655fb30db1129edaabba831fe30da2ec6864dcced13c8a2ebbb282ce23e536a35eb49431a7d7a4ce1d374f6ac6afe3a9a2ef5aa75e404c3f2b85afc3933e27520d9e29d727335fc00fa69a66c6e16190f96d58c29383e9f7326cbdb50064680018f17324a1bd3ce5204212ffc06aab9ca7258a5458c929f3ec3299f22bd262722827560c83f79931044729b612d4b30f150ad884a15fcad5db4a6791de12543757fb94b6395d34e76ce469a4a420428f9dad67a0ba34a396d99c50dac50a12a0d1cc63a20db3217e6166aa214ae6dd6190dcc9ac390523b2b9c444031784c8a3a05c5658fbfbd3b8c4fcf12be4e2d4a515bcce508ba340009e09bde6c041fb5b62d5bca54fb7baa8a22b78b10dc4134a0968a0dc012ac14ecb8c3cd121a43d95bb0d8c5e545785ceb212a92bf374760c6e4ed82e4f6e3a61cb0a802e4f963fd14bc56587c317ba0058a608b088654417cfe8ddafca2f683f75d9d441aa46cae0688be57a4db40dbfd3bfaa4b5c99b3b92cc0c79230a1820674e500fc6bee11af3505c27ea5e76a0e8e37dfed1db7f0b53e75ba4962550fdb6a6ccf5ca6f7ed68edde40c0453e3a9ef04d3fe71c8679d709ebf55b0013b53f5b3214dcbb3432133338e928ed5a0fc89cd3a2440f491b108365bf5c91cec753c413ed10663b60fc8a76a85d14467f1f9e7b321d62ddf80e1aa58411bdabaaaf63f28e2749f6a8d7f68698ba10586fb4ef4600f575457d7f4d310be52e9f52330d262a7bb697ace18f376876bd4271bce1f661c62ea4cd465318ed7679c30182698575fc844e63f827218288eb474018cdf3f790300762bef4b32c84fc315acd8fd7d107c60eedb5c0383c6d81a9a40f15d2aebf06dc7e64cb79f63d4197d88b797f156733ff785f71bb9f34b70abf35ec3c5aef3ff463b422cd37a670ecb5f52dd9a980123d11f9e53668522a4c0b725455fde377f10112db02e2842728372a214b10986bd684e05c222bbffb4b67857e0dc20c9ee84eb65d3edc3cdbb2e30419017b338c4c970ebd27e7001d52b2106151d864d8e864106b155fc0491aebd5a6e3da4209f2b68b21e9adc3487ff637e44ec0fd8e0088c1d144d144beadfc5564f149bf882d5d7394ac777979f7bbb367f1bfc8d4d59b19278eccd378b06be2b8dda941585bcba1477f10fb91517b129d7669811f75bc6b37811c8450113369b29288a9a338f3c2f1aa85d3c149d8fb4e123f95e339c4fa6988779da05ecda08543679c4ca55705066fbcd4bfb96f5f80440f89b6c707edd16f6d200a6a3b66e3228b26ac67fc7704b0583aa4ed80662b6e283345f37c59cc26a01d6218e7be1794327d2ccd59a0ce8c22ca3e54471f0f525598829680ad9bd73862ccdd53a1a1213eba6c92bc79e438eaf30b40a1d6841e42f2e36f57693b2016109f58ca3532af3ec0079cc5c9326b935dba6a31d18d93d804cd2048bad922beae0d1caf0ed13124ba6cf1de6c68b3b4fbdc070bbbb10f798f6c35873184848cc441cd1611187153c512dc6c6b1bccd46358c7716a0bcfbf614a162e8f30ae037fc593e627914a24cf0a94eec067f2028901fd7434ee0ee24113cec32c46ef462653079059329446fcfc9188446889bd5e47f201ffe136cdad7309322868a9aa7227ae5e737a8b7b6c54e03aa96d5a7655e154b7d8dcfc5d8b5804e00be474ffe933412f84bcd1a5abbf0a24cfc79a3b4a39692b3e3851d88409fd1427a12f6bd1b590dade66de57685fa4f9f391b60ac92cfedbeaec15f7ba8f15bc8afbe031b8bc40328157a77f2c122ee41583cc0492bb698e3018e9df7c6272e5da0064db4fe8692495eb30448357d6d32f9e86b9a31657b481a124ef3d31d92b38b353daf193f2b13ddb537cba8867f7eedf9c37bc1980ef80e9bc21c4d1e6460c4969660f1276a95e1fbaf6e3e3596b288b8460bac474ee9e4c120887599166e509d5d7ab3618df62b1da2c0c2020e2a540c68aae11d65e2b6b58319427655ac40cf3dfcaba0dfced0e697e4dc3f63282c98eea629823fd731a218f21d8975423109ef7965c80275567746bd6b6a4900620efd54796041c8ebedf797f155459e9c4cdd0e5fee53bc25641fe15b4afacbbfadd53f189ce2f2abe1a6249f505cd0fe61e312b7ff881c78f429e52240e10fcc35493ebab9e8e687cf492cbf29bae1f20bd34d0bbe4c1de3e293d6258ffe855d93e603b44b4d7ebdddb5f80fbb23f49a27cc609c2a0fe84826c406f8d5f55f96ded9fe80df6c4fa21bad6af5faddefb98263f3e15c270db5c9298252c93074d2c92507e10028a25fc6c43034061509f06aa3ac308891c82557f5c4f70a458c3fb1c62e720dadb7abf5562b2855137ce7115d66717399da992f29c4909370b5701a407b461a452b436d6aa3ef3891b25dd83f11e8c3030bdc4c50021ddaaaa4410b90d305afc1b2a514333d0ba9eaf7edc9e3f04a118599015c3620129b2f7a918a66d073afa7b5d81bc2c3b2c2d0493f5ce6432ab9fc9c0f2fcc4fa9522e2b2f8353de4198d73212f9c8e5a40a0f3cd5de071cff7736b69b564f499ee5d7a25523790a75f9424fd0f586f49eee472523f901ebe1eb8c662bb084ba5b46f2e967889fcc2c22d500988a80e12c826cb5cf295448de4ec1a6f8c5e9804a5d30c8093513e36891dbace0d4a788faa451d1bab870cb77c2073ee9d058316ffccb1e93ae75c66167acb8adacf0c9e824f9f1dff3a25e7d3a4580aee5237bc111d495985bbd12338a0cea12a8c2bf179ca9b1a5bfb9d4a935e57ec29a351a696f6da791ae98e6ed9c34f0eda635f1fdc035f672768dba787ccdf97fb1b641795aebd369266ca6fdbd95c62b953414a43f35c22d0c79f1b190e18045807112211a41c473753842151fb571d78db93065f742857e4c1354b02871e390fdc680db7a73d054e9bba17d4565a7d270eba8222c2de371a0d929e8cdadd5dff11a2f696300edfa37ec3f957c85d31d7d2baa68a9cf0f886b20407797c49b496ed409d9cb8b41e8e34238418f6f6e171c97c733795bf0516a095491c8d604806711f081e7b5a4adf285cb373cdc56319d659863108fe6d0d6625905c061fcf47889b9164b45797ea2c4ddc8348a99ac896dbce3f8d8742bb459cb150c4b8f9e6fa309f931103800ad713da4f36685377c5e8ba2dd24d09f1bcb459b350e1c2b391b9b0e04df2544429b4752120a09f35b22286882a9e095ecd791ba5ecedf7ee0e435e20f0230b4eddc0217f6a7aa915df805821559ce60347d90ba253cdf803046d3703d3b7a2ce2f94773fcac0129514f31b7d7e6666a264fdf543884128dc372c2778bbe3336c0a7e3615d9a79c16833858ef2d71ad85b412b123d5180eecfcbc5da2804600e58d065e0d2daa886258cedb6b84a02c3222ace1356ee779144fed50062f0bfc55a307b42d61442c2c61f79c94ceffc32ad5c3e680d1b99a29809cae08b17d06523aab6dc5b939aaf6eda28f68723eb5e947b416b35e7d574fc91cba08c2e173bf89c16874203c1877a0d7f2456c86687c8fe3bb9592902e9f583e351fc2e27932d126d9355c94b445110a35576b53aedfafc0378588a3996e11b071edbb59fb55bdc7ca5ca80e60d339024168b4971145f69d4cac6b7308c39d8c71c23c95332fdaec9bdafe3a2aa9aa832c86e6b0ac6588ee067ff5d8da62d983ff319fd0f05efeb5932135e35406807ca74c4e4db400596955824c430704f711099a0819270955a262274408dd039bf630c94c04ca2bcddf507343292fbbaa769f4a4592d3e66fcb8c83f5c7224be7f251b272ac7b045eb5b067a05f146e57581567f3e863c3676b00b0a84d5ed8c83374dd7d3c22467c8fee560307588cf0a19dfc02df208385b49cfe24d66063230adf0721d28978d61badd300e3f6ab2e7a44bb273b658fb8bc7abe7a2e04fa780de8512e6e4ab9457c3bc3339323a4d76415fc81ebb28f366ad3c759a70ba1f05ec8df644a61916dc099506e815470b6dc8c42e3c7f05fb4c167e2b40ca965e8768a90769cd66c4fe8553b1a6f58dc5e1b666236fc538a7dd282b63b18e352a8c395282c4b6b8f9f12624945b35ba825a97de9e12578219e5a22b646b5db6c9c18ed849ac431d584b91721eac271698648327e118ef0124595b5b1f5ed91003d34c1c8401a9b6ad73aac58d87e741059a334a916eec54e15ea05fbfab3879ffc529ac33a3abda9cc6bba77f4d03def872a14771549aab4b7ef346bc3302cdeb9dd07c1b8e9f1820c0bde866d8358e2fd44b34e30cf04858e45b40d0d58c498e22aa3155e358533a67fc3407eb3e2c0b9d4cf0c2482f0964d6d5a4b666d09f91e8b1ced82e597611c9cac0a74865c9101e770fcc3d317870b514066940fbb87b89c3658074208aa19538e117e8a0f8c4c2cf341ce832cca0bda49f338cb7b7aaa456d86243f9125b7b23e5970a80cd76f0c69d8e64789a36daef18d9929f94fd73e0a02912308359a2f71f3924135064bc3ed4a90e3f0b1437bd2602069c387933590726a62348fe7d2cd077c7eba0e89db33188aefecedfb14897dadd31f394e0c291f80ec16a3933f9578448a345f50696b3e1c4d5078e25130cff6e06eede00c4cc6035b3a0f8b8452f600421c19c4e1a597e825a12994780710b272298aff2674aa787c9a3e7702a1241cc2f4df0a3742f76f123d019630e131efaf6a7304c5ac987569e40fecdf2cc1719b997ac8d757212f6180ab1444be8aef45f73f8105fe71f663e056038056cdb6d1084dc05fcebfaa468cb598a72f0b46af82c8d11213133353c7bb2c5c6c49622559706c75d7dd291754c1ef10a6abe18d00c693bf47306bf2cc29b3bf253d0c2bb57e5476ec16072333f136e1ea2a4dce6e3d1d53ba45dfe5f8f4a33c0062e71449677a75435e0adb8aef2d60b8f5ea54798a596f6853dfb9910764c39825d4b10df599b7dbd19166f3627c5fe6f0504ac94f4ff1c94fbbd536ee3879506c9b327c34d8d60d10c4754651c0bb410f9ebd20710f2d53161f88e95e468c6e75e08fd2e1f0e78ba1d92e103225d25bc6e565871e0b63878cce283770b5b1be3a7949b4ef42d64ea126907786abecd25c644a6b93629d6e52fbeb2fed01c9de7a298ab3de73128e322326a0ecaf53c0c3b6f26786b547022e70516059c503288ce5f48c52404dc78a5b1c9e828ba328e54310438111e77e4855e7e0ce61034c8294d95ad43f5d4909c39176e00e896c5eab5e65bf71e212715c8380b0113202e47313972c7d0155c9b7166ad5ce02591c3c8f426fd25e1d1fcb8ac9dd690f935ce528d14b069b26f0ceedafa1f19b50aa350719f08f4037b07745212cfebe5e23fd874041acb60ac0b6b8496e217ce501fa9346c2ee917f59196a8cff9479866fd58964a771ad0d8303654dd306c588e42201aadd70cb5f8114b32b3d9626044284aaddf442021bd20fa9aa64437b663408a21a27bc22f581eab803c492ea0911748dc90afcbaca42a1466b556c5e6ad19d631829d6b7dfb1064c750c613891fc30fe68d20cd17f811716978ae7c1f8dae4568804be26bcfd499fb887256731db232148b569c80557fbe1806028c8993cae0980cb340345b971aae40b8972c104378a17bd86738ad2145f7579cdeeb148fd2b76ade974a81fed0340253ee0af9c7ae94b305bc105b182a8a45ddb35a860a29266ae14b3c876935c339f6f51b6cd112497381f1874e96c26aff5e00314b8925815a13d3a3a536d0f615d7919abce0b5b188a48fda38cc9169c4d8dd527346d4982987c04426ab6ca83ab931ad724cc43e63e6e0eb8582c313c63118d1e661b532fbede58e5fe54977f5a4a5ba5ab7b0c81a8c3561da45bb6d8e5bf983744ee548f5d4b8a3b0bdf1cda68e5bff2de79da05491bf6551a3ccba1aab65c024f4328e6fdd8e0219be3c364ba4bf33d34b38afd8ce5738770f69d85d332912ff23bb4a6407489dd25d61bb0af56a13f856f4bbbf62df3166f3b997f402d959d7e082d6af83a250521f42a3c00db6c3596cb71eec09ff15677ede9783c132b2f1b2672d8e3c199ff768bd4a8466e1c262801aa1b71e0bafba80469e13c05e46b0dba2d1ca5f6f9bb5e46321763a73f787b95c5e16e9e26ed66a1237079c215d0b38bf5b7ce68a8b45b40d926d4dcbe7891c2e0e4f1eb778ebfba570083f5ffe4a5858239c150d674aeaea992b4163a6c093aab11c4eadca9681c036b2511c160b5543675ef34e99606c8b3562b023656a30e195a5cf343ff9b54a19526b28516ab305eed9992cadf5c3e776e603904f4c3206d38eb2ee82f8f4c1c0535d5e9c5ec56b55299dfbfecf5952aab932cd98b5d38ec2f1ccc3d37aeef2a25590035d9394c1b0f1082b7c0f2bae8ce57386e2976648142d1355cabf4f66deeebcf8bed225c1b8f071b8b715c71bd1472f87c6e0cbc0686b6604bb6efe7ebd4b75494c919eee9ab7946e374da6472a5f08a8734078c77526ac1c9dee6813612709b307149d1813e521cbafde2600d0bb07dc6d489eeeb491c56e5568d2cd9f3fb73dc6e13a2d7e73922efe340e84335dce0879e0c9ea6460e19912793affccde4bb388de55e801f9185900a3b725af4b446ddc9128c0578bc83c6ad08d1a1a3b2446ff4b4d6d5fecd171d106967a472b23c24f3ffd63f191731697a55bd9b820a159c292c379214de372c2198c99e9764acbd2bfbcafb150c1716aa8c5764e464dce703c574b96090a44b7063130a34862f21527fc26d093352890222a8ecde9fed88aa680cffec791712a6a3b69e1618387e029d2e8c185808cd76276e91c7c064c6c92e252b505e6680d39498fdae5527ae2e53b25297719352280de387a834f84d2bd233d79bd678da94f60c113d6c41083a782f24983086deb5a3f8ecb12705e2ca03e053d61ebe8e5df7b428253e27ce40ee4df9b922ece307b5039b496ebb79dba99528d8ce366b538f212cd7653b785a8db2983829c3087b90a5bfb30ec4ee572eab7a10b4b8d9a2a77f371847b28f24a7729c3f19442649bb1f10943b698d329b95136149f417c2d8b493c7b1b6554f0c4c288acaa8b6be29bf17ed7e6ceca01593c6af8c6bf1dc343f1496b386aac519ac1515ca1a1e49fa59d4b02ed46eb333c75a35e6e50b73d7d0803c6e35d8360ff24d46fb36b46b15dd20b7621c6c075a7e604f6fd2296af8d743b1ac15028c75451c8fb781d3467864064d98480d4703693bacbaab2cae8a0419170c32125b8f92a048f8f5d7c4236d69e0555f4869524131f20be7f9f7026aebe24f4a559246c4b8bdc0199ed5b7c58149f2ae8724efbb8323981740bd9cf13f0d68aeb914e4379022d1c118ef9060e4dbc0f4400649be069d219065e7ff542ec0080eb3e94e60efb98e74afdf2fbf962caced8cbe505e4abc6338c93629bb55691727ba1b27065b91e04a3a46fa5ca040ea266b729db5a5bb4483c76755e7e3080b1234ba3021f7fdc34284604be0769abbf975b79df9e16f340827f407a12fad8c0d0ceaa4b2b04d0cdc8b2a47bb6ea76f2144679516f34017f43529bb4c6cea6f7c3136923b9c8a2d7096da7249ad27372f2195e528daf1e6e606fb635a35f3811af4a60795957d2ee5562af03abe4f983492eaa9e0ebdc1acd69517bd10d002eec4e75319856a59f38be4181f53564dcceb9904b6218c5aa5d39ee1f77eff24a1795eb2dee47656355612456813b05ccaa67d54e4231792498c15a5a943997ee3a4831658aef995d3f032dac5011439562cc0b3d227f4007616b65043f09064bdd58ffe84982b6d9792048eab7be72223ff5c250c50ee8e7a1a611178716a41b1646b0a707bc4d8e53352ea4d9b0f74808c64a0672ab4ceca241efe325058fc027a3e4e789f109d7cb24612338ff5cbe81d8e9ce2b55387b616c98c3a01feff00946318468601fd0fca49c0b0cb6b409d8b23acb29c05d4238e29160718d738de7ca062f5241b61b83e3cfac58a01e2c895516c3b75defaa4834502e735645d8e7583d0c0619c8f554f38dd29b094ce14040cbb7dfa372ba6f00670be7d4a130e9c716e6c44965d7c1b0f59dd7bec47ab97e13b22acd9f1f8dd3b3e3e80163333dac1b1b66f9c859f996af76d2beeb3d36147739c169691afe2efab9f26f1373793b1b60f83d59f2aa956a460599ad7225afd18c9a6424390eb36c48a7afbaee433ad21323365828ce38e1ecfea6af40081ead7a113cfdca5bf6e8025a3a282288111ad6c4b511bc41ef6d5efcbb330c819a0e4130238aa5bd531899ab9ba3a3d5e05a144b74fabeb1183be2f64977e4977b11b1faf8ada4a52383e2170a8478751306768005abee38678225859fe2b6dfb79751821e0a5f0f8337ed8cfe43020563a9ba1ccc004f950657422cb319f65f185258f6a44fe68f2a5d0ec9e82776e5527f5f9f7e29f73136e088843e3c1d4dda39f6060ac1ce619731c763e504d63d3bb2bd0bc6432df1267efd12d3d4836c3fd63dbce77a8f14c1df4efea36550539cf5d1888b0d97aa1bc3f5a3e8430250ddf909c8daf293023e8c3c777c31845dcd97629fc8818b33947c7d24b39ac152293ed631a8db999573e97b7740ae8b0d1afa2ae489bcc13f68af1bfb3ca14c149512c3d0e5bef51f55b70137ab3d89b4ed424865ec999c8fd52084ef0e8fe67ebeab87e4e1c12c08dc35c95014586aa5e8bf2733fca21b59ba2616b94e6a849eeff7f433ae01542811c4165a73eb9a9417b2d74ce466ee357fb7491fc9f29d846a78d1b207e1753e9a098b9cdc88594631710d05c9bbe4948c147120fb6b69e0395218c72fd0d8eef5f77977678b6262fa667e2e5b8c6d954e748a25c9aa0407d14c3c2595da7d292a427390af61ef80a64f8a7b8fb3567ffcc72780daf30e7abb71392ae796711daf8a5f6362d01acfa66583091041132e883c0d08389a1709c93cd3bebe0b8b5fc007bb13303c0611f7b0c16d928cbaf4ec4f944af148a1e670c96ee4ebe9d6e4ef80aca6c1605d34fef1730918dc03652c5d1cfef6f6dbd77dd25f9e2c9aa21e2c03594960a439885c175c4c5b52795e4648b9d5464eb79a7b74502da9ee72078c5cf957ff4a93483378b4c184e655ec7d1758c88616286c8066d7501b602caf3e9d8183aebffc4fa8bdded092a0b73c194c551ec857dd54068073813e591d58860f721b186b3240c035804f351a26913c2f52c841dca06c1214085e088df7f3981e7ce5ecd85bd56d6ab0ae0aa60b83a4c8672cca8c172309702331a713661dd8fdcb470fa6247eedce22927b88248f4fe4f2f07eefa16b80b89075ff7528bd0c03d984c94aa08a0a495cfbc487266407f7be0cef224a05ac45f3be95fbf9337e03f1571096c56166995ff9c057f4fdc32dcadcff388aea4a5b0a97675ec65e97295a84a25575389a78c5ffa0ca858d380aac25dd2dc6c32de63e38a6e78fc5fe8d1b997d3e4ee67ba93124d6d91d33c5955793fa89df4b539e7160c57631e294ad8730e250773ce47c9bc4205e5ba548db1c29a42737c32c1a678b065e7d5c272df9533573ea5b9d6cc5ac9596eb53d150d887add26b8ce8841a4966fc90a0cb3b9efd05e7e71f119297e401b825eb81f24b1a7c454e88f0d13fd60be7f10c04a4dab0077ed6dc1ed0512f8ba46731589aba5ed87b7689cda1b64f22a95c593c4fd5f29bffecfe4a3c18d4c5f96692b0b7c52c1b82ff448cbe786d8277da359b5c4e3d5b0731f19bb493f737547f9db486640efd324193bbed1d0d32b139c10cac857ed70c6f97d8ef940eab31d26e9f9bc04ae29eb7cdc3998fc2020df2568c3aba7f74bd78be00a6839cd34d766c9344c34b65794d3580bd52169239c6f84c62c817a25c13bc278f033a524f09f0c8f87b452d9f9e6e88c1c8f9e22fa7fdc035fefc1be5c5b0989583cadd38ef1f93dec1506c834d9f4e77db070b142ed1b01404d40ccc7a404bd9d8e4f10f2226ed65f764987994d89d9b31943a44f22f0b6e37340f21e0869b03ae6c51ae1c5a7ee8d4815ac64392fd7aad6fc2e269ffb7d9c50c7bb04433f2434d71f886fcaa737632b64d09b288e09d5c38a570c1e88adcd161b558628f35269365f11719a402d8888f7dfaad7cc5c07a6708cacf8d8fada086710a4d53df9cff01e345ca2d375ec6670d4e445858b6b3bfe2d7ebca772ebf89431a2430a771648f50bd12dec350e96e60e4dbadbc92ef6406f10c1fff51197e3206c7fd0433e099330cf4b5b5abbd4e1e5329fa535ba857b6475266d3802ee6962ac984db894eb4f60b343f2412562fe13040ca9efab20097e1d2fc447bc282b0a859c1900d76dacdd88cd1564456b74b89cdf49f4f01156619711d35c6f4047a983f97098b1ef3231897fcc7d28fc9e585f7891f8ccb335ff1bb8d5b79bcb65cf256e54308d42b725d9564b74ac3e61a2f54dfb34abe37037ab37f9e55e8d46ac00b528c45109de3f4de2c8808276dafac3b95afb1af5ad5499f1068d918eb3bf0f4f145d273c7cce4cddfe8f8f14433d41fde85a3ff4cc8e043da96051640d9fa39eebda24f7b831024166c7c51eab9c341b94bb6bc29247045d07b8a25fa997032bd75b5d0cac8727521f87d74d1df622544c5c130bee2d455cf6b072d10b3a0d74f0510b3a42b7ad7fffd85f1df22b9a9f4af15703f3d79e89a4a188de1d8381e74ed4da1d03a6b94674d55debccfbe6dd10a0cfa85b59b9e8eb5038133d4360d66836a12f5dc98412d13ff5d9b85ef918a94aca2ba6882b3b652b831a88e839ca69e4ff5312aa7a4af0296d3f879e83aa6a9bb8674290393eca2be1868e5321663843d539c5a1422d9ace02863849eae87d15972ad25c4ee81709db3b6aff97aaefa25023244236b3e44f8b5943923a6e914ffbcb37a500f762efa4c430bd844331ff56b3290f7405885024149c9c7e26a74687ef679e983975ee21386b2878c7387f88825b6005d1a1c5cf11d593be54dbd98e12da1d82a5f03ffdceeaafbd9da3d51475662571d00eee63d25f60c9b5965271787b833847bb939f13ec4d68ac985fdab81d991f53223fc4c5b7ebf824070505b7b8826874cfa767402729454b0ab8f8b2ab01ef6d910480d50172228ccbd13420ae4758f85db6f70d767635d56e97f1d2df52a836b4c4340bc34eddc43ee0e8090d89e67e720fa54ca15e869b0502aeb8e38862dff39ef021f237a6433daf15cdbfec4f3a4319a8926569df569e6b23b37e504602f6d5a6ad0c4afa66f73adfa24d5d6e6358b617d6e94b6d8d11f184e564627a7523369106a629c0fbe4b3d8074dba3276267d5124468cb75d5a3b29016a9924c0166ae2a97b89dbb154a542f7ab1c97a00f9641d37555ef4acf90de41f8fcf2edc0a97394d4e9cc2034610f664d3736dfce8365f6ff42ec1b1f0cd0bcd7451464dc862f98a5029f9fce2c0658a42832e7d9090e565fffb6f1ae0f7773d4392d7eabc24a5610917d2dd625f05e49f6391fb98245c066f20e0ad1091742ba8d577f0541623e847ce8d91ed1079a18986278aafa3683b33956c2cf2f338a29cb57489a691bf31ff5da5d73f3163ec280f5711d065e47dbe146fc356a7b8d544eff691c7cd9a4e2992d4627b89565161a873bc38df493ff5c656063533787b7f7acb67b0e2b0d7f6fdbf05aa5563d33220ee65a2de7f495c642d0af6c2f49dffbb863946b558269503673031339629da8aa4fd8015a20a7e8486203fdf7e3c4101309eef29cafdbcb3609cf3454ba4db3ea5032d05e92d9ce86349275cc7aa8365cde0f818e85fefb722b78fde51fdb1788e853a45297f79cb467a279178ad7b2684b4b675b296481accb5a7d45afa076c3735d3149843aa20fed727386779319687ef5c0e7ac03266de24362474b749fca7b58dcf5a67e0ee547128d827f37d8a2b0da6aa3745a8e08b94ad0ba0fe97ce4b6283816c19f7052b8cf8c61274bd0d16f2c8d9b98026f1f72ed301ec4b0b0880fd2b49881f4d0589b7208354a45a7ea855b3776efde566a9b6e4ce3ff4ff93263d69d0efe82320a3aaff68d0e87fed8169f4b2cfa07d6537af033ffff14f3ca96e364a536c92eb282ba8838a4ecbf41fae63def518964087ed08748cd33ef1269d37b0050bab7501ec79ebe8843045ee25780a729874b22be0811691d592e3006e55844a0cd3d9e8ab09666cc0214516d946c23e9c1c1eee11bbe1fbcf194406e20ad1e902fb9097be5f22eaf85820243c12912c6fb13f051b03e19edc769d3d1eb109195a00194ac8dbc78a459fcc92b98e471463f44dc27c154f062b1203a516beae406498a62e86686ac6cb0e09472c40b47aebe130835652633ace407a78e40f9ddeda0acec90a566d9292e470e321557ddbe141222e352e7c8c237880aab56f401899f002234d395c64a3656d244b2efd491caddffa4cb610c739981c98a3092b3e93402d79d40fcc3023c53abfaf85d9fdf4091f59073e94b50b6023b19acc9617f0949bccd4f2d5fbfe510ce684a37fde6b648716fcfda42c0338c9ffb57cdcf0c7d681d286a22e6a295b981a6ece788d1406c4f511294e4c8ac9a48c9d9bc1fd10c260df89fb94eb0ed9f97ade17ac013beb8073d992eba0d51b50e4c13cc4dfa935969a781c29435c22741133276aa99786c23067b1a442bf9f6e7bd11ad954ea869687912e8341743cf7447dbbaa656a069c06df660950f5e3ae84dd1925fd2b5bdace3be5d729a79d10a281bbb07ad3cbdacb2ae5ea6c217383a96ba208b2881eff177f6d7de5b232a9be07cbdefc2edc53451a8ec36bb33f8ccb342af674f8aac31952c4778447b0ff20d904540813d246d9aae2feb86fb6fefb963f17fd086c5ef0703dffcfbff49ca9c00f441bbf13a329e0d8857faeb093ef1711b4947443b3d7a1604fb4fbae77b233afc7bf1404b0ebbfdb9705369ab42658c40b8dab198859d8cb5583f228d4e1debf2a6ec3de8a5f8b13ffb211edfa2cfdeb7f9a0c00d3955ffd199164f102081c4cbe39943f165361d9bee70156381cd9032ecbcbc375e9ba5094a7d3ad265fa6038b4aca17b35fa0ffdcee4ee84be2096c9b1e76b6fa15f9b3155866086ca05ebdad0178ce567a508be61a57d8e9096d818c0d7df238c3edffec17f3726451cdee5a78b53cb700e3100484003dcc2b03e045103b652c4cfef56170b3f92951d161bb8b9a09dd048cede9a00fd163966eea01053c7a75177353aa7a56415e854ecaaae130fed91e192642180c4898fd1c4b02559e242496c02a7cd0f152e1e2e4de3adb47238a1d190d4aa4a4400d5f2852a228ee2bdaaa0ba2a9751a2bc464d18bbfab9f333088d3e40e3fb481442cdaf2f6204723d440d84d9713ecc46a4b8d9d8f26c0c22e4cf0f880c7f427f881b86adf9f927c973b2d0aa492892f4c3e73de21b3010c14b0f16ea3e934e8071e16f1fc6fef27dff3fcc4f996db26833c4d6c6889eed3416a194b266cd2e464c00aa7e8196805eb4850380e3a81c14f592c0bf41596ecf779edc489351537e2a353ded297495708d069443e80adfe459acaa10691bc506072efd750944f9b25c95f1020c67218f3134a638419e645bdd81aa352030e53c81ab7555410ff4b1871ee7ee0aa98c1e505e25340b911a69b0c9fa76a0e83b94b6276ff09ed69449f16c45381d202e08a33a6dcd8d2f697656fe482b41a330c45056540826b5a4b7bfbe50f8dde105df9dc11c4b06ecd90ce1581051d4d203a9b0589e5680f490ba418443f1c4cd51c8316479777d324c913296bba29834cede72ab58fcbbb7631a6c5f714524ee587e8a4de7067517a03ead865987351397fd109b412c91cdf782af92cd08087476f4cb365fae619ed04319c5ae5bc2f7ed7d6332f324a58d2e9c83d784067fc44f2981cedd1a807099a9571ff965768dc75a586ebc0184a68c9bab8f685a446d8fa92b29df3c23e60cbd98fcec92c7e94a81ae72257a3facc639725d88c55f401d33445712cd82b247660d6c6fb2550cbc64906711405a69cf81a753b45e5ed9095380428ee722428c4bb084a88d82b43fba75c3449e299a731fc13e1fdd17e3b222843bc108c6b8c0432fa09563915aee2ef32de87116ebdbc4abef52c52c458f5db464eab0ca40c3c523eafeebce9236fd821e62037ee2b76e3e246b52541a54ad738f1cf994db57b26acba503c8234b04ce31e040877313c01e002d73fc198f5ffa4c7947442da53bb9419cf0d93e73333c3ca9144f52fd1a1d49067e2682a820a81240af713354ce5def651a0239c2b6da9a1a4a6bd70678d121f9ecfeeb0a52237f8e122a14a6234c5782802d83b45fdd7991e965c5adecee8ed94dfe4922a9e8dce094d832546ac791ffce8288b501d631447fe30dd795f18e372ffb4c3b94bfbe3604529f81c7e0b68814793338b386d1834e1f561a2b2ddcc0f4124a9fb95b96d7e7592d6a0fa402a4fa6b3e5acd20ccba203d274a29ffeb4a1a9f5a02e3437a7e991fe20bca1a40021ddd78fd716e5f54a923a16858dfcce93805a9dd801fd03f81c5552d2ff6a78ba3bc81f4cb2bb431e85434c5891e556aac7d3858058000de49d59b957dc44a03b06b4797b2b0e8e9c1ccfccc6304250c55c258b2f29b1c79a5e5863f8e1047818e9dd052f55cc232bb32649351cc4b3a940b39d7d5c16094a313aabc9050673771f2508b9c2a0718b9155671d0d5c48587d0e6c3c31f02de52e34a18736d540697a2184d85d92814e7d4af2187235176129702daa945e5eab8059631e1da280264d0e8dcc47bf0d2452ed255ee0a1da4844b3f7649bd737541fc419179474acf083328406a96b00e99131617b69b3ff0f88ac497c35d81c42ab362eabd90f20417c6a5d00db18a71f09676dbb85cdd6da93aeb7fe7b31212d1db0bacdc46576245d67194bbdfc4bb195440978bc7da33421d8a95c558ad41f0b81f6e284d7fc0ee14a8dadc56a546f98493954d16a86abfa0348e8d3ba0c157f357dda99108769825e510007202fcb0b9df282af8f3be08886158ee7db6f5f7be1c5d7c32eda9f61bcdc8063a95b4d13893b8a1430d659137438116cd5ec7e57270b066e87f462052186b7e00651523f0ca99783807401c92ddefa0ad640cacd08cd4e01e1a86fbe4a0c1ea2beb75ccb774cab18fa462691401323e3cc610ac3399b8ecfe5f297f13ae391752ce272170d6b14c03d630bbb88823789d896f09892e2f103b358d0850712139e237d829f6d151948abb14261d4dc2c959f533b0dc4abc84756873825e27daca7036743210bd2c8c748cfaa555ab5651ab26687b4cea0df1d37821cced95d9e46f06537241a555a42689b50672f70439b191eaa0418b1fd0402944bee190605c2859a13d401550f14aaf56c7b19b46098f5dbd17bff7ac43b41512fc99892f0aa025d124672a611013d8accfb941dbd08d44c9048ee0c7a1942b2220249ae7b2d9f0632e0e3083744f116f94157d1e9b789b9941327d351298b77ea9b59fad9adc19d88e889017864a67031a75073843f9e4ecf9e75a4e08ba4bb1293e708f2bce6b42edc5ef8407df8391723468bc68bbaf81ab45396bea12f906e732ba075d6417f24056c7ceaeb968deb60f9e116e5ad1c9b314af6464ef5c72c1ca2a5d16ed4cb9d7e638f0098b77b16fc7763bcf6f798407c3ef77ac7f9a14c1cf18e5e6d8aaf6313b94e876ec0aeb28853c94441f727a09c2da4a035b42e3ac4b881a278d3d30b831969b320d72bb3111cf3c9171b166a437c85409671c34f960f7283a70c73a8b49d4f14359613618cdd514219bf296a578ccbdebc7425ef8a52566057bd2b58dcd877c6dfe533d31a2ab6317e023386d8d400d02153c08605632c138255e1ef6c3b3ed7fb11e1612040c9acd3ba3542100830a37436f49d962c3b59c384d0d32acceb5f0948637accfe218d4636e2de5932f1c50ade5647f218cb53167b7afa6843615043684e5c4a8554e2ca0990111afdf81e21a0d285961ae150f2c04a3ca7abad9ac89d57715e853a90c1df2c10187c142682448e0d8eee80eecc42c165fdc7be344138ee2c45b99da42c3f9049cd05c2eeab2c114ad9c2530f27415f9b2e2f89cef24ac0028aa6cd0231c65a1bc3960d2306cc47d6ef43744c16ad3ebd0006738f43361977c8a135dcf7c629f3ff4de5f41f5db0089bd7e6ca978439764841c117530369026cdec8cfd82190caf0b9a5443cfc7c0f12badae400a232fcd45465c3724643b41855e2f14dbe0de6e2dfca80f9a50416358e5b2e609fcb1ec0572b44c36e2b64f330dd5b03a46bc858cc427c83c39ad8011a1c5d790302ed600438648c6406e190989ad02b9cd01df9ab90ceefe46e9884a3a336d25236b926188dfb3397417d38c66ff7df39b6fde1119a8dc14b885658b45f7cc209ed51d3189484c70984caf48aae0f87b783f7f326ee8efe5a0302415914b2b0aab619f30a59b8f60902b023101724f0e2e128abb24930fff2aa0048060fa71d899119eb138d2bd0b21c103258eb81cb2a2f852b60fd76eaec1bbd59b104c6ffcd196278726c6381395122f31d8225ed07825fa9d82b2fcb245b5b138709d9263031d5af6439ebfcb4da09fa3c73b432df1f023699536cdd26253cf91566ff68ac084ffe79023c44005073a6c0df35da09b094b269ae26ced50c5b6cdc22d07166fb1a7938389605abec7d7d131ed15420a85a1f2adcf90bbe72605a86beb102f423db1df38877b3fd0ba93f4474dec7ec905640bf32d6112a384fbd663c80231cbd89ae227f0de4814473b8cf7770adc2d089b109696454720d39136cc254c821b98b5d6784278c576619cc87fd4cf6fe13b5b46623ebdb8952e417deceed0daa75d39c36ef9fc17d926b61ed052eeb50850501ac524255d8950456e427adece1d9445c65230ac24aceef2a5284ac4c95a66adf79451a881ff6b7789630c2e6f5e6862d8a942d73c115b8342159942c751df95b14cb75b8ffbb86038467c0051396d83ec2c2110bde9175c66331248ea0e9f1ef61cd92c3ab11171c5de1d8813881b3ae6e54dae37c1b507938c3e4c33b002dfe9c37abdecda665d7c774411982b6c6d2210750953e7c410dc54ae527730d3c93ba2c160f90a488e94b8e6930a1e03a64108bf0b889619aa55cd612b7b7f5860d615231e69341f39f054c85e15e256b90c7a90b3311f2bc349b08fb177c7a4e43dbea0c7c9ff3edde4590a6261fe84327aa0e580879b81a294405a8e0b1d3657f4ee680e710f1e5858bbd54b85705ba1afb6454fe469d6e63780f51dac2b1c663e69bc5b1d34fd4210c1688d07cd0997fae63fdfd62d021d065df371894983f0d96e79b4781f0e1531ee7c4bb14c26ed1050f91baec395b05d0a546e1fd5bb6dec37801663d5cde64234f561405e27e5a7618925f48803da6b527a5a301a12a703d9c9f89d8902d64dbdf259336dd6ff05b9ccc9cb1f6545a4e2d405a5fc3c770dbcab7f2b3dd682e3892f03b030da02eeb8d15f20456380d2498c27ca1cb2ebbe2686bda89f05fabf9a46216d6fb9b7dc524a99520aa00794078b074a8250225280d2c5312df4dd9d508286eec6b66eef93fc0534128f6372e097276a50403b21bb1f2dcff1d1d7a6eb61f789bc6f4112ed5afabb73375da1e3fa8e6e8abdea1c7ef1c6825dfc45221494cee9951b991d0efd12726e72cf69aab09f9b18d0029f6ffc183c33ccb89f9f669030366061b297078d02d8c53fa777ee8bbf9bae938f6a7c04dde426298fa0e0d47862c73c72ba96c8b2968fbca2aa1575a6da5cffec49adb5320f0f0f0f0f8fe46942a9b522d1bfce164bae7cd970eec06692074a1e2912595b5bae7f959931e223f90dad0b889b8d71f2bba77b9ec30b466ccd7a2c206b8d616915f6933cd8fbb5695fe55baed9c505f63e209ae35edd06fa7e92e78bb10316015cc3ec3a406de0180e7e959f0d871cf734e79c57d6e39ee4812e27b05fd662552b3ee17e2e57871f40180a1cc6173fa08b67adec0c263167ad5ac4f54ac4f52ac4f57707c852f75bdb0d2152023d0fcfb216bdb80f2ca2798d2ad0ccd69c40f8c82f0c6d45cf0c39dd9826109456d7dca70044d02542f95404493a7cf13c02a01d901ecc2f935b2000a20577881014e111942dd94528b31958e697d9bd0eece21f0614608018f11b30938f26b780f0d1bde41177e1171b24f40a08a184946e485814d17577b9ce5dfffe6c776f4d41409838b2a564c92da594b293e058c8b9db30b75d4f62879bc0fa431971268e8886c5eac14e489c6034636026aca685cdb0583b3b3b3b3b3bbee33b2b2abf42c493e83cc179606056fe7396af288b3546f7cf399f07ec9e5fbfa7eff88eef787cef99e7e2d8af7f6a80792eb5901484e8878ca04889e5559ee5fd61a03f5d798e495e05efb84e33ad371ff559f445dc9020564a9428897e721f658da172e36f7443585ec5015ebaf13c7c05c7e3e886e0f8952f52aa2c9ccb705c4b909667f996ce655ab267f996c7c1b50471e171bc0b9d9b70742dd9b7748ec2c93a1dbc74e36fb0749e44467b6e4cdfb9f151855250549aa6d2549aaac68d1b2c362bb01f65b14e2c2f81bd787c94bdaf6afc0ff47a131f856cd8e07b838ba5508d1b2c9fc27580de1adad7e028a7b97783f3126541d24541a114948ba569174bbb58dac5aa71e3060b666333baf5c8be22362b1c9754382ea1705ffd400cd05842c9da7cb88dfbfc7aed3d4c85e3d20ac725eebbba4f11d6495c61b1583d2b2b2aacadd5ea6141d28a935e595159e1bce43b9044593b2c16aba75756549ac512d122216f49713353a6fddf3152ca4c5f52c952ced92d386cd73aa52e9fb02f739aa3d7ff63987b3648ae31709899ee60e2cd4045222c58d10d110098c42d2f6cdb9d03b84eb98ef412d92cc1e9c10ec330c3ec10c2830d33ecb018292630304fc6c041164f70b0c4c9ad529372eb9f811533b84172ba1f0c121ac96d7773800c2381a744bba3fbd3ef4e8b34c81002f494ae873260723f982ac4d0b9b9b9ce2e822e6e9bb0af63feb792b89e11f6f3606e4a07060646ee605ba8215fcaf7804820061d5ec0c886ff10c2caec637312f60c4a4112d651483bcad5aac4c277bf32b60587ebf66377a3dd8152ee3961bf974ef048e6784b25fe5a5cffb8c331f1670aae3fb4e198f9cf31325be29e121e655a708603a9453522059fb64516d7bff6674b322d321c5423ae7a3f1a840c07d7613502daf0cba76d71f9a58b3b204fe3cedf405f508a63e4c3bf32fecf79e454235549401f459fce3927b333f30e9844a3eeb9dcc1c3b7cf17295d3be68e1d1f17ae13e03ae8fd3b0792b68f5b0fba84f5b78973ce39e5fd78e5dd3e29b114ba6ce0c29efed74ceac103ecf9675f390ff0c8bf074892ece2af030befc7abeb735e3fdd6bd90dc4eb5dd3a76e934c1bf1ef1b9038c6f512fca204cb70e297ecc6522496a14bfc1d7600f129afabe6436339b6bbbbbbbbbb7f6c668622482924516aad48f45f79ec208463a04621c94b308e4619a54f3484cd484249154a4430259628cdfbd1543bc124205a38268ab0b0555c8fa2c669f0af52cacf0eacf3d8e1514bf08bffc74cb8ae048781c376bb6bcc0cfb71eb54d336404012e6d408fbf50905fbe4521eb1a97a44da4829a9dd91809067834872b5c23dce94b8ac13c592cb0c616f4de5473ae7c9463a2114ea8a943e980303035310a7f35b67cfeb9a1dc59298de1cbab2ae5b8fec6bbca08728a779cfdb7a6436b89620367ee5576c7c9152886b0912fa955fe986ac7c6845e545d7abbce857b896202cbff22c2b5dcbf5a26be557545670d558414959a961e7e7f3f9cc1595aff141993538be2b5c2ca1ccb9b2a23279401b1c9742d5e6f2c03c9f0df9d069d015545d9707a830c4a52c4e1b73da08cd396dcc39e79c73dab0119a6da3258d8d396d84e69c36e69c73ce396dd808cdee59c3bf0c6e6186e12e00470846e765dbed36871d61ff7eb2478ed1e3fd2915b02e9b7139958232fc083b8644b9fdf73c18187b5da2ae6c0496faed22ec676fb4d61e39d140e1c1ec30430cdc64476c7618237347991bfa879f637ef896ee70f0db4f822e49e1c36f77fc41c27ede75e8799ed3a0015b2094343e7218f89230991a7944e2481d690365134892342ca5a49134d9fd248e94524a87524a0ef6902ddb492e1e2e6920894b9fc4999142766685bb7886e35e8fcc0a29cf882fb31cf7fc71dc732af8c5339c2fa322cacfa8a01a0f2c74e1c62869248da49934474e59aa22a114033df8088646f2030f6d72ca3d29a51e0dd38a39336de669de4c539c1ee3148249f49dbb9263a677b2055dfc5b929a5a25d8aea3c0c2d69d2dd992adebb261c3a4f2ac73d65a6badb5d65a67ad7563e11bb2ff52668309a694fdf7c29d5f4feee25f6d6a927ae767725386eb521a520bd75f9ec134f8d72578c4dc0493e61462d224b9dea5e6927c3ee34cb4f4f9cc4b1ad712a4bef65afd22a55a39a992aa96fefada7fb84f2777a08bffd6b5f46b5deb76f65927796a2759d3de50ece15fd775595a91549b7a9a2725982451cdf3344ff364bf7a3a31b9fe7549d750e3a4ed3fadde542b5a86b875320c4df298248f29933c26c9534f1635ab8d8f36d0ef43a7514f9084c447d76358c6c512e57cf0a559f65e9a2748aa749e4eb09eeaa99e6857bf6f92f78188cca558f7d97aaa27b638d46d164db0b29e6b55d98a655c4b426566ee71884256a391e5892184f2b31f9d733e9c964372761042a8b9477fce39218450328c46bc40031dd4b233202f403d2016e8096805120376b7483ea79818e0b24eea74bd0035a1b96e2fe4da89899a4a70881b62e3459fc20d51f915cdc63d24ee6da8ede64ae18648f95028e5634c49f9e66497c241787dca757529130d9775b4d8b9f3d6c40dc99dddd644f5d9f978719d5738eac46a37ee692c96e43e3bee89ac15acb6f2950aae4026100f9af4b1812efef5fd415d704cf651102dc182015d8470fd9becb807f262c77e8e9e1c3dd71f540304b2a00d4bf92f74bf8f6abec0a2bcf65141978f34c1eedb71b31418c15e3efa349b8fca8254ffdea7fb3c900ae682543beef75181ecca7e5acb069240d8c7e67a0a880907f201bffca05dfc1d44052788920032818ad0906b957b48ecf7515dff8feac3c46f307d2905d41d880948e55e12c4b89f0652810511c12f5aa4bacb3a5ad4e00046162dad9585ea6a2d2d8c689124e5415ef8a83fe5e3cbcb3a4ad8dc9ac2818cb84b4aec40a62df4881d6807b4d2b901eab24e16ac172eebdcc074412a4802994caae80d3ff13d762022f845bb2013bff817f60648051a03646a992009d4a94c57278b1c9d2c66404c9cc42523d4dc0fa462e2a42e710e8a30036a729da337c47509727e9ba91699b0a015880552cd23d308cdf539334d53a6a6dc73a9731b4208391093d68e809a80b493110925fc28638c90e6ba0909fbd527d75fe59e5726d7e58c853fffb5162469ad562b9381d55ad75f6bf98f37ee6947bc465b41926682daaa3e99b936905455d0c57f87ae2c8f88755db3a93daaeb2d90ea03a9402a1afb815420d5f507a9402a087b6ebf4083e2010002d618c6187777addf578581f1bc7fd1d57da25496839d3b71f8c4cdc373fde78e8fa617b3654862fa52fd8943b7898303ea688b5d5a3d509effa317f4d92ca5206b3f22d1f6af799e6337d4ce32acd6d8a06e7026e61a0aa0df40df9f9963eceeb842e1535e895a841d0f7ea132b0dd276b58f723c4803c2204952777e9cfc1b122670965c10d19c952b66c6606c2751799f2dc73c92eae8363cfdfbf2cbbfe2d9918d1479186371aeb5f2133b3e45c321d254f68be9ae92c99c9644a67c90bee57b32f93bd29c07b63c0c5baec1e94524a2965a4d8a494d249299dd8d7eece32ecc2e691d30d990f13a1943cd9a8bc40929239928944f9f39c73cee99b4d953547aecb23ed29b0b725cab31b1fc9d3e9c8a926943201b6c2b01d7cd47d0109703363b5497d1d4ed2fec361a1baaa9d04dcabec39fd50507843c2024c129d34f7cea0b9363fa04b10dae74113c3300c03fd4703fd470369bf3d04b4df3a087c1ed4fdc8980802f41bca5bf973f3e11912219014841441eca37c10db8382b08ff22dfd4140bf7d1094b7df5b4b773a807e7b08803a862e1040b1dd8e4f6b871cfbb1ea8a56da97764012a76d2d4086481144fbcf0f017541866c1d63536218a519670d3f178bae78071f6518bd6a6cdc5b92ca7c7301f38a397eb6ca784c473231649a642d23192b7372fd39ae563a622a5beddc2f63b5628c31c69dd42ae5ad82e0c17017bcc501bc55f6c5f52e5f5486854216c6f54abf368675438894e8f3f06c95ad2eeec36e539989747053da2dbbfb60fa3b8a217aefbd9e955f184c62b84c93961b617177b7e8e0a58d57ab5ef5aa573816ca2a3b4abf2b260df1273de32e1f38230459b8b5cf70232b48da5e7bafefdf3ddde218ece77f6e120272c6b1b6711842f8c5ffe27e586d9c979ac77b4a1a7789808a234a44a44c498af9454a5bc743e37e00812eee2bb84c7ac88363fa3a7f01c35dac9a348f19167eaf787cc47d6786fcaa3599092c44112220562d968fe8183eba56abd5ecf930a1b9a0d96386cf1e61201703bfb80d201a68bb146007ec3c6f14dfc39c60a1e74939635059c767993b27c572a2b3a457ce743a61a31376fe89637c62c03d1e3866cba1dd0339a6bbfeadc3312890947d4bc46a9e9b7325612390ebe384a58dc4491250826bd081655882631ec02ffece8313d6b213ecf2e603d60b8463aefe1c7e692f5c871c1b6c98618618782787777ae7049052110e2cb70cde653a76becc819970e5fba600bfdc32746745df394cfc86ec9de6744ee76018cd6a6c90a06e783e2d50651f60749d8d4c030527c6e8261f390caee347dc88a37c899f1cc9f58f2a56b18a55aa1f3f20a929b55624faaf32cd041a2e789670a1049d5b65db5c3f20c94b3030ded50d6918d4787153228209218912ed86c032c52301d7d6e3fa3e1b6ed370fbe5360cb75db86d83493c421ce3dd3c20a9916097f9f3e327d0c03c2fbc8201eb6877f5117e99df32dacc7c1c4ee2d27c3b5f04495cd2516f6e73f3e3e40d762a33d23e42a3db5d877b3ef2ccbd935b048a94b2efe4ec74a4a698b9f27b903eeaf94fe5e8e54b393b20fc22cfb03b2d93855879702fe2b40a079232c02ef1634e8cf10b306c7c6e1c1a4aad1589fe3d9c2b845dfa59b4638b46489ce1466c091ba56c9eab89ca3abe0a2f8c91631aa760e17b9cc147ac73c5e9c60712756e5c318f7351d1d0e971ae150ddbdddd10429713c6aeeb6e06f7206cd9f83c169092a287dd8b0b9d7bf7e0ca08acfff7910727f909bacc30890774914f8dd823352f1259bbf32a1184301402e15308997be61817dc57ec78c5972df179eec07e9dd3393eaa4b52b5b5d5f6f25554b67e6f9a9396a675bdc45de7cacfb20e53d981fdb42529f7a47bf275a0051ed68116565d92ef28347afce6ca18bb3e7263f41a277149e3013fe6497dcc934a09812ef229b55624faf73c1e3fedc033fc44a9b522d1bf17bbcfb3e2c9ade1b2ce0c742ecb3d89b1c0faf716bd9cd5eacb819142384608bfe8c082d5d1f341526577bf108ee9db1dbc5ee386d07eebd69e37edaf4bd3beb9a9d53ab5ca61afd18bc1a796a5a29a15d5978fe3dff3116b0c1ff574ab9fc8d03fd5f4d78b875fa7915128a9c9e47bafe3a79229aa94524a2550d0580221dcefef55840541177ee7620c23720d32d535c8ae795a865e02bfc48f567ead2103858536fc1265f7318f8dd87b53ef3e6aadece29b6e9449b0fe95c6bd23eec5ebbae6452f7ad1ebbae4d5411af7e24f78da6a2c8cb1141fc616be5fdf1863a492068623945272c7d07eb6041365bf08c35f7b6c0bbbf7ce9b77d40596089a2be2542887ca3a362358fe4a863f19d0392e826d81000c42b640c07f870876a908035d82c0210f8b948a94bc0392b5c0b6fb10127642b80d552d830938a6bbe601bff85b99560c8a5f6414ece29f53825bc5f5efbbd9d8cf5b2d488a3db1a7157bfc4d903469ba062e38a6bf87c02ea9ae0176bdd332f87b96c1c00c60000000404bcbfda42925a555487a70ee274222f65c6fe950c65b9715ac7fc31d2291e7b5ca552ac8e32d95dda1a93c83b582185578028aeed021742ccbbe665996c5d8c1f8007d4716b1fb9d95d9d8cf59246d7bed8b94405fa454bb96cfd72f52b25fa4d4ef2ccbfdb01b475776abb11f8cc689b621ec27ba0d4dee359cf9686165babddbdc05142919409172fbfd7df0bdb1854db92df0533280e2f2e623e57601c5f531bcc79d38cbbd1ec27ecebafd1b1396871d3b3a00b90639cade6df7f110da81869da1a3ef0311999bfdbc36f083bd72ebe1575f2839b803735259476ba121eeb5bbbbbb7b841452482184437c804666a6504d91eaef084f1cc54793191de440e7caae057365a6685161c5fdb87573fb87742dc302d163b3c02ffd7e06cbd0580a2ceb4861e47ede72726f904023540a26f7f316eb48a173fbfd0934d566f66e6b7d307b7ee3dfd8c2c6f711e18df179b80fee58050616769f7fee43dca3efc447aef5f8886e48ecc72dc6507c1c61a6c75ebfb9c0c65a297c72a10ccf85dd27dfa906ba753f22a6ff88982ec4e173bd926131960eb084753dddea81fbe10848dc631c99eb2daa4345ebf60f7152979ab68898b8ab81e87bfb5edce48a5cf975cd859ddb27ee35247da0bb1b087ee9e7e150a6f3967b4d6bec57e47a439a1417c0ad0737aca2bf6562a33607c892b4c9b1a13905b02e9c0bf78b3934078b2c270bc2f5ac8bebd916d79fafafdd4de9f56117b4136b7c05f6631609acbfcc8fedc61a63a49094015663600696538e0129278eb703216441b1e0b0ac58c460b18265e7fab3dcb0a8589ab0e4b0e85c7f1855502a2815940a4a05d5590a8a8630c2aaa42ab1f1a10a8a637c8650a19b09050ac73d19dbd2dfb7058779bb53b9b935eea782524101600b00a400a0d39571fdbb1e6e8bebcfa5726c415339965c77010ad7df0516c7f4b36071fd597258a26092a4614125719de508b9840a4a22b15fa835a3b05f0895230a1e816a3c070ad4448e9b0b7ac28515c7600faa028e2838267b1427ae3fc74826ae7f8a63fab3295c0fa142371c238f84a4e09144823da721d4d5491a49c382fae815b20135c1a3d0132114e889500b5405151427e8876c7c2485602fbe7fe8891954fc2fd4fa5422763f1514fd2f501747142d1c287e711615140b0aeb5cb85ed234165f7234c61a4c7c1cc614321a7ef1235911ecf9635b5cffaf061557d2f08b63a91afbb1a072e4e458e223c9826241b1a0bc9d942d2aebf840b2a5642066f8c94afea093f3db5efa018463a40bd12c28aa198e5ef8a267958c2ad58f23a7277a6aad5cf9ab7badb556c6be08e3fa4bd6766b27579fd30de0b310008fe2ab1ec2c8b1afb4010e18d38247574db95cdfda35d3b49a61354bf825a5c3e35e0fd693ba4cd765a2c9d13962a451bda44f175fd7755d317a9b03bc847114ba986c703c099d3613898fe427c98440d2e7a9b500bbf86f50a05a19293e6313c23c271f5d357e03663299289548dca5ffaab199a9cbb324def3606070e69cd309f69336d406096a4e99d34d30b314e9a0343b62a37bb0b71e734a16334b9631e8a845a60ff0c679713ec0189f40e83d0b6a2bba8f60081aec7162ada8bef5882df28f6e3da27b7193f3a2358b356adb16adad01218c8cb2a56c31c618a37b9e0e1c90b3b1f5f85ea557567a05be5f98a2a28556341b9bc88648240aa5d4108950ac482402893e9b4824124096ca52b7b31e540bbbdd67378410c62827ac812768d3afc44a39e3a4518b3d42212be2b194526da270e0103d4b74ab92fe5a9558fad57debd1b63fab5a55623f7ab56e0821ecaaa4bb21841042081b7655d2dd10420821840dbb1b42082184b06177378410420861c3ee86104208216cd8dd10420821840dbbb93b7e1ed0b9c8d52f5ca1c6e76e88145f92f810682ad0800732a5f8b123323f0822f2e35f1ddfe0c2726976527432b163e822c1b05c82e1a4845ea2fae0eb43a7717770039b7a790737387285cad2044bcdf59d7dd7eeac3208846114c0a8b30bfca6ce9e7ca75956c6d535fb9557cdae325cb853249215b8304e243088e640d26052081e19803d7ff8f300d294ea418eca3d9f2a601777c972543e9a26f77ac0a37902f672727220297b026764ec40f81fa863ce7620eca6c9f6705b01d644fbe9ed69f211c7db1d6f4f153089ce24ae3fbdc8a08e51b8b17bcdfe69201c609a5cb8d3344dd354811b1f0a91ed4cd096f93577b029a48963bacb549c0dc1c8e597369094a524113cca76dcf38c0c76f1a71916b21574d9f151c6726f083ccaa490ad522b4892406069049973bd6aa72d46593e9239ee6d356c6cbc7d333298747d8685eb7fd51e2d7632c2b9f50032436de4e6bd3676afd93f7136e7b0f8456bc2f65799d9244a66e62889b8ccffc5182111ecf147e8d349cf0f6c27b093267e611f313337c4010303568199638c0d6334b1fc1861c7182f2122c708bb2ca7bb1b3e844a884c8852b2a47442b21a65b37202153b086186e2008a05851659784df8835484cdf57f876c142c8ee743bff8c3cd8706220787d5448e8c3178384dca96e4f8c88902285544e51c2d6344b5bbdb37da00bfb0637823c7fd682db0de0ce347762e61c4214281a849d98dbb78668345b50f2846bb9620342be21f016e13c1b66381054d9029dd7043d7d057cc41a78c3aa926f7eaa68cd00798461a37c7ed152984215322c0edd4e573ce276ce8b28e1218e8e014875042821b1b60a189b597756cf0841d1b10c1afb0db651d1ba86c90c2626709b3a38410bae88a0f4531c6f81042c810724b90ab74bddf245737240893a5a4c810429b054312f69cc44e8146e8dd256f4193b6a2c96501828e1e5cf831033338a30a268a6002ce1360584108d82765fb955cffd8d41a19c30917480cd14413967cd1f2c146412dabc16043854aa6d4efd50075fd7acb32e21588386275451a2598e208191761a193b32367a4b0352eeb3c2145ff7b09c851e9d4e08cbff1b24e0dccf028c829a5ec5a360cc9ee6ed8ddddedd121102e2cc22d077867d67d22d9bd108c6379f560c129e667d95f61c0581f7b2f061c71cb21040c61867d9d0dc85ebedc72a8c0bd3ec344586f0db8e65f9ccfce3a9c004cb4a98f43148a4b80e98196f2826788398b30024b113d2cdb8899142e8c484208492a22c40cb400238d2790c0440c5f95c145114f4c1d0c68bdc20c862c27221824dc95cb3a57e8208b5a8dd8fe2f74ad467954c4db792aeb6887516a53d3584788f28b09a4166d0f1c9597c39a4a7dd40db3e33d26c98f9141d0653767f749662e1289b8bb18a3fee6a2471689ac6d66666e2fa3720c4b8be04a8c8a7c7ac14e8666ca5583a2603603d58fb66ddaa782328ba1d01a57ca0c491b51057a5f166611ddf87843af627c7103c6a8458ee58aeecaa59c686e49accab5712947b7242c63fb3dc618638c3146ca7129c61855b41863f4b02d078983dc72d87208c18d9f53a98f6ef00d967b57e6a6005aaf8b93ecb271806e0aa0900ba5dc8a6990ab716b666fd5eae773eba78234c869b7a26890cb6e4dd12eecd6140d72f4d690664383dcbc75a5ae68220d72f056968aa3e5c607ca1b4370fd3b46e80e935023157887c9027c0413bf3661bf173efa02c7708f0fa24768717828c6181f09995b411e22597e1be218be0c755c771daec3232565d87baef513d77aaeae4687db3cb99fbd99639ddf706e938a294f452b2e99b8235950e3c3af1ca394524687e1b68c7b40b8071be607f760ad5ce4fa57951ea95205fb35cf630cafebe1d6e39a576d1df760a7dc834fc6d553f28d1c48e9fe9a0a15ec7f9dbaa27bbdc43d98c3c3254739f7321cf78eb01ff78c804930f0f3a0ad623f384908ec198ef187f27bf0511c01bbc0ffe141ddd7376c84adfbfa0517ee745fb7e04215d67d8dc4854f3b46013fb974a687f8c4c6cf82edb9feac7373d3e21dbdda87bcdb550bcccccccc5f4fcf694358d6b9e2e6815c3a7c74fdf53baebffe7a181fc5eb8be15edf0cf712c29fe85e7f5defcf2fd7d7336c3f43261ca1c9734c8f7eee15843c99f6cabb1585104208e19d2d486a93a9656ab5e437165dd0340ebf20210956aeba45a9b5d0141be5a37e39ebe5438b5fe4efd0e44a6c8939414358eef6fd28a68218dc9307b8f2257771a50b8f100cf070819671722590203b1ef520c90250a05e27a49ec13a64ddda09b627dcb81929e093e04bec347c6d643e0f872608218470c3a16f3c42067672080b9fc70fc8fd8073fe70ee070ff7e6633db001a184a8b42dd73535858a46020050000315000020100a86032291603c2689b2a03b14000e788846764e9d0be45192c3288a420801638c2186102003040332a351100086c98a52ad7590d61740d101ab93e124865426838aa47e156ac470a030dc7af9e68c612ba9c5e9ed7ba8101d24be14235d3199ad4d825fb395ecca0aae9c9f214f8f020a8ad0ae8519aa3b2b165527c987de57a815fda3dd844cbf56267811d499197889ce63a002cb2655e53e5037030d59d22933e70e049c804c27b5fe295c39134054e6aee86a9e9b6d06d0703a87088f96b2f1c4bdc7eddb3dbac0184708683fb329060b110f0859bd6ca42032f56df06d41d5e6592430f4bbc940150145e24d4c18ef9803aa487026fc49d9364cf0b4e377127b5536fa49d83dbff450df23df07b7aa3087557bfd522e7bc07fbc0218f15dcf441bfbff464daf2bd8eea76d23c97fdfb90180573970848217ce32f3cda0486d9903f2d4331eb7742c768ad9318bc978ef11645794fbc8a6df23db8c894b56dc9967b9480895b44a2c8a66cccac67f748487a5b4d3221339ff33906c33e817f8a48190e0fa7f1a265fd7287a9ecd05a8511106aea2ad847687f73c8de62673a4f37a4a54be923b786d32eef49091b9754b2e83d515c6ed612575b3f49bc64cf2d44a9e6338e14386b6a139ec4f80dc444518fe08c8a2ef8f4eafc187133675036bc31bafe5785e184b77079b384cefd46c46d21a2a0895e3703c4a6e3b3712dcbfd2c7edc1a4488ab7bbb8a7d35b42d888c58d73e1c78431694a61e8ec9121346273e35c31d7301212ebf4122218c1ce61c86eea21c01124a2d35b42d4a8c98d71c550c30848a8db4b446c84d5c173dda4618849d4c153406444e386778d0383b0eecb29c6506ba172a4bd63058513ba26375230e4f6034fb5eb9f33ba201fcb401f571365b6cd176956b16287be2fd1f8411d9bb129d07d2908d07c9edc0187087ec3ce9b3a1e38c128cf5ceccd3e1839e2f9c622d0748b192e372504c99d518217324a8954cc10271dd395b0fef6917d88a844d419d3a359f554d52e5f605522f43c444562b21f462c8aed6b64a2a790c588c6658839d54068e3d66f33dc61fd5a7c7e08eb702dc31d6ee4436d18a2d64a8c91403d0b72f3c8ec22415925212f7c3b74aa099f13798542a4c093382a284485df541d6867aa2a2bed0bccc72b6ab40225cc071ef36bb21d79e9badfe2161a8a3da9bc48aad2771c14f736612cccef5673447cc5ba074583f788c426ba80964f7f103304c2aea872310cc6fa2ab4b8611ede124f9cee19f4dc5cf1e84d78e51f92388bd15c7958b32a5a894b12faada39ebbbee08a2ca8a0490d1457875aae395fe031bf6bb1123046fd7e2ee6066e7d8c230678df0794c9135b85666596614dd5292e73d8ccfa02a4db633f47580f9bcf122669b29d6d9eff8ea6d7d7b284a8647755d8296fc91cf5360726c38479fda01bc9856cb8d1dcc4e9ef24024341ff33046a219e97c971a3fcf614824c7f7548c3d36ade2e43a8db811b903d2095e9fd826b6496bf848b0e29c2b10548d3ce0221a6f6100c40a14c20f6ec9bde602a35247d9d00f2f9c7587754714e9c82f01049866350d1fde6d28353eb843340255a8dc9cc1d7ae933bb66a743e0b1978df9ac3ed71115e18de894e09448e0fe91b49931511f8f894ebc19a61a750744019a1206a8cc27928706c7e56662d6ba3e1ef65f163e5ba0fda7c4e6c2811dceaeb653de1b612db97ce8452dca1d38f2555b2c14162e5bee8d283d93658da3479b42eb7a59ce4c6759c94de8ea508ddc0f1775efff53135a94e7d36e4f883c09050fd4fb58839450d9e74a8259e20a157f6d7f88d1afa956fd7a0611563bbfb040f541ca65e5bf7b8520df72dc3e5ce6cda85a30a01934d68008549cd6d8c9590fe425ab4747c0285380b23ec8b75552d2ecfc7c531501259c86304812ac778b7de70d1a25d2eeeb07c6dadf35f87f8fe46b7714959c30a85b34f9aaf55ca672c296133ed7e83443d243b76a6d65203b7dae3350380735425cbc7767dbc30cdd65edf6fa4ceda1d2d3e8304a65ac09ef73353d0b4dd87b591bc9fad9ed0ea25ab71f200dd6283395d4a955832a340730687edabc9f6baac6721fdde17f22e5cd40396eaa6d0f80221d8c49871fd379243c6a11e6bcaa833f369c6f282d42dcd71101e0a08befc11218385c4a60396c3a643499b4bfc3d7d8b56e87544b73a1d9925c17862f852176563a027aefaa13017b906a936a4793f25a8c2e135d6f918ce003048e63642e2ad7fb325d634582c27ff12cdbd10d7f2e81af15c3ad65c4e92ae701048c832ec2f54e94e36aeaf3add007f188381ff9a3abb29882b1a6b0d9372fa566892dd6a85d0d27a17e7cc0b0cb1546125812a82b31d1c60368d58a66080c57affa674d9fc7920923868e1dae6940f9bfefd2776ba64a7cbbeb22a5582feada52dd7f79af28f1c9d85a6b235a9d7b1b62eea25df7d70bd63d3266563b90a5032093570bc87fffb3f10fe12f43a6d8bbef4e8c39b64ad854128445b1439a29ee8b088be8929624e8865c309edb706de0460b5de32a2621c632bda4b9fba2c1b2872bd4db8b330602ebe539f7e0294fd30a6a7f02b1dd6eec77f6dfba35d1f2db869f0bb8204441dff59a2ab68f6e9fe9791bef1af128f09c48c04d505a93c95881e455ec577acdc92a044ffc777a6112c726a83226b3e7ff94775d6a8cab983ba6105c4ab8f8ccf7b7efd566de330b2f4aaa12116f6b727920baa9c22a29fe0c10c2794b7a0e004692fc1269eb6206fd8f720069b4fb97e1db8a58664fff13f5a212410b72479fc72ec0927c69627deb5f943b34bef718d8877ad3381abb491b638fba1cb5eeb38d2a69d06f3d1fc1ffd2823f1dfde39d898c20699f5bccf07a41a807b159368d7e9431bf6cda516db7069a7e9d41662760dd226d695c0b695200bca0ad931215e43382bbfe2c896278a014481bfd7ce410cbae8d51220c33dbfcd187a948761f2a3c96a91cead0b17ad5576d8d15dfe3b4be82d61838ece372d127309cf742896cfa84d684bb020f15de50abb3e55621bc2002d0d593d88b1cd2a5e416e9ff0ce34faca564e300732c16b9d4774d35226c7ce40fa45e0b5cd419613a4f97f972e994bc7717d15eef4acd9979267c274a430ee0a02e98b18e6becc2536cf617a442b74d877664e4f06d838edcf5ce9039e45c15043fb7105cba6494dcc889a9601b11977b20b40dd20acbe2a4d820f4ebb7093742d24a5b612230029f4be81d35d7619bc584590b2e44b85cf253b529436cd8d6746d5a612035dcc5c3c3bd43a5086690490b8b569969fd6e3a209f78dfdf6a3f2bb3862606a5e651263bc97c0f143450ce91bee8b09a083c2f92921963d776356eeecc22930a926bbfbdaef581b70a7e7d9ac2dcd12d88df4b7ff48afdc7a0488f280bd94ed965bc797f612a30eb19149d9a11f00590c1496b6a70339ee29b04c9431412431914c2abb0c962f7589930099431ca2b024e6e0c15bf0c916178f107dd2643e4af5695ec94fc027e5f930512e61a4a7341e7aca4a64945508bbe7da3f47ab43147821d1c7bd9eef3f795e57a06147e3b8eb494d06af6b96bade9b57dce80b6fb32e5c89a534b6891e2f7a2fb1db70502df1f8578c576aacdde53f654bb1e9ce6f5145b69e1ef1848da4015cd18ba821eb435825c003d4310982374b43f09aa373862aea26ac035aef2312d4b4f4247460481c68ffe6f41be02b619ba376111f410b4aab47bc2c59379925c2407f5db658acfcb6364e7d2e896125ab9a8e55e11fbd1df91ccff5f0339c4971a54559212a0ca04ff7762f48be97191bca465220f511b127ff65bc7999395a5641523c8272e4826a069bf0ba90b30175a79ccbb2b298f395b7e72a4941cc0293824fb5881b8b3266efdfa8fcd2516f8818c4e00950036eb877a7f4b945649de30758f0a965e227abe25c1b8507d8f0419f9e41318ac1b17dc0bd40966546fdd3622908db3cd04d4ff14ae7cc28493ee26121456b859a1e2666afeaddeedb9bee03c21ff45e6fbf5f51cadf3d40a30a85071e9a340550f40e68bf5e11fbfdba9e95025a873b385000a5832d8070822035b864436e8664862a19a9cb134d404191135d4de595471c4debf11f4e09849a426d1b35426210930b45e99a411bec73fbad19420092b3d474d355c321ebb272a2e085e396c30afa78a1d512aab65ea3e08c4ae15ef0009f4212c0cce4efe977da0056ac3be0c7430b099d8a708f2015500a65c9e47c2d070986b1f422b3009e551bb8fa315dd0b4a797541e12e017b9a5066a4c419734bcdfcdb3e464ef97500535ea2ea69eb8bcc3ce7048dc1f8304bab049271d9e4216ced0d64204860ecdc1ccc79761c78cc3a2eef55091e016ea035c97fc251da9c294b82ce3c8a9e52bb38279a187eebeb5c1ddb8b3404cd1757c570abdb6548d1332881af652b0777d85ad6f11c0387509cad6ea03f24d657c7eeb844c2966adfc1408c8af952f408418edfb8789c96b4568412dafd62cfcd81df661195170f59918ce12323fe2fed0824e6a833a869c367a307341b3823c8ce230306aeddf8ef9bb3eb5673798b707af8c8e06e195c0fd40c638e2b580e7487b680418a06e423a699d61c1b158d7e786c86d03ee3d275ca9558878a98cd6e21eee309dc154a603d097928a79f7ac980a5ddc9b1da676dd6e3f1bd17e5a286434592f9f864a75ab261bfeb84611608192c9badfcc43616429dbcd45281b5f1cc889da7004589ed7bc6398e1cc43b3456f0ecc26a79529abfac02052dba3b2b791bec356840131378008622aaae594bc253156a975853ead7901236321ab6371187f5ac1c6f57746d53c2ee483c499486a1d2a5628f563307aad8b4c0e28681c0f81106f6737cdbe259394e8301886147e998eb7ff0e733ae3310f3628ed81712c6436e9e48bad735af8bf4c9e2d2cd30ee49bd64f5812f501b7f33a2a547b23989501bfdf78e677d5c1ea0d79b3a175536baef9957aa352e930e0bb220aa7eb482ec70b6b668000f34fd733600a6c8eb46153c8b915ceddc6d22866de7e3edc15b5c87386ef820ece1d6ed6a808fb6e047c04cc86d2b850c445be16cb9dd8fef7d34d0fe506db688b058dc22f681406bcd5babe0e1cdbdc48ee40059e78c33b6f54e18c91df1dec5e674018647233d5d779cfe8e3155fbb07720520d82d0143e22575412d872504812118761a233bb5fbb777c9e016342bd81a76a04b08c00220442c7baafadf68dd02346989eb87d591118e312290b6ab364014e3d38d61ae087ed7a95cc3237c5c87ae755f6cf1a4b978095a61b16dc928d5ad7c1ef9532811106a6977a3c1a8e5013b99386fd0a6e2324c65e5480ccf2467016edf2314df6ce545356ff662c8582555ff1b16a1404ef1204ffb99428e52c3f49d55ea6e13584094c3b7bdf604fb279cba0cff41df044ae0b0ec217bb72d7c65385eae96c2c9a4781d86cfdb197595770ede227aee4be50839ea8ae9b2bc61870f866135c0cc0d98a8d823f154ea2492fead74c32b91192562959f4ad47d2e5f17dba75ef41c2d7891b3c7adf7dcc1b20174ed74c129b6d0587c591a436db0a0a9b2349ecb61114867392ed6c133c2ca724dbda2e48180e49b6b14df00c219f5bf87da5ca504096f2fdd41aa01bcf10da3e19a1fdf17abc0ae186ff4504c3b52eb5f17c7abc599e25aeb9170500185bad96d926c234620e84634bba03eb318c41ebeda0e5ec77217b8fcfd55ec92fca8eef74d6f743c2390b7c6a793ea48f3d39e91638606d8f32538ff25919be4d0cb2eb07d3285a61b1fe992f085929dc914893a0aaa640abd0add90f76d098a1164cf63960dff8ff5c2cb045cce1d089700a44431c245d96b62e2ec9d8b69e3070fcd6e8ad70787591d5eac121254ec1ae959385bd8e4988a7fcc2980f74a29c1b0b05eff793885b36c9647e3464c9b2b26c9a2e9c8386d772a2035beabb01f333fd4160481f9d6b4528b70c23c0f9c65a5e1e9cc0666540b1d7ed33a1d19b95f9f6ea3ee0f4df4549d9f94c32b6741cb5eccb8ae2408ec57560adcf1131d192da3d0fc12a0ef5fb3f018c7e81f4a9606e47bd38b0da5bcf99df4b4460603231739d0c1c38513a18efa341f75845e38b4750f2b1a05e9c8fc7e2e597f2068ee116b3df57b16916ed1129add1e583d2b78dac4f017a6e69f9855d5cf33bbf6e29ee7584d6a839f9fc900dd0e16692350745c158a5381018b2ef02cb6f029714a4878581bc19de8b93b63064dd38989e9187408b2e58664b950329109428c5a2ee1aa972ed4892f05b590f5605d4a6947752748fbf67f08b0ae8a6afc23cb4ce1f44e8ef012a7fec36bbca5ec02f847d16efb43680875d4154764a5851df27d75d6a24a19efe5f21c4f9af255b826bbacb2b706c4c732b4d5aa55b6da1fb4ad0ccd9b7078b0524b427a43d1d10e881fdfbf8163f428501055305255aebd32873a7849bb8e52a68e4f0226e3dcd3c2b616720c2717d86d873090d44624a0168fda4c014ae83df811195bb1939d99ab3ab5541416f60eff5f84142f38312b23d6849eda542abd48565e90aaf8bfbb2723459d41c3c13635b15d006b85834bfc88d81c30286f038ac8ea734b82ad5c1a2d528d88b307999de771be5030107bfc6eaa3df4f65dea1d9d1d30ae11a903d983f49919f6e2c895bd0d11bd909345dd801c8a04f61a06dec0c4f9ca61b5eed455c2092d985ffeb02a5bcd03c896931ea4491335b37d661d7fb43dadc0b48de9a53aceeb83a4414041a1affdba914d46c7dd2b096f9d1a9be76b67d0424422627c2cec28c0e53c29a8791d0461a32d4be2b8a2d3750b501e1c03e3b30649a9e7330f8399d2182e84371b9ba87548c8688904f5cc0d35e40f5c4e8e19610e0230184db2af45b4bd7c9b4ace4cc6e046e65b15556397086e4a954dd40a29e168218ff896f81bd93fe732d1646e67a5d9b81c2992075cd534578eebbcc3918dfb172e77e9b2b1c33fb1dd99458fd912ec4390cef662b2feed8e0753c62f9e29ee5d8347d967bac50957b994eb49383e9034fd8d4f6b0da4a8e6e53fc42a83e91443640936e58eca35d29fdd9f6a4e78cf10380a765a2403d8d841d3d55002a7b55a45b930360c933149227096b3ac7c42f52dd11cacb286642745433b75668c7e7cc28230922ca27c939e4881bf39d8feab1347d8a06377911a9fd74a99adaed3f116ab56b5bb99255769336f9bd9428b6b650d97a04e63b831d92fb299223933f2d07e0c23e1c7c4522c34489f4f2f603bb6eaa7665c4de1f2221c03a86e30663275ae60f20bc3c06d9b1c369b13585e0940d53694f903730f3d3679bd821735a0471faeadf6fc7803561a9f3dbc012ab494c2f8c56cea0faff16b6fb5722698480da8d2006cbd630324172d05c333e1872bd6d77012d6e568db6fa7a977a7abdf4f253204c7da9a9e43cb0d2c14b37d2aee79a85c1e10305757a804b6f6e4a60b7c909030acf7b522b9dc09d1f08d739e141eb68c88d5d3f85d16176dd06b6e011d50ddd1a0e88766352c3526ade19592f249b5195d16a018da5b11ae71eb49664d6aeba92b201ee603bb8310be2aa7a5946c1803c540c64b8d24637ea851d9a32b0f786c0c89ac504eeab1d5b18f61b30f1abf5ebf98d13b32be939bc7b2b53e26b4ded8e4b764c375537b376b0ebefd9801cebe10e272126c0707a92453e65ec7b3d7bc1954fcb19e81e47b3635ca54d7291873d93c0364c840cd5900589efa1aa76cbb50bf73581f7cc8e8985d426d264af5a8cc98b1905ffd93588c51ca60f3d90992f3439aafad074ef575f512426790ff65ee053704744ec1510b58514e686c5fda458853cdadd3a9a7046b250607e5b11291e789b1415a0d9064cebd2182fbb17e12edad582b7ee157573baea0a608e7112aa2bbbad7f80938541e8a202570bdb6ad130d571ae0dc6aa5dbc2dea1a963cf133ef6eda617febba9f89ac19dedc16deb0bb96f511fca7a451e17bf7c4c3cd1c27c8469527881c8dcf0570889dda247375bd35cb29da4df8193205cdf0d33c8264a2284f4a534670f5196a25fe19ed304e4bea3763c9d26e60477001e739b5558455ed7172984f62f7714ef06861929f64fd257b2bb1e8f83199311d4dba936256e4b0054786b9e57af92f06a3778514b0fadc6ba2ceda26c80a5e67a0c7e0da2bdf5a8fd1a7b5eda312eb777697ebc33a381fa69862c1342386078b4e35e8a7ffcdce6aea3f58ef08008029a60a0e4a1ce7ae9fab255eaacba3dfc8afa2345649f4861a2aa4f22934bc9f37e3295e650bf5aff9057345d3e53fa3122825f67332648ef4388195813912f68e02fcf7e0d3c15376c817a8b742539fbc7dc518145a4c71b842b38c6f924c364b3b9add2a885b905a9bbad3133b1136607c37013cb742abf1c95d697b39c2d05be243976df232a810f7afa4661c369dc699e2a3cf8e3e7be4346a90f5fec93fdcd747b5878b14b2067d5af989e033c6d694a626fe9b7c93900fac67837744ade206e7eeb99b3c402d3792b669ee1763d0cd438d34341463fd04813a32bec9309d0d0de1361f67aa8006de2b9dc0610ef8bad1ad18e457418d3d821ee2e4f1729a49dc2605a85461a79bc681d5941200541a86e51d98ce95275ab6861fe932a85a9057a7371d2137456efbe1503e1122e722f7c34255ab9c667e49314ec3801d281301c82fa225417c4edbb9b8988b8dde0d6ece7545764d18e16ea898fdbea77775f63701524856842f8a28b19b0daea5df5993ffe6e750248af1e6027ced7c2e64ae2355effe62c9c84535baa90780c13d91a4562f03f3daadb1b781f0e30d8da5e0c44950c321bb9ab70becde82e3d1cfe64d1969bc02966bae80afc30300f1d9afee04f850015fe3015088640866411ba6714493b3f637dd6636d6856043f2a365ef654ff002848dda37e45d2a895005f4d23deb509d4ccf868e1ebde73435c89c060e48dc3d1c1eeaac5db455ec38d1d4cd2128745d2bae68adcee8ab221eebcc8fe4e858eca4d6521dbf9bf1dbee7cd0783443fb1af8e027f115790d38a23c7f3425f79beb1a4eb7e75090caa879d37001e4cc5348b08d4abb21fd30eea30bcea6d12aee54d6b835f5088d76ca64f97e2c1861fe159f3f0eeec0b7c0a5eb18774e23ae1ca3a354f74939fc3b10203f2bf9945a460c96e3442021fe03a9613d72698755df7ba8e86b8437de899e5391f098fbf06321d6b9ba7cf605976938f8e0d955de6abc137e837cc713c324e384b843b7c247bebafccd0059042a3d8766a0b5f0840cda63b2dece7eb260ab246589789916ab259546b04250ee54050bbb6a014bb5a5c3b9278b6c693fd8dafe064f43f4eb89fb8adf36bb4ec6ccf689dee315f423e8b528a30ced6b3bb35827941010013a4a750d60726e2721eda70492dd3f694a1c43b4aafc434328cb1abcba0d7ae3945727e96c976adbb0204b8c565b800b3dc8e7fd91738ce88b38830b7fb728426976e335426f07894593245ac8b72619e5e9d9329225217f32147d307012266916eaa61907bd219cd16d366bb690d625bd67a12c2a574715b2c716786fd2528d7b6ff009c410b713048300c48e31e93aae908e16e938aeabeaadefb38ce216450f844bcc4f3f70da3d077c6e3f831814de3014494983038800639dd6c060b45664f343ac673160d043b2f1bb23d605b0f051340507e71e4cef4e218c4fdf1aff3a4b51aa64e6ff30c612bfff2cf02a8faa82b58812ff48469787a3fa3bf1744289f325954190e33a16fbdcf3c69c4681a5b1ac2fe32c064923c561bb80c1687c82528992ba94e200c4e8dd99a32d4f2ac3660fd619c506731eace307b8e3d14bdec14a2dc869dfb7cf02b6452316b3ecd26e2cb06f961d378c5ca12f9dd13677a0d1b46b24f508f02b67f9082b948a848f2da0d6804c6e8a28a31742229d774bba89c3c092eec95f121f5c4cd7749587d37ade9658ff94cc5270ca0455fd5758e924a8e0f5779c10a86ff6ad955812569e319a323c9b532d00a0d853cec4f59d7ad436555e82838aa7b2d5d89fc5842980417d08fcb533aa708865072c9f0e4395927ac1b51c5039dd051b7c4057f4c2e2a14491e4ccb4b2d920d3f7545ce8913f26546bdcbcecb827d1b0a36d7993f3f86f1b7ee628e008e95017deacd64c51519bdd1184a01431a008381b4beb900833e269dce59bc754206db69136c4b4dec9a94deb568b57a803b91cd017860d3e5b23188674f5453f16a15058b9a325092c9b4ec73f284973d451a785d1c545920f0d01d8d162c8af0a7522b1708763471f435fe442cfd0c39bbb27245e23c6310604bd0631fa29e95c0e39a5f439d9941678811385cc3aa8640926172aad3aa2aab81c12fbc2a8d7f1dd0b55144e10652cb583dfde1a55a31d20c8696b6127eca11d3d3de39f8648dd648fba62b4199a97f7fe2012d75201e0fbe1f38aba4e0f4c0575c9f8a4c4c24d7bed166d0f5a7a4764321510717912677fa66a2d0defc5855415dd4226078d55cd7b5033ef5218aea57ece2db65ffe27e3669e3bddb637d4cfee3cbd2914cb76ad0c5899c9ee1c9914cae6a60db707984f42dcd502a60f1c38d0bab076618cd08a5790085835f78d4e0982bc609977bef4f0c48d392fc2c975486197d96f540301d4cde45c170d691dfed5156b40b2c976e577afa1dffb00dd2ca1f5351a9e46bca558c6eaa0f3011ab325f820bcbfb78ec8f0858f6e0320fa2341d27269f3b3ba062fd8311d36bc792e3912f813d53897e22ea5b5a02ac37075f678007e7af2294167153614b116484550b826ccf663214f3c0e2190016c80bae11991a432cb393f7f6ece7f10b657c31a8a8c6db600785dd467554f0ce7f35ed33839a0018f5670ff400fa8ddbcdce55f91c8bc8f9217e8840faf9065f6529dc214c0637d4a5295f9ca6c2f62b5968e2c37d52c8b5d3aceb8ae3c85c7507b0a5ed7bde7967cc629ad437a884e6a3d8a4208d211a1ca48f8ace5fc3cee39342a25fead3174403c548aba9a45ce2392e12d27ce930e0bc8a83568eab69edf043ac7e26c489d834da3400b63079c56a13f71e08449842102f3d48cd8d926ef33c96e33c29d71ec2e483e2bc6ce74487360a2a2bbfcb9bef0234bdc5d4247900e9b54f6c66d2b5313bcf555136c3fe9c151b541d2f3c56963fe5bfbe413554e32491fba5658923de875677e1a69540cda2119e8ca5481cb073a551e73fa60923e1cff071cfabcd16ed8c6b7ae83b889a3b079a38ff4542f90a1888c7613c5bfccbee71c6552ffae8c338f1341ec204fa70050765a1fb7ac92a51ea5a42c7ae0097bea5047a94bd471ea6384515ceabcee6502d06e399af7d963adf942679a798e5e20149e417d3833a72a6de6d782e109f5218676cdf13ee9ed9ab46c2e83fa13e861a946e9b3545372b4705b3673d71352e9b301e98b0f7efd9daa0b4e7b2ca324824f6c2eb4c610b796b957ce06422a0cafd357f1e033c402d7dcee5b226348cae0ee765848087c1efaaaa6c542de8cc4796c05b49c65d0b731c16cbf4e456c0f674712f1b48f7318d52847247267fb3cfc8c5219a6736d1ffa4a1d9c0356dc059f2526be31ab2895428c51a58437142930738810bf9e8ab81c71f9d018da3310d652e53c4bcad9498d5bd4f705699039e4f288c154c823b20a0fd29c6a92150e604127e616103f197896f79d7856e96209bda79740b7fb6c47715c857135a443fc6ce195d76c3f7953d88076b1077d1c267b989df22b69c6868096e7392e4c392211092f0539811462570143633e51d3415a3ecf2a94f6ff746b8d9cfa06ad3326350861ccabc009471a8bd13019a3e3c216dada0cef4a22e1f7cb919ab0c7ccd1e7d5558e0256eca5459825f532962459bd75789e10c8edcf0b2f8b0b67c82b4c302c6370c3a1161691660209c5349b11c5df13c56aac22a6477a7fef42066a79ed56e55097b9adf1f055458f57c32c1b1f3a355a3f52f6426c9a6eb4706065d573270542954e5d335ef946e411c8b6e6ed3a641986c9ea37826be159beee181c843adc0583460acfb76c630e813d5290a1ed35bccb14e578fc6d078b54e22386669b280532d02a87a000453ccf50ebd2dac608632487a72825e41326143e94f0dcb37863426d258f137f05b17f9a0f7a0ae96b6b420b7ae20444d4c54a2b424d9932386702aaded5de2bba5969d50f6724f35c6359f214067ac4fe339a0f4cb8ab974b086a84b0bb45a050b9f95ea834d055abd576bec6d3d9b02846c129b84c9f9a1191c6a5d0364a64b3845d67fdd485f1dc1f7c10931689d667fdb245d3689d02bd01c537fdb300d926b1504b6d0ee126917c0f16cd7bea5d9d2c3809ec470b091c1fa669644222d1901a87a7cb327b80def462cfdc2894dfb6658a88e952cb81cac8d62ef26bb881af118c8626cd08b2125e3c758ee5c87e308b1321b1288cdaae075b0529c1b7e721780de9af2992e144e2ddb604afe8618a643d1e436295c2c2e0873e81fc282999b56220c978096b1b33d96043b9fd7a134c131de9e7aff8c88fc91099fb89cfdc52448c7ae9d0ff97375c068911c9962d368e9c145e73d10ed49bdb2f0ac3a3dfe57b9d0602fa551ad43b15b47a53e2f4d1546d5e70ea6a8f9be0498df6a86f1548f68b396a50accc553fd75a526e672c6203b10c73b747f0f7ace03ab0bc4610604024a20b1cf702e2f00e5526f55dcb374716fedad70f171eb280768ab2fab0b9dc39861da170084651f29cbf0e3df3c0aa50279947b34c1b00e9123496b1ac7b12fd9f773b717f8025aa65b6238ce07331611cb5f13fa44875699b8f7838f736651db0ce950197e813ea8233b3f14f185c47257f0593e1abc0a353f18776f3a1019c5592749eb6b5bfb58b46da6d280ce140c7cdeff81e4bb532939e85a629d22e74d6509ac4873d242673cda20272ddab3b11750027a9c268e5213149d84508c70afe5c2ff4e523dd916228327feaf6c01709382a3e74d016a51f1a7f7e849022242df29bb6321bcbaf1199c659d55a71c32f9092f960277b34a571ae2aee67645ea566f6251c24c6d7b7582f84c48650157cb04774311a009bef87dfac611944313182e86a9b45e6c0cb3cf7d82298eddab1a369f415da7dc42d9561bc448755dc43edc29f0b005bb05bf6b646c01576e7708750f6465a9a30136448fc75545dd562cd2f3c881c276d8ba43746834d45651e6e859ea9baa42d6b43f07a0d308431e11ed8a0561a39ab11b78d6f5f2ca6a7fde2ca3eb26db0b3935a03677e1ba2a82fa519cca34660f7b0ced7f381d09ba218e6ad6de3474c981b3b2255e9f1a5a68dd630d0655325b55309d7b9a36939108d8330c58f8e386fe9b520337aae30d9e37be3273d9df3c2072dbad73f179a990d5ab586699c802d74dcb4aaec270d1d5eedd276289448c8f719ccb3901a9239f10d83430a33057fac6e2c5f1d138ff5a54b9a9a6b7f3c64253234b242c4674753e47610b23e551e83a48493fd61a4a0df8c5eb1c21e595494b0f2c01bd839701ba631174bff374f8e107ed0490ffc8b27a674a65a77ac66bb828469d376e582a7836e79fbb9dc7aa1b2465b3c40d7cb82730f39266fceba6de48148139a43ac5888845171fa5a557426e43584c3c7b9a2b5c6baf06e7223cbea0042f633871462315d052e7ca7c52782c492fc7075ea6cf0fa9d0d2f58b8fbffb554be871e2c0663ed873df6cb105ca78e0a0f2e28fccbe7abb7214cd8b3f2990bbfff7e534014d11bb1c84192038b872b94c310eb95a2893a175b599aec252fbbcb8ebdb7324b19f06139f00c39cd8dd5a19bd92912e2224c72ec981a549886240b38b3b32015c3b40bb3e8f3bc6b30297b11dd8bc0c010bcc85771bbf22d8f69cdadf9be79d014261ed59148fb78a0ff05e64f7b0981ea9e93cd154af2105cc1f7efad6ffd9a80842ef464d3b7489b994629edc34e3b92f2d46cf14968dc7371261c75e2fd29fee804f430ae85a14f51621d949ddc2052e8ac32c6c4b606527aa2ca7906d14892752da6f8a94db2d305b396393c722ddf178f58ac851d2bbd272f464c4e2b6765e0af282f3947a20691239b314f5a750de59a52439d8b83d314c52b42bbd84760212f9e38488764a1f4385182242abde44f6ab5f041c0a6f59f62c2cd5efa37816332f4ec4d707e63d9a0c184bf358b61d3b17312b299602463ebca45de9ca2a1e5c91d84b595e1142c627b530fb0bd67570665402c41cd36ef9d3a4ec01b9fedc23db678c33c4dc24a22082756510c2f40a59495c42716c2dd15c1ce35f8579fe0785d70a1e4c0392470c73a5ca8b50a58554b0ca131ae0e39362cfe0c047ad06167cfa5aae6de065d7ca2829e4cae39035a2498068c256fe5a55f2bcd40c6a217e8fa8095ce7195d585385af557e0c75572f43ccd81cf6cf1574f1570b990a808bc533fa78a179f21628ebf68f6ac0d7ed911e39d037a26397cf9b9fa360cc10c3eca748bdfbc0839575bed0a746233f1578b38b99e365f2ee3028a14778b27e96f196835995749163fa37937913a4f004bb3f7ea06fdcd599c89e1f3d6e71a9816312a99e6e2e815a61008344f1600af942fc7c06605be2bf3d29530371ae46b2c7545a01bdb4723c6a037212148059a14226256145a80b62e4eaa01d6e9617353e170629a15ed44d33de3fcc2820ee289052887707544729287d780503b56899458b05c6fcae5304e757a20d78d150c9a041b16bcf05729117c70cbd2644a75af2b7874ba8b73bfa2534805f33a2af1300abd634d46a0e2c85402bff089f4cbf3ab14b5c092297217968ee6514e3f1edca20462db4ce22dcc98c76d4164312920e8d6c4b97a6176bb8c874cd88156ee098bef5a63346ed384c7e5d96b1d28b6a7dde8bbc4e10799c20cc55aa510654e4c0147920fc86430f4ac4e16c7292b77366380ea67b1e56e58f2dccbc54d9147904a4fb173a22142b6429089426a6b1e0ee3b182e15821fd3ee7e6b6d89d57fa7c75cdec8fced6e2950c1a48ff737a6231ec685792c882415164e12506336678c4351e05929483483f13a5c0180baaa460f4e6f60e044f9f46861a1a7615b04cc5bf0cb3507342b61364ae538766f42e47e6a8e9ead65a5966a808cb6b5cf5ec1853aacc4240018ed7a3cf6b6ea056874f1f6a0d655d52c703e6fa27be61f3b38383567cea03533d857d695c8e986af2d8f392946a978c8165d6d6914e78bd64f9698ca9935bef30c1dfca938ace49c5f53360ad2dceba1a7b13f1b1cd2ef63a7a52712f3baa3efc3bd21db6b0622d667d2c7067d3cb824569032436dfc90031a094f621807d4f6881280d28122c62746c0b4e81b5a796af88d177295ca83edaf0fc4e19b939b83febe694f31840b97a508161bd36c6f74d64f9fd55bdee4270fc5bdc16de3816e2cccd5a148e2e065ad72a096242ab8b9809924e0fc1489a53a13bd35c833369e1da8cc408f3ecd65b4b7903726f5215326d32650d688788f33b5e5c9a2c1a89e2fd11d751b2e3d5a0300eac5bc696e0d31864d88bc045197731792357188c6b130ccb02f1f934221c116b68e0c39106eecc89d9312c91b051adaa6278311abf9a0f23899cf3639d088c6d2beff4d414b3042f630b03baff9d227a80692a83b1338760965470f51d8dd558df76d856535791d711a82a7ebb260312fc096cb7b15d557b34806b269f7cf86486f261039898a777362f0a3fa66a0d1bfec254254e508a0e18fc2200511b92aae5629dfd4cb4cce5828ab0140f739d02de4208ed07aada48164c7d2039ac7e1e2a161e39a1d0038a151efd79f99160b6c2f963d2c2d0c7dc095af6dad3e2482491a944d7f70c37ac14eff19d2ca41c348d8e92f668af536a4cf7bacead5b76175d92f4b507c88fde40d2bde3735a24ab0c04aea020f224c404be780834945ca577e1575d1baa86865306581df4e5d090bce7f6a62e1516a6ae8cd44c2ccb1dbc168011b2a7fc923dbe98fd1aedfd4f67e3b5e1e8f16215b087ae91a67023546a488fa0da401a5b681cdc0f9334f43a2317162cafa9ae20272a261ed6a8dbc3066c812bcd7b825a4359cb1672cb5820153a99eb1647faf2429b850c210141feaeb84695b9515495fa32cfb09c805cd0640eeb4144ea3f802208cb4f56041accdb4cee41cbdf7eb77533332d52d3a454e4f7cdd0b954c8f53ad66d34d9d9686573c17f3f21d8cba79b68ad530351f130c5ff3490de7d96495db9383747810e74feb3f513e04d421be1327f32830b7244c7f143e8bec0285b652fd2c15c0e594f5ec3f50855170663879ea7be890647d79439734dd4358e0c811e5f7c8527bffc6212b3e6f694493d973592c005752484e1fccc0a115645e7eb17e9978fbc948878589c6c8284254d219405b80d7ab12d28782e0ffa6885146504ec3a36c1f2d08b5c2702705d85adc9708a8e59397c62d118c9bca08b920047505c47d6af5cf3c88d7ee09e098401196d4268da785cd8d4bd1e216dd2cc9f142cf42c3ee5cb42552f75d71c3e7ab30fa73dd6299630447e9f047e9b8a0cbb157f82ff28f76524543070eb2f53720642f4e0efc41e319fd813e3887d2366c48475f54d300ae63c2d1baa8c6f82d4e47ae2c192b9837a4cff191fb7e83fa3116621275b0732a390ecadcb2e8295faf343f326aef6e974d6654386ab4c613d55e5b8fdef2c3240fecb216d03c0297ae5ef4202c81eacd458b576124d44f18ef57fcb05f5af3b8973b832bbf7e0b45fa4fbbe311895c9acaf61225c615719f6445c59aff35bff4684e1ac69884c15a987c3809871c2da04b2b9e380aa357687208c5902c1f7c8a5baf6ed69fb5b044c82afbca3a7db8a1189ac501cc64cfc08f9f4936aae81af4e70d9f0105373d57ad1581308dab505b29bceea8a1168636dc606a690e3cb54e8770819ed489ece9e8419c088723e054397f08b96dbbacee468844bf436dfc3dd734130abb39611fcb136ed2b8368409f66aaa4b4d3f5f0ce1cbe5b19fbc6c9f2231ceaade6c76bb7f64347892225597e9c2fcd1484e54115e775fe43b3f4fb635aff1964f9398967e97c4240f0653c84385856ef852a2fb9d40a106731a908c5ffa6b1ad4e113852c9fe09f1827a4b4b62dc5a222b91b05a2653c8c2539f07df3180e61f8ffa515d473778058afafd39c3406566b81bc2e648fa9a28014b7a09cb7107b5acae83eff2874e0118e1c2b00768268146ce7ebb7b79ac2032eb70a2469a5f68207a5d06a7af8ee5e5d0380eea4b81e7b29a8dc0a9b13800d9c53d0e911ee8f5ab038bc87f74c696a08058382829149844735677002c945d0f7c5994d091969f40c1979f217a315eb46153c2423acb8418fac0c10123b8e2a771402525451b1daac2984ad83c0d20e859c9cf22bc8d009321fb3ac2912fb95939f9d7e2db376b3f567cebe0fd1581e4f61e3f4414d14fc08c53604ed44ebecad10d8fc773e5f9be86dda09df7a709d80eda5ed90ce5dd08fc90ec218077c39188fede931cfe628f1ad4ae2ec8688a18c5641f8a924cc824cc73fd7b994d28117e056d94830298b24d350a1f8608355df163331a4b339745922d358412d321be1774920594515e2f44614826d7a01d4ef5976d0d3f141a66c533fe185c3b662828a2eb5707314c444f809928a4f4767c1a2140afe5dacbe6190d86e7ede005723cddb0535f165a880c15cc4b3c5c9083e6274044356a59a7959a879acbff86b03747fa4566a4f0f6d319cbe60f355b51e683b4676592cca0fb1dfff3b1530991af334f028d11880cfcca445d29f3154e43a4e287222758cb3bce55160f56fcdd8e9291c3d9a8c3a13824e7807431dba8af74fcf4d26dcd507fb63abfdae8476564fdd2f8c4021de22c63460c736a0b4fed2a5d4e8563b28bbdb1670edaa5a3d05258c8f4ce2ce5a17d9ee58631c28c891bc4a973738e107b9a0120cd94c41aeb30535f168791cec0488cc3a120db779ac1eee293a10581bc45146196bd6693bd0526b1c91a2e58da0607e320b5885d4793710f39e1fae8e5dba61b7b26148fef355f2021492eae56e494f526c10b2d87eff59fdac5e13f4e1b500ce94170903ab2e1124721cf20d1cc508835f552d4f3eb13a623282cd35f427ccd9d5640413b8238913fcb85f285b37f624683e9474dad01e75b7a5d5db2f04c41c8eddb96c11a2ea377593304160458e65da77ab80a3cc24dbe6a036ec36ef4ce291dc28872c0d61ebf59bb0ebb10fb7670d7b22a4b4de60dadd2821adb233c3b0ce1bc414d5c4e028b6f950f32ed0640dc269c6a2cc16c4c7e6a1d65cbaf963301c91849b0d647064c1c51eaa8c07191e897ac693f37e86776b8bcf2989cb5758c7d73c39e9704425fde2fe9eab4c7c6c64c89c26b935d1b443587c60203e57e00f59bf18164e195e326b1fd262a765f8601f40e573d05d7efeb208346ab649f6c7838b5315788ffb6a5ff85026c96bc54296d1215c7d63122f8da9b17e1b0da92f4a30cd60c1b71cce694ca2d755f1e0769b7fa93b635c1756122ce293bc588c42c10987b3e4ffce6a56c5cf33f024eb51394b952a2f63dde516677e6fead4efecdf732b2f2618744b9d17f9f11daa7653c344aa515315f3090901a5337ad5fd84c8d10525f486b18cd22bf17ee57591ef03f5047bd663a0d1f8eda33068d548593ac027e8ae0ac931ea9a2e84814bd689ee75f5b6bd0c648313026391278909abea1403bce29b09ed58ce54b06b68a91d44c7304120722a6ca3c98ece2751f86b8575517dfbe8ae72b1a738bac2dde677184663bb1ceef07ac5aa5aec2c427968ea87a84dab1c3dd31358453a905ca4a145c9c07bdc35d205a0270bd2f18bf5cbbc71dda89a4a58a5324cd21f92cc659a69131a26bb19c29115107b804324d410c947b72f29ef2d212b8d596d39b6ce639e527dede45648bd51a66adaf2ac93dcd5aabe53ed8985513695c32bd5136a22925ad777aa86a96a2c16e44b9504e64eba186e8198aac8ab20c06c7734e2238c11cc7dbd795f901b261a7be8352cd72dbe2a1f77c995fa19113b66bee2d2e098d2a5812cc7ba3d027e91a8a821c5a1c24dae8784cfa9636fe5497d9d460c20e6607702f98f6c4d70a19cc33c8fd5abcfd9732c9994031ee30f16d354fb8964c7d8de58d15369b7c263518ff58321f168b05b679ff053916c757ef39c1df8d4df841694e4eb948afdf2d764756d77f139baeeaa8280b8ce858ee83659cdc1ed4a3dfe5b89c44237bc0e585ec5155cda0959621c84f01b8c1da63b861aab0f25bb465e483d8ee200196451269d45fe494c3f16f2a20d04e8dd52c7545522e1f4d9a20b03c79a9ec798036bb722f4747a387327ae4696fc5298d589fe5047a9ff8a666484ca84614df52934d396635a27202cda90e48f73d4aa8c61d212ad92b845a5487eadbd11d13fea57dcb06a5882b5b6a54f6db5e3170ea438f12d492bcf33c2d2d37069e0ffe83a41f4ad25f6380a33ab039183e22a04c3e43bc98b9e4243b1f22f1a52a5d65d5e7b83fcbeefa8c5d9b66743ee9010220995cdeea9331e7153c155f176b9fbaf54b9bf13678827a8fc605f2a9ad28ed0b592d7c81f14e5a23eb0c87b709d8c8a2780795a2e4a6a6a4c8e706db4b6b60834edd5a4e43423964e8c15ad63c62c984aa1501dea14a2acfdd6b1c08db703325866ec87e999796435e79c3f4f4b78def12c38dc3e2a22e44971feca5a5113ea1156f787d4309032f097210f42055383590910c50a864c2969c3f29b5bd52a28b47263797334455a06c632445a852fb1d80c62f90d3486ca053f9686f15f42942e567f8cf44c695f0da64d9336a3bde59ce0b4ddca8af1a6026cb2dbb032905141282e3720744fc38c4dc8857ad2de8c591a7a9dc855576f49971ce450888b2a6b8a77113ab13358c1c7b3e2443f4e60a6d4160dadb59314973932b11f8e111bab5726a2e0788677a291b1d82e59bb8e63ff8312fa163c55390d156c9b37f8cbbfd7376ae6ce56a703d358f9d42581041b7bf545e5f63cc56d824d3e25e8a2185a303597a7fe2b309447e8f9583d46669d713abdfb304957336dca8174536c08c224e445d9d963e35b069e0b044e430526a9e1527ea0e5437556a7ece458e6178710c79380de0687abf99a0e6f96833a6459e64720838856b39fa6f230445161fd363a9d8e6304c1f68bba87ef132f7ed29274393ca280edc6de0f1345955f036cc41fed0a04fa24161206e743dcb752cd52087a045e713f6235eda7995d9a7bab0a1a0414c642e6772acd7845153243a59b0895425215b45c9cf1a844f2a23f964947583488011559f81e540a5d454d2db0bdb8c48582f57386f009e39833834c24c4048e53289660c066377dbe5cc1391ef1c5e05a41d6651af4968323d3a10b8afb1f8e53885649d7d32196bfe8782647f52d14d837bdad09fc3f51934a84a0564aa4ec2abd52b5d07d286e02212507457b60e51a2c0244ac2bdb42541fe050cdda4cfdca203a6a6bb8c766620a9c1ba9bd7e88e7329e6b9ff8fe6104d1d2f97f2b8148edd6d0797dadf1ace8bbd3ec81151838cee54ab14e9c0a453afc78374b8daf300d7a2b96bf63fc41e00feee6e099d183229fb5646c13273ef30d9dfad2f43450247d66d94e32ec532b176edd265685d27bfd407cfd7cc7a1689bff8fe8f4a75de8609551d27f3882d2138912e476ba091e2d05af8abb55c8f5c2c03dbdeb4da82fd62ed647f0d917a142e5282db624ea5d1477259db2f82b2d48b6cba253592ee3a66229f68e9ce2803655baf83a78bc9d59f005d68e5aea92d5a3401901b723b80c155b8fbdee55861bfb9e9ee15b31290a3faa56bb0e1597c57c633b479fd3bcb415f35cee68de0750ba803f6d7d51acaf18044b55b12dcbd8528f26f381933551106ec2373d6f6d295304a740db7cb345f474b59a1737f0783f84020dd95deae1e724c6acbd34bef7474f8e014ca1deb43e3dd146099b694ffd78524ec8a34c9317e1a6e7970617fbf9b5496cf5e78ccc6e675f3df26d6c91555053bf06a1ad05d8bd6ad02ff61700f4b92939dfe0c34f637e2d1602adcd103a10c2cb6d25c09579342c197ada43053a0f2d8c4316ca0515f6055ce632a88f325c4761d8150788c3bf4757333188740c298f0aeb0cdd995bf70c32d288b8e7402a7226ae6e213bac10d7f42916026676901845a64800f73b31ced7e189d0b3ac66abc21e36e3c99e19eb66b06ba7e320a99ed45fad25b95341fce741093f7c3100700781d90f64bf21de64760678dc957a5d0a86b89e28304746cece8f405ba81b61b98278005a0c9badf50c26c4a9bd1d19913c60da7a4fd4088cc4c74804e42ae20a42cf9bf9afebed3422f5406a69a483af51576405353ffea1247754e614d0a29a243cd2db41f80974dc436e813a1d9bdcf055aea6210041206a802097023bcdbbae0c6d06634f3998bb6d9b6fe08cc106479b2fb8d4a58e30cd9802fe17c54f947379a5e170a1529ddda64aaa3c234948bada990f11ace3fcf8f515205648a462c884af163c677a8b226da3a6d7ee354e5c3228f7710da44a80d162f759c8a4271f943977f37970da23544a0055e05d2e44b486daa7fa59b07203cd8f1e17dcfa96b10bb7043204f6d0b68b8d59a02989dda625c471c26733d7e311b31635243dd2cd8a38b656fd2548d8deb78f5d5b348bfc27eca81158cb44b65a7d43eebaaacb21d8c32060d22a49fb5c75d495a30f282c88f59087f47ac1ebeda1f0a1e522be0341206398ed5cf64bb848a48d72c4a63d5a4d80454732983004845c980cd724335d8b2d526c19f830199954c4d0c677d53494ed021039e8ba0198a5960553581c1b63ccc447ab74aadfd5c24a10dbd8b7e1688e820de8a558a6c95edeb374d62556c6fa5efb884ee39e5ba40098a9626420184940d91078bb2f916e8271f72c894d5a23a31cefb74e0d6464ca83282ac1c76275af9b56fe349999274ab8597052760c1560df2903e6ba018683de2d65cd960713037def9ef01021d19fcd573f57808a38949f464590ebf95bf319cacedcbce47fb12424bc57ca7ddd33d7a465c9c193c0d5b8f9d595401b00a17e8026eb845c8c7bab5bde26863e13037beaf60ac94bc2c53697fbbd7fa8ac82dc07d65f15070f16faa0563e51b31c144fece966d7474d5eec561c8b565d0dd4e496d0469ca94953a5ebc2695491f42c72ccdca6612872771a2d79390c00366e62e8689f49cf85628dc5e7cb004a905b846b38ba1d3f40c4a9130c1fbaf80c8d7295a161103d82c74293ed8d46178615b8e3ed4f006c1b0caed7b55234bcac82948123e6c5b0a76cef2b4e6f89bfda3651208e3f4ac9faa62921fe9b0ac5c15993f1c8c1e24b5eabbfeac2cc1651b1f98ffa1aaa26564d61f4be4aeedea81e9f5385f3d2cee30e639367b3a827948b9704e807d008aac422d925f4b7619747bd0c793492505f243267c008de7194931c74f0e163796129747820730e9c63bbb19195f40e2573d695979968c4cb2541a4e9237f93d2de6aab22653126339c5346324848e0c83273803011fd8c0f1ff302a30eb385939fd0659cde704b5155312eba59b08e059bf0a65437a75cd153bf25664e1fa67f88ac61be1821859baddea5d31aafd8a8046342fe38f75efe157b91fcd194632a754b16764a273ea2a930f3983c453d5dc3990be807f6acb0884b84514bb8cd2cb279bdf0023dd13ba641d7d753d7ddecc04602e99574b427426a97fb9434ad1bf1ea213ff9c9a3fefe199f13add95c8d5dbb51bd5617b7fa9c07439c9003d2cf20dd5ee15397288499b87a468dc6eb7a2658b0a5d1e2644b4b825ab08e496416449a7fc9d8f8b42442839b0aa956e71529700301aff5958acd077b087c7a58594eac27a27df849ee7ba8130daced8311b2ca821b056199dd01279715508bcb96e243213874cf72e3e3a9f595af5e2360c728ee9e0df376d2648c4616f2582174acc91d951c31ffcea253636b18449c2c35c3cce56c5cba8f034384407ee1272b5814802c65670037b11552302d712f12d94da8637d914048c081b9ef4123a4395da07719b1c79e00d9417dadf50d863741c7315dc8d8a31c9d217646d009ef2b7048169932111c65dadeec61f0fc690c26e70d1d208a140f4300abbf2febc19d35af05360a771e9844d60dbf391dbc5949008105ee2fe443a0884b833474da65180cfeeff7ad50363c37916f384809bf8385c84618e0e331d6eb2a61adedd969a73ad0356a7961c6b9574bc88a5734db22213eb6db2a7f1b2b1f64e7e7ccceec503fc2fe405db87a6ec4cb2ecb2975b2bd3b4c5a9ce50081145ed2e2b0a880e29960c750f514a9ae68e7dd8685d7c524e02ef2f4d16c81bfe6a395ba03e286b7e15366db1bbd619db322b0a8e671d6985b512c00fc65def7ed2429f140accdf08cba3c0c837e8a5c354e7e99b2ce532c9d3ac723b470290468274e7f09e66e93bfa1ef17d0604086fe39f3c9bedb99c371fe72e8dee91c37e5246757b2acbcd71edd8fe792e1c43f8a4a7d3838423cc809725602913108a738afe61e13cfe27bea8c5472404cac6c8fa6b95a5c42025733c898993498e324a1c74ac498cd74293c39a1c4b5608e43611de1e9796152703372bacc5a88dc084e96f9fcd1bb87e1e8b10fb1e52169987ad431f111c405b8d61d57a2a4779d986eade81812dea400ec4b4c9a7b6965be8259a8b11679089549f4a3d4c694cda89020846c3a6a24792623eab060a8ab7efc880ac2552ee124d9efc252dac64564e11946920e5c63317d1060ee1b50f7173f4e6b5653cd097542a6a5361960c67add63d5a6f34652eeb1dab642b4c6e71ddd6511263989b97194a1e229c7d9210219bf77389d637559cc4dd071a427d091a9b2cc350413b9988db78d103f0ce553ac89afb10cfc5bb26136106e6db53ec04ab8302493f93605036fe148b7609b4af88d58d1ee2fbcd982af4183a500aebbc814b184987df89e406b614e7bc32a8ebbf4e39340fb9b20ce8a75828d6502747342b99b58022086348a251212a9348c07a79aa4bbb3c454c2e4f5dc51fa73517dfc5f538895c9db8186ff1c24f4f98e947d843283925ee5c7167ea87cf5dc0fb58bacb2914748f4cd385f1279ff224b106a00ab673737d1e69ca7f125f5711e600e98caf7c9f1057df44d55fad9d90fc81d287e779d9b834397ef8dd2882a37e720b864c3042e3e62de911365409b57f3d85b9219474ac736e8315dc55fc74ec83c555e235c01d918b8de8197cb79a9d7a7156ce7b535772fb432e8116ae893155e8a73e628a8d196d42f599fc62d7571f2f23bca3cb7cc170305d42f5b0ac432d8ee63cdc8730e1a0da6e82f0bd74173716a23828069ffee23ba99b3a2a8eea24cb38db1a2b382c9032bda0e28e1441ade704106ec7258b66f9428830eae6c5be71702c2d3593bd8fa590e0e159e6b1bee40f40b9a9d7c18ea598848db22c1b534863d2145b9658e37c6bcb6274a80d407632850dc539a93eef18a5c1517f110330d5155036b1f9f3d89baca20d11fd8e6b26aa1fcde13e1041da0bda871040559f00c2693d4c634c3188a3173ae6c94b748dfb6a0c6fea2ca483b4a0aea6252dcc74865c58c4125f1a27624ae8c90a760002b5c3ef3db75d94079f4d227ee5399e10d8acc531092187aac8d52121d28e655f96d4b4355c933180a8987e7c8cb948bca6934d71ebbe0dae765bccae0758736621c52ca092b918e45451651d22557e770cccb324303fb81d0421a9d78a4ea07c8b5f1a2c0271c0fd54d221cbbd3dc1b0efac601d913cea0281e1f2d13867645ec6322eca2a9e081b3d0dc6850765b9d7c715c64d551c65594d8ee0792ff9e08f9a9c090cebfca2706e743ecf3b88e26cbc283d9f6c77dbdf4822bda1f25eade989aafd721db91bb84de96fe748379ed45437dca8bb03ae3f60b62c3166a9cb7b25ca62b740b5fa44183e5a24fb7891422db1c62a9cac403a65fed67602e511deb0b06eda7113708344e7df8435db0a6722b6722501131e51a144ef3d4b29e79be0e3799111984eef20be5da8c3a08671e7cbb16dd543211398da1a3f7c877eec80b71c3330aa4da1bbeb30b4a9fd8f058262e506c25df2e5eb65712648af65af04d0777424147bf5e2d83dbe785db1f978581d9a50a02a99ee1ac8af4810a224a56d159618ccc18bcff17382e90ce264dae68c7a341938f5393da2a74a634f52b533c3a6e87e9336ebcf9b9b0c154c6b8e04f0fc318eb000d54effb8d70dd59f9ec97f76f0fc6dfaff11950c6945783f7dd1948376f245e7666fca320476471ca6dc8645caccaa07a14491eb4199036ad25e0e2faf5ec5fa1f0915ca2bf3f22ee331792561ccd19f2aaf3b9bf415537ebdc8ed72d7acf9b05c3705346ac34257649d3b239d569be8fe083a2154e5726c33b162b855528846ee19e01e0118461d60ce446595ea9f2982b1c793cd53b9430b2d4a02883713e35006b9f3088135cdda02a216e06e986503d8303dd64ad9cf77e063427fec1e2b721162eb2cd00e6ab031a7b07c1e9169912a26cc2efdc72272a09890e8e09b68e6d3d85941ce8edf257780bf1d91c7d453de03bc58dacfef0c2f228729614c7779f1e90367aaec27cd61b14867233f06f65ecd2e9f5bc10c4a3ffe83d6911d5d9ec65a7e2204e8dbdc5362ecb4b84c8b2cbd66d1193a2f27b4601d386518bc7a97fd0e0b7940c337b192207089fe5b82cd35154b408e8c966d26bf18e245c7f53c2c5db7330b1f70e41bdeba616d09c73ad5246dd0ada2d4494144743762789e729d04b7ab3160cfe410a0ab383ae2367abc2306e58229d4288f884ed8b8556941725eaff33b5aeacb1611c0f67741321db0f1086da2cb18f5081076ac1861c924210b618ac91a897e53e285ac4f4c88a5d52085a62d425647388c516ffe3d18e9a9d6ea0df849afc931e95924de035bb80256c711ebede43786b1c64b98ae18f85d57b0a2cc03b2e6c213029394921489fe292fcea5e7a8c24015456e723cd358ca4535604ab0f7986519a14504c9ee2b647cfe8b816dbc2f6119a02fcb8be92d699756c226cb965ace4e15a49a5fc5401925c1bddab523afe82609242f0ead49cf157b9748afb68ec769d40a2a6f193b737e21a2fc875b18eb809ebd136f076f415d2a8d1ecb24f026409ddecdcd6fbd51f96ff66cf16e42c87b4aa40eb26f672f3af9b485ba501ccbc64c2ee009ea2d787b5c4483af0df950b2645e57e3482287867c0af37cf06ca69b5c4da0c71aef10fd6d82771c4edb388ae5b3514b6f69a708832cadde038b0e26104622da9fad57b36c16055223db8d92132eda392c6363556bbc998b5c7541a54daa49cee764821ca502a2c18bc9b1bd1c73437bc57bf67a9a64b21808c80c69e193d02ee9c209f86820025da19f3ac47421a78fb0b6faa21c3e42dc6cdd8dc0d8188de934269ccca70735c4d0cb447e6d8848f324ee20ee243764261c51bf946f352275f2309f1c0635672d442382deac9732c92a88ad506cda54ca468a7203c048f74ee42aab20c7de69ea1eb7e75d449f5cf9512798d17d3022810966946a6591d8684feef57542616bedc8347249c06fd71fb50a12e57c453d6e7956b0d236acbc8a38c6fb9b328a8e9f29b24b64ed0ac5e5896308f5b8b961e1e0ecae400bf0a7643600f91d99a19e360257dd1430bb5d6de366ad4a72ccf8cfb8052a3e10ad829d215445b4c4629bc32968de7ba7f625cf142f2ad057155827158e73f35994548e95d4acce234fdcbd7206918a619286ebf0623d3ae41d6ba523d52b8ce4f8591613425434ea9815df916b6f185dc73b30df034a06bda8b8665baac3936f8b7100aa87d98d0393c71f292448895528a4389908f6e8b7a2d4209132f9d4540feb5c7d74917b4307f7198a6539fefd91ab7ee182b3395f30a828ca0f856d454664269ae037f1712acf0e760ef43e70db98139a218577d2956e7de18d09a691784b9c42c40276c8e0d208fec096116c6662d86f07db1f7adeb11a182cdd90427e34df6301a9379ae3543e31586a26f72f64219f716993f88f25829abd98d38c67f65a8fa219e975075445d56df264510a1ab286ffcf883e0acfb29640196af2bd68eb424884583cc2a595430de5ca15f63faeb083991ab41f4a88cd7259261f1058c718f16958493c190d5d713693dc01cfba7d48b8a695ff75e9423f2301256bc9a665325bd40a1a706b705f72462d1a11bc6e9625fd01123a87438eb53fb983f2fab4bcd06dc5588ac9fb1525bbfe4c119415335ac8458d1c7a204edebd94a9b7bc191dc43733fa99fb2b80d06e58e45a2ae99a6fb60227994554213304a6d2a32f433a02f555dcb59d3b904426a7a6f8cfc86b86323bf5563deb409c2ca3db1d9d28e84848eb5a960bbc5a9ab473b8655f7350481b9b949c181587ea3c4733ef52462714043af9352919d93de8a29294f267cf55858bca6b2b3d46c94a8682167a0aa4ad7d7683708fa5676714cb9b6a0087524b2b20e94f110251580ebe28ef8f5e249d7c8007bff93702d2f14446ba32373f65c5fa405d9af85e6f836ac2f8aa98ddbc240f84f6c1846d6e37757a32466293e7318467d00a7fdf63d0b1f624d28edc67403511d23d1e5b10cd0f87af5fe8813be8437f8feefaa3970c6f0e136d215cb4b39862b716421b1c344a744c73d962ad35ff52314c490435717e0aeb2e01684f7f763d3e1336675fe880e0d986a989f24256561b55c5ad8e1ffe4ecb444bcaba5dd7821d3fe316a567d2d10519a1c554e17adf59766f5897aca5b3f5f9ef988ec88684d9c8aa769cf412c2c89b62ffaa87cda7fcfc59cce80a38bb55aee0aed728e28bae0df21ef26b7420d60e2a64b2f21b04fb31c79ffe61cdc5d7f83f56fec31d4baa159f40958e3dc165fdd1387705edca99766982cffe97112baa751ba28536f889252f7343c2deb2e51a9af053970f02e2deeb34ce9dc9442d241fa681598eb4969b4fb2aa81d67090c660354d1605447668954f814c7f34ac106a73ba5161046f8414948636913c95db28e5493dd6f811b93227b5857699651af14ed41feaee114e9d6e5c4309e392d95cef0ee40c7b134addc5ef2ced4d4b4a748a9ef68dad0ac5f5c0eb10950b7eeb3488e117f7730b6c4b1591a6f7c24b6026e76f6ed193b93402caf847b56f9485dfa2f6fb01ff0f9ae58313100822b9dc289feda11c79f5b086c11076945dc7d53e926277a09901c01bb0ca01e313d3f82ddcd69dbb91c996d7486c6ea784333f2f06e8c6d945c8172f6d97c8567316493a6c691783a8210d38623d3b7863c5f9e888749a7a88d782c6c057239425a6c7afc0c6448896ba1534f26bd0dd77745e1a1fb7f2b85870e187e10437d14e9fdb2fb25dbecf624bc25bdf12f99d0d063ad0568f0147bf8284c1673e793a171316bd985c8496a08b21b598fb436f4e771a11bf5871ef2ad3e824d989a7de1ab47e992ad63a3e9d1cf41115f61a1391281c345c8d1abb1b96b1c39c9127ac9bc18d3e3e6cde3d26aa87e82835856b4b21a6e160dc9144797f6c965a1de122cc30bb5c1cae9a167198325fa1266c2b3a0d4b6262c0a0d3aac40f4ad94072a1e39fdd6ab35b38c2d9cdce21cf5b7cf1d330f7d58e362c997703ca870555c7f66b7f97af68357e05e186e1c358c1f487163a3b53802e42beb208cfb5089a62588af56b786dcddcf4fc3f01180890e71a5faff141e5a89e38a6f347302b75141ee6e1115c0b967d546022d82240905416c1288df2cf325666c0ee86413749713906e088e910aa2d69c6414c98c88f3bdbd191ba2edc8f0336556ea6f30dc4caa24882ece37ba5f16e55b80a23f816f1b0854bb74616e5e96e4cf9477698000941c09117a7d140011dff9cfd1e59f5990a12c6c1854a0489f5e04cb5ae71a81255821b52698fe49ef533b86389042dec887cd5d0bd84fc63d0cb04ab3cf471db0f183f6f70f5b099b9d32818dd37a6f12820c8214c99a8515b7d203632e9c8ea1642c21a8c706186fb59c3a23c56447e7135c0dbe7f411d394591e7fac78eace8fd7e96888286f3a47fdb5fea3d167cfcc5cf2157c7be1f657a3a646c03dcb38124baeab7be102217da9ed1f46e82bbbea0c9cf4a2df1cfbd16ad54f3324266f3246bf1cdef4b72d1d6d21c7495523972e936bf92ed38267228a228e91702da96813d8840f8c0b4dfbce8082849547791cea0b901039ebe986ab674cc31312204d3cc1144e2e5e3cc6ec4068e8479c7d2b596a4ba5a287be65a818e8c2e7c542af851830fc1b42d3fa0a62c5304e682390c806c09f5c0e15d171b00808455272835111459e6122058a19ae5267860bb8274ec9cfe423831f1d21644af1d8001f2bbedd331ee9d63bb6817d6f55f518994ffb2b4ee846425a48251b4c908ac9fe1932af3dd84cfed4e70dc38397c44c43a599ca18859aeab5b618629d2c8f00ce4964d3c1cad500f474db044a8c8301c3afa20481e0f3dcd193105ea93a6e64435e01560635cd9b7c4d42cb6cc0515b6f7660f19fda8b34726b69e9e9667c580afb9bea93affcf37e123cc7e08e14901b4b26fdbc40445915ede5ee061d0f946ddc545af3d18c9fdc28170534ad36c22fee9d03614d1aa6d8bf5cdb6f1a2e696a1808e5e6a27b6b8056f8508f3a6543789155031d28218e9335d8b15a9699591ac85a503fb824853db4320b295729270b12f721d8cd0d441e2431bc6d02aac0a15e6040925d51075460911d9fdd909ff9bad9b9a16318621ed8146c29c06fdb8be59a17a8c704ec455070f17566343adc7e47245c4e90be617f638e5d3346a866f18a8d31e134461ac643f4b987b1867bb9bf8edfb87e100efd2d9bec26524a29a50c6f05e005d3057f6b259148d5dc61d6fbfabe7154a95a600bc6fb55249148fad6eb225d7cf1c5d8eeb0e9bbc6b0c685f775ad38836f2bce487afc913ed72799df5f6ceeb0a90f8217fc3eebc83b6c3ae9f37777ee47c0472765f333334adf37f38e8f7ecf08f8e8f7496200f6fbb83d6cd7a123eb95f3c1ff401da4b367db2fd761fcfcb49dc32aae562e182fcf673a6d169647b13c8a7c948b944ef26a63dc590abfc6afb566f1d4a352a97f21c94f81e05b1d12bd42e955a7e3e9218a176dac7c8f16afad19f234cd967f41a19e2517ca88392c0b0b4bbc817a967a5bfa4915dc561c9b7a55eac995ea532bd37619927cd4872c78ad3ad7fc67c5c4ac46adbfa4b5d6e68b4ab4b1f2e38729f855a9c671ef57eddf7bd7f7cb76aeef4fbd2cd380a8383c6c51e7a9c401e0d7bb1d745fbc544bcbcbb7fcd6dd978c65a3b9fb1273d8eea2bfd78f326b77116fb090a894e5d530accef8c6fd2c26d1c6eda40c46f5a4ea65fa57af437faae294bf3fb7507150bf3f44a17ef51af5a569bb490c00ea53a947a1509f7a9d5bea53f53c58baaaa35e65bead38d6a64e30b2f4d2a76e18659996fa196579d6511fdad030d3e982e8f8557fc51bf8556f451be3577147874ee9d5297b499d3a5e3ef5fb5952bf22de78499d28d45ff106eac95f99b5a71e654ac0f6d4ca297bf9958e7a2deee8487d0fdbc97fd93b759eb21490fb224f1da9277fff0af9a27823458ac06dc5b1a163e57bd88e8f6cd82452368c327b947bf290fbd2611ffcfda298e37bf0b978c39ee1c5b6867aa5de1679a2ce527feddf59abcb19d33f54ff441c9697f1aec59d0fe6754bed27d364ca3ed194f11e56ebdc7d6491d8353dca54fbb4f5ac8f2a4dfe5dc3305da5baf2b7d0b30a3def1f999f345b1e725d393c73914cbbad7c2d6fffe5c997a7e7efb678f5fc66d40ad3ed583a09d06dba06b708823b6cfaae3b55ddd308131580fafe32c77e8cbf073f0c2fb7d69459994d62c726d1c193d407b0ff33593ae9c43b2cd607c9da15acb85b8b3b6e4bff0928dcdce011622caf73f7197e78cd72c5c3f83563961fa1bef0ebd3cb3e58cd59795b7b7d6d8dd7f20f4659ed75147adc177ebde33ce1b6748fdbd23c6cadb3fd251d2cfb6e6e52b0660fdd12ab8c32bbb3da1231e6a0cd7f9081e6a2066dee4b97c2955debb66cc6bdb3c2eef0ca3dedcda6ef7749b7d5ed0ebbec0e3c31bead2eb33bddaded168bad7818531d7f156fa4b4cf6dd56423ae118df965b68631c618e354afba25b99e3f7c19093dc3e899a667133dc7f46c6b2ee1e6aa11c616ae0a5653352bac562b661d043181a16576b7dbed2b5469f463d3ee808c3a37ba253674fd07d0a9cd7dd50c6b79fddfcd39bd6cc6f43217acff06c35abed3ab4caaf1a66bfd46a3fe4b4381e0cbf6adad2bfab5f5b620ac33faacf7de7bfff5dd16ce3152e8f1a49ea6043efb3d6c0af6cb7a5bf7eacf9f1b65dfdbdfbfa2e27c3c2ef0332d57c529fd7e9a8a03fefe9bfb3a79d8ee63b6c392227dffd8830d7dff8ccdc6a16f1e8efafebcf7cab8d2efaff4fb323dc43c344bf06bd7f195e09923a7df4f4127a7dfcfe9f77d744ccaeda004de5bdfd65a6b3d4b7fbfcfde6b499fb3cd36db9c3329ff259150b8af12f8d59d75b63b1b745bbcdbdac180131c90f6eecb16c970276081fb12bff2afe1d7529112edbec2da51b8af7befabf6d25fb3f61ef7257ee927705ffcc55289546badd5dab18ba6edc16d6113bce0efb047e0b5f75e7b2f6873510846592db2c045e14ec0a642b6775bb8c76de19ed10127dc594908d7da7e5a6b8deb59e6d7d91a85b9667cd68b2b10d6195958bbbbfb52dd046921f13d90d283ae4eeb203ea1518aaa07486c2041fa0d4242aadb53ef5e68b05fa8382dd418b6d6d8213bd549260632db4586dc57de67589bc1cb0ae31dcd950b467deb55c4b77eed022c3ec336f2668252b61fd34f269375ab3435ec724977e878ca56401de4e7d03e7158b22729da46dcd723c365c458697fb9c313dc252cbec0a39023b001a2e50d4459b7da0265963de20cf8e445a753b6d2891c30913d20aff95c182e8cb2530d75bbaffcaaafc447dbffc3f06e9a62ccbe29eee49eb16932cd5795a6da89e7b6ee690553910908752703cee34522119126d6c4196aebbe6833cff2765ba00ba5c7a626fdfe69051e9cc3913d640d0823398293f327a3cca983e68fcc976440b414ea5d69324b9e4ad353062955289974d9ca5c9dcc15aed2dcd7a1a4df550eb5753ff7261963923716094375cdf49693ec69a1bc95f66965465289324b9426388b3b1943530c4fd15682872136cb1e5e4eaebef307758ea0f9833abfbd752e9540319f6ca71adf3ddb66920b6eedc983d4c30f6bf8b774d0fc818179940904f5e79bffbf39ef6621d417b7416de95979c3ae0be340a8ae6b2aba2dfda4be4c3cd0b359aa47f79ca678a4b6b86f9ae209aa8bfb6f8a26a830ee97a628638a2da6988f1079a8aefba419a853b4d516f75f80904a4824a40d7d2463a838f749186a8c138fada938e1f794331b14e9f755c2505be50f1a4ba9425ade306c3544750181d7a154d77dad9ad496890740fdfeea28d565e58d4a791b2a6f3bb287acdd968fed86cba1d8c5eafa5ca12f1a1865a2ed1b43102dd22d98dad0edb79c3e2f74fba65376ea40bfcf32310ebbecc798e18b1727115cbc7801438ce1b7b6e2d8ecc4f4f15ca13fe4ab8c40614c8ed616a622ec32d5442215761222d230ecc4c3799c972a32994ca6242f60bc5e98cbc0d7bfc4d80ff9af6c139ea79a941e0c136922b9bb2f53ef7219d497a988da2ac2305e845db593900ae351c4da7d9d7aae38437d9d62a8adfb2da622967e2aea5706a64653cd5443996569963516737564a6d0633415510e31f5eeab6ca1b6781186adaa5457c9c393287ff4fbbc68c55ba1ab5ca5b90fa218b602a2baa2ecfafd5593ea8a61a5eba79efb5af1b002a30cddd510f8a8cb48948c8184a1d6dcff4cb28849d65626797b31491c99c3aefb2fb28736b280dc67cd820cc14082208181f400896e65e54d2848bf305d56defafdf2765f484a1c4c8c7d6779bb296fc45889e4b6ca23e5ad3c924939fffdf248c549f5efd422ed8a3dd8045d98f9057ff1d96c86ad34f6495395510f9a3fff329af49923496f179538c367c4986843093156de445b792b6f3cbdd642a142450a16fcc4428c9d7c6eeb3e8d18135f5230cac89e5abf4fdaee4b26dafaed2942d6489ffb92edc0b7fba24d9b664c5802df3c4b90e062e5567cb4dc1e20f0e168874dca39c7e0090b6e13143cb17580868827353cf4e403444f7880c6955e754e829002274774d98f509c10d1022740e0189c387192e485199d9319b0cd0991203809721b5d8eee9429489a0c31a381cf08be40ebe0427951d0a4065d931f2c82b1d4abae8908c6ad6bf24207524068c233845639f5894a61c1e5ee30f214ab601465d0c3382e3982da807d50197e40830c31f25e75e8ec3a19c35e754c7c5085494fc7e40639e79cb10a4c9ee898e0744c64c0328c5faf3a26448e6092011b8ce20f8c0c5d2346b2579d0f32c0271851bdea7c6841097cb8a1b7b2ce0712fc8cce87187ca081a5a7daa3ec82a05e753ef0b840a8dbe0173301f47fa5c11f9660fc64a3fe2e90eb57c90570fdfe0578fa8e9b16209f17c6c6b0b97b44cdeaa07f2a766d60b47f8dee8ca38e4f5087b1f66aa11805d1656350ff6e1704240ced10d5996a13019b9e08c28bdfc70e389ba5fe1474aa18d3b5ebc098f5ac7e9f25235799fedd97d65a63d326f1e3cefa8ddd8a57340f9b442d71896baed79a44bff7deaa57be10e82ff7e7fdfd28f16a63582ef2158cf63fb174471999fe9d3c64fa8a8db1f3b045fde361d3fe3dbe2b5bb304407fe9b1097ec9044b56ccff9932baec76bc23a37f270f19fdb3f9e2bc1281db25b0fb77e638bf710b1156bbefc53967ad3f10ac522a95c270efbdb79857becdc2328e4748a84c7befbd4f18638c31c658b770eda2512892b4a48b0beaded7c1f9fe034ab9aee39ef6f4b1ade84358ad8ea113c21b76fc2acd8cfb558ce1fe27085d18ad90d1d63cc6b5b2c098d3f45af18a2ec31863ac02e314db45aab562dc0c2ddcf7d55a316e0614388c7309e499e433dad727c6194c8433b5f212bbc29066b03ebb6d636b33d6e6ed9b36da377d97618c7148c3acafe58431c62e18e358fd0ae352d68ae2010f56e3e6c14b4a67958a7ff7556badab17b284c10a635cbad40ac34521b9316686168d31deda26c332bdcc383ecb69628c734d9f5c5ca13e2781eee9b504aff55c3e139ae0b59e005170fc6d2323238e31aee76cdc1963153c8518ab5f33d62ab8ce39e7153c74e186ef360ff0aeb99005cdad618131c63618e31a6b53c38266858a14ae168a1326664a9ce6cbb06260ca954d0c1a680e838b31eea1a8e653e371cee37c0553b25e62c214c849a45017ea70a1f9f3f2a2b53e426f8bbf1ce1d01c2e575b280975a12ed4c98835718693ed5403892377302531ddc020420e9af64433e54e474eb630084577393497dba5380c876979596aecb5f20794c32e1c76dd7a90dc00c3aa97aeaa08f5216aeb64227b298a1ea5282ec61c7130e6498742a18e72682e26347f606e3037e46040f42887e65ed290bb84e58f7256e5a8a8b7e3a5401ce1d01497569a1d76b91c1581440f79a919e6251487a2b894f394737e82bbb4a242ee40420179686ab2d2da021567221134047741170689a2397497e36968fec8c8d86ac8913852877c2292e680f7c499f823d66e38f0de4cc4996ea5d075dd322d619eab4167bbaf92872a4564512f457727222809258d09cd9f9818908775cf58e670a8921d95a29e9421b2a89762170f6d826e9017d33bc2a1b89734c74f1117863825298ae3a528d02e28cde5783814681784d35541733823a38c44733c1c0ab40bc2715668feac56ff32cf2271a40eb9f444e444e33d5e442edda1b6604175719f658a395418f75f4c3127a23b7126e2a0e060204f8a501040bb274d6a0cd30dad381c257500ea24eebeca26b555de90cbe5902b69e52cc5b0b285ea22725fab2abc08244a5b5a8e202dd3d4eca868b5bbad201e769129891ee1501ce715f1782614f4fb30e58b139aa2486e699aa669aa244d857a42692a14054d795150a05d5014cee3fca84c51ceab2d4e34ec32e5b0eba7c24e47aa0bc34e36969449cc996e27194c3fe472240e4d5124b7344dd3345592a6423da134158a82a6bc2828d02e280ae7f1f3944373288689b55a7a5f279e1cd4d76985130dc3c49929876120ef74a4c24c494e360c33dd6ef775c2e1505f271dc413ade5443be54c395eaee77018c67b240e2d77b9d2765aa1e4419c615869029c28e4067156f21c15f130ac54c194a49c996e18b6aaa2430f70f7b5a252d68e2861e0952df08e724f2a4d935a53d4c32ea01d76913c32edf7d11445724bd3344d5325692ad4134a53a12868ca8b8202ed82a2d46c3ce43cfceeac67b376d2ac334a409e8e302c65c3ae9bbab5cc8a48b4df0773ba14cdf15214681794e2704a5214c74b51a05d509acbe970688e8743817641b89c0e87e6783814681784cbe970688e87438176413816f7d1722910853b61d16eeb0eb9ad2bd2fa7d7b41b4c46fad5f2a4b457afd120cf5a5baad1a86c17cfd524fc5317d3541283a40a05e1f6c525f2780bb8a337e7d10ad38a7afb5a8bec6e9dc7f9569135458ce42c847b77585e859152a15a667a8af2ff3f5b5ade2b47c7dcd938b8ef4c62180805261ba07a677407bfdcc4385699c7e9295f4fa3987fad2e86ded72aee2885f3fe3c0d2e65f3f935fff312cf5f55b3618f6a2529148248a3b192dfe294b21140df5dc56188662eca7144f3554adb6b0e1bab0796d5d31459af802e7f128624d9ca157441108c43f0c3937ada9c8543b0939f1e0d376e120c9cd98aec21f69023981fd0dfc0cd2e7c2b8b755d3ed49d66e0b87530dc370bfbd98ad94c8c222c67e582bbe12633f2c6cea16d3cb526389bb30ee7fadfc6d1eec9aad7a407eac86aaab86bb35c9e5505d48fa0db595f6fb2620a0e0faeda9d96e2be54db4c99823cb3c85a385095128d417c3553f2c9610dd738475aacd4a1bb238778253b02e2928278c8fe6c81eb2460644108165e8e0ad3315bd332e22436748a7dfa0cfd0386748e70ce19c211a35866a68dc87741fc27d286603372141044242b9cfc8d80867237d06d10c1a42d0a881b30e11d621ca3a44311bd612d9c0990611a641946910ed94909fd87cf4d65b6fbdb5ce804ea96c1e5a7b5e2053a1810a0d5468a04283b544dca004b5a1adb3ce434319078dc31ed27a0fe98dc30c3890019d8e05238cd07a53d15b87031ca4341419da9a082a7a17d99a082a7a17c979ebacd3bbc8d64450d1bb488e18d39f8365e8e0ad3315bd332e22436748a7dfa0cfd0386748e70ce19c211a35866a68dc87741fc27d28660303b100aaa0371154f4d669bda9e8addb29014706300b9845108d113770e870e4d0e5304167c20c32c619679c711e4da71617149952bdac625819ffc0d9250a4be68dde3c416cb3378bb3670915b5c48cd18bcf8c09a3171f13278c5e7c4ea0307af141d1b256e8450815095aae11b852a820529131e9fb8888be1460524ec18a68c50a3186693226c22b31965340c30208163518a8b1f961d362490b119688e0e285077eca0b185360c01063f895b11136c5585ef282ddece066841d8c8013238a099f1824183141f402468e0c9c858c7036f282c9d0c159c8086723373762ec1b41a77fa48d83969d5afb63b4ffdd700d3bcd467062f419380b19e16c4447478ce1d7c97d46c646381be9338866d01082460d9c7588b00e51d6218ad9b096c806ce3488300da24c8368a784fc021b0fd4642a367670e4c858c80873da6d2db971438c611c191be1bce4060e137e640f641b5ecd941c262c3121004b02208025027021421039c841686d2a6b83418c2ab6c70446fbb7db23c23a2333f129a38cd3ecc53967adf5de3b3f49dcf9c052c8c51596d1746ab1e12a4ee3442a6ca7fc87cb70b209c112c2828765b342fcca45939bcf79ad382aac35cf146709578999d68c8924286e3c2913274e0ce1b4b4eef455adb7e9f5a663db2cf57de3a852fd6fd146a95b920c2750d41f769c5669484650ccb45c3f256a45b84a1ae76f93c01db775428fdb42c1765b49be170b4ce028450a15664db593a8b04946f0396d458585d582f64885711a4da6cbacadd27648c27b6e2b5481868510160f0f2be4615113d3438d0d4c0f362d44e0a1c53f07f8302c2440092e5cbc5061182f52072f184a07b09b1192b4dc504ec32e216ea46eea29c108383fa71aa7715aad564204172400c0f402060072c6d74b8c911e96632383c5be36f89c765b4cf7fbef46da38b819815b15825498edb14376aa79ea9b6a0cbb015b73adcd666d7603b59c1c31963fe765d8e88c405c62ecd4d6dc0fbbb64868371b521bc39aa0d6d45069360ebab5f19a0c9d1f5eabf122743ab7b6d99159a5f519e00b9b1c9c43a3460d975e9f89d9e02a0ce35fff398dbb6061d666e33424a6bd61170b31084d8dd80d1e04e6f6d0384d079c962b1ac27b6e8bb623c6f2e7cc2bb2e166eb61a7045e2b8e0d8e507cdea3e2b57e5bd666793cf666e3b46f1c59dc68407303c7c591c3e630e148bfb6eabab6860ae3b44ac3a15f5a0f26709b1636d594032f093c489122258acf267d197f770ae94ed977cac54264d3d61b835bcc7e4b6a61ad11e3d8fa215ad4d20ddf2b43af575f158400a2010c35a0a700a21ebd3e94b536221bf12cd824d2943d05e3b746e8bdcdaf4a19ebf7d0ebf562bd58af4744449400a204106d52ce3ff3950496b215632e22f8c1bcb899196a610d84f5e67c6b480051028848fb3201c25a0810e5152590944919d7eae067adb53b442570b310ebc57a37861f30c6d1cb2bb45e01c61847a057b54f682fb7f8f211a730e68aeb05410d0b1ddc7566305a7b314d35c0e832e2bc22eb609709b7841cc696aed9295ed8a8603574764daa33d0f219420c5860e10668507ac20a74f8c1c9141e6ab0c28d820e01029d0f3d35ffe3a852b1e0a1b1d6aea83855a7d82e520b05ae832766363637372513bb195ea206d3dfc25caecb7ea759ab3f8e322c9e53d8c25d509c7c49a978542f378612d07dc976e44abafbfaf02a3f3f327ebf375ed9ef4bc1dafc247d9e25b6f576d2361bcb24338ecf42aba1493b7b682578ad9e40d122ed227a28c3079a610afd2b78b5a9391bf30331cd6561513397a28b71c5b6628c6b0d5abdbecd1587b4d1fed5d9c5d62f043d64f960fbe3d8f5610e569a989aa8b40b9d0a62e86824004001f3160000200c08064462a13048133deff914000e637e4a646044998743419283200a821806620c328618428c41062134374500f8f80f105bc0485cff8d348eb05f17bb668cdb489e06625bdc81fd40c9f068738ff4bb2f63acd1c8c344db7313df7f5862207fe8886738f67d92fe688c7fe0d88b0bc0eddcb0e96b933ee5940fedc5ad0709f74ca855535b0911fe167053dd71a622805348d9f8e15108cc9e36717b7c29a176374669bd6a02467037e99f3ac7ddb4cb48064f050c05cd176ce33f26d3101fb50b6d20d55e4ebffed44dcbc1405bcc6a0bf27046c5ba15a8d11a0b3ad1462f0d7da680bbc741faa4812b36236e4fbd607edc520f585157e63af47fac1f21ad7abb6a59ba6c24ad93a9bc39a0289995c9b7a0bbc17d745b94f4b607b54e4cf56680a23656c7950e6f1b07e99286f11f1da54ecb8cb5440c3af280dea633a35502b312bfc2f012d6fad237cfb10711a38e3cd06d4ade78a71c6b33422b1c10532782b9a0ae74971bb5491e78c86ddd81e505a5e191f69ee4e37f66ac81290f8b1bf726bef3b3641840f67b16d43d3d5e66e3a95e8010e11ccdd4a89d1e3608baaa5a1add277ef090529984dc40cebe0cf817087d628221ba199abefc9f07fac0522abcddd83d63e9e323b30ab9446acd3c2339b158df921a7afb2177d9e31a43b829dac4c4344c1c1db18f2e4130e9581e64880eac01108fc432faf629654a16895ef73eb3d1eec58f02492ae967ebe2693bfb1ddb51c49563c2962766aaab5f22a765652e07043bf3692a29ef09875952b6279e4641f9127bea85794e86623bc965cbcc97dd9648bd363d093b9a0a68388b26ef2f32dbf8ca130b034361cf5966fbeb57cbd9655b801e880814769abe03b18c33e07f48c825e2a2c38e9876c14b582558dc28e5a72366976d017570e14489d14f99ba83a06bbf5ca4e56336c10a7441a507052a89e99cf42113146c56dc4c0928d9640e7829f9596b7e0ab7f15bcd8dc3bfd3aa66a6811a797562ab6c9188fc9cdca1b6f039d2be8c1cb6af7aa4d48401cd8a1b5300a599c8097f2a97920cba61cc252b72ba0f3371eb0d08572695ab28868453a604cc53e539c8110028a41f4c38e808624a287d36b8c10491ff4a4b9371689fcc0ac58aef1dd45d076d1cd85bbca37a09e34f9f474a6283b1ab022ea287b083d96b6e93e0a35256ec88d9ef9c2831fa2957f48c2d16417de3bd084c66b908b04e3d2ed929ff7e238ff11d2336e7bc7b3198bf0822b543143afe5dc76772cb8bd2fc1dfac20a19a59bdf8f1c45c4e4f40ea323ff59c6b7d87f33a40b6fb10d082ef974392c4c15bd4069c7d39f3fa2ac85f60ff51e076ed30c9cf12f19de1232c1909785f9ba5f213a9f29e8b7d2d57f952f6f75b7bfcbcf0fcf531f47845e10969516b80dd7c5fcb0ccb152bb0a05369ef276781207cc99722079eb28d97d0e070a49ecb8021bd0a313ab23427e6259d5cbd3a6cf8180de3869c9f1a69d2c2ab1c4b8354ca21af1f03b5c17614d8229f53a29662c9a289426a0b55b90a20fab8d98d499f27eb24598b321bc3c4740b698d42b0a29b589502aa75fa060a20a1c6bb1bb74aaed7d7198cd8aa551faf1ee2115294ca80b8a09f1826c2608c28dda9ce492d1a499d13056419a542f33c2acdee9de717b2e0b496e56b0bbb579dfae7c1abdf113385cd52f8d83c686082a32dc415d70caee0d981675e9fe66ccf470f076226c0f3116521eee0b64fb6099646a468928752f88002af9550aba321ef4515499c581e83c066f80200377c8d6d4a49c42477b7172e15cd760dfcbaa0c6a6d97541bdfb6f2de0cbdc2e9d135295d209c614bde80a31a3657a096173d8f98d221b2f87c4ab16c845cc72edcb59f58814bcb47c740fe4de940eebcd61d7e2ae097dc2efb9a2efa92ee87c4d184fa96bcc4976402551a93508af0c0d36f39f4090623cdc62736bc665066c91654bc8014921043e0fc68a03b2eca5cdf2bc18ddc403b4d7c2894a34d56d60a2c8556d250437878c0041226dbf03eac267d209698f648110a4b3f2fcacfd7ee5a9902a41ae78467bcab64069088fac64320e21f421a2dd6003129561c350821668a8673ea284bfbd6523b3e60bd18b56d9607eff44f03a1016ce2e5fa1093288c203c2f4e43865edebc3506866ad300327dd58a63b75d4911d7300b2c88232c1be447a9c791a600abcd6272b43cf779e4b1096c685aa083d8db37b0949f79c49bebaf689ba99963d8dadb3f64a7b888cbbf3b3f0a8da4795f8488f1d353656a08fd13fbcc0e303f7f34f448e4238c99a542b399d41816e4676168b5664696031cecf83fc1b9486c198763f57f544331f86fe7447525c5b8553659794624f1c345f3937d0c179d9b6a8cb25f503488f2378ec2b68e3fd019a1a43be1149e47d7fe2b8d7cda1e735bf970c872c66317f1aee113d2207d6e45977af745804637bd85634d05e33130064a27196973b32e84f5301adbd49a709cb3bedf0da2ed3899baa2f10a2e41b33a817ab9448337615b494aac25b3da5f101b0c86ff82618c8120d9e3df273cb298e75696fc493a363d313220d583102226a6afb6c70e04b86f75e544c20ef855641f0b4cc5a348e9d9fb9f6296ca20425160ffda06623ab603efd60241693631ef8541c4dacfaf0cf79523339d0c251a509cd024a9d3ec115c3b54f2e0e3b13858ecb0502ce95077588a03e01ea9954172f4e74c8f0cc7a6d8a595ebd9f0fa917679797ca4c18c29a8fd93e4214c2e99ad74bb3fd5b87207c60d5f475c7e520328ea417255ab3c47290eef8e0468b4cda975135ee9d03a0f10902faed3084de46e1f4f9a97c41bb11a5e628a1dec2fcd54d78cabd2241df47ea95f4e328a2206209c0560b35b523f521b23b0e971e076d00492adbab4911bf306a98838e8043a6d072f0a7a3d796291b01f44b2be62885796215d344875cfdeede03983030fbc80bbb7c0ec3f21460d914c424fc6e011e53ddbd2c8b15081c63f35f357aa48dc34e9e04fc9d0487b413e56d40f029a4e41fa982786dc691331741716196964b00d52e10ac4bf301cf36a6f494b15b4ad6911bdc6cefb94bc8bfdf1b43bbbd5938b58accf845ba0d492984eab87c2eff5ee74c304957c2ed4c98f5feb6c4ecd79b04d9418c8da223adf82809bf98c6c04109cebaf0686a3c3e481deef5d0387a0c6bd0c78a98448baee74e2c7ae23800a22ce528619b292d8a538f04998c32cab18686062b093b271c0d9aa243c32dddfe7e24a571f4652631dc466ec560f23ead2f8f77536a28a72d62af70700e4e06458f3efaa83fad4555b351c385e2405c96ee29bbb89118a245db1b1991a81e984e3e381a2bce6367a9be690fdf03ef49513503e329ce112308711eadf283480fb7406a90ce9840fa74c57de846bd89760fecb9e1dbe583b4ee4e06e9101c11cc61fa16efc943604bf763b7348ac076c42405e39a437a4be6635a45c2959c17d48b90279e9ce866480dd3f7648a39416d6a445f037d204a59de12c642fee59c1b02f1c564bc5c3e497169cb722585b46218765d6900c6f2d1a9f156f8177feaee5ca15d8d2e2b8690ea99d6d3d243e3ae083140445ce2f7ac7edc4acb75e2a7a5c15e529a30c46203017f67556bfc286e4f448ffedb831252b7228a465c61f95e6069455c8f1909619376573c56e39e2319df6107c7163dc0611775324249f72c6f905ee0199130dd7e7e073c841eba7036539d2416f75bbf6afdaf612eb90b3400ce32411b8aac3644bbe38a199f76e8986d9759df682713382e4ed570d7b031f332daaac77232c3d9acff6bbc46561507b1d7fcfb541ded68ca9159c01661ab06ab97747695bdc366f6a86d62c3b5e589320fbb1d46bbc438e0ee687b76d05030ea04c895718ec43d174e27f81e38b29f8b259809c43455ed6552cf408b8e7417ae89cb000844ea2646ed203104d72678d1168838d6723da5419ed7b49b9e66231eb9a64951e68bd96e734467bf6738886c4436231959220811eecf6c44437624b0f19dd8875fdd4cf4cd329de74f75d638fe446379935765660a67d4234b2aa703b1518978804e5e5359e679082dc6391a4d766f0c039d6551b4a6c6866d2124538e3bc86d6249b75e468c5ab995433677e332ca7d966a3bfe53fd49e51364950005a1eb1587187ea9b3020cf241f8acdfa877df80469b0d6a937ab6e2cd24065d1c59a109f1cb200b03d84cf208c40c10c175410385fde0e6b367df854f26a876d0bd7a89a845e6f2858667c084e21fe3bff1708fba3eb9695fb87eac858e18d9a3871695258371cf931dbdeafc93fbe2d9ce01894a11a1481cb1b83da29629eccaff2f59132bed56c2bddb2897a44fd8fa665050e81a89e45f73f0e0dd526e62b2790ddb275e7ba89c106df928c6973c5ee559c2d3d2134489c5e73a7c92ac0b3978e7da1d1d976be40b9089f7fffa87960339d8a9774fcf600bcb0555166c13d05f7b634b7c4374fb8aaa9f1c804622ed228facc4e4bf574929c28d2b47efa513921fc2c318d27c633e972b0738b77c91d9ea5ea0dd38e81b83c90e3f2b1e93c9406f161a93857c13ccf89b9313c9a1acb2677234d4960f4cd2d267e7d728e9caaf4a949f45b29bb6628cc97f6a48e0e16d1844a80a83ca254430f3939aa3a50e6d8700d078847b036f6f772c4d9adccd53884dcf5c6cc388ec0022f32589a0ef85806887e15d4c06c5e8d1effdb71489fb89911ce5fa0b271a9902d277cd578abde1e90740c96088689837608c9ca23cad4d6674af16e3d28590ec814ccc75d43d1b561088c5814546e98f5dbc210900d8b4afee40f019766034de42c6eb158615a0850f03edfb3a531d3de41a1dded6f967ee42962353f26012ca4f45ae0c38f5b24c650047655b76bb3e4973a5f569b6849205d0c06fac13ebbc89f4bdc3403b6755461e7fed21bd81085693e04c265956175c8902afbdafda6e0d22767f2dedc88cd5623d2d550bf4921449c9f64356192dba4bdb8b4efd21fb694ab2f2128999fac6f956aedccb547a5ee0ca57375a6a226a8f12c904aa05626c6628788fe7cf30154204f2bc14961a916c86fb711e838967a62745154cdb4f18f2a84687b2595a75c0d20e9162a566fe11dce9b5788a97cbc8515f699e2f25b97c87f437146127b5084185ed772c8cb0f332994fd44dedcfb0d7886e33c868e3f4f5051cca506621e3087cda579cf395ca2685ea2cf6fa240048956f435596851600b37053535cb15f51b3a6cf304e668e86f1c7f4519d1c571e78824d39535b2627c9f11784a14b176f1daa8316d4d3dca0777b758e3fbf12d3973009f9eed90ce4c24ac560a8548193ab79249455a857b18985f55086c8fd90b6829bb06c36176602236ddbbc694b1f31484c0147d741121a7b355043a95d5101fcefa24843e3a547a826eb63298b8b7bfed9fbf8afea3cdf5f88d0c1ba62da3b113d86dd1a27592c7f92bbc864e9f6d8a2b4a265f69148efd985cd6ba25620a3fa33b5f1bb23fb5afbe97b01456ebc013d9765afd7ed9a79691cfa3500d8a0c09f8d5aacebad6f824d1d9c70228a7d02c2c1f4c3034dead81cbbf33bc0c54421ce7f139c49dc1ca07d72b6e6f510a03469d9e57c4f3ae49b871483eb73198ac9dd5cf677876c3ff3507394b75f72ee628c98314885f9ee5477645e2946d3e071f460f85285e4150bc2ae532d1d9c786cb8a2532243115a1835caa2e0c6f92dc02c613d6f74c2fa06360507af9165c722a2f83fc16a9213bacc483381a976b1d7bdd9c8ed8a13245d874e9a603bf157357261f37bef996fd749e87802c6131ed8e8a93a5b0e2139314b7e6d17aa26609707ae7f2afe5368fd061cb7804696e02c97c4225d5481f1ac6f4011a9918b9d075158b1d7bc82c83fc377001e75317b3e161a34d4fe5d7d4406dcd692c413ce6a1014ead6d96d665d67f3c143ed028e37192724a015298d6c2c89ed86eb3f6224cdeb3b6762e3050fc63e032095215352e3666c54b31958933af68773e13e1b70da5b773185604bcbe2db1e89aa4533c0a0e8cbfd3bebbda6b33428ecc6fd863d1d519fa9b442e4119c111b3b4a01e2c14ca4298266013bfbfd6c556c26c8b90cbf5c0e18702513662ebf47a7d7348e3c5589a996ff5a881057beab29dbe4ea619ee2cbf812d2f5035ee908ece448f0afb2a3804596d6a47160d86a4e9fa66d1a3e4553ce6e24ebbec8df43525f5e6be129574890cc5febb2b859db21e25930c0ecd469965964059c01889f26aeb9285cf02509652935ad6880fbfe1f29fa9f82fed0a39515e5916f5710d474ad73e80acdd03301c01d4dbb1471ce61db577013ca438850b92194c86bb20b14e51999f531c5f6b6c8ff4e9bb436c9e46e898dd709a6d37347fceda92410ede8a85df41df90c3b524188f84ed97edbb32a4da1710f1a2c8bb41c86623cb8ad8f3b69328302e0d09f1669e5032bf9e9037d211b887f37389c21ba47807a30069ccab0d8ae51d1c075fc789eaaea87b5a4a239a30355ce6dde3069bbe244d7adb2561878258ee32c66d57526f8dd5a881e9a2b21b8c947f748d47dbad8bd4bb90adce9fe13ce7d114682496481e4560e11f249f806751420ac8579f5f4c0544dd4ffa6dd0e7d94cbc0786721c7a7bd96e1b04de0a2489e984023737ee42fad189580a71d0633926771caeed215cf9d778f2a2cca39c84da17b9e917a40747316a68060627e11c941830f4ae8aa214e0ba38b9ce1fd0bbdcabfbd7b7a18855526590cdfc35a20db4ae1cb43e4f9d5be718d0156f4fde0dba1218e8a7d0b31b17cae3d320694d0dfed81e71777ac4f3797b445235710b90a535e45d30fe46a7ccdbc72581414e7a0875cdf817cd3477a9566dbc4bbb36b9af83c95868af3b3bb2ba198baeceade7181711c847d9b1e146b9b384188e559c8e3311675fc67183c9f8c025432f6ca2a5810f5dc6e9da87d77a493c5af48ae1459240ef74d89f7eee66a7b68713241c320d6b1da0323aad6d966f8c7ca85a2246a82b02aa47eea71da14491f827d7c034400433529f7abb13875b30d44f1a992697ee270e4eaf84757fde610cd01bbff93811f10d732b4942991a8d54aa9c6ec1a715acf6e17062483f6a7c0d18325f131c092da5ea48a2dad734625555d93b8534e502635550f59097ab5aac2aa16bb7aa1b4994ea0f51c51938e304ff7b729e2c11ab6679834d3be2efb76572f6300e5361f63f0878c354ae492eb6c56f40c1f8b855af548224ef1d5820e5134918298670ff31990703a6b2dde943150ecb8a0ca89e52288d88a3357f542d7d3e5523227fc402384efa097c543683d9f50df2c4befb68b9da0e66f91871740006d11647334356465fce3892d2ec538ff11008e6343cd42fca02a0866b247687f33efc9b8e090c1166cba0ae6021267a4520a050770e40c5e04d4d5f534412b953482129834f78a57d10fc18abea59a922da12cd311e8118082953428564a391c9608b8d10166658b39b109ab5495f810e2c7284425b4bcaa56ce11d1b129931c66848732bb5829c1311acfb8db72f103e28b841aa97b6d77b791a59f6ad69a68129d361482673fc82ba0f80dba7970e5a7000d408fd4814305053edfb49adcb72657f60dcc411d7eb0535dfe9861c590eadb868693fbd93faa9f6f0e6545975076200345f5299d2dcd3bed38af468874bca1d28e497106ff130a85095cfe21f3fe8b8d8da787b9e2e50430b6bcbe17b53e6c77cfe1c9321e517bfa8a02c3723bad14bbbe5ba4aa6bb3be6f96d17e5ce069f51dcae3ffc811a9a75943031e2e1b436bef1e7dc34aa4d8ecb345a15bc0845f2afc341603d1faf1ad5f2b585cd21515651d4bd5770346a85bd6e0eb51f3f303744083e95a2a86f31be20489cea921a64a247ca14238a822cccef74e0542f8a5a29dc1cb0da8049d7a1d6f7a5d84f9b564714f55fc7b56171cdfd6d40e04ae1b80df83d3480b4bf82ff5f64267c483f10350aea7cf4c09a75552932d5ca525389dc22f327d69422bb1362327400a2208d0b1cbbedd81e3110059df51cae6b2ca15e1b62f7103bbbd384c2bb956ddf4e2b1a8802af484699bb70ebec72206add27fecdef247f8c6dad40b202513f30e05317cb4ed7ae8763a1631b6c0228e76213a890707b3cba6ee2047e624a7e58a855db8d28ff195a013881355d04ca6aa57428675b822b175640915876dd9c992cf26f19231a58d68872195fc14aa6bb8a2238be23458a0d0ba832c2a73c23c23f36f48170a3848d1d61f6a582df450232463ea1cc009dc5d6aa31526674867cca3f03c1e8ad952d3499e1691e40219fac7836aae0925f80590953e48033e23c4ad1c8ed4c3ee9461b7006f4e905fb364438680672ffb1fa0eb7b097db0f3e1538de47b7e181173feb35afd8cb229f5c79971044444a20883dfd23a1386dfc80c07bfb980985dcc713ee4bab8204e3e739be951b0458f798c71377e33a4c48fe01b3116e5caa5e626203c21bf10d3c09ad74027199496f0a0bf777b830e5a0004ba097242d6cc2aa8daa9e107177c20c0e92e99d1415afd3e669f601b67d199a0237ef8168633fea7a0d75d13bdf8589c9ea85e2600844df0d5efc9d0006d29d25e2f1c879b7a814fac2bb71663d3f8c22ed6433a2bf9b2e342090eaad6e87a32950839b4f3c8135669e7c8a0f88a79dec26e2de9aa080b9429871a5d3fc36d4cf6d044e02cbbd719a4dc974c7ca3693f2efc20bcfb270158d1336a6fc84e4ae80a0a64d62f1e6716a02a9344e9c3ba4f5cddc550aba2ad36ae0ba333720ccadb671cab77834fb80928c7fdd9200f5fe242302e4b235f11fd76e2f79b26a15ecebbfac1f1f98d0b45062e0caa8f19510f3f2a33f6faa4245a452711dd4c71332a833ac0618ff2063862cdd839913d27da50ecc3e416f2b9fd39e09b0063cb226124d6b95222e6d6f6eba7467325766c78c070a960c90c32b82f381fc35b943ee1e3dc6ee7e212d5849a02d597b3cf3ac78ce4c8045a3bdf4f3256ec11c969b5733f9b47e1aa1154108fedbf3077b549c21ac6eb98e512f4ab7d4b18954c5ba1f0032757c5573c97a5ccc358723abcc8f05e814d6071b33d018c3966fe0c011ed562b8e684c91bf2d4e35c78458d766990f62c187c9c1f8a9af551ace74c9195e1e8425019d86affa3576a40e8c16e537f182d85af57a987e836d84fa3b3073dd1e05253b0dc481c970e2766ca1d2253b416dfface19ce0aacdad97bb6e7f6d4dd8cab07f002938e5d91a9152063fb082a87449ecf7da933a93708c977095674bac55e426d3469f74e4977fd599bb42ba45e41b1b33d018838d4e233b404196ae5256438bb13d28ea70f28713ae17ad4de0af614bd9cd4cd46d1fb44b058127445ad19b7efdcb1ae5dacd991fe8e9d0e75bf489f8228b0a272d616ea272c1d6b0003e42ba0a79339828e13cf83540c1b053fac5c6042bbb61cf20b133f85f2002f07b59517881c6af3012b80e592fe2c5304af9f340de75c1dadca066e115f926710d7b853b9c2fb45795e2328fbbe98f7040e64006dcbd05c6214d42bab6f8d187f717a98210ce151712a72ca7a18e8d484a2e69952a28c71bfdff6491432e8c35ecd8bd6d539d7a91db74f32508057db4ce05a375f47f21324b18df2af38713b02597ef8717bdfa71b1b11f62a4b7ccefeccf867d9b0543ae7d6f2d08b5912f1d3b33f9229a0e9b528eac81054748e9e5e50e5c433db07228e86c0f94e62ac0ab6c8664c0fe7f5dd538cc84f6fe59dba9ef08c20ec2e752141c6cc3d847437dd8c76c7f25c6f0b155f8c12e7d1c085a75c41cab1e99f03f811e363d7238c7b0bad0b77ee4ffc2d3c6ae0401956785b81772285be4240dd2f63026a31b1e83f47d1d578a4dd81dbcd08f7540a98bbd2b2d8aa752db2c98d12b1f6f4e57ddb045e56d598a694a875a51bbac3dd8d25150eab04af30eafa646cce150a3fd0bc0762f48f3ea05d54273b4769780a34d6335e2091642dede3b369fac362dc17b5f4d099beebec8f0a2ee302050166f55864038d7277036350c04740bc787e7b558dc0224fe2ba0330e4701287a43cf13ba6f2b006bf19d12eee42f1bbcd19be708a7bc5608327a80c3bc7ca02b0e6ad24462f51fef23a3f4d6fef819d47e7412befaee97f97a1e26ce4fa7971b718e60eb4d61ee34b03b14234dc13607b92a8b39f2aeb1c15a3567810156d87b049496ac203c4a5f53b0e761a60518d6251c947cb0679a32a4eae6c8b2fab420264fa2c5841d447e5e222cf58362bfcb8017c0f41008b1c885605ebeb93f0ab468198b48d00d59448e1e76e5a7dea8a36406a034ea7bb76e2ce4158089b2640cc1c5cec843b27c72f82aa5ddbe24f30a73ae3029780fa9848eec56b48ff27011ebe658a0d84d7f6e8e9ec0f639d90d880fa0e59c609a7d97448b1b97ef37aa7c64e9ee5a4a861a9912d51b04541161fc6ffcf953a14b8d05e6dc97bd055912f81cffde617460b99245c5c80f86373bc58bf0c15f0b409ec917e2d897964c3e4afaa68c49174c698d229f1ffd8f719af7d3de28eb7e39f86258b5b95f95327232998f07142ae8e5b7dcd42621df2386e26b271bf196892799cd45da19a06175bfa1442800592895442aa31c4949614b26c6c0224b17ae0bdb9e5ceb4851aa39cae1542a4f64895bd4d28157a5cddf8b63f931d7c9b766cc56032db563c4655a2c664fb0fe59c021dbd02b299ac952115619d30ab3e10f39d97fdc2ee0f156b06e83ebc496a7f2470afaf0ac6058794aa879739040cc18ce16e9f84a2cc5fb5f3fb0aff563e6ed098cfab0256baa923d753ced25cfd696ab555836842bc614a7e70078a8864b7ca92bb75c4c7e15a9ba4f3c6300f6c4e52bb3f6839b1ce286669b0eac4dd37311d1ccfc1b1ebe111fcde4ebc3ef26113adb5acd2ca554ea751b71923c778bdfee5d57c652d08049c4ec0aed51622050e5e1fa79c9fe3f5cf6c2d3dc1cc6cdeee2866f508247b766b817c7d6963e03bf11f9298622ab7a4349b120fbd5d1203f584b3082f0a5c7100835fcd45f8fa4b1f8df2c434c35162bb89f7792c25fb14f00f0c3087cdcf32e8e2d7559f79974c288c6f1ccccf78c6c6194cd24825aa752ea6d730c5710f4b210d86d6b8e17986b668da8395ea9ff6f6da9eeb9bfae3db95c8e171a8fac981d7b757687656333575fb5d94532695d3145836085f8b3dea7d5ec2066b70e81fdb49be32f15c43e24ef125d2d924d1ac0ddf6f55d9513baec9f7de1edf62d88f8f066cfae48231c964879be613d4dce31f5fa64e1f04f8fae902659d281669927cae167e27cb9e0c29ed4f5670af4a4cc143c0a1825cfe992c56f44b57dc1a942af4efa61a0e7a5a8ebc54e659fb3e8c890d4a0481c8a965b37c4bc751492680fc3ec48141e33707cffc2fbabb080a779f384ae8ea21e270b3cdd61885a4dd26c13ca3d203adb41c2c567fc8f4704463214a66c48a7075af227a2e17b3a49e29726c484e19853d5ffa735daf2094263b089144c3716bacd295c8f1e023b36093df315e3745acc4ca47055e28390a5e79e6598509af584f96c8c1db97ef1c02ea48e889345c9a49d4419093bfc3207cb60471c600471b43a32394e2509f403a81b5a95afb7eb9970e68a07b648bcb237226dd015240eb80cdb288a11e9ff3eb92a350adb887d01970e2d7b1413be3f811a5a4c2911484d926994574edc324e0aa4d6579fcec6b18afc3531903f8b42238d295fe267e75545c02a43ae84ca0e1241f80e7fd71fd3cb33f3528778cd6d9caf4a7638b029c0d07efc6cf93b7fb03e402b8968c61f935be9987e76ac05fc4e88afcc658262a94335253b161ebccbd2ae3bd0f7c17977e7d257be6c80e03422735c113bc82d38f503a7a3ea1e59f23238d362b5d9dafbb12bbdb0bd514d0a87050333d097d608dcbe830f39d97f132a4d36653da1865984d99e36184c994d57f3f4ad0d2944a89d0c01230a4da8e55ffdba8df1b46e58e50db514f85473535ad275e1ebc0026db55bec7ba03a6488226d9f0b55022030b05a1373da74d78c967474a16b1bd05b88ff013e876619274d1ee80cf3b98c2e07f1c610690143826f5f20a7fb9f8f75ebe64b4012324f405c8a08222464a9002b34ef2eb9672739aaf77a78a53b58bc9250b80f3d716b53552e9a48023373a64eb224534a8673a6513a5bab49b2b7aec2186dfd8e9013428a4b7496e2c9e862896f6dc3a8b3287333951fb8675eed43fac568961af0779c962c4089eb6ce4d2e5dbb73355ddb105c4f9539550b0ff8f085d19bbfb9c3a43abdc8dfb361e6bfe318cc4633f292d7df276bf2506f7ae12367f8907e0c5af7029bad9537b6a00a6c1d4601815cd91ae77b4eb24cab40f499183016dd65a761f316bf49b5570e2071077f562e42d6f896a4b9b3c8ee4e247235b5aa6a858e64619496d52e67c56d94144c513ed37e1ff41de0889642d4a85c13a4c503705013ca96df60c15cfcb6b8a2a04a8e18b1f4564de0863127cab57f149a8eca235c9ff883e53bd2af47a5576561602994958de810dc67389ec9fec5af9bbd714955dca6e32a52dcdd85e2fd477cd14498b3dd171fb12890b455eba70b3c9ac6706cfc5ae630d37d56b14eb7024fdad0242c66a12420b0d66463a55b262f3a09b488d16899999652bb3250dd9710330bd5ff4106ba2d7e1ff9e50ba0bbd3b94ef64ccec5256ecca1bb435be8aeb81640730a6b69b3cc3a0bd66a9f849e7020521675cadac13256da3f84ef7f8bab7d30866110d99da021542c3ca0edfa789365f2cfaca3d074efc3cad57b9200a24fdf816713efd9c23e0a5a8130f51d355b49e8a14c54f698ea809240b2e0577dd90a7892edd56920c29b38223d25acb2841b01aa090e485aeb17a590d71812c234508e3f7c960b4a556624e0e3e0a7c574d63ecbd0fcd58026559a84065900270be75e519ec767b9586a1412100ed826447a4715d1301606337394dea67c1fbcf774eb7c89a24406b52f0e1419e3f4b11c24d6757d36bcd7d948b806e00019b60bf645a1b8b28cc4d4c80a69bbdd1a0edd2a9c7e7340d925f2c6b916675bbea6930201d6db3d28bbe5e0984ef89f1bffed575ea90f765e9e3e83f30c1a7658f0e7cb08335ae23ed44743064faf9c044fd33566eacbc8de42d9929d7fdc2832725cdd1690e296454674b49c2ffcebf8f12ce11114b2f4917394c2d39634fa423a744549d8878c030810451f3f0ed0023d39f67d5e3043145780e2e6439c6a3775c82864069432319e799e8c050b6541d6ce820bc620b8b15dc48fe13cd963a18d0c9ca687d3a981788d9460520714a13ef4374cddfbf55587a2139354f3183dd1369e0966322a46e0e4ea828a9624b545e91ad282dcd85223ddb5307c04178b92dd825e0ec0737bacb267e5b7855e5c994d7f03224d2b53aa0153c559aa17926491fecebb041a6a9317212eda8ce1709454c1268a7a1edf4d2c877d5c0195e49bfea05af44c302a8fecabd3e8d7828fd3147f057d741086c83537413cd0141a6c3ea109763bc30efc714cee5e03e5a4b83cf22c51ece55a969ea8586261dc8096a86c5da2f2a4d0e519c8f9efbff07b4d1282898cb14d27248b0bc62ab611ea5afd6b55fff6f6355017fe77afb1e45442e5153a50e5718ca1051b4bab8501108991d2a954c9a8fa571435c1993fc2f75ac2f44a92e63040405808c31867fde8a660771d055bade036fa79016210caf559292388c0b18908f55d98d7c098063c0c4ce598e28eb62056b23933d6e4109b93e8a72fbee152bef5549376d16742c6d31a5f9519237c169375ea4183723d65350ada54f2335d859e2c7237638be007b9aacb91478a77749f70bf1b83ea763070126226eec23482c63aeed72337dbee1b86f77785881a4d51c8f3ed8f117b9980eeba6d93c28c10e2fa68b476824094e2c8b0ecec083e1d5b96d29e6726f79ca3b45e72695b9be8a2dd95cd737cb6fead48ff0a1881008020327e1b6265f84cd5acd2f06e3961594d33fc2972860a4fe771758685dccbc9417b6821707b590c377cf71da2c651ba944b59fa85696fd42731785ee9043ad6261d3f2abb1ce80d258fd7439b08f5c6ad0f3bab012c54020de83d2cd2cada1b7f4fa63359095dd2a8f5951282cd7ee2a9831aca0532cfe3e8a80da08f8e6bed50b6f437707f06193ebe86f0df6859ad6f4e6b193dfe6aa3286748066a619e09065580761c9f3a4f432844644ae02bba36c501440413e07fafca340acbab4657f7922e65480cd112d011f1e946fd44427a618b381f2688019849a20e913837b57a55931e1ab8ad4a0d0435c0da39fe4008afa08621c3799d64692d86853ecccd2d1f02eae4b1bb1b875b75fef7e92308415351fc06d221130bcb21a637bc79c320b49fbd67f324377224b761fc9a46441a974b4da0098a962c734ec1b53c09350850c43749f57307f1fc96b6ed9b8591b7b073cb0dc87c0e28c38ebf61033cd7546225bda65247284ceda8cb8e2527f68eee4bb52fb8e7689c6cdfcd8c0970d2e466d1d459e1a040a714441cb5a99280ab69b85bf04a95960eb46c3957533df7c66006c24dc6b35ae3130b7787b18dd8ba9ad456c88d64fc8573aafc114bdac06027303be48bc82aadac491f3b2fde8510b06d31914717ef6aca3ef0325bcac344b22134595d8124c7a98ab3bca4568042cd7386030846341f36021ff9fbccac4ddd4155f88284fa22f85ac836a32700c84afb672e2120b2a87ac097528565cd97439de6e44cd42b072bf7505c2cd68b3d6c20745e765c550ee2e462928437cf757638b9d2c9246acc824c59a5ab7f541aac0333146f1508bac6abe12bbbc25b6fd6fb5b78dfdb401656ac47289b940346131410174bc508b648ee05948db8481eb145dd1251e8a98d40cc838e41b1a0613674753e4ef934be6adecdd88b1d1cc5c0e3af2026b8d4bb764de0aab8763410a8d32727e71ff4a6ebe0c0bdc3b199892e8d3744f76b04823d8bfea6db7630f56174218db6516b27f9828a9a2f6e6c89139b6407bad21687f800ad7aa1cfc1d1b6b553bb57698101e092a10d37adac9a0a862c3312e4de675f99f97585608bff01c7a1e921204af9a7cfc301ded3dbd63e7954246ee2d2b229e1e27a52f718eb3abaf381934a698ca16b2d34293279a14e5acda666f5979456e21fb61bc33a32a794f16865ba656c75856f87605165753a5b5960b81e46ccc7912a77dcf828f4854bb2c1beaa16a307a4117340d417b3da993a2f27e19345c2b0d36abac8a60dfdbd5ce5e53fd91b5ca442e459f6abfe15202268e8dbf8791d631b027853d10cd159092f66d08ba137a5135357420c880a988c439b4c354a4d91c3e7fae52c046bfcfc5e27234963ba148868bb6172ebf5b6216025b89a275ea9645481d6fd29dfde29f0851be2e79a703ed7ffd7ef6aaa55710542d9663bb6fba52e1153f15f3525ab3f931bb29df48dba3152b2e699d358e476bb6beeb75f86ebf038cfe04b0a00a6e3e24aea26636ec3d14c53357cdac991adeea8a0a3e57a5a68d3032ce47355c8e03446b92426af4531635402d46870558b37d1a107b6c7a7dd61e6e0269b58c269ecefc01cfc54e832e7033b28292e0125dc49722377afffba28cca065cc64b8708e7c259f2c63c4ea9277cd2f116b53a1aeafbb886c332ec6b801f948d61d0cb41d28a9f4f9bbc8d34264ad769f5ffc371585df338cff57b504b909965aeb175b10697ce097a43c819a081d55d63b4b1ba17f13b9a92f178a01a7bd5cc9f5d91d726a44ed463b095f5964511b3d97ed35be15a3b5c161de687c046c6ad72b965c2d12d15408740845423e566b96dc1b88116164fde6988bb0f2f546c09b799298938c97ad98f6c738534f499c0e9b25c6aac1491a59504414a8e3329e8cf81fdfec02b22d10b53265a7e03e9ff95edc2371d59635e873a499ffa2a6ed7b477e548bd4a639233bc9959aa66447a6821fd5c4167d27e0e36f3592ede66b9a2e5cafa613cfa74220b45baf1fd89d7ce337ce2e2d823728d2dd4234a5bbe1bdb77babd9c6c89d4a6fbfa9336418e42aa1fb584d3c598818ce72a32682fba29b0061bbc04df50d840299e3da0b56c51f561a8eb12db00a369a4900b63ba6395068ccb45ffd2981a5f0fb0472612ac18b8f800493586f49664ca7d8a7ceca1d34e6f8850b14ba8fd3dbbd98c70ba382d592c7fcba3a094319f7279f9541948bf1c2c0c3c9dbab0a119c8d500a51f38155e485a2ee192af871c568d784de826269417918938256c73d41c2b99564a28786c209fa37f9320bacc6a8a26a2469ec44684c8a67fe4886ba81a34dea990549ec79b9a93a67a8198615c7f3f008be1d92ecea419a3d70f8e080aa09b9a75de7a76e248c1dd8d365d0ec09d904d6f5f7aab67e8aac6c9739712156a92e78ad0962c932eb92431f61e850edca88b59f7b824b5f68f905a81dca02a444473c071d36cb79e1f4830ec9a12489315c77113ca55a204f5eee1a3d00398b68c5fc026214526ea7fc2b9b9604dba4497d56eacb9a0215875ad966910365ebdf4182c4130c663e87cd4be62309c9d8c47f7958f8696970bfd3ee9fa942d397980850d75994e41c4a56f783fa4b3062f9e54e64bf1504afe8e99cc7684244833dbb4c427b7521eb36ddce0a7fabeab1ad9285894a9a774945893f1f561bb971efa73a98ff472f683d3f8d453101a48d9c2abc72f9d24c10211875997a5db45f72a4248a66be83e5bc5cd9d0e42eade453eabb9591fb269ed9463839a834ae4ed3298448e6a4f1966bf4276fcde7cdfffb2ff3def79294f9ca086740a5078c839e354fcce7b20725db3e56ab8b0fa880c82171ef80d2b1c2bbc90ead375e1894bb1f21d6a9f1fe71c5ae44a3b686ed4e2c72b8414941a0dca5de69c80d134d368284a67214ac923446ffa858b547fec85328712ee147e7dbda19e6d25ebbc2bf07951a6a017c5e948b174a315d0486defb42c7cc99e26216c1ac4859830f695c102f7b96ceea3866ac72335b7b16644bcaa0c86861ed949f3850764a2391eb83c9958cb330e5a424dc000a990a26340e46176bbb61db6022657dfdc369e14c398a4ac511c656421be5eee429912caacfe4926956bf9e8913e4f8eb74393a487f1091a32b17009650963bc79150c954ed16bb2e0b86e06c418f068143bf7abcb4393461f4c05787453b018db1b7584d53033f24f675f6f8e0282dbf52701d1f4b8042160f487b817a35916603ef943212bacb7d30ee3361f1bf44691e85b79eba51f2198df7a154d2e9e985fb8c1ded1e41ee61b2804dd92e04ac6bce5020c71d187be1b2a298074e3dcc97fbbc89e6a0b41d617af12fd28309a597fa6386bffac8de210d60fa6943fa5b6cb122285061db773f50958c38d858a04e56794e644441ea933f7d2a1fc6ab1f0dc582283be698e47ca1ddf692fc93d72a96a23823fd41690fd2d716aeef604e30e5ff19923a61c8473d9b4e480617919d14eaec9febb05870ac29974901fe2ef0255307787070ce7732a048f66ca4a354e2c296f85aa7b4d8d2359f7d5f04e0a05772bb24c3a3793af39770f792222c4bd22a7c7ddfcca5764849763897ac6541d1aa703fb574c41737fa6725181da64569240a875bd406af9eee52125c63165773a6bf17f4fc32d7e8ac68b2acd87bf184b9cd44145afa5b7eaf5631c456614901fa6a542ae11608bd6302bd9abc5c57f99b4ad43bafa8fa1c8da3d362be12d0e853d213e7ff4d326b8642acb9a1e6fa8c7035b6291425455b51497d3b4a4385104d22ddc86da1b0af5808476682ca13754db2dc4ddc9b397df504c8f13a6a094ac66168ba8e435c97f8bd9a49b45994455da17020c42c5730e2347394b479af01ab034b41f456966c3197a3060e6a26ee5adc94ff9502deee63a0aca5c510453c999be177ec1d71bf4c62cbff6d7e032dc5522b40ca6f15dc365b0bc1984f988bea6df41f2a45f38ea4df526702469c383562ff72a93979e0876a81222ed4599d9f6661c4d5932249b52b56983e60ba96e67a515b48dd26ba6bf8afc46f2326eda3478fe3aa7c9d6d2c0eaf5c6889dfdfa10091e732c642025a1121bd2e19c5cf4828a6735556d610f0af42fab9324bfbf242128ccccd0d02771f31c1d3b978d62471e48f2ce23a3faeff5321782d4d55070d51d6b5564228f16a32c2116a73862f0c83484f6a17f2408fd739ddddfebb42f54f707531742d5c1ae6429215d95f98445e474265c0a04ca869db67b73b020815ca01f76c51070a1182cda36953cc80b16c7df2d7527697366d0a5405f383c31a22b194a3cc86a9e5422a7c94447ceadc59c39265b1b23a00b4e94be39bbac2120632ba61cc8341cbf1f60a9982f2d9a911f98c2737bf55c4a1765daa74bd42db5b4bb4e76060896b909aacc3632df1e984d6bb8feace550ebe05a88ba17c3a116fd56b9171b8afc108e226f7f79169fc3d98e3491d0a731834ed5eaeb3605da6af25868b1f1ba753de85e8089fce4d2117a1ac0d5ff08148a69734c7fcd14e8d0334b7fcd4549ec14a515cdb2a89ee22283d5163b90e382a445191e37da3797db2de419a8f2795f1f369546f49816495abc32f7fc84ce6892749f6432678df0dbbfe5c214836aa47a33a57ea31b8f918c8f1ce7a70a8298cb86e24987a1d017d98cd1df7fee3365f60d18ec8513fbbd89622ea53ce5cf4fc5fce53ff633da247e4782d74fcc45d0b368960f20ec3dbd5f453239ad13a4367e9a7ee26c990ff4f058d59b58b5844eefe92846eed984f481790e7e3e5b1e9ffc5cfeb2dce64c0a161f8ba94ceb48ebaa22ee2da5c788471fe1109d18087c3b035213c9f81f5fb8cfcc0220504142c034888b3a63180b8c3e7328f84642b97303760c2e2eeaef850351034edfd6ee10399fe4630d10091ee6ac5185af498f867a168d244b5d7047d1d2abd74ed0ec2437093d8c5afaadaf9c7c48352ce221b988e5050c322c30920fc4f1b18ba85d53eeb6daef09235794ca786816118d081f74f3fc25d651aa4e4ef1dbcf1b4420b26030c741617cc768d9b913af34b28c38bd558ca2b9233278d38b4905127806d482ef153d350d823d81aab9e2b2141e342185e6a2f009e712136bcbcb8cd02b56ce93fea5e29bf4b0a5c6cd1212c393fed6ca3f7ec173cabb4ccda7a4da9d73187b0412ac85f861101761699297cd2f61e7d280043602404a1b84888301fad120a978bb3b230d91c2e10fb12f019708b3802b159e07f904d8464e2064a367ae2a401210b130fa4357d6414da4b078401c6f0737b321d7a40f99eec0b466f7ee2ea469cdfcfde68824e03813b5f6f9fba57b7bba7245dc2a53588e492c203dfda1c5ec3dfca9c4c3ac048d6f5f11a61ae92d8daff4a38d5d871ec505bd5becfcc9e98d656836515692dc56e6bef7e471d55883722b11d414b71d83146b66d607dfb29bb4a8ed3c02a1fac3af0bd4ef033af6aa9a5c30922a6e0e728fcce49ed49718e2bb8182024a1433b08b0d072736def2682e08ee336c8dc9754276dd25ed14bbab7a41488400105044c48a840a645a1213d8de05fefa1e91fbde89e011668c5f047d63fbb7b4d1d2d226524a99a40cfb097c097a094fe61ce14a1cd3b7943960395ed3e7a04a96df48ce7b9687c17b96ee859c4a6a535e692a85ace092964a1d1dedfd0fff48647dd994265931706ed24a43b28f64b09548f57e7d19459716946924b97ff1c06721bf3791a34791e1d3f087a36e052bc7d5db6d8fc3fdf6f4b7edbb328794737a8eab1b57bda75cf7306cef95424a7f04a724443fc7d58daba86b80166e09c4a2f469652b915e0375a34a9d4eeb72f4526b4fbf2e73ba1f8e8398fee348d46f24cb9f485de2b8f105ee518fc33d4a3ff75ee26ccf52e6947ea3ac8fabac700ca24ba58e4ef7db0a254b1249595bf7859c078eae8fba80a1405321f449a2c5b6cfae9fc3c7554e62e266fd1005fa146b110f362d4931578d2b58dfb5b22a49b6eb6c937e366d439fdcaea4a15d49b41cb01488db470f4fd9ff4630bded1aeeaea1254e7eaecc19e5e8df3617ca24a73f1a9aae26e7edbb52c8ca6f2bbf6d9fb30b65b10c52fa1fee2d50212a64009b6bb8a721512155d9f649558004b12b97b73d3436456b432c7f9a285bb3bf1732bf0b497a91ecbe85e41ee5fd890cdf448277e57fb889c6aeeaab870648492a2211b5507a2f913a3adde7d7e19ef4e32d836cbf528ebefd11ff9ceef37b8943e29e1402a14b2465bd4083509b6ddbff805d8dde522940a88dcbb6bf91606c5b5b3d2a0aeedaf685edf3e36c9f7589939f54e68cca1a06d1091ffcbe7b4e67fbfcd7069940066a6bebc2eaca4068748b6588f51008d1ae8ee09a7758316f5f2f2a74eaf14f2a04f3279db9bc7c0bcd167190dcc790ddc390a81f49967701ff25fc96d18ba4a7e1ff701c2465c5b04692b24492b25a5e76f5019bb22f9bcb5afed7d7eb7bcab25f7bec6aa4e5f802f7dec3d0fd570af9be7baf147204e7fbae1ca910ef39ca75a4e6381a9a202d6f53029db12b2f9b7a2b2b01d4142d81ced85cd27046e8fa1514edeac80228abe53d5349ff69e5e9d7b086d1ffa361f4a73bff5d0065b5943a3adca35ea77b16ee88ae5fbf8e5e06f1e8cee5578e5e8e2f70ef3d0ef75e997364fb1c1487d3b19477088b3c1244ff897b53f72be4789fb2bc0550962e757448af13becef7ddeb8c5e077c1def79dc246b80c4200349b29445537bdcb47f39215e2d43b07f473e1a90e476a069057a7ceed5dd471dfecf5f3a14e8b3126d4b54a9f88af4f66b155785ef51bbb2dbc7be0b926c7863c3fb20e9c3efbe7e4f7d45fa36b0bd330309a0db2bebabf3d1678d9db565bfce561219be9b95c461f439435823af9667903d7a2a8e465f496ee4fea3117771f9323c8ad0b6f45667c347654eac837a85bbcf0062afb1810f376d757206b186c93d69ec3ec12e78a2a666036db5950a9940ec3f15a2b5096d2b1d9d4336753901778219669c7106655d569e5281efe2bc711dd7c1883c665fb50b7471deb88d831179ccbe6a17e72d6f30228fd9d7c519671891c72ebe184674ed85f97684aeefee9472955362bdba05bdc3e0a533f437bc8119ef8f03b70ee43cb0fb400f04bf7005fa8ddc9d764dcea6ded65a6bbd32e7b66d9b05396b3577b23eee77c0f79166fad6a7a58fca7076f575bf3d063d9c1ceef31016d5b4197821c5091eb49480a1c66c270aa787d027078b1169c3ce623af070f13c68d2b4343efa34d7f8c1445510d121dab9b02a882801c5062bb2c17c80a470c1554dccc4ae30b275404e1451aadd99123068f6a5240c29604b89183738d183174506080acc49f88a95208d20acd090b8b4684688c0e8e2abd160b606e744b528a064a0287cb0831088d4aa228a1fdbaa428a151055f1049231ba5dcdd031b8eaeefa10a0b2eb4fc055a84d5762ad02aea2b22ea66c2aae438d3d39c13eeb0eb54e02e2aa5a61d7c7229c5df9d32ac5ce0febaba0934358961cc2fa7c8918d4589f7d811134d6779928f2c3faf00d2ed6978b2031c472219e10b13e8e480f11abfae00735d6e78196ac501429627d1f68c92a851242ac0fac5310d1c21300c12c5942510f5cac8a8330dca0b13e8d46108b2ac9420744ac6fa5893266accf14e4c30feb3b351154637d2c53e0f0c3fa50b017ab3ec1021f17eb13e90d5ea0436ff0021d6fb176725083568df5d522caa0c16897b1c5fa60bc529812b47c3802637d2f48a6d862e8e504d3627d315e694c55228327dea8b1beb116b5f1430fccae77c4b1ff1d195ba051762dc7164bd586911ac0585fa557280184a1d3b56465c20d1704b16a0fa4bc581f0ed09215c90888585f0ed092988a0f11eb7b87620b1c5c9614411dc10a88a8b1a80fe0042d595ac11b33d61702684911788b8c1e19d09222a03220604163d11072e08809c1ebb82d871042083a9ca4ac4e0a6b2bcc79cae132305f26c1c9ccc9cf36d7792280a9d01c611c943126819e496b68ecb5951e6cbb2d4f532604508b987cb142675378839f14ba306467989b49756fe4e5603032e7156dede5b88ac211c5a64151c488302e2f238c1883039583e53e8931c63f2fef617b3ff06c6af1cfeb87fa0ee4e512c43f9805d80806c246300b8230d0f55e1e0f36724bfc037e5c082519ada3de6d0300d8a34ba7fb5be9f4e2a9f42277e24abded083beb3bdb6e57dfde23b18fde2e7962137cbd525f4b8400f098192100e10d16217461c8ae58d4bef2bc97f8583bbeee2ac17bf580729847cdc62ff0f66073449ba4f95eda1c61e3975d712faf355c98999d7be0b145d8d8479f30b801fb96a9dd919c00dc848a7df479772561f30184c1048d0ce446063262caac62ecc31699507702e42426725b7c601b9dad5940a1da452944289e2439d174c9912a4b8e106dbae4486d9fdc9223b44d971c11dae7dd7e648a5dda74c99112049f88a4babd386f5ce77d6038a2a595d20a8f8b13dd5c096bad2b26d9c7844974f314de7b4f2c59c058502c2826b20f08540baa2517b5882de21ba3364417d125e3c07d68b8bcb8bc3421c2a4c6bd8c2f2392263f4d7a9af4208220088e304d685c3541412291483138381c3970e4204921d37ac17f454ef7c5b5f0a6b22645393ec76bc1a345912b9a4c26d393b47b2a62616161214b2d863e335a5a5a5aca1038700c171717971064bc18c77194d1d135a958c000003b00b0630b18e7e2b4123bc01c3972e4d8617237093365a666708d4881d5dba29b21841042082204000b970e1d3a74048087d025b151c3293323cc8c904551165382980ccd38b0360209239030a405165cd805093424d0dc2859a6aba02981a6846d08a64b10400902986db1461a68682101982000136e149836a18709263cc932d14d12482081841e3d9a0c71259450420903184013245f0d5635ab55d7031259c9a2e6849a9a56b7a96cd67382cd0927804b80b2590ab8d6cc071b146c421a6a102a499f86989297cecca8ccce98d16642b3293627040a3e5040a189d03e412a6b22bb51de470a3e7c14d92748655bbc9165578d2d561d2a49ad00da618b29a410dee04b6798f0ec6d53991324368d6d81c4f3a171b2e344e7855485a6b22d5e7b53d916aeed0f5a295b240088020a28a0400002a0ba482185145228400158625080f0a6000528c08f1fe10df9a245d11515f0c40344e85386479f662843c5cd21579df77de87bd287bce6352f7222372b8a47fcd104124fd58692549a5da9905d89e2ec8cdd29d91d49f7bbeabc2f3eccbbeafef703a218ebfc2dda2d6587bd6d7fbfb5738ec5bcd8229468faf41a9108e32bb3d56add106bb558f52fc9d99513556e28886dffbaaa47d8829a4d63a6a14f27aaed7a8a4ee439c0b63535e174a5b39aabe90d92a871c30d6108a960056eb4b1c3bd2f2595edefc2896bfc8855c441193bdcb8bef78a6c14c152515de8e08b9a0332687073557077d72db8c00b35d0d0810837d6607915ff1eeeee9b0dbea2e3c238d9a7cc09fbe4d1c3471797321963897dffdee7dad8f7b5880314ecfb8f8334f67d930cd9be4f436564b8b16f14590e8ed8f74be1cdec16f1c0bbf7de7b6347180387ed4ff28212b55a2d12b0ea9fa7adeab14f18992c0ab0cf1efbdac00b73dfe7b40dded8f7452bf6fdbf3760435693edfba3f0e6d6dc7bef901508218312c82007378ed07120a8c173efbda89d7b6d40848fed0f8251833760f6fd2fbcb9dc1a41c8b706496860c6be5beccb7101650900f6fdad0d2874a6b335b63ff668570c1a94fb5eeea342c6888e204612dbfd7e8dad008f1b4110f9a20c2790b06e1bfbde6ddf7bef55a2cf0fc38ced7f5d65535f9468cd81a1b37982c078f15004060a7ed83eb8c03062db4ee20f2f4fd11eee0798a7e83eb5b80511453b88960c0c293c00d1b381806931263303f6460f644e66588c51860637953999728393222ab8c0c10b2e88b04ab850011074de54c60590193d53b478a2c39419ecf369d4a04b76aa6ccbf2e7e12a17417fcdc60d342a9bca6851eaf3d854460bfa669bfba1db8ba6fe18e568bab6f21f9baa2b8e1684ae708c665740dcac513607c5cdcad54a8ee6a60482b0b71bf6f6fe9466575febbf168d0531a8e4931bf25ae4b83dfdb12b0e0c9aaa3fc696b2eb7bcc7fec8ab28076f51847fb536f1cd35ef2c8f298f3d772954efdcff501b92a89afeacfebdbf9622604b2ceff7e76edc13a75dddc4810a018904c200a19a4a830a86bdc27bb7ec53cecfaf5dca6ecfaf5e4924882daf8bb1a148ad0144aa5c73ea990ce0e4fd15e639fb58837e3689c10f7b3eb6f535c45b411edfa98873c846318769fb88a76d7a036580c3d52373d075d9318a1cf1a8301b571dfc61c65675214a5a036f8eb7f98c400256363c00ed1c463e3f6746fe4cb7c14d42663e05a8ee62a5a8510af5d9f83526b88804d01dedab6c400067239d69d4b1a65e7df3e9718a051f6f6dbdb72b43f3ccac6248db22fc9c374d31c697af858e3a366d7f1870a6e568ee6e5a939daaef69b9daa7c54e62c6ddde2a332a329b4fd3dfa532163dbf2ab62d426a3296470552d47ce4d1f7a6d831091dac3f62f360d65c104fa5f6cdf623b0abb0ab2026efa5b3c836cfb67a0ca66322f90549db3c6bce862fb50ebef515c8ded3fd8a78f4d87b6d33244005d51ae00dbe9924c6d58a0bb0691cedc2fd9d566ebc6d9943dfdacb54add8e349da967750d8d5dc98ddc06ecb63f5a6a53dc756e8acf56777b31293c439f1cc8f170b3737777f7ea6eada524afd65a6b996fa01ca7eb905d771661549a772dfd8a5110dad65a29b509c31beff32808ed07a05820b1411a8ef5f39b36feeefdf7f67d76f4376ce1eef04d1e397bf4768f4a1e8e00df0b185204900d690471c5111adc8045698af423529724f2bce70676f838bc09bf1b9167ce1ebdff4afb5ed9630690862606dae4017adff3e8de7a08b0fb7b1e39bb7bfba6e93c7ab8b9953435983452b4ad29696ad027d374d3c288507646352761c328a2e9a992fa5e8ebbf7de3c82fb578fa6c0443e2ae37d2830840132fec08a5aaaabbe566048ef4712fc17d2f42ee4e95b449695d2ff701892b258603f35343531545aa5854fbff07bcfa3811e8d466371008df60007c4c0f21e2afc42965247c7f4def7e1b0fc1ec7fbef7424c88a4a8bd582e118e4fbc20f83360cc3d0c4f2e18765cee9597e08cb23bf0749961ad27080baf3d7308887c9188afcb8696b68e80c0be1a6f1cf7b1858401762700501d2bd4e1e838cfee0e8e0e3780f8a5e6a9bda3efc212c4cdecd6ddf71e07b8f03be877ad0fbb0cc09df2bc3075f08ca83017c965248089e564a1d9dd27fdfc30347fa0b492592776915687352103e2a736aa29a9aa4ca36576776d5f2f67456216fd5a23c545621cea5d4baf41e459e449bb24255a8c67da0aba788f5aa423556838208d081a3277d0ee81854859ff42633469f50059f8ef461f01e2c8508398203be578e54c847ab67bd562caa5015aa33a8585421a151f7b9e02b910688c7c07d7e1ad27059c8f075bc3f7d0df7f3b3909455635732780d2d1ab932c8578e172cc7fb3d4e773f272cbd9c53194309c4a66c0db25f89ac2c4c6a6afa9b484a4f9415a4fb1feea4cea84d915d816fab942d649df3fe5561b6cadcfc098bd06715aa4c5ce5aab3cab6905799ab9c05e47b6b1fa4449505c4ae286b46ab15b97ed28f3e04fff3be7b17eaacd62ac90e1555a12040aa9026ca7eeae2dbbe7eddb9307fefbd579b2e3531e4f73024f8238912c911bb90232e91236e2147ecf7efbdf7deedde7bef353d65ddaf3ddfaf3c0ce09bc05fa1424cff95237d90d4f75e7c6f69bbf7debb79499b9b857234d58431eabfd7393d884da6adfbdef438df9b50ffbd973860cee9c17cc4ff03c9911c73f939dfeff1daf6fd09cce02b548cca8a70010931f361e25e990f8fab48fb05d37f8f63facf2b7358de548e389738dd8365ceca774e06293d8a147244084b39fa9b1e7cf04fa49095727cc1f4e08f5ee298ca11affcf723ceca7fef23e6216b80904819c0dabd17863d7472459b3a927be0afffd527f60388f8125db496138d51225a44fab3b6b61749ef5bc8ee5124f72792c54472926857d5f57af17159636245c15da2f8db77cfad68da6d37160b627abc6331d6c6e58fd8d5ef7a45877b0f9738dbebcde376893c1284f49f05453a83ff14c717b6d70f83f7a5c7a4ef1a0659f11f255d4313d331fdca7b38bea0bf7b1cfd5d9973247f8ee9f5e712a7f45c99b3f225fd1c59f24813c779d9ee92264930406290e103b31a51eb877dd390eb60edc5a4235570ada377b67dbd5359e2dbd7a53fc5a7f15c48961749d3b790a82f91e0af9cbc8fd44fc3119756be1f7655613f8462d02edda2e956c5306d770dd707fafeb7f9409f2fda947507d0680fa0b1a103e84c0c96e3b41645d3a4a1a9a9b9610d23f6babf5f431afc6b701a1640593a3aa867791df04defe588cb20ded36dbb72f423414a6f9f86e5bfc761f9efb9d3d4a6b73521109a02f627406db86dad6729a56d15a88dbffd1bba72003dc3bd42b8bd8cc14372fa95dfbefb1cef515d99d33df87d2d012c2c27f285661fb3a912e828153bc6f7c3d74b2e57d9fbb4bb712c9bee5477f7fc4f70bea8223137856433540f7495693465ff6ebbed2c065d5d9a7232bc9b97b939a2b613fafcd80ba1c0f14567ece3169da9ae011662b697ae172afefce92cc0860b303dc516578c317698d1e90153998bdcac2b981a60c1dc218a87d6928ffc51db6bf5d0431686ec244c7f4b7007f5b22b5369513da391178b81ae431f33954ae1cd37c54d53d3341a4345a46d5f1755f1bf44d4e6bee832b10cc9f42026431436f172d5ccb60ff2f80ac583f2f1f193e94fa68c83fe8a8aec2ad36c91e94f7f2aeb503904a5566cc2dcc7f2108e5ddcf7dddc3cb021bbba4e227da2e8720a6fc0ee002b5f62413fe96bf842851e7dc7c2e8fbedaf93b492b042523a73a2760d5b4e71fb0ab43cfdef0ce276d4cbcd50a63bf2f43223181e2ad19010de4241a90efdb8465825d9f63fb7e0eb654ba00fb5a974c6bf5ba214c5ae54ecca82fa637e4b58c54bac4574115d5c5eacb516861b7be80c92fb43352528930d9e3ab0d83a665b070d5462c87a39e43d233892a44d9fa3f8ab8783977dcc55e3e72a03fc59c2bf0e8527eaf542e48be47115f7f66588a84d8bc784ee197281e505cab75582890195688f711cd8085ddfdd9d1c2f0e7c025ddf749f52a16f7d166d53e26c579c03cc1fde64286eea1a42783302ff05c9d8436d30a5dd534ae9bdbf9d393e22fb44bdc8f3a3d9f0c6cb5ccb3437a1b85984aeaff3bbca3ff6b19779ca3ef5d2098d7ad9154b89e2f194fdd3a9747f99af584a54cfea9998ca9f277ba4027d66dae973cdae506f5b5a50e50b7dccf484a699062ea1391349926519de50374b1a9db1af6f0002813fba8c967dea28f40fb5f1b68589b0419775d0755657c905ba844a17a360187cfb2824aeda8292a8362126a827ae1aefa502aa60045472a672cb5c72957a4a3f2557095f7c296bca0bac0c633a84f006fca133d66563fad301ea086f341437ede700089f7ea9f07ff8278208e14df8df4c787359f4bf1146086f2e091bc67704fd3ffc2381049ad2d38437fac32392e38cf186378c3dfb5be779dee6791daac74d5411377f502f3765a043f08660290449e4f9d1ce194aa5255f54d97489174fb6099b2ef9e28aeda17e4ca009268437e1833564c17b2fcf17247aa480af368548e3b798d4813f9844c2a6d91a43a40e833fae3a350dc85520125779199dab3a1d42d406bfcd016e75c80b57d8362eb16bc8baffe7cff983fe1b79e6a843a70e2cca5324d29e69a511346247b05cc137a846eb514076e52cab63676fc87ca51302d1a08812d10f8840b7ff4c5ce565945c993692e9b3e4ba1b77c3715b783f9397a46e8631d07900f8075dfff42c7ffe0a31fb6ed3c7ecc7c64b93697645a389fbf44fb329fbb317b2a91148c39c1fef381076fcb39aabb68f811f7315dd2f137af234907c999b4c5ee89fb849fb58f83fbc92df67720630bcb91f86fe21393a79c15545a3ae71d6945c74660a0dfee02f34cafbfefc1c25c4b6def6af74857a51d40ff4862e3c681ab539a16ad4e68bf212b35f08667b7bbce340eed9f30d0c289328989b16f50a512f144f0faa88abc2b78ffa0949140fcac74d8bea411541fd84a857929f0103699aae8d57d37c058630d05f8f5d8d30a0848c8e7aca32955f4f1d61300919bd4c427cd3b34ee5109697e707dbd524512da448a25e3e00f005f6ecfaf83f6653f76b6bdfb2856ac3f6f28576dd231d7d7eec635fe238ad45f1af69965ca813184aa19daa505f02772ac803ee8864e9e503b0df42529b6229c1b62db9a4e8b188abf04ad32cca69ae8b6cfbf6f4a6127543184c8f2a512f20f4595d44fb2cf990236c2ce2a67d4db3ab92cb53f6692597a6955c2f60164b897a1dd1f8cf8fd178a02fb5f11fbbfa271ff394fd9d1aa943ab32a3223425cab61f7b987d56d70bf96c8bf2214255a81ea8b94355281ed4ab6ea14ff027d3fc47177f2ac9b96a5c21669b9b7e25c75beeef0490d215cb53f00574c552964e1a8a6dcb924b06db3e2abc2985510c651ab5f1605e914dd56f71ae5dedcb0604eb144fd992cbdcb7ac4361903e336dec19617675fad981ee5af1c7f6891c7bbe1442284ee46822eb0e3fd5f5b3edbee5d86344e73f512f236e965caeb23ae8b3e42ab9dcb42f97097d965cdbfefd13f53a4b46c621ce1168db2fb95c75775eaeea71d5f529c14a3faeb25f32e2aa0d0889ab92b86a2bc54a325731f9d9fe27cf847cd90b7d2c6461db3a84e88cfd972774dd27ea157b651440d3470a043053220480c7cc0824d0942000137a0c807c558e55cd0936386250f09102012ece5ce77d254d837aa15eaec2db3e8ac7c8b68fea7195b8eda3622826beb299a17c5c45653d28b22dca0890927da23e191a5aec132543c1b6fd8c6f4ce62a7bc3b6570791f67a248b8fcaec38c6ee60e54cba39abcbfaf2d2843eb90dd4fd9db8e4dc9cb2aba3b1611706a236a7dcca3a5d8ddab4ec2136a53db8d28bd1194bc5cf8e1458db83e3201ce47285f613ec544422c2ffc55c582065db53d1e7f24367ec934e44a4221dd3b2138cdab400bdb45cf0519973078e0dc4decb73c9e16d29c5ae2e0aef8ea688629f249e6ded2f319aa28588ce1831c5784c2e576887d95fd9a233f65dacd022163b7079de25442cb6b53b5c74c6e640fb9f31b36dff2c69db7ecc2c86860386a348d9a2362d1e13da14dbf62b19b377d4dc65077d725b733cec831ac65481722f2a188163c71c26c1fcf72505dab710faac7667dbb798c762fb83811e23c13b8e49eeb4edb7ef253d2674ecbe61b7bb6db537638c31a56fa9c532601d88d4de6bb1bdce6d6b3187b105efa5df0f374397de7b33b4c2d002866e866e8668bd19da74f8bc861a776aef575baa606bf08b2b2005670648c95b0d5236ae06299c5dd5db793548f1b85b731aa4988f1aa72aeef36f406e4640feedbd8df4ab42d9e36968eccd3f340fd3bc186340cb3cce57dc81b8d908b80a0c0f600fe0818e13faf183ebc08e03c316382236e79cc419515471861128dadb5476860ac43384d839e79c83802da1499bcace70c1c08ca2fd26918c9019253a439f4b4229a5a55b6bad5b6bafbbbba5ee94523ad2d1f56d3d4523943a116d531a545bb51e740fba9e711d665bf4a310d5a229b17d7a6bfb3e5d67fbfbce769eedde23d6764512b32b0a258d14c4808b22663041c3867d562130b67b6dbbd316314eb0851a32f009028de5ad7dd69e1d00ed5ac4633625630ad9e003126478d1840d5610f65923a5b57fc794e00910489ccc76682c7f63fbeb196c772d6060f629b3839a083cd08107b42945b82dda95cb7610b4bfef7378f3f9b8d5a6ba40678020d13543df9ff7bd46734bafb959392fe24a1f8a122c4089e226dd9de778e5e0e1bad46c73a959979a71a9d9cce4363c84a1298bb2f0df3f3d187d0fc8729cd6d48365d8ce97a49c4d656ee7c75578767e9ccb182e52656720243b67bdb3cd4445f2d7925569223fb755a0fc1e1257599d9ddfb338ecd34be2c976b6af1ba336a89dff85626f86c34765cedaa24baa38a2c5faba32677b5c6b60832116fe212cf0878c38d7e3fe9623cecd7f7f080b24e918babed39ab811f1dc14bade2c7e783588d56e88bbe561499525547665555abd1e348dabe8aa7e0d2d9f86c69ce8c17e7d13b66949a3532ad0a7deb4d2d22381ae5e1874e6179f77c4f11e7cf05eb034ae4065409832c2603fb014e2bd3f659d1bf09df3e31a72650b2b630ba58dbfb4f10fbf40f798fb4c96630bf8b9c7cf951d701910a6947626a90c083f1b931928e9ec5ec54765561c101060487c97ded8ae4fe3c3571b8c8da05d716d965b6cbcb1cf1ebb3eb54e6d6a05da0e992fea4a85a894d21e74c6d2d03f65f6c3dc7bb913dc20c7e54cbfeef0d6778a7d10451fb4c796a12b6d5322cc9783afece1a97b2fad01b23b51864d53cb4586d1e449098cc3d5a23e69aa6b59073bb480ab42850555d05a6541ad48573b7244ce39e7daac23826b606c351d6ecd04417c10279519b14f4aa350645476d8d6be4843aab2392a1c11cedd1b1ea0d2a05aaf7eab01e82e2f404307ec4ec2eb481cbacf191282ee3fe7dedf820fda8eec3e8721acaecce17bd04b1aeafbef207b2bbb9248f75e5776efd51c72e8bccf81e640cb1cba52ac7fb3751fd873d057dddddd9d5ab7d6ba3b9d711ae0bb3db523eb760fc9d581f8a8cc496bd6e24cc399ff353434406cca7fc41084ce6ab588ab195f8c61b6c0186329d2c062d7d7565cdd45492349b7a92c8d265ab0a4b361f6d910cb54f45c6143b5360d9fad3795a5b1c3aa4f4b21f42bfd5a8eb75e13ff773dd0f54f707253436798e8df67cde82f835d8d9723a9d76c775bb3ebd34fc14791c0f83ea6b4a4ab8ecb5b477ae94f80f77e3ddb92787f5e2df53b72c1d48a338c6c4b76bb8637a20e349ddd2c3e5a560ec4bc181294fad30d7bd53fcecdd29a2014dabf7e767f647edf1dc97120e6c590f062b8c74d0b82d999ddd0375bec835f6e5a0cc345f04f137de2d72de2668f5de11f0c7313893e31106cf5fde37deb0715d927773d55ff929b1251144929277810448436a304ed9048281c95faa3e7c2c3810facfa618e251f0d003ab156ab3e8823069d0c3e118a0d8a9ffa5e4b13d7881d58f53b94910d0a1e3896224a6aecfa7a0856fdede4e5a00756fdfc0561258bfad85b834b52ffda1d844fb8a0bef531ba274e50df2b17a420b45a2860d5af1ef3bcab1369ecfabad6d515a1a042d7a7d5d23dc4569c5049a82454122a0995844a4225a1925049a82454426b0dd1d0d68668684c6b42d8100db7d6525ae25cd9c0f8c18dfbe158876768eaa62dc3d80782ed342d2738e2a75dab69d7b13a39d6ea64cbaee2aeeed5c9955d2b39de7bdad8496fd78aff23bd30a133ccae32605344a86a026e5a17b579d915f736ff6c9b77b6cd3ddbd6964dc97081bbb564702217b01cb7790d915d8d75ac5b29641b5d48e7ee5557e5aa0e9dc981ced87732dcf5921b0a5db79f3466c3a6ab7ac310341f9c541db0f0e1a6b9d1fcd7b4745c40497cf5f2daa912f381fd20b95e7da8c0a4c64706fab0c0bf596badb5d6879bd8bad4d019cc819fdf7b1937f1e314fe8e3479e49c7326471bdb9c4bd14dfc18cbdcc4d65a1c7313e3188ed9c7b806cf6e150fd6a09d9c3bdc615c815c45ffde0ae4aa0a44bfbf5f836e45e2fab4ed572440e03e2b103eed4c02b979fdebeffb953c6d17ecaf824ab6698b2c7a36bd620638d8951c7149c2566d1df483961c360d568cc2677f18ac41bb5ad1a2ed5a6ec0370ddbd6c06d8283fd6d6025c1ed24bda20995fd716025575afbeb4027b5f061dbafe468ffb4b7ff3cb092de46627f1fe8a4fd4a6eff69f05f98d033bbaa2f9b8a2288dae0bf9f637615de23a879ffcc49f6cd42fb56a0fae3e611545595a0e6e57e94a81fb4415c4b15ccfbf4e4b1ef8f3c1cd140b26445e2e6fded0a2d8076ad64b8bd2774cd000d4444442e2cf1025d55266aea3e9088cbb32a29d5f2ac52ecfb67b7ef5981f4c901ddaf482ecbbe5f6b758aaf605e354992ca64b62f6ddfbb652cfb406b03b7cabe1793f55500e20249caf785314d4d4af3514a29fd21b56ae0a3326709b04deb77efbdf7de7bedb5f65a6bb99577bfd2ebd10e76dcbdf7f280edfc27c8c3c7cd4cda5fedba128f21682ae4d1135ea1cf98564c2b46e7635c76e57dfe98570c8fafbecf1fe3e3aa181f32c623635c36957f2363606e16719323716c70877bb4a9ab625c6e669297312f37f3b762beb28ce26639e4662e6b6e5aa1cb5a1965c7ebdefb3576f5e312853bdfab2d4862974dbd2e8db233153be3d7ce38f6b6c24647c54868e71ebb32cdb469b6f39f5cfe6f3b57d8d8f9c527a619f7678b1b3bff4692407426c7b49ec4b85ca16f00627426bf8b153aa6b5e3d53d8d10b5f1efcaf32e4164e7b3aced4c234467f2fd73078f9e9d7fc76b47cf8eda8e28018871e4172410b5e13eb72e50cca632b9bc4009b010061f95e1ba4d7f490e1e68ab417635d6727c01e3cf5f6b99cbb16e9f4359b87278880e713eb0400b7475d694fd5a1bdb521f6c6b8fd03464adfe32cc9081da23026d408d27dbeaf859af57990b54556398e8fbf08e3e6536c53a68fad4cdd447654e1d44dbdaf08603c3f073f7ead262689a0ad9822007860f565c5d5a0c4ddb7ec4be0d0cb3abe4e2c11018b3e946e341c935b4e52a99966999865fe3cfb65532945ccb43794a26ca4555b6d6a6b3edb80adc5e1bcfe6b3652e04c2a12b832fd0748376062ff6559790beef272e67f0a8cb0e1ffb308841af0b7187434c4b2eef45051ff33c8fc749da955cfeb58ff24353bab00bc32fed947636d277c965571f2bb9ccdd8ec33be8f031115d92c14dfb6ddbc602dbaa8e9b1474b2e4f27411e83ab812b9cb5fdee33e5ec457a85aa5a2c6cfb65f8bc0eb5f912eaa3b1e22e0a25eba08d330985dd86522a92d2b1082a36d695cc77dcfbd7d0d45d34097a38ad8f66dc884067f7eb67002e106663083411b4ce266fe0959d8f6c52e3af3a259d80e2e7b87d0a097b5b502ddf2903cc17d823f25239808ccf1f58bcb24586e12a78c3d3b762f93302171133412e3bacf44a24747e8d39bfef47e4ce508034a080b0b905d8d38a65339c27012c232d53006d39f9e8630b0941faafc7a4e240c08e7a0987f451f958fca57252896331b1500db37b32bd3a35ef6d3015b60ebc5f57c2c01a36ba8d46c9666410c95a21100000000e314002028140c084462e1783409b360593b14800b7e9e487656194ad3208761180619640c208618450c1001909299d92000a07107faafbb51a20718060a452660dbe5806892b4a1496bdb1862281a782837682f0561f25741146fef711ce104eba12b33ddfbf8fbbddf8f84a24e64920ec0f0d4e46c357b4b8816180372bea0c14f745fc50758933538c432cddc8287b5c209f581723f822984a92ee7a1ec8cf6213f7808e3d9e855ac5cfee75e17c78830b2530614093085c52ad47f083379be4e40392149c4f187cb8d763bbd98c3dfc70e98f943724ca44607c7b0a5c3dcf434fe7ba850bc1c9d879f9e4291e4b2edb3a2bcd5ad3ea613422b11e0ed8a5bd425dcdcc3e68a1fbe94ce169296142d6d3cdc0e8263758baa5bb7c558f4be819f25ea365164f156286f8a89da1ed3fc24c5d8f78e1707db8d6ed38477d705807daa315910d315007c83c9a08e2ece2f7d5956a87d21989c239c3e287bfff65446488fd1aa690b516aadda0ac8ef1a42cc70e6d9d435af783e8e95f7d2bbef7fc2776e75d03e9b12b0d7370fa81232222240a9eef4a97a35de7ae6079683a48579ca00a004ae8d6f25162044c8d51da4af3db33a843a113de9ac44ae72a0c6569691a92211a0888204731871f5052280727d271b503c62e4a7bfee90e6483c27ca6a05b7466dce935e6d63b5a0c186ab4601b0a0c99769cc73389090b9379484d346b7e85104b1f4333d2318551c2665948375c828a61cfc9caf1c14e76cc5c3c96bb5a2f994e63f93629d2a3e111af812247288d45189169a0886747d8988bbc9af65abe634381b5d9111499ea98e2e991c01b749e93d44ce87a2439ffd1ac6942063898e3d054570fdc3fa37d918cd17aa1e1848c682650395481bd01ac74650c55f5e0f3b098b2e0435309b1395a2696207536a4c50d22e3ecc1deb3cb7e7dce3bbd123a7ac6e9b043c5b84b7e971cb9f6bd97d681f96bb554ac3529e71dbfe690daa4f2267bfdd5f31b7730e31bbd66ac4377f1e53a75000bd77691347a7aef9cc000cc5b6ebfa260b7aeca25a333b087e0d0f576434ca7cb53980bd935237b050ae106bb7b80b837eea883dd7557455d05b67113b20e241d8bf67b54157a671b338f06774de732ffcc462a6c2ddb6fe3ab7f4f6dd86a611ae433b0b38a50329c567838e949e440a20b92de70f298d8b745643806d76bb6610ad85de34e0180cb09caf17cbdaa34d5b2d0a8a960cf4c1ed9aafeedaeaccabbb9cb6ae91e2e7af12ba109c81b7478bcdf54a558f6b44fe0791ac454b1e6e0c3ad2d059b9634d659deda9f46f9efa6ffebf4f3a8108d96d24e32e7d7dd5b7332808a639f544a4e0dcb89c541391b1547359da5ad2d40f5697952c62c8f81c1b7d50728212ec2659cffcd471c738a16afa1fca14e408f1eaa1e82a88754aca7251162ceeafe291401d62f57c03b7cfb3ece705dc7e82bc42718447f761551d627ff3943f46680cbbf2efd0a139df8387e236ccb3c87319d88e67cb49cf1205c5fd3dfdca192a73a450177baae1de004155567c7ec4f3b1ce94b8eab15dcdb76ccc4d63a74ea4f6cfb96a4db55847e1f29310b13b5f629943fff6042c9e12cce6c9543a398a699d47362c130198ce4439c5079d8450fcea6d1c1d005f9338ce0227532e54592582e9cac45048d4aa75c8b010dd97fa8f28a063627d591e7f3b94f6fbebc40ae8931422c134b9a9679199fccbd092de966b86b5daf0ad191852126106bc070ee22edfa2a39feddf3600bee5d2273a2527d8123f9995bb4e17650a9129bf76cf55dc8991dc621da8f9a60b3c4f0d2dfbf2b782a45977e06af0159f39ae1f9d185827a1a9836db10437bddd17418cd518fe9a3c109593172b0615d666412afc28a462183e783d96932b4fd42d2a8c45fe7541a538feea3c48ac7fd7f3f0ac135f64c7db9a3aa17a5141f9eb78ccf7fec4a261cbf6c9b1568ae33b6f084de43db81cad77ab0c5683fa6e49e022e5e28c8b7fc4d5c813c1930e05ae77684666b7da6b2c981fa54ed53d67acff8333eca10b9eab7f5f83d38fb0cacdecf193b225a134f95e013a837dbb2762d92a5c550ec4fc814e59e542f2923a2b129c5298f75901543e2bcb31cfd84d000bbb06ea1cb92244768305525a62d89d6224fd3c4bd2e2c9334ab819bf5f4f7170ebb416420140d512503dbae5f297678378b9237eea1212acfdd9ab43c0ff99a3eb47d71609598d15fa79f44a1dea842ee8d259430c880d68799b0e0d24ecbdc40a7bfc00b32be7db66f9056e1d22439ef0b7b8a65bc520a28bb481d2135efbdc1266ad330e3780a461d84b5ba5eb7f2499063ab24aca95747db81efe1c9bc9d5976f03c0a9b94b13e108c47236271fc36a4fac734236dd7a78dbee9a5d0ea0876ee33de1827765427461e609d3fdb8294878edfe8878acd7320ab8a3bfe2caca13beee1aa4d0477b20ef84d20a3c0a1decfdc0911e408e4b5db47da7a2db2d357ced5bb5bd1fb23ba3571e7ef4fccd920ee04595af5c4abfe63ab77807746c6a1353bf0d340611da4b1ff3e0ffcfc0a6d55e6c1f860f5137888d295f09517526c75c67309e9f92efb12b4c2c8aadc57ece98201010ecb6c54e1befbd90d2294d5e343b17177a326e604b85fe639bd3ce3b71f00ec935bc2039fc04db68f7e5ad6caf96c62790fd67769549c9ddb88a794e8ec81a29f48b5b0d81a41cbf9cd510ea2b88a823f934a27c6f648ba21beac28b191440a8f9ccd79e79f5efc9a36460a71f6544951d02a3e6aed5ab2d939477e91f5fb79409abcf77108b134aa84571107656faa724372647925ae206113d73adb5394835ed12ec9062a986f99ad93abfaa971c996d610e42d4064bec2bc3ca4db33e0199271a13e7a1deae2c7c481394ed3fc2809ed9ae2a3f8cefdb820b07b84221b0332d59a254bb21bf270efac3cf75e0b6d86f56491c1489692819dcd25b8f9645a3e7414417ce74b4f7e3c3388d1018ab19a03f16971721c523c36ae4cb1fd00a94643f88429022c77692d2cbdab98cbe4bce0b16232fcf85f93148971a8a82a98458cbeecfd8942af4e06640eaeb51bb48ed7d91d4d63f2281fc167ba436cda7b071183a1b24eff85fa1e39192d5153496bdae0b508ff551a97256c6fe1f840767195f70d8ab0c6848a9db527224fc89fe5db603ee7f96ac0603a804ab59fec8d888158470eb04cfe2b627a8f309a82f00bc3a91c011c9b0e24beb6ad77be9868ae77b0226a2bd813b793901766dbba9e264b5468b6d7f06daf547e804b1b62cf1a1105c9ba25def2cbe8b1d21af75ed04e37cf8914d8e3450382c06773c55fc3975e5183515298371556da3249f3756421bd576345e9038d931ec6e12a659965cebacceb5fa5abd2b9ad0154c8a5296d41d287a9f50343383076bdd47379e51cdccb1ffbd6f7afc828ec663f3edf6fa3230a3836bdf6e8745a882ae7e76b79adc334982c87d231341da206dae899c42b28a6fb829b012ae6dc1638e7e07dce96854e97b61a2a9db84138fc087e88ed851da1acec28104f76d66a253ba007fefe541bf83263abe64a1f5017dabae5a5ab1842eb56f7a6ffd763e38d02aba6f5fb0bd3803aa816578dfda558942b2fc706da34edd9e244792ae9d809d74faaddafbfac2bed81675348d7e771c6664715f592bd2ebee8924c3aed2563debf21765b49775db609e138cc5aa173ce39700bc3ab07f7e27e72ec489cb48905b1de74a3182fe871a51b537063f923e041f99daef4466d2b6b9a12f58bcda8f2594d8a55aaf5d283a2b164d221c1622aba3f48906091705f063c2f286bf90fa075f642481d86f4c0020905337486a3ca0fd53a00d6e05eff417838f42da31d7bd2ce123b9c1d5408a34468d487c293aa3a535805e57dc30f0768bfb168e1973ded568bb9ca1c3cc95b6ae873ade98828f1c60e11e24e159bf6e689c72612d600d420691ebc7165a462e5e8857ebfdb02501ba1139c816052cf04e6a1c49004ecca521c8dc220b4875572089b4ef68a9ae21c6fb42099b3f2cfd59ad0507094a78e3554511ed633d25c789763278c53bf1eb8b28e40eb7d36f876055bce1b6dc29ad0f473d5ad6ccb46c87eb2e3c800e247b55f4db0ae6fed880dc747ea7321c73e869bdc78949aff0cb4a4a36d1e2944455943e7ae346007893d3b336e244bbb364e0d8bc728f38215b6d73508b418a13f285d551df4a869e68f5f83ac60959ad63d88aa8937a14aa14fc74966b674b7f94cbda1ea3f3e3084f3475425accd8185327881f56cb90f321b4b64913a2d313806bba20735df21c5337e249676207fc82209ae680062cdee290cdcc638978135f87f4000215b4900cc8e41fb9506f68c40335689d3a696a25a33fb95ce40f8fdf642a97a44d397b30fa93239982de94b2eb7d9d05717d30b8bdac886832b5c24563282baf5c25381934204024756556f0f93f53db9006f0813d11203814929edf61b3e28900818896156fec0082c52bcbe3e9b435b90a86dd2a9d4f6b52701da4a30c9a08283fa9d74980f77965e2d415caa868944754d74b7d24ae3091d106bcc13b3ed1e79f0b62d1723f61d92abe89ceab6659476651ec2dbc0dca6105465c57fe9c4a7ea891459b0dfc4b3fbbf11532598728c6a16e7ad5892331f1501a89bb3a39f724ce0a1f3bc54cbb02a72abd82e95ff799b7da6cbe84e7585d0ac9f02a3c74bea7d4bdb1c317d954b5d184d193401c60646397a4a0d3e2abe9b07463874b0a48c7abe7388f7a98bcb7cc290c74fc0888066c7220c7f6a2f671f5dbf474319c82e2a766adebf8ef3a3d31ea923e1e108ea289bd63dbc5dbe9fac426beb29e0b19fb4b65aad29c13817b7d3937d7b9eac8720d9334f76e2934b3ac5782bf7aa0d1b3f9cd57d7933ff9c4da1c25a4d93e26281981af6f3e681a55b9368068d4dcf007859f9869f4f28f218290a5b930a4d02e77589730bb81ddd53a83391180717ad8b5d298b16aec9fb65e695c22833b734f752510f9a85be046d6936b0117e9159c3254b0f9905764d63d81e637618fe3cb069341b79174d373b3e4be643276174d2a99f0fda0cf0371a96393410f054b3c1d82e85c5c4e848886cd9703b932909912399e1fe7cc3a0b741be24654f76de304fc26e4356d70386870b9d106a387a3bbead9f5a48d8ffd449d8f74c65b01ede93c1ed437f311000e2f0236319a67d22e4797ee212bb8565b1807e42780c758dae3e6bd8a162eab703d77b35cba1f4f74394985ac603c03111662a4c78c925ae64622d06b8821a08039f8ce30d030d9aa6700b34fef5ff67a055563646b7d083180788c1bee39fde5d7cf878d4f49e613a20df30f356d93879db1aab94192fd94fbb3919813e1ff85499b0776c1d3c671b05627ecc40eb07134e70fb1c6546825acf8089d0ee104bcafa6e3b2eb5c86641f04910d1bb07b44311b74a4dfe48855f6394bddd0057d941a9c2ec51503bfecc13f57adfecf719dd865cfde6190d041f5e4020627a894e83dafd63025a2f00b0c3f189863fb45081ed151153bd293682e7a88023acf84c21d5b0d6e0127201327d01e03a82b374e35939c7b304202a8e65190a0ee85e17636045b01c4aa0a809d980f52fa525ca010942cfb007ed65ad48117889146b4bd80e3209e7272d02437adb255fdb97db4d36199fad5e681b36acfd6291051803a41b82ee2209ba2e62f988134f95d6861e687bb16e869c8513dc29d3a1f7fd7815eb0a03ec03e7c6d1ca08b15149d3b7ad2fea0ee3dbb09b83ba01c16c404c2700382aa842358e53b6db07b7eae3c55c2b02489106256b3c7e6fea11425066528d566c19ad078d826fc20a5c6aedb66bb435483b96bec24e6f8b6d4494aa2dbdf10c4150040c09484d9cb58e02ec4a61709e1351371348f319f89bc9b94683026e88ba5ab8d52351332ccff93137ade416f8b3ca1fd21c7922fd485616513d494c8470282babab25e628fe0e2a7a6318f6a970e7c80cdd20d490dca967022291e580e366a7f521c3275b15f5b257dc8a3534492d572a43f33ef3c8b9cbf95f9091a288c60676beb157e77d5c5a34879dcee4aba3d19fc6231dbf9e0156f5f978271d1d740ac69158f91310c572090b5016a32779318257392e5093a8ef599819b6e77812bb1d9bbccba2162934239d9d22efbfa97adc89f47890aa7edd3d116a6831a87a6885881fec843c25ad6c896dc59f63fd26cf3919cc3b75f2135a30ba8dccc2e537a1434acc745601db0e4325baa7a0ba1d8fa785ce750152402114b1c440f3d744ec85a033d6d8e6fb3d0c56789a0f95eaf6789e02e4c70b9958375963e9f654851f748c182c94fb8fb720ce70b65d1a19d3381366d1a3d3674bff1aa4af6cff51fb6dfb81e90adce3104580e1e3e361d3322d9c2f3923716c6250602648b1fa9746a7ced6cebf7d57a558f1aeae7d610cbae023fdbae59b5a4cfed18406b79552e697df49247ccbf0bf460d5fa6497b6333fa1516e7054ff7c3bd58984302ee8b436163da4849f003de3d7668ef82dcf654564a88451ba9c22489474dc7798f228c9b376c45d9b4e61eb327477a92e07900475abbea7f07dd0d2f4d403da0209bfb3c0024e11f9d5dedddaac637940578c53f3463033045f8883cb7c1e4dcf91d75e41ec200118c438bfa61bd3777e475e1ef73b9cbf18c481a0175f327917776e9bc1c7d7bc43b77aef5fdb3e38cc14e4e858bae5471aa2665edb38d2d07f42c88b270c294f78ea97a7f6815ce0f9809b33092371e130e3906bab30f12a1d3c4bc7c49b42e8a93426721fac41afd13977e738f133821dd471f672204dfb58bbc1aaa1f9c9e27c2ce724702a02ec22be74766714762c35980fc00268f89aa9026a2c716308b184da4a493e05e8332fb28623a934197aa99a22c12f912e42f42a854846322ad2f1c8343dec1922b57e64fa983f3d683dee112f37ba20e57d28a0dff720fcd5aaa594cee974807ffead1a7cf29790de8704bdc32513de0403638fcbbdeba92ff8e6e1cef6f3e158325fefc7727c8c003db3f4e49a4031b08b446bdb9846780525d61cc0a5ea4985be789f035c7110bc02c4e1033243b9a3c4d8b6e4cf012619b6edb7f3309072768fdf1d5cb313633fd8c6316635c99ccde712dbf2a2ae4cdf145fe000761f213b27c6fc991b74fd88ec205327e80bb04b066fef20de58b87ba013a5b33fcadb437ebd4ccfa6693ca1adee51d4a2f8300219bb5f4fd753563aa55060bc976a6443f9c8b8b704e8f18deef4385199ba5cc6763fe9fb6630f77aefeefd317bbfcfb5a7361eeede111ac48d11793b0dccfab1f63802078b6d0e4feda5d932259bd849ef78b6c35d9c1a6475e896bfd236d83cfa483657b83e8c26a6a20eff03c7240d7956d16857e0b90da737c2ddf858eed4b398c4ad962987ba53b89af590c45d6dbb0244a362a1d59f378b29e1af28ffdef7e53b9fc5f11d8baa4547d79d9b632b242877b7d6c63716dc07308903228f6c7f90efc427ef872b5cd17293f2613e21750b1cb78b888832ece340454291a0a7631901fa5c3a128f80e65d0bc2dcedb969212a9d63d9eac03b0f47664b006c97ee651d440c5acee33d8be1a969c99606182a0ae377476088b95119a726ba54cb850ac9c0b8c42d62a40f1e77ca102042c6dfd8969ba93d9a76b21b1c1763f43ad3d98e9ce012e9cd20ada8154351443f82cbe6e7d418507ceaf8678da49939fd2d3863bffc9186fc1b262dd0aa746203b22d427e693d87398950c40c673192e21c525e2280672ffd1d08f28534edb30c400205864692a5a6ce411f37a82c118182b605aa2ed336ea7974bbc91da464d7bc7a3bda171843019db2279bbcca6f7d2f97536ad0765ecdb66be8029e8df03bca7e626a02a3bf0f22eda40398e710ecae4eb3566cd1e055c30bf2091401ab8f635244c3fd20ba2263c745db44854a44b1467f0b16be1301f1ba977647c763f96debb206799dcc2da8b214a9f7b32b5466edae933ed4ea1b2668ce4c9488f884a75821ed67aa9aee44c2a34358038d20ba6d814991b237c32f6c9e1988e76b13cb3884b259aa4c31c77a1d69ff8664444362c80fbd51b26b579f397ed997fdebc08ba9b38585b46b3fc49a4ad935ddf2f8f48f8eeafa4aa293fda64ed0ef073b8f1a7729988fb8c2c858b34faee2b76d79deb1ddd6fe048195ea6804cdec3a5ec0913bb4e0101fa712c4e0f0503b9859c3a30f14de1f66b0407b7ece9bd403d3009685326487782e7457f1c36522021353f899bdc3f315f5b6b0ce6d51fbe955f83e427ee78f746c12ea948cb1ad891fa845dda42d3d8195d30a89819bc78ad352b77ff390d1b75206cd9451988fabd5d5fae338b944bb9b8182fef8800e973951af53d9992fad364e73953d837cf8c08f0c2e8215dd1b0ec13e8b01692025b0fde16d6c92f28b6da9e4e7d1af6d514383c1020bae95de9dde4d7a11e77b83ab71eb773eeb63492981b1c672542933b8c905ce9d32dea120ea6d6bd92839ead942bccf64af43533970019c98c98c2ae4642aef0d6a7ca160ad0d59894d10623742464fbe8cb0fb2d47ca88338af21589323fce9ac0fa2c7623c6f8138532da333ea17808117fd6d4c0b9e6c7e9e50dcce2706675bdbdaf8ffeac6253567df6aa86c82db2cb1396e58a93cb599c8d660e83ea23d70b9146d8c4c3441c0de896e561491c7c10363fbe66e5d6bb2e2738aacb30e8a35b4ea888c181a0fc4343c973f047b4aafed4aa1d12a27422069462b552955edd16eb9dbd5f627b02fe21008f05357a157f8590ec233b9e54bb16b9b4ddbd98e54b01a9793a98f1e21578f599bdb87e7adea68e4848e6fe078db0c2a5aac961be21e7e39339608c08b5fd7ce04848240e9a12f28f327c8468d960776e414c7ac1f83db1ac20263efea20e3197221088e4e95c8126bb44c474951387cdda6a4a5316a1efd7ae835a2d285663f37aef86f0af1892c471d690009a6da1d5241e70cf711e943a5afc5e5e707f880b407ca25665a06156c4fc1beeed3ee507aa063ce7416d068a24d110cf95bdade6a289ce58681b1919822d1706164244632055c252320aa1b3908d28a9c3c6c00f453aad86337b16197d8daf08a533f771e491d7127ef67d2807125e7a8e49030d88342ee69a1b02cca8d0b8c9dd5463be803eaa8e4b7f668c633cc61f48fa510981120fa80a7499a8dc4999b9f3f29c9e3b1a653e19a4e25f04d69d63e10be19f4136f77e39bc1262c30d853e59b4f0559eb1edbc1eb36a5099bc1984590b1dbbd8ed822de8fe2c494d686e25dcd36e31adaffebe03405c96676428e6c2f5e544be0219a3836f80ea7c41a697a0fe6150a788521b7a4debcdf1955f063442e1a8a26feaf3d5d1c304d791dca7d3b603662e60cacb75de951f494c8050d6f63735e122b4fce75a0710bfc055540a6929d8dc0136a431fa5ffbf0c8206b9221465703abcabe9739cf8d5f2f162201d461ac34762199c3d927d51c72133bb3ce729557c50a65d960b568c3c02626a8198a847b67432b2df49b11e9266e0ae9fc13d7a680e951bd6b2ee57eafde2717544f44ce00e1707064bde10a3860de184ce424982a555fa468a8088b21f246108959554cb36a04caa75c5c465355c10359d9c6232dea836be834b0c79a5e7d120da449dcc8f77d0f8e93ea08de8099523f19f94f26bdf5c9d44b0c30ca5e81036267e060989af780d56c2988076b73081a8cbceb3c9969396ba243b359b6ced763a1d71f0648600b9e0de1871068a375dfcdd72b97327e4dcfbac6ddcf1b5967ebfb64e1ca23c983b4d93fa9b3b59922825737203b5c5bfbb733ae16dfda02c9c103ebc1c5ee6ca0cbd9706d6269157746a69a0d28a7c00ea51b00734d0248b98fda3b0c3a381b1941b0a8c34ca050acf63d5f63947e529d5b45b9fdff60ae99b8b4bd484f8fb545ea9af9e39fa1c2afe3837b276aadd3297f482a9065d0f8ef0f3088d26eb5855442f1a6470c793a7e45207f5278216e8c2dde5e521f84798468a1853905f16b0065dd0d1b6e5ee6774bc1c13b581903bc2b18a8ce1654ece81ae0436b8a41f3330914a76bf232b6b4a13c4249fa6aa1cb8a2c54145031244ebdacc73de1839e9267747988599a3d9b71bf2faa25f6498756725a798cd3864e140ae262e9cfe78802558a572cceb4d3f09fc30dde859cd98e169b3e868c55dca3b0e3602ff867bbc0471f8139ce74796ed41a4fe3b975166efa8b3476c223de9f343028f953cd9b4dceb584a2fb1f44427e5cb1353c2e575df5e565ddddc4d8c34d28743b1ceb967d0093df5a834e0ce820e86bcad97c6fd02c177295b5664cb3628107d3681ed4baf7998d24b123d5b70a82d90951214c3fe2d92cf1f7a0c2b6ba67789931bacb13bf3c1ba10104f40ce1aeee11858a85f01fbbeaf4fa9125aa38fa6184cb9d72a1c5f02b7d0a73c3824b3a89eab4f9372a6bffb709c444028d4284598e531741c9a50f45ac2929826f11595fa6b6ad80651880679a0ec7ef710cc9109ef19dfbc3bd5e1fc15c9caa8fc8f5b17f21674c10286d704f5a9770b323aef1743e106a803a13efefd9cbe2f4296ebf8b5011cc681d0eedf748f4da1af2bb24c27e01f892f591c309f91cf6e86b243fb485b4658d3892669efda1d4e20e148aefca635db68e066d5ffb34d3dc76b2fc4eff75c988cb2599d3e8d1ced5b498a1d746832d93cf3b8c66114930d28bd1c2afe4a47cf26fb545e681d5c71dacbc07bd71946cc229f0101268dc0d59f7351ad2e491852523056cb3a43e8a5933fd6d311b5c15cb387fabf42cf3c9a3dcbba76b0a3fee02754a338980267621ed23e7eb79730d3b4087a97eefffabded58e9f40f6fcff5dba9c75a8c74456295d00e2e69f615e8a0bf77929e23fb45fe43643710763fa6f54c3bc9a1edb9f482e9f547b59c3117fc66456047c1d17f403f7ba9ae3646a40e7ba48200070451c99262162992310f112f08ba7b05a01565edde2ba90a2dd28fc00aca262132353e561cb303a40afb51c6dab9e849ad8e08324b0e3bf58395a2268aea116e7d5cff8e4d9d058b72852f4bf9fedc8aead7093460cf396053aba1fceba7f6b90f1df6ae34c84f9a4e29558431c19fb513fa80c20d35b56cd3f4ae19f5f2996bc1332ae1ba21a5d960dc8c8c9f008e1506c48d526841afbb045883b0800bc1fdc44c87efcc973936a7d937c6878dd9cd566fb2a0ff0ddad447db89eb3a7fa4d3a25632a2da5c5b99c21bd0c33adb12e56dbd0e7e38bf31a307b9ff859b944811b245fadcee0b37634bca98dd50f56aa79916476d26cab8b2d6541b87c15cd3007d959b8d1839baeeed649cabc9b298e55ef9cdf3ba6e282355f4f3d4bf4cc75ae5492769e4b4d3bda89a397a902cd1a0d184bd17d7719af38c32134c12962f33731569ff4b4eda13ad40ab5dd28db7d3e40d8a7aa71715a3db8d8c35df8f3290090307f4ea3ab6f060f8aac9be86a6d771d197f0a61e187380f659110dbb664b3c09bd70381a9f14a4755a1aff025e5c1cdae88ca8ae3b7435d763faf79670c42c874f2685f304472e994b4b4f6b3aea3dab925314dad08e95cf82295c6755512af26868e34dc6a8804aa6a583223426b386c529e7cc72fb7f07580a61c2f1c55bb8c6e94a755b5e628136bd86380c60c18342231425b62b063a1dbd777c6c997e817f6818a501b75e9c6f1e3786aebd4172509b277e36b6cb79e47bf26640441d35bb35004467cbe896b52d3e50696fda5c708a586fee70946547560d75b2c7a88b4c770ecf6c8abcd5868ced6e7c423091155fb631a8bec082f288b7755119170eed89c424d04ce1e368f151405c4e16f7cc6f20c8f79648aac8372b23dce5fd311fc8e9c24f75174963a830927c14eefdb117a32499a4b8dda161f13e0e98ceec846786943692434e4cfb36865158b83bcb3d541c8740ff1387ab3e6d8419c47098445b1f8ca2d1cae88e9cd6304b3b5743c4df25eb182a010ab41502b840446320d0302843dbfd98ed12cab359370b8051cffb9b63e8f402992ced8f8ba8eb0f552f20461e723baab79f6dbc52b529fb2c1a75e3f6c026a92b74b7e206714e430d026f53ceb3bd8528e573a5739caa487c298c84343bc5add90b1778c9f9a98691e8e6825d1e026bb155947eeddac9b034a05d795e04d26476c879004bbd9aa5439f91c3a01cfc908115dd8254e5db45301b487fab877d74255b5ccb448c5d574352daef05a292cba1468eb832255d3cba8ca8cf77bdebbcbfe7b7cc44686d848173c554d3ff4b55bbb4c36c04fe69506c50eedcbce1f11d216410c5545e90eb2df47c7c12b98eef1ff0f3bb4d1cb323e319d4bee20a4039b63a4bed8fccb10790ad41cdab05146b67d5f1faaf41e349d824a43fdf47e9c5eb5e7d2240b37da4b5a625c8393705762485ed8c2380959be879c032c78c7c7a34b0185023baf160b14b30478a2878b7a777347d01e0688228197f94d2ba5b9d2efd30976402f69142c26d7c11ad60afdf5529344f4e5a8dd436ae4b298f3edd7942370e37f6af389522cf4189d5854b8326155e9a5c64566c6b6312b2db17708c79aaadbf7eed53370231dd9430e55bc0c604b7b572c4b364a513182c0dda2689472bb32cea6bd0a7353eb625a5b6ae7681c8a52595d43c282a6c54c84cfb01f0a0247c71304bd1b2872794d677a19c924f44cd5a6ee432fcb00bb16e64a8dcd90c3accef224dcbbed9d6b09ea2f3ea74b0f8d7e4ae3aeb9a8b319b2ff8170b8c2756225fe9e7fbb179fbe77a8593a6ecba5c5a05464e418c8b7c83cee375a35bb58f18d8bd5ea40c612ce02a0945c26d268ddf756be594f2ac5b0d00c9fd8774926a7ed9c363eb0feb29750c85090ffec54299193833624f5e9dd2ebd1d818e78319e97ca9ce30480c950efac67a350b9bc18114c00184a2c34579f4fea3550bcff1e74074a2d6f94eec18579e92692518ecb824b74e76259527038c2d072b0d9e80553378d9de310ea396a4d112d12c734b302735956a358b0d26d986e7f56aec75327f575efe82c65ec87cdb8cca468fa6215ba33a58e71d99380dac0bed4f7cb19e103991993cae761b1357c633e4d0310d0486c4e883c36ddd3d12ea5d6c8a06da2a2d834cf56826945d5d80290d4513eacaa0eb9adb02fbea0f4f3b54afc918d437cf9726de0d89dc0568e1c4fee08415493f88ba6ee0327e492ee5ee932aa1a89d02b4120272a7671ad730af934c48bcfbda251a64ce17af0d17a180f89fc387af53bbbd27155812f34db7d9325d2f4b0b40e3492fdebb83d8e67dc6fc351131f3d749fd122ccd34c6344a68462be2b664fc7af53743c0f12ad208b4850bf67fdc0ef8bbd0f6578b37f7155789943b54f1302e8f147546b75b156094d24b3b4256e3962d9f8b951950a2a158db81a6b6e8f54b16174d8835967cd9e3e537a0f1381c0777ade8a54a4c58e79e2d000964b357148ab2e5847cd8f05cc02ac1384d658afb7708e94831fabc023a0a5750b28b76a249770d18ed02284c425143cef057cc5eb6d0ced2fe3161896aaae3679760c5896158a29dc1e32922be179cdfe834d7e01394f23eaf86dcb59ddeaf8ab644f59534c0ef07a62bf2f6d9549f6f73739cf0e4a8ef89f900e2e891e1a8915e172ec53eb5ed7e270a87b63251bec43ba50b6b5c5ab78e3431b21b1ca9a6b75fd84acf9fcbf44e07516d0e08d62b9afdac3ab7271d462d3ba113263c0e44ac7699d1acc68e831024d214c80842f2f9a2c8edb785d9e34886b5584b2530dd6556ed89900b4bc25c758ff08824c96fa2645f57f5953cd87415b16cc931399bb90f5ed37f29524f9a51b8ac3c8b209d4509bacb0f290e93396e9fe0021596a4e6681b55ff956be0178be56e57f67b61babfb65074a02ce6e9e19934cc878fe59ceb8c034264d844fbeb1fd7ac8091bbd2cd524cb312b2c0a5011fafcfb09e77ffbb1abab2e4e40de689f3bdb0fba03d063867cc7f758fd9a1297d48a94a726ecd3f8eaa219aef4636116eae34252cf09dfc2d2726be6d95f85ef0c200a542d8eae0b92bb03ae058627fc8a530a714df7cf1e8109f38a712826e2c2a23fcea8aaa4ad45a2285b8a8334860f577e86c1e5f7cd47c20c37e681a042abaa160e7233063a3b0225ba33e4c7b884fe62f6c61f6b11ad9da6c9bb9cb34bc069da93f6674fd95f4ca8b11d96b27ef2440cfe8d180924ec99efccf1d0ae2f1bbfbb9a1cfead6ab99b1e9c1a934895f2d7263402fa4755553e0537b0860b916497665cdc2f19301b4b4f5bd3640a96304ae47039b3701fabaa7c8a11f89795fda4b8463984686de735be69382d0d6995d3596e13fd9936812c43acc802cd5384f20038b292b994a641534071efe5d3376b0ce37d68a3d1bd37eb6d248bb544acf80339efb55fc4b4d021012e2fac471c0a33f45eb3a2a2f9e93f9e666c8902e9a463bf5c407cbce538fbf6f48f55409fbee611cce3b5261172b556eb859e02fa51f21b0a3fbc58b9c8210531c0e5c081cb459f72c59be74062303b8b967b4bfbf069f9a881fb4eeb8ffc57feb5777b2d346da2f7afe11874110bf66cac5f236d6badf7365b9578627d4c94072d2795800d371fddacac02b32ad8aac2e5a83f1c47e0a9a686070ec295244df6e3718e8aa46436295340340aa60c9f302a653e00b31e9f530669c0a78f64fb126db87f8d564d1b9007cce3856d3bf377287f070c6d6dafc352b5510f45fe8407375198e79b127b0bbbb89affb9dfb103d3827552d57179b727dc967b5a899ed3f5ae2779a0e0a59b695ad86de008b60728d84ebc38b5453aa7a03cdef3f29072673c4d546c561a9d0a28a1423a30c90801cfd55dac431bdcd2c4cfc0e0526d2b30c889d530fb6b584cedee94f282210cb3db887e01758de8a1a8b0019514518cac62ea53e40349295c26e791ce6870194f5cd7fcf04646a10086cdff3c393631c7492ddb5830a21772db5729976d61d5312b2ae80f2c4298d00ac23d5613941bcbc1aac2c91a5611a358a31a15f55fde6a92eabb6a4de1c181c77ff0ab3946299d9f2a79dc091865c04c22c2dc3a361547ca451a969528d55630f765f1a73215f913ca0c42e8da55b1a210fc130daac48386a341e0190c95106eee6df82e5c969308ffce0381d3323234e01618cae8782b0799115b6e748e91ced1e78e0528a6425cbdcecca4720691a2767d9985b821c2f36f82fa2d787a3fa446a000e2a65d0eb0cc4c4575f57d278f1b16e6ca673ef80ed08a41a3e882cad1070aa17fa02adeb677225be5bfb02a2e6eaab8623988bd8a1bbe6e0afdc3dba07f97249867aeed3c8ec31a04ed6e730d15744b20c52274416ae9477b328c0328403e21f7666fba9087339bcd84bc7fc565f20400f688b7d22153606744b462add602ee6f345ac8ed69f58dfb1920d112f922fc26979a1d4e7d3adf10ca0c783efc6b078304f1254fdf521a39f00d73dd63768b07b269bf5fcc1c9820969314ed571e40f40c929a0f3bac2127514c73865d1c03669b7b5ea0f45e060d152e5b40034155b470f46b520a7a8cd753504ce6f89ac59eb02bca134765004dbcb588df712a5b55d0f4bfdc0cded76c5c376ccf0384a14c57c7401967b47d716764fa01dcf77bc421eb854668f1e4fda797b67b80aff3a8f0407d7c7f2ee9ab806a0151e8566b12402cc8772077b5e4d3e00574a81698350eb10a206bd52fcf2925f3b1b9dcc3394150410c009c0bc2c8830312e5e5bf50d0d7f9ae61d13ab690b336ac4e56bdce29ceb9ef7fe2f217c0d66f992d7fe6ba98dfccf3e0078069656dce97129210b4e3c0eb99223041f1a4ac55fe502aba921119d79aa897a39a6d90d95a10da404569197284d665e96831870491b1352a447f6883e33152d4050b59c1d53558ff4951a5fdd34b21f0e1434a961767f2f2c527548a8ed0abb59848eccc43a02bb4988ac111d67426adf025b829e5eae96d6d80894d3c8468dcc5fa155c59623be629bda8dfb17412c271fb85e5f4168401aeab31c4ba039d8954102f743adfb47575a720b25f067c1a441b6ee217718a1e89c420ce543e5f6ae8fdc92d5669e93c8e4c0d67d863c3c3ce2f5341a00e8ef15ad3bf83a3d449c99bf214035e269c6b5f023f7218f3eb8e98160b669c43c613d50f65eab0fb4b55a43d2867c179a63e1edc6040d79de88067444192d30c89786ec4c19914b1e944785c8ac846604dca3263fbbb82b10ef63496e482ecc85e672240338afe2261aa1d72bf8b909c813e77634e25ae6a14f773b48389498fd038bc230f5c24589fd597692654dcd15c8dfeec3ed7c30d2915bd62f5a93a5e77dbc509554d9818dbf43a2f70979065ba0d995b9e2384a495011cdf6c9bb2f7a4add9f7b45b6f5a7c41f30e59822238f0b02a47587675915ea045eed95f7b62e8f5a485d5d61a91c86e88ad9109f20a9032c39a8eb25b6f08bbecea8fd8706d492a8836324237808048d86d69273f1f3d765d6fcb64b7eb829c754ce212f6ab2866433ea4eb7247293ad4770c0028f48ea1354378558bf94432ed5155b3a454ce7df15ac303f9828e92dad9eff0591644fc578c20b686ed1ed5aaa71484c5ec147726094c978df07d2ae5cca247404902893645352cbc326cf061a29be57aef37457ba3a3d521be2c5bc94d2866f57c5555c5563f1004315f6de1d6ac0a3b0f26834bb2028b2b428887ff24525f5e43b744399d667fab988686b5fedf3506739dafc407159a6ee8f5f17aee2dc4661a10e8abcdb416d9025d4de7f00ba926bab7e35e34985810604e57a4b1bee43d0f697f46dbaaca0b745901878e7bf64d602610d225d176023f965403cb58554237df4292168741c3e6051acf1f05836467af3c0d70365bfdfbf0e84fe240c1d0863a26253c17f48859f9158a0f86f00456ead65bba1f7425d4b3c18310f407f56c515fecd945969c2fa619834f4dcef4248210ee81b818ba580cd64e95aa030588e8dca6314a6d246cac25bae188ab418624d8ab013daca87b3d590c380eec6f079aa83c91f01d71e3e0a10fe89ed41a3e33ba75e2c64653835a5dca6082cc7353dedbfbb2953883c742189a856b2bb32c4b05c3c54427e89e1cd4fc7f60b07e688bd3ce2245223b9f602d70a21334ca7ac9260cc487aa50447f6b9425ac7f39fe9b74420e097262946363264e332264771f90d4c5b0cf6ec35f5e85f17d5bd3494d0aed2f356bfe54fa8a68000d20682fffc8076d6a213fb108ef7c665b82fb04f84f4a479096c632704c53caf131db33a2ec8326a17f0137c542b2f902602a6308526c0f80bdeaf554f07f3002d1524be038341d92c02d866f9357323164acd510e3c1e667962803bba06dd768691a5870434c4827e7d4c498e647136fe5f757dde27a9b53f02adf2e6f83c0c6f09ec4eb716a8b2a74eb1b532c156ccb4b0ed77ff9386ac8cf4bbc6eb68fefcd8bc9fdcd3d1e17fb67f2ec8b43fa08b7a813c6e7a6414552a230fe40c2152728869416732d108fc39bd22dd42dab61b640455ce8c5a88fa935346dd6dcdc9cc212727b682e0d768605f1b43480370221197cdffc2dc8d482fd849b50228025232d0ab1eab1c17bc23580b7ecaa13c0d9ec741d5713ba86ba3f2182027536cfcf62d772bcc9e40a800fcf1193be0dbba24a96bc0bdcc69b98ca40758fe38670624d155c423dc3b36164e8631ac3cc5368db0bd7f7187730de12c2e649e3b3a32f7f3de0bdc184a02e39fd9125d954586b11ae6bb7587f839910bc978ecdf8c6b62265a0c02fe0689aed47bde2ed92a97d2688f48f3fd0870c2d75ede5093f6998991d8bdcc524521a90bfb1f8fc07a16a38786d3e81afa1beb70d71c9ccdb555ecca0804832b80ddeb3eada4a2d90ea7fe722de55b6868bc4f82bcebc0ea7fcb27515d0e7bc3bcf6b0f56ae6f3b9a844276bd2ad7a0a15f2bbe45fd82d576ab2ecf7850983a29ea91a65709f7b63e57070a8ebd9832b7459f13a58b67bc4ca32f1060a50de40a79aa85aba3ae69a1e4faeaea5d077051199c2c0059b01ba71593284565ccd6bad0685f18be9ca6a0d223144c5145ed822520930bc290ac0a2242ba3644c895afe4391ca00f9cae517a8cfb3417767c4cd8d52ed30aa4fbbf7e22098e7c67593f635a8f8c2c00bcfcf8d72ad64816907d2c2061f390a504f997752606ad0eff936476099bac06d36c5da8da462fa4221f4679a778c95024a5743061219a47361bbfe9896c960b7ad5de34ff52214475f4700e0f9f22f4a4ca7df4cc4ef66b80fbe11fae6e6925bc43930b2a0a9d37d3f7dcfac069d801372d01273360af47841370eae9d913b79020fb614764e59328d8b37eb8e62bc47d97ae459d06df9e5f7225be79ab53ed2e5034b3aad6e53480b6fbe201a00b85a5bbe6b3b0e6d3cf411694b95b8d635ef20ada1c0d30c96d3db0c27f042e0db46ada79404acd8a9489bbf82872195b624376ccd971cba3ebf99b6eb34739800334698a1662dc19d163fa8c9070a75f59c9ad9c8ae11a8d186bc35904cce628d949de0b9ed92db55aca0d19aaf2eafe118bcd698d9a01d583550d1b925db547567ed8f1f8f39e2b1e1c762d7071f60b23e28976663c16716c87ad463816d4f551d8298ae944c2c60ed4b4c939378bfc8bd37f16dfa0856f468cd455aab260b976af4548b607ae4debe229ce623673fd56b9a62ee8eb70d9d6c85f054bdf55d8b650c4ec836ffdd36addfa0ab1f3f81161050509277757c00acd1afa39e689c56a522a451e980bba1db5fd2067de420f02dbd1d945a1753d8c4b7006fc746afea81da08dcc66703c3498d3e2cfbfab948fb463b6f4704db240bf7f7e91fb3f5434ee7fb591b6c9fb237c336c2ca77795e39f44e812530c5032cf53d4477c8516e95b7a94e6f40b9e9cc8e2c50a808be8b6986cd390d688e73844ebc7f58803e39b53f4cd2a44602efe74ee900da7dac4ca26980de4aae14603ceff658b19a3f7c45e2f35b6dd649777a2f187114312cbfb7f1507f661c4a0df439466c67220aabac7cd6d942745c1799236cc6ad48ba47cf8dd22414df871f8262187ffc27d373ce1101fed335c1be23b4149fc9365e2e9b2da820eca29f6e9e3f34199e965074e397f423eea95f84351ae4bbecacffcb9ea1af3beff1ee4ff192d1606410646679b8c53e4dbd3fca24f185e6ff971407fb9063c8e0a56fd768049d220e403883d33dcb038a55fe39084e16205c15983536c7ca0334b12240869e0fd040d02b0c3f8803d0b886f843383438f8f612c07e2eb3b1ed39e9f623e6611839086d1d4823e665799ec7c613cf11cdceb237b4fbd12bd7b1ac6feafa65f58d20734287ce8f594a235d1b3ea0ec3221f05d0440238aedc2b2a04feeb6579a4b7319d156a2520c53fad231ac089a9aced7dc89075254e17767299c00fe57525ec1afd049b2091509d4c7664dc8f74f15e9259ed25bd932ed9faafe983c41cebdbadb771903d2d1ed25c4499a6ea1f04a6952256f82f45f64508672d46c3030f5006f3f4f42cc3f56691562a4fc3b05d9d38ad71d8a499516711bc8761f421cdc9ad7118814ec0f1c59f7cd52359200f5387d669870cbd80284f2bc6ebade16f132636af5b43ddb1434d02567e55181cf6cc82fe6cc081b862ff62b6ff13bf6b4d3e785ec79a69da0ec09cb4b10f0108d1dc528b4f599735e31a8642d44c3279443147e80bc61514b44c1f537a9530a553f4e86c5211bd69879e41a89df950d78ec65ad8786c8085ba3603995b279bc417bec3347b03420e7c89b6bd2c10b515c86d883f52a1efe5b8cf49fd299c001dc888832d556b0a01f59971241e0a7dcbe79120f3bad11a23c9aba30b7a7603ee524ee48ba8b5d5450798f03e999489662cfd659a9293a1d7e230181f6a9b150459fc6453e5a1e9667aa1467091a15be5548ddc56d0454e300fb8cd55e746a788c349fb35e5198f78840229d9b6a1e4e6d180969596221f4516f2da8d6f7af14700aa3662e2cc042a572af333936dcfb10c9ca08b98dc31ff3bc6361fe23ee271d291cb3a423622d32a3168cac89664ef90093b09fdb3aa494b245d16123532e8d5291ccb7b38f1dd7483eaa45abd99b0a324fbc0da4c59922f4a9b1381e674671e9433a8d3e136c4c357b9c441b01bfd0fdeb02f234f3783e873b84144413dace4446d9f628959266db737e3d2a11096fe4a497f9f9876f97e209053d0ab90e1b12a7ec2b3e4617ab6ce7ea6662a668745ad596e149cb52f07ff69858aa7835665987f04f1ab65ba4cd96c80d629486ea2cef9cf2f73b0c60dbc77aca5eec515f71677a3c1539e9817d6538a50ac45ddf97152ad41c62bef2d9c5037a59a3bd5bd6ac9a05853ce9a38125f27705a91fa6dc081d7fa33dd283db67ede4b8dcd88b22e282a8c880d6747a564e48c7e89a9b1d77ce06522d3053a903053cd581d5c6ae294c71ab82dcdf65154f4020b787597a170988433a1ce6822e15edaf3d761c28c3523d37f72bd7e07ae4ae02b22c4cc1384bdd15aef94b74b86801fe6d7a564eb9fca26226ace92b64cc08ce2cd1f7ee6f6066a6637de99a04187651a1fe49dcb8456bc6ca47c518b32d963382e10f33c86ca01536fb66b0bf22d1589e7d62eba44052dbfda485e8de7147dc3e3dfe04e18cc19b92382fac70385f6f519ba936f496073f12b266f2290d75c4281fb6eab3403bb62f39b5cc1ea279657ea055800de05e06ae610a5209ed6611bf31420877012980c8f3c40397dcdf8543936ff4a02ce82582d208865684135ae36a5d9d44b07e8d69d0c0c36e77f00ff950e76cdb8ebf18cac2431578538ac692eac392e8099a770d26a92f36e77b9f3bd5ab6cfeddac925e8b44e7d9eab522d535451e5cba67e409910e1918e2c45a1e115d7574b0e51d44829487359a8a032eb9690009e8741236e1e5615aa49d96f1263c4cdb5a0efcd32435aaceeaa12d36049623e961927e1ff1a4397caa7c41c0f0dd773881bfc8b4f8234c6c8bd68bdcde30e6560f9af8f8a129d8689eac6d3b8084c06489742a25e334a692e6b122060290ba9bdb86ebde5d58e011ee16b1d0d54563e307a2caf1823d8f7dd108dd644f759b18ff3f40b33406cf0c94360a061f0e5b6f9655a148c917d13504814f566f580107ab554f6410e8479d3bcd58b614224199c44f75ee832e8e3edd6a9a38a37faa74ebfd3f82ad3f1f98ed91a15bc2ae1e589c70f85bace122f47d9bde1f1fa60cddef678ba1250a0f23a410bce85612bfd3b31a0fea26827c2b529e5507168a6ec8bf61c1814c3134d46121386a5ebb5557b62eca1b59e33dfe253a1bd90eefc068f2a38c4ac2d6e2f51eeebef3219cdf7934b179f74ef677da8ae6eae984654307ea81672d03dddf5a8d4d9e023cf1cf3fcf199a51dc2abcefebbb6bf65f329d60ee9ca149f37573c80ce90dc8b4d7bf2290063343408c2e5b36e5e7911ccde412ba700fbcfd3def04ed98bb560c3f95843532a81b1260aa3609d303e71c4f3c8948d1ad9ea719fa881ecf9b61cbfd89a0e346fc45d1c7126a47c78d8045ee6b9d3bfc9da844bcaec311c4d4f04342327815ec410879adf886779c0fc3b7e5cb928ddb0d8cff1e8f8c3427840e187f081e21132338945a2ec16de1209c31c6ada63d1c605704ce9bc0c6b915b3d1f225e86427ed7ca385372112602343a080589125c56665a4576f3ff1873f832885c45a2434f8368e35606d1a9604f0a7c8bfb769675d81c9490c103f27c0696ad3fde38db000af696d6b8a485232e799fa19d87b38e528348a49874fe1389234078e63c34b553685ba339a6546124c96f32d674ef45ac1d6f0634e8c2c6ee7cab171bb499b54df5707df4ebd1ffa2436fa16e15efe01f49903f22ad54925c88472b156a5dccc903adb49730c16f6ca133edca7935715d0ac3dda1465fe17f57571f5c757170d2695058bff68a937d1cd9ccd0d2d7e4c6a1fbedf815ef6605d2d4ee12b72a589296495f1f21d8a433a73b3642686b31b5755b0fa22fb9b8e61d779547eef72204490a5d09590849c5559098a0950820d08584275b6fab8f43cf25484f82e0c8062e4f2bc54f86e9d39bc3335b98b7f54a056fb6186d092c3bcfbb60eb07c19e5d3fa980f2462d4118ca2a1d882987f5435566c9ebeeed31f56f39563379937efe131c7bdc502339bd30ef338efc8b260fd092e2892a8809c8e3bd075277e7cb6ad1e579a507ede79358feb1464452b492554a030a0c48d705975a444b56bf43071f03e277d25a373d34cec731fe07242e65af7ea8e691246f37b8030e1e2779e592ca7baee088e35eae5dce7e841034aabd4db49cc3936b249acee2f4aa75ae19102e20591071e6cc37fbf6bd86f049ad4a40e9170c92b1a70641e1f34773c2a3e7f325400570ea9130b210c16a15c0c1dbb7b6901805cb3e3f7bec3c0571593b2cbab45a44ae9c6cb78a1a4274b4dafc7a26b36b73d9970167fc40ead80e32e1511ca1a0e7a13e2f5fbab741cc56f4318504721b17f8cca709fcdc84b4b2181953187dd7e02dc75a2fac83d0f5bb5800bbf3f742d06250c883a6a6353c71d5aef5aeee66e410d27d127ca5ba4b36ece8ab8631506fe0583f22141902b729a9d98395206249409bbf3557dc4ae17052860bbf0e0dd303b6d2bc751d2170185ec161b65319d53c936ac2be9a84dcfa24284d1069ea499b32ec56cf9b2193f4a51122c2ada09acd52a7966748d830b3524cd592a9565d5b290912f4648bb446a2ce7b69e845a351935081e2b8a55502139ef5b0505e9deaa05f598e1deff3499558961609376d9bc017e705da1e44a8bee28abde20847005a060394374d206c2de9a410bfc42063159b752e116542e3668ab2ea6b0d038de825bc0658ebefaf36cf15a4d8cba5e7938b1e1daa4334dea7f2f6e45860ae309082f034d5c5d5aceab3ff3133692dca2273206f53774d9aeb1eaf96ccd943e5964f509fbe20cc7b0332066567bb1e07d9f74bd667482fbe6c25a05a39fac8557091078a2a361272b181f00ae86c6301c6a17eecdeae5ce34a17e7d2e26ffb08bc7e104744338d3454aa655d28a28a2b6d88fb72c32b48911c9329d47f906b70a19027ce263490604d44286a35fe78fee642e20e5723f90a5074511ba1295af7beade863680507989859b30bdbac1cf638095806bc72ec73559ac306d0f4f1f11a4be2970d3e145f9a9fec35d3d4c417c358e8f73d0ca4c7282168c6ad9b3012782b7679f48254d37ca0b23916be3edbe4bd4e82a10e66c8d590766644e4ebbf37666440b47cfdb74faeba3a7d8e519b1c63dc395d7f33c88a3f714f173ca63b2d01368e8432ad73e5685c8ae7f9b6257603a993770ec316643c5e78208951fd06a3ea603b906a2fbaecd95c93c955db72ea35b58924de2ea793e1d184e424400575a751942e6e479391105e3ee7d16b00c2297a73bfbc7a775c338b02d90cf80c25088702e3cdf746710cd54d6f45c2cd825111d9ef8f8585ef79d6b997ac66339a913859bebdd15248c178aba41abbd9110fa3ef399520d4141ad5947d06a7fdc89610db252dfd25d2971770b65a84f09886906eba84885bbdaa378aabca8d1b12f19c91838082e328ec18f79271a264211a568f73e687c15a9f0ebe32d70761d6e6f3f60c7ce859c160590cec8ce473d4b86014b0b2d04605feab9534074319f75af33847f7295afb773b7919dc55a749c3c6766c43fd00ca31053a724455323b136c8f782eb35c88ed1e056a806f8b1f8862907191b6f9d81a52487f536e64a02fce373631d2c65087794e35432cd2788e1605918a9acdee4a0ea40a66a77c8c8173275c5b430c5c87b04f9b11a821dad381b4bc6f618ffce193d4b4a0bd8ca81697891bb704e291b339bcc85582c577289b3a5454bf5403700a67a4f823e6b720df93c3d54e48762d940a6cde771d96fed82a094e9de7f1d3c2ad59dbc0007172e5957ccc9b07abf7f1aee439778f58111fb42b0564628587baca00d17d9c3ae1bab4f2ff553ae6af6dfd267e1be5d6e95684d2ead41d1eec1666f449c1800ba16f8fba8f5ed6c8ab9672c0d85b66ff47aff42778e67c5022c7a01cd0b2584e0a204755ee05b9bd39fdeee8bfa94303ce636bb075a6e362c806080b4b1ba643f81cb25d42031b3435a19c00ab0f71aa6b56c513961a4c3595b2eb8f78a806b2114c528c4a2c83a113b23ab1437c58b6031d1a4a87a26ba24dd910894e1fec1bcf07de38dd5adcac8ea4c627ec3e78aad94b2532f397bef4e57431342c500efc16bff458b7c83d0f40e5fe054b4138e235f27f34a6f2bc3da0501d35b8ca41ff27e9c110f373bf636af7bcc135a3014bb9c39ec05af20d3a4e1d514daf651e72f335e5302301178ca5b7f34fdf13084dd36fb460d4112d4c416ce797757cfa44e530d3bff7a4db06c985004cb60394ed896e6f8fae67eedf148d5975a57e7a9df4f5382c5a6b6b1a65052c599a5cc67246b83b22507e22f69c33ab325d81d3496454768324a19208d0308fb3008549a6f4cdaf1698de61898d3facd71c7a059cedf890975c881e2354641d5cd4450789be5e73105f91dbde73a72ef58820126f03318ff674ffeb2a71b907e100c2109a252801a5e726f94f3f98cbce3d99d6e4eebbb66722cbfe1e29daf220ba53f843bb12f4f0890484400ac770ceb85c7cc230f3399bc527503cc4530032c4c31b12ff53a5db816c834eff1e27ef412c03da306e48c6713be6299396c650443db6ed82536000de83b91da121762ba3366543881a08ebad79b6fcd2af9ea2be352c41a910e1c25285737c28ea568125a835580d6401ba9141eab90be92b90fed1f367f11cce0011729e4315985d7fac7e3a0596e4967b8f0400296b975ec8b8641f1c5c72ac770c81c40fd44d06af78c78241eb577fa0ae3ff493a418a508ed9f8d8ee63887877c9712eca057b8d59d3e233274effeed25fd05843e0b0a033f92a82932cba304332253ddfa059e28734d4cd18ad78678db7b4a4c0686a65eead17b9e9d751800332674d3c29e2d410bd55ed7446aa6abf6dc8d49604b8645d220ec67b23f0e5a27d36dda196c564fcfbe8ed9327ad277b046f539cbe665c34e27c4a6ea563e660555a91011774c6ba70a002116b95e5233d28f9ceb015ee2fa9cc28a2313f8d5e4c9872c7eee0e725ef8c4f6bee3de62a7a17cfaacc93203664ff45779976bbfc72a6488e12ae9a582baa72cc26ae7bcec6acfc7c7b7f2f0c775ee1f72ca89cd178e8c559ec0631b9fd75f18867f87b15aeacffc5697fc955be58b4a226eb93ffee1781f12d9b61cdbc22df78873b57836afa636cb21dae713f8b63cf8c0d328e7e12bff9bb1d35f3164106b62533ed89ebce4e93a2b5a18e4337258565ab9a48968ac3e6e0808628f723bd207012ca475e11702f5f3647244694fa5b7e63818fdd6ef295f65a848cf8207990eb3bfa5c2162d86c93e3746f7f323ae2128aa48721f5dfed4d6c80f02a7f56af2f03fdbcdd90ca3ef41db3b92d598177e9a48736113173e672b44a3161ede5082a8f4152aa514437c78a50687a38aa5235e68d126ecdf35574a93eedc5339bf487538bdf94a94228ec27ff513559ab06b34860d6118caed6851c5ed1df3826fb852235e375d10da023a14e9dfd038cb0aca4e8a63d3e1be9f138aad633ac2ac48bc3d41d6e6d097d5849523bfca7f15bec107a2980631e44dafa3e91404d13a26319dfe2a309be762d14d6320c3dea11209a324b6a20e4547049134bfe104aa5753709d5270994c7d251242cae0844ec76841a76d49e39963cf913cf3be4b1c72938c1de2998aca201dd51629c6a5f2d5b8cdcc63a26e2338abc92b9223230dabe8ab5e3ecf5f434b58051971f4839b4060269b5b6a07d70bbbef7acfa5ccd574e6e36a40cfd72c45b11b446a4cfc4cc454a5ad7f4e7254486251a809afc156446e5c41e16adcfc0dcf8830ba0b2b6f59b46c17b2bffe68449864be410916d56a530ee23e4150b5248810e0b46587f76ad13221f5e152fbcf0978746c287090016a8a2028d7131223402607cde01c383c344acfadcd0c26c2ae963213116d9b5e62d292ee982e041c44866ea979d6f233471c6ca951602524738c2f9ddaa00984124addfd66c05e9a6532276be740d4b14c475ae3c8be5de7c92333bba47a027902201fb366fd59d093e9431faad585baf52403a3d54054050db441a8463007517882ac7c636df1d839f5bd3ae7623edff9e887fe5ce23e4cd6b443d4abe3eee68d188e4979bf7616953debd002317143fe98c7883926518ab5ddc30c28486477257cbac6f8d6862cdc11bccdced1f39f2e26ae1a0efa29b139bc3ecbf6f2b139ae424567c23c5d07050d17185c2372486165f6ba74c6d9bc95caf6d6a3c1442b28bde51338c7c5bc7247bea741018dfd9df1506b63973d1b5dedfa0503c7b8bc81638a484cb0454cf593bf039fd52e62884d4c4051f869b9fee61263853b8550c057825727f67e761d8f1421ba9bbdcd236da5952266370eb4c0b69e0292efa2e2b4f020c48b189c30e91f60a2b8859a449d1e520b1891c99d44d395a5c89c0ebe3741388427099ea4ce13bb4d7139341cc58db11b3666b21a17086f56c1e3ed1418f247babb299a5eadefd70804999b9a85de46c2bac1e49a902f2a5b4237c80c5aefacb5f5a91313d8f0ff82ddd8eaf71ddc50771fba161e2d07c94e77551cabb026cdf05c40d1f383269717c70b7bc3126ca206108e36c898eb29335f13e64acc6a0a2d25a53b1cdea0ce706a11afa1d7b689ddfc3e31e4da11b3baa09ca897ec92c04588eab7560baf14b88331166b1d7a539a7921c19a8a6575236912aa05ee236b49db058f0e66681a5c111441966f46688a42ca5459baa4ab484b703c4512824fcc2bea0125bf9adbc8065fd776bd00cd8071d7877e6d377a5ef0025168a02c1e1341d285a9df04dcd4f551a38b85b23de7424b7495c5e14cb4176716ae8d513b23c572fec96b5c0453be90bea3860c9434f58e9d16ae34d47d2f8a64788d5976cf7c6c4ac421b975a68906817ff409c5a12513427c8869e71449848ddf24978e9820acabb718faaa2f6f57eabdce964f8ebdafa9060393abc04cf40eba50dec06abd028132dc30f7d605f75c5a5fe2dd71fc7db1aa78f5ab3bbea14c7ac3932ee2f57fc4e8dddde5ee9083f5b36cff1ea0f791fc54517d9fd98ec920c1a2d71a8f851c0dfda81b7e6959d6ef9571d755531185926cb98a10cdd590ab81dd1e9ec07371f7689ce1913c4c4c02ba210eae2400b88b05f03e0ad4433fb81236204440d8788691b6b08c2585108498387c6ddfdf54c5b609d41bf641a555961481ecf8deac2b1e85d4c431acd77fa14a19543f8d0b8e8f306ce9372335b77fc70ae8274f8005e2d2aaafdb9fa8162bfd4110912c0121dafca7e2f3fd548ad3a0c2f7a51d3f71ff8fef159fe02553c0ca97fa53ff26818d047ce24cf730ba51984c432ded086999fe353e82427e1a55f72d6a04c2b77f040d14fda5a975a9d4a79f8aed8806a20e85f3ac90539c80f2e96e888001fe4c2bb1ff82405c4b6c8915d5e662b49594e63e14c523b1153646d2323b2162cac32533f72508ad53fe067a3d98aa2e211dfa7eab5260bfc25dcc7ce5b8519439c8649ec83752f21cc0b1f56390849592ad01855ce298024c4c00387a26a8ef7eed7d61de446f3404c16ea0df8eaa7177ead9f3ab6e23fcfd6f85159915febf7d60ea37b30dd236d028dc7ab6c8b0a05ef15ba497db74085c0f02ba9711d29e51cb718ae341fe5179ac36fdba73e7fb6cfa6a3f06b0b874266dc1703992c8ee110699a4ddc47f19bfd4227e21c9a68913406b7f00222336c0fc5f8f14d6417c0cfdf755489f8ac17e0e0c5e27481e5a0ac495c5d961ade2f1c9dbb9b3c5a0abe6572a86a0fe6a925b3bdcd7d15f992e01b4514b6f68e9114629a1720016e005fe95af03b8ef669ebab23edaa97fdcbeb6ff940f23b42fed287ee307cf3e546a32fc2da048722058719cdd637eaac6267b7e25c16218424050cc340e04ce9a5eb342b03ef8cd4e4c78c4cfce08a5b217615f5cf0af69814bd303fc9d5803b0948084e8516148809644007ac47ceaad522948028e4e01a937b4d55a42f39b04404670050991d28c10cf206d85c7b44c8f65e180683b3919a80b05cc81b300c43324d65cad04dda956c243eab0ae5453d93a47da6bf32b765cfa54f726fb94517b4dc17e55f32c38b2cac09fb74616cec0953fdb1bf439c6b743665410f77c20a6222036cd604849865398f6b60017a23ff19c964677d7746b4c5bd3325e370b3da48487e09cabfad6c34ba3174cf534f9d625828b56e7d4ab38b8baa7a7a90dfdc7db150842b2810932329ce2deba204d5626a7a67895049e374d44825492451fdd37e0b74eba809f318b326a6d0683b8b8a243caa1287caffc17ec426d0ef8d6bd915b3c4330597207895357b0dba86bba8819fa393471c8cb3ddddff8a3e6726d820fb2e51e4b12d14fbdc039e4383b8d029c36fa064d7da704a571b5f0e6dab81deaff3d9fea0f279b831e015549ac4a1f460d18abfab04696e4b605cc18850c515cd08b96c5a2df5001b848c1d6fd0a4cad1d2834a3a585768460571d7fe0b135aad4a312f611eae87bfb5670950d7becb151676c99bf619783ca8eecc16eea9e9e3cacf87e60987684088a33c09239d9655a16b46cc836b24291ccfd43e5a1cf6d932dc12a5887992cf2f62959559c5c8876b3652cc27d4ab8b198fe54ff93b21ca871b3fd333eb2d443d7fda1ea021db462fbd9f7a480b9acb80a2754fdb77c16ed2124cfbf56ac4a5974d808cec9f2111b599c19c29ee8ffb45dec24c4dab16153ae008996a529b0c7c8613e8a8936f10fe1a1c3c8c8ff3a908c595d91fd036458415d92891c38d9a256b23a2c12f3ac4c43ad90943d7defe10b3ddaaff2bdf013b34757581a1db778a31e4400f8e1d50f6be5f5f008273375069cbc9b41febdb76485684b2d2a712432225414c6466c7c227b94e8223bb2f23de51b76b1daf7acc07561f130be14d630366f6a78ddd555a8e8716ca2a0aa45a9737b356e61e6b4212aa1fd8947a0946949a1bd3fd10130f0c9935d9d027d0c0bf21d273c0cbbf6929faae06b6f6569833a3df4f6bf81489751c5b9f9b7f1db67cb30cbf905b615e01ea4955066de4196e99442aba99bfff76c8b52058d41f87a2a26d705ac49244e30d6278bd99259c47bbb986d45163ea734aabb373952394f714f45e049dabb6ea2345331f753eb5aa69c4247439b27c4c44ff7abb19960e4f3697e864d45fef467809d189cdcf4f7a8b99b877c887202b015e6465085b28fa82503b43de1cb2ee50c1b16eaba8241f8968a2891abfdb3ced80885cc8bd3341c032ae8c190f4e427b744744333ee18193a58b1f2b4cdbda9cf092bb19b0a42527b68733834ac183136587298cd430ca833924d6304a2659222e0a5f6660e027d62491a851cc41a3d7b535cdb17e3b3b70200c0b8f75e7934a1cb86619fafea705d2a3e0734b55cb8911f16385fd077a125d8e043aab70c268c5dd4d65d0d2980820b928f8ea489c35eef4de23ee31a430c573b69fbad09b856405dc3d2dae448068e187538e350199773ea2d41676fa4514cbda59f587bb17eef0347ed177a8ac5f0163511140448d27352cb04c483bd552405ba7ffc7128fdfea3d76d17ba8ad824ac9843f65d711534b8720cebf400a3d5471de4b48f136098527b65351c7c749a697732d57136570ba3437017f26fe2984d947c9cb3d5aee0aa2888863ecb60732671d87e8c1b416f3ccaf7fb0e6c9bfd07bff0cd7989d94d2f89fc1af297dcfe9c8cdbf18b70b6943b890924b965a638f50f90b2e2496d9216f13d630d3b3ef729803d80b651be4f0547ddb220889e99507bf513d40f4825c2a91ff27e4cd6b8817ee47fec079fb9c68ccac6ef6521fd8c8ad0da303ca5898274df8e330eb8e31237ee71c30967dce080abc0253e02017297a2a7244eda01ecc5b19b6f01ceb9ded9beb21c81754765b5016df71b8dec9d6f4ee776ea6bdc88464cdc903d74dce023a8cf377bbf6deb2c2da7db05778098a0d9eedb9495bcef20b6982142c01b2e0bd13545b205d6950edece490dcf10f151e7dc45457225341b506195fdfa0cebddfaa26a54894706da25c9f071b617f6630127911e582deecf2427faab7a9a2ec0854a0b7f00f563fb8b187b8f32c39fb18d11e789305002e4b543b4ea8c8517b11a01229013cb077ed299aaf78e18dfa3e4a4809b783a755abb549a8218eff418beb5aacc8e8835197bf8d5e8fc9dd66c9602387da42d039efc6d6707bcaa5fe3f56bcabc56df5e4714b89b99e54bd92f09ce9a28a72929be8c173821627e4ac699bf84be595f1e356ac6ebdfe2f2ccbc471490d453adb6c45d91346d72823aed28e2a95ed2bfdbec83b5fe8aa75082946aaa537e6db683a7cc2eea64f9d82876a6c6f2ad653f2401978dd9ddc939cbc30f0a0c9fafa58f40141610ac1b89e66d6317ac544e4bad910750e63a275654b53144d95843f95a4b2e8a34479720062f33adfc64a414e56aa3a54567f07b6f7a7c7e5abcf90d10ec39974ef8283827fb65380150f71781cbe677d879d1c0010469d035e22797ab34a8cecee31a2090fcdd6e3fe0f2158c29a60b9d94623d6092ffb5e5e2db9201e82f85806520dea93ee46601397e60e43f7c5d2e85d000b8ebccf490670718535da82bf839420fca705856e0eb86b6fe7e31a36e364b469b34a85e8cf26643b5ea502c01d6bdcd8b313eb942b8323ff97fae24f5de86170341b1e73a2c509eefc63ef4536e0e4ddd8b0f8d161abae5128bae5be15947015ac29ea4c2c3a3490da1b060d52edbd76c7a2c7be0adede3f9998f723cdfbc43a96cf3732e2013d9397aea678180f619a90211767fe3841f86dbc4e9cccbc72e6da9a0f24d8de73f8dd29b3387cab1f51020f3b89b32ceefa10523a4a6071dfb4728c48d92edd5ddd3e90e0e8da93e8880dc58dc44e1bfa57e2c0ab000ed46b60fc4dcfcf3716ac4f7c34f4afd5814c0704141f6eeb7aab8f4337be7a22ef7c86ab6dc40926962991073414143d79f1123fcc4f772768a32c3f7e1d27a71a0a860c72244b60bc4018f8b4eb83e8be4376af141201f50415f61a67a6f85407301e711a92a99e21c13010cf1e950b8a006b82fc3eb56328d7657ec0c508df2060c449cb013eb90561d1089a22e4252869a53067a5bab71e376d663cf6234a618f91cc1f872694c3a97cc97ec9b2702646af618bc0524e1f66216c00d0169d53597a21aee1d91eaa9da4a4d6c27f5bc063ea9b0fca6a1f1acc22c2ede8b2ad6cf343b4faeae116088583434f9c244aab6812ce180eca0f7c3848cb972e13606be1016cc2df79530eaf78a5a6a9cf197f0034497577ae6c3be4596ed176a07fc2950b9b004f4fb1ebd04ce4664f85f640754fd029a37e6705d40d6554d079930b6aa64da01ef2fd1fb10e80389af4e50f9a3cb95dc197031eb9fcd6ed245d2901fe16d41582b2e430ebcb83bec15771665e5434fddca47d09895132429119ed1306ed15e9e6f8d65a48db45023bbdb965b4a99a44c0123070307e60645a688e245cf45a620f2aa0d3cf3c0e0070976e9330f0c5c1f55cc323273b2a7aa33cde69a5763599af5cdf32183a5d154fd6c68ce7fe3b26cadf41362995ff38acc1b74cb30f7074e6f4f03cccd2f5c802a428e54c58dce256e0ba248102e78140c1999c81e5b0fb2cbf0a3a801918767e738d945afc6b2aa53ef866cb17678301543c479faf507ee70e3b22a483d1543e8e97701d2cf4f4875aee2611ee4f1dc8aadef552381431981e7f5fad87a9751ca2938761979f493679e71e2d16df00c138f268f1e673ca3e4d165f476f18cebd13bc633481e69bd79e95a5cc24bb7b28997be01f1d2436d458a0a5e7e41b4084351898837f508da10d9440f407026dec94d9e89735cc93339c77557f24c2ef24aced16ee44d924769914a443d8236c4f660a5d87246de8c50b4c79b6f974d7c7b03f1ed6dc5b74f157c9f380d59db3d185fe4db53d6c14ac4b78bbc928fbc94cdc17a846f1f792f406dc8b76fddc843710eda1ebeddc445e7a095e2db471e8ac8c12de7db397bf24c3c1bfc12dde4451c7e895ef2e28c5fa25f4f86fc129de4b58b5fa28fbc8ef14b0423c851e47c4c024a276a3cd966269103c2cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd76e2c30a4b8e4a0e8c9c544e4ace8b1c548e8b1c16f77250392e7250724e724e392639de97639263ca29e5dc1c52ced79243ca19e58872ba9c16979c2e87cb09e5b8ac9013cad97256602167cb61a1859c16541d274f8684a2ec49ab66b710d78946a45b32999c4e505ca05ea4a460c4705aa99417281754658505060e85c5504e4e26a6128ba770da55baa491c8bd94e8aa33198a3aaece5e7ac8fb5eb8b47016d2c2976ebf16d4b3a77cae972eadabc5c5c5c77e7bc56a9cfcf6d270b617caa7f05cae71f2bcc249c86adb48c6131a8e04bbf299c81480f8e83ca2d39b522aa9a49246a7913aa595524a29a594524a69a5d44394d293a7d4435a70ec02c680bd758e73903d925f3922553e3f3e31d8ca135265e4ed0f225265bd890fdfae60abd9db951da962fe959195cfca6b75e4ad5d19c2cdd1a4938406a6239f303b5232719f0a8caaf8bcf599cd39eaa56e503bbdd48d7969082e68f2719db7eea2a614bbd6f999c8ecf5f441161768f2c159c1648cf4e1adaf746a5e66b2585c350fae7e4e0fae602bafcf41030c1d5466bdb20ec39935bd140d2995a05e594f39b34445aee629e9d4352f255df31e3c58d3595c2d9392bec262d33229f9a51c305dc5a5abac7c3ba8d72f25a5f4509e7b7605b35acf5ba72a61ca900bae565e6f9dc5056b808ef82b3d3b6f5788bc75b1e117eb2324aecaebadafb4e697a2a1b2b4959a1d2aaef2e9c012d1a07d2bad5e59af9fca8ce2cc94149edbe1b0420a4c0b1d93cf044db2183d36381fa0a1a2d66c8e830eeb5c49873a0f96bda1695f09a757967aa59e5ed9e9954253cb2b2d912a6ba2e1a467aa31fd70499589c7b9f4da44535a626a99685a3246fae944f221e9489d2b3d130c27c429e9987a7a657d7e259d1aa12d0546a86416daa48fb738b8e04ad05b134cc6706edda4734522e762c74999c44ac673e5c3d1cee7878a6656466ad5346bb72d14da821bc0921902b4b80104759d48341a918c9044332b1f233fab232b19c7f8c5fecc5cd10bf3573efc220a6fc94ba299950c003d0030994433ab2352653310d224ee7643285cc5a4ca7e2b9954b1c9a9338542be6ddbb681f757486e50fde6ab990be74e1d8a6866a5c4437114d1cc0a8954d9cde56f1f08815fc9a4ca9ea0a0b8e8564644332b18bf58ef6999f9997a4ce13485bdb2ce8345bf1dd4b54f46afacb3e886e6f3db315dfb443c5c700543a5bc709312544a0a2a8c00c0d94979818a11ea1091312553cc2413cdd8308d82b8a615f556b15e59e73ac6e6d208e4c08758d363560c1d19c3e3ad0c31745a2686ab57d66d2886ce1643a786ea63b84470c118aeb7ae62a3822363c0183a6fddae603174640c18238c614d3a5265bdf3158ca56673965628fced93cd4213b4b244c684dc3a8b4947c6a84a5c3429913127ae09385d9049ebc70ab126b4deba49d63293653d76107e5ca11d7eb1be322263ba878f8c39f989c998d191954cc69cdcfa0a898c91542c0007a9b2d65d78e00ac95b47f1c0d5ecad9f786009e7ad9f3cb014be75130f2cc1de7ae7e58822cfa493637e690523796089662bc14c356d0a1296964819cbb2cebd7806bff5928fabe7ad8966f481a5d75b9cb72e622d43a31424634c406eac65986565771674675766f29147666f41ce6744829b72182ebd7330b63a0f871c8864a193026b934fad71cd6c640cc8b1fac356206feb119da883917291010719d3b9751d3246e4d6739031d2add7d032d5ad751ad6de1bd2403de52ca2613a8c8f668990f4563e5265b76d8b906f4252cec2f30ae655570562f3d65bc1bc9511a9b29ef2563ed200b6a657b6d6bc75938f6d49950d997cde7a2af4d5901f32f95837fd5837c5ac9bd458370162dd74c4b2b894bc3505bd3569bd35f9f1d6247beb212f178cad576dd5a7df123742ed2129db062965cada483dd2508f3534467982b0794a2975abd519a8db60908d50e9b4beac8f1f3e3f2900b20af20410b2203f822811e249c2c863c0fe05481f5de787cbae905fa47b247e696faa840ce5dba98f368b611e1f7ca80d25427b623c3e50e1410a0b797e38e241fa33a3bc7fc4cd8334c837a991f021486cd9bdaace762ed6eab536951f0e59a7b7d3cf07777a7bc421bd1f47bfc7e85bd40c391284d2e25c3e70d14a95acf73bd1342d478d98d65d5bf5b3213657b956a83aa76975ab5554b99aee6d0b7d34a8378f2f6413b2dd7b05d359cb6c32240f724c8bd11ada835eda6f32f19c2bb4048e9d5db83979fe7041baf34c70e419d35f51f0c025635a7ae48da34794c7fc81a58fcccc5432afd8bd170e8d8d66a3d968369a8d66a3d968369a8d66a3d96876a294524a9188f103e9101f43916015c561efe4a77777778e1a33dddd9b4f9c892ed2e282a3d8c8881b5fc091cf4b8f1e685f10b2b9102b9abe05e1a54fe728b5a23947b1cde7bb40ac42dcbe0dd6379a15f2f84242df8e1d58f287abf9e6d2a74771241d826346b29112a42771e2a56fb06df6d23758cb98587b37d80693492548263e3a384af2729ba13ca594520a820749a149125e4997a04912364912b6491293242d2685dfc2832649f8e4e2538d6499c0acbdd704c6a20bcc0809f98d6685766a0c10e7073be15c22224061362200c3160686092ee41c0a2e75aede55bf321220652c0e8f8f2055100fc27cfdc00a1e3cc0579e0fb49edb429cc7fc9281f043d143a9183e140a9b27d319239522ceed73b00fb914bd103f24bb11d8018fbec957abced0c7ebce218fc4133fc11c5aadd6eb407d64ad3d8aa66b9a735a7f38dae5f36bd4bd7ef4c3d1deb2a7fb68560f1a6b090ccc8f2e5b61abd50252d3030bb4b65bc0dcdd33c65a6957d1021342fc182244c18f2ada0431a835f0517df880fa80f130052776c0b29bc851d8a20822a270c1112784b0fa882876504b206b7c24317dac00885a6bad3e6ab89a1e50a8a14e7d8860f3d1aaf17104f591d343d6d480e364f0ed2754f7ccd36305cf3df3f438c10fc72e31b2dd6e6976770c75006555cb2faed20fb81c2f708e17e48b62740065c5396d9531555a8fbae2c7bd434bd904ad9a5bafaae84651bdeabe3266523ef2f3c3d133ced994db663ddc383bde38451f8163d68d50e863cd439fed558b78b8d6439e768373fbed50f5aa6f845cfb76b8143d8059282150d3ca40bd7e38e6c791c54d3ba3849130ae439e0db9fd76a04212e07cfb7670425ce991c5a2054caf1f0e3aa78c492880c58c8c36a513469086f2e221812c86103f0a49508507f9899774b6e4e961072fa577ffc28fccab1f0c899a2896401d65dd360860b1005a816f9f9eb5ddd1b5ae9b0dd85ada6ec9b567ca49234a068bc1c880611d38b870a70d148a613030303035c8e6a44e58bee1a9b75b29af0a6edf70fae81393d99096ad7529e5b417a66b13ae7556ddeeba053bf11cceee8e91c3b736caf842043053afcde30639f8e944d46a0c1c465e55910c2d030f1c3c75e2278d33886319037617396619629e1b9552ca2965adcc1ab59359c42af6d92e597aa07d66d168eb81a7c70d019e7968b278d3334f0f43be0ab1f51ca993311a00619e71e855f4a01a64367c248d5ec5703ac0023d6c50822480a0c8107860cd0fa65745c094e04194110faa8a785006091e641f221e64d9c7117c0b529ca008cd12542ca105ab817cf4e97185152d08c10f588480c55268d10326f4c84006533c410052fcd4207644881556b0a2d368191e47001591c288278c98410e8b034718294209456040050a58d16b68191215aa18e24606419af8002b4201044a8e5042084978410f58b1f534e40e9147cbe984208ce821c8338f0786bc0f9e797890bdbba85c1f1d053112bfc8ee59c460fc0ffc7044efe7a7dedf9d1e2ae2883e1f47f453bcf143491516172451c17125f697b889b6b8d1394ef4832b5d7ae414c04fbde2b8003b18b7dec18303d641ed032d37adb5de8307cb7e3d42ce7decd19b5588f590fd7cb0be59eb5b0f6bbdc7f6dd5eb1f7e00f656f73cf2c3876e1783bc1c5a16558ee9031f1ad565de5ed551c18109feb67633be2821c4ea7d13db559677518a962f61a5b4a9844ec130760bea2208721a6c6506f196b3feda3dc8cf65aadb34ea7a19d73ce6ddad0329b4f8f413c630b96913892071fe4103f6538fb4d8633c4e946d91a9e7ad844a4aa7bbec306f8cf6fbe186708179caf8f73bee6901d1913ed4b8a1caab0f301782652851f9e2381ad437e9dde1f8eeab67e38a64ba7df277a41477c194535e61783dc761df2dba37ce9f1a5fca20442fb4f4a69b7b5dd5ed75a6bb3802ebd59a71fc8ae7dddf5b3cccc2c550ef69c48ba89922aee584d434a41cad813e09807d80fc83cad20e6e121c8cb4f87fc0ca05e072a6a55a042eba3f3883107278dfc286284e6b9c8144a1eb42fa7903d1799c2e7c119bc6a9bc3097d6e85163aeb316ba5528dfa9b33b4bbc22afd4df6a4a85b6d10b66a760b719d6844ba2593c989f28a8a30707282e202f5222505436585c5bdafc56505165a58b5d032b24a359adfe417ea1d98f1fa822b6568acb3a3246de1398d85e7ec0acf6dddf45cde432dcf71df739df79cc89f1bb13c475a79eeaa3c5782f19c29f59c49ca73a717cf9da0b878ce05aa071c6e6cddd3732926cfa54ccfc1283da7729f5b61193de7a2e7bceeb98f7bae25f49ccbf6dc0af63916b4e75aa8cfa9e873abf91c00fab900c8e704d06d1eb3e68b8a4e184d89c6c38dfecc2e4c1973e8982fa495a221b2a84716fd6a3a16f5547bfc540ca46f277d7f208f17c201fad95e7177b71338760167943b9206dd135d905fcf22017ac033e2d74de097ea1c4d7ebd73eb3c6df805c7ab5b7b2f0ab523dbd1bac7e4337da34f242a7df7eb9eee99754ff77cf5d6281597fa9435b2a6439ed1f9c9abb7131c338b6055f5ea72a7654e5fcfdc413b9ad9b8b016e5de1314eadbf9da7dd3668994b54cb417e53545c3c9c94f9c59954f3c1d3c70e228be0305c5513e1d50769c388a14d938e1c14ba46ccf7ac637ea449da81375a24ed4893a39040505050505c1c071cb548d7b50f6a250aeaa8e12c405dba66741b3356ba66bdab870e219fcf2f98252f6d5656d8353bd75aaf7ab7aef74871367244d92503d47aab5d66aadb52350c2125103452541cc410208b50902cfb431ca90a8e93e7a1be1c4e8a34b69ad943c36fa45d558f1d6da1b54f5639e1b9f7ef3036f7ff203dd646d1cf58083e13062c789fad97de4a6d7df9de92458eae8481da92375a4cecba73de4d33b081c337d60554dcb84be8ef54ab39b0004f060bf44d676f7722854d7fc1c72b5da35d105edebfe8167d4af8dc02fdfaca154dc9e6eedbd2894bbf4f919147b624fb48936d126da441b1bec762d4a934da732ec762d4aab322c7851f5533d4a1031d92c68b6664dbf78b0a677d8d3321c4e6f58cbf8f08cf85d921855d185fe62f86400c04b1e24c1e2037c8ceee4d27d31f0dc3eab841b5d8552cdd62155aa28608250841c3e1ca48a1fe4d90c0197c3a97330b48c64d15a3f0a84fb34a4e635846ce09c06bb857ce32aad1e7b7673c2a59e669d86ac31bf78821e20dcf8214f46afd87e9d05c72e9c0becf3d9615a464a5474417e30440254af9ec233e2a7007ea90ed37121192d43722679226bbb7b39142ae4ae523d88fafae5d02b134c6a44f455295cead3550e60907dbed62b55f5f28e4b43c2105d42ac842a339e81025bc27446267440ee99092085b8d4e3339da167e21201915983d9b7732b3db214e31101cdd3075b6232065ce9d99131a09dbd30f2608b92174dc810448becdb5b565660df1ee5494709128e3c41c866d402d707aec0462cb8d2551cdbbe43363b241ccd6bf1e9954a129519bf8475a5a7a5c52f0daef4acf4f4aa5b622d45e09618cf882d5bb424f96eb9e27bfb5a2c0a555b622e9d6f074938dfaa2142362db1938ecac52f412ed812fb7e11f6782f5efcd274a5e77ba567e58915d84a100b8d94a1382b464410d4125b39b2225b99ad2c59f1f9763a634b2c94c918f0c5abe5480b92ef172fab9ab5e490fcf0819d6062477605cbd022bc92f18c085479a8620b0a4592ef2933109d73d48fbafccb119fdaf04bbb8dcd11383d2f5a4186d0910dd9099fd091cd9028710111e2b6f3334ae8524204088c90d8e3276393907ce49f8f3123368830ec0032040023e3a30b7b5e64a992208f973eb9f6bca3fc8e00022524d08607b73a32b128c7f56d2359128a112ec9bd067550877cd247721d4ffa484e499674658cf5ee034b4efadc7e336251fd7652c6e4f65a92df80faeb96c745f3bce49927089f8f22d2c7d18e44bfe45d6b9d8a1a50df3a67f2684ceec359a66f09eb29d747ce894433a36e34baa3eb37a08c087ae62902f630cf3c459ce0b9adbbf76b510c95e4d61b7929eb3165bf8e65bb1e97a5cabb8ee4c5bff77a9bdd26920bda07477e43f7d66dbd4e1a4d3e3ddbaf932aae21b85cf5ee7ac8d60a9e38af0e43c6909cbbcedd2f0503fff517f8ef972a398e2fc5899b8ae1baf56bbde421e7f19b8f4825ef8a9c452392c7e347de0ddd8b381ab24371293cdb36adfd6a273b275a4ecb35681a47394e7a9d885251b7715a48dbac26655c82631794265cbf3da5cf4ee4f520f251d789462291c8bbce455d27124d9a9edd53360f8e5166b36be019fc94d26dce6d9b5e68ce90e65d48004f9d86a42e4f3fd2cf8f8bd0c49e453190beaf18a5e082f7b921b0cdf8ec955da6aad7761aacf7a7c31237a4b7eb60290dad83f54d7ef6ea20bfd48d76d91f5bfb5956d4e8f494a6d539e784e19a41c07ece39e7d42a3d4d24686aa666fb0de9dd2e3f10f57187f4d0773986ee673b6f06b9e23a96abd333fd3167052390a79b8cb11affb7686a5aad19a48abaa516bc3f51293308ccdc3c4fd7e471f43c75cfea041fd23637a398d9479c733681d9b6eff84d8828a5d69486524a29a594bba2fb4134698d31e6b8a26a9bfbe419d143ddb6bba71b4e27d2a68568ed64d442335ad7dd36dad04aa2fac1f003cfe6ba18afe8443d5c9d23d26c1aca90d1838c1aa19f5beb963a5327a3279411b98803cf76e888c0049070df042210c307060b189309d775dccc8467f0e9c4e564bb8b62229201c7e9642a9d8872cc4cb7281cedc9d103783466da44d48d5044396642aeb98831461bda1650ddeb974fa777b74fc60f4a7f2472818a8caa756405079e9eaf5451e9317e1ca314f59c9d566560a00fc3e6018ed3bced5ffbfadcec34cd9bdf09a011d2ea8814d25c6b11c79d330cbdfa96364a5e3ec8b21c6ae28f4863834c46b2e492edbb41aea40d3332990cbb75a12d0b8fce2117dbddd30d278edb66a36e8e99766a6f536babd7cf45fe3a830da9921f0c40c8c8738eaa572b6344d1356a0161364d47d93cba75d2b2155d40435b689b81b5d6daea3dbd356babf7f4d66ab756abf7f4d6b62d0bfac5a6da87b62c7a508b8052ad66b518f44e7b4fc35e76bd96dade912a9109c77b47d3667446abcdea0f6030f2c1ed96d9ba6bd76e9c96a9ed03c7d45aa1f0d26b28bdcaa4aa4ec13155093e61168c83afb296e91dee1ab08ca6d9e8e0a54b73bdf469998682bb0a4da6c9b4ded17aa7ca344d56655556b380424d62e7a7eda0fd6665f74ead816247c3f9e9eeeeeeeeee596da81bb178cf9fd93fb37f66ffccfe99fd33fb67f6cf0bae1b5dd3c9bd9fd93fb37f66ffccfe99fd33fba7643aa1a0dcebf933fb67f6cfec9fd93fb37f505cbc48b9f733fb67f6cfec9fd93f292915f77afeccfe99fd33fb4765c57f66ffccb63f2cdef367b6fd71efc76b1e4b7a561bea462cde136836d06ca0d940b3816603cd069a0df482eb46d774720f6836d06ca0d940b3816603cd062a994e2828f77a02cd069a0d341b6836d06c2014172f52ee01cd069a0d341b6836504a4ac5bd9e40b3816603cd06525971a0d940b32d108bf7049a6d81dc03f216008518c32662e4a54f1825a24d4d6b19b5b09bce202fbd4e1c6d4e20dbdcb696719bae5a63f6c84cf6d2b923ddecba96b18b8542af6e0891972e0a47a42177dedb32de1749345392405e88d2a4393e9927272de3097fdd7a75cc150ee18273f682563bba5e4be2489dd78eec99853d309f58bf5a12d66ab55a2de91393cdb4d7ebf57abd5aad56abd512ddce744239cd82644bd6b8c21e984f2c0cc3300c5d2e97cbe5ead84be2bc5eafd74be725772a9dcd66b359188661e872b95caed7ebf57abd4c5050292661ec89b0e81373856118862e97cbe572756c16245bb246ba6418866118ba5c2e97cbd5b18e75ac6331548b29baac0d4ed479d51086611886aed0e572b95cb127c2a24f6c7618866118ba5c2e97cb05e36b29d5c0b2d882097be552a9dc51a87ba34dc4893af115650cc3300c592e8c958133ab41a57247a1eeb5d6caee8cfaacd239eb399b73361ac2958ed330d22527e325873d30e9dc32b4fb404b3f1c0a83a93e24aa217a0a2302859db48c5af42322b488b6ad65ac5c6480106e141bc560408e455738933830ab81301c8bae50e2d0aa552dbac2d9a495d6982b86934e1a5d3d5d4a29619e256914bbd1594a297906911bc873ffa82dbb7b76a4b15ded34648fa468249cd735b4475234d3dfd1a3289a5f70f1f493b019290a725c415b31c618233572518a40758c31c618e36c28eecf586b8cb1866e0105b08831c61863a4536815a5522d5eb0888a1e551126ca881ea3a8868b6f25417a8e502d711c58c529f1cbcde1461af483cb518e50783cad41351b6fd8c0691c191344ca549d1b55677bd19cd8512a868f1f88818f0e932af627702877c6a2a0746c1de97befbdf1933120a0cc3967bb58b0c1ba8667189132f6b623f956c925dfde2e9e7eb20291517fc0a896f8c807176c5777b541792bebc18df52bb8039581c9181709902b1aed7ae9aa47549b19aacdb31c31bf6c384484491c11421389a049822609254e52a064043d29782205b1951100212283273c139141159e9d6b6cafbd27e524828b2e418f46dcee8fb26c09c4c8cb94979204a343803441890421e56c96e084f18c9397dec9d34b182fe90c0693992d333333333333333333cb1a729c16524a39839c9d001a324a10d80fdcdcb78d6d4754a4d1d4d341493bd288cb1edd36333793947826e94855fc00c7524a296527a72c3299b6536fc741bb7b5a66772d6efb0c30485502d8a3e0f9b3dfca54abcd39e79c936b5a882c3033b34b0bfdaaa7b965d956422a1c8c2e254a19bd60ee98992f33a35819dadd26a793c98909a5e4e2a2482f4629a25407835309ad6c2cd635af7eb465baf40a9285d842c7cc2db0a01a9d1041b31ddfaef02ebf69f687fd389d78a8c46c190b8292a19901000040005316002028140c88440271204722494ae30314000a6e8e426c4c4a16c7025914a5380cc218c3084080180008010a1499a92902014a448f118c931dc7cf7e8c1c85b66d77dbbbf324c8131646ca8dc51166d409c43bf800de9b5219030961805ec0716904860c23648428f99105bce3eead663f43433b3b167214ff08595fff49d00867aaac74b4da0728ca2253f7c0e035aecf6142ad3143b35c7b20b0be6ff98ea0487e891a01502746998f6cd52ecb8ac891b6d9d91f3bdd7cc8397af52232a090b44b69f6cb526fa7c4a76e77fa0b6e618d4d074a6ea27c3599c3fd85350de27ec4d2d5ea86c430e85feedc7685bfb5b8b6cded93a5c2bb264ed4da70d3217d7f4212652139bf9f022f576f1ed7c205b93d48fc3accf411d92cef04fe34c6f7f7809badb6e3fd80ff4807011678fd7e56b9221c3d4df03e6fba772ef80930f108b6eacae6d0cfc965ac4d80d715d8688500e3f89f9231120c3e59361970bd8416a53775017798d08977362c3c8d390da7973b5f11a8e645b8eadf7dc71f86d9028259fe1f9c413237b60f11940c90957205eab98ef4450984cc1e9498494990c0bd99639348da18a18b9e959ed9ec852b067c7b4445979abf6da0b14e62205bf69b82435051a315de042995fc4ec09f872077555096e76d3ade58362cb3b626fadaea823600ddda6d7eeb968124e33308be51b51cb72a9d30e037372503b9f7e849b06e57a4fe8773f255035c42bf79670cf931b077140438e100bc3bc05efce681ff116bd79933c087c233a1b29e006ae881880a23263da69902e970a74743d92abf2cdb260c1d8b7a7ecdd8de911ce8d7a02c5ff4f5818049d6c36d73c13f5eb8017cb62c9e1e3433b964741907ed86f30d362b3ac0cb0df1b71ab1461b7340fb3fc7a341a9a44f087aa92d4505cfc8fa82935e574f7a800c2b426b8c63058a910fa2d4a8e4b2fecf488531fdb49eb334df85edbc8fbce2a5db36c40eb76dc9c36e023f6e7ee038a84002afce0c2b3726a99e2be882125e6bfdb214d4f366258218e2487b4758939fe1b6e2664ff2a455e3d8acfef1c62f7a7c03d3ff021a7428de133331c082b91a8a70847b2bc7b6482516c36830055b32df65f6b8df65b4b10f3202148e26746fdb8d3714138859f1592754772fe910a5948b74c2cf880f7561e52e427f46bb5714b1869aa2c9c704c49094468fd847b6bb08b94b0a4b22b4178e1adec61634a1a4e2ca48396ae66cfb38165fc30be52cc201d6ffeb094142534372bf44ec36326fa508218513d226420347ebe95bd77b264745e8b1ccc952df331a07264f883d5a61e9f54056b11177e2cde32a57ad6c4000630cdb8491e0c3c22bd944b73572388a859059805a057eb68392dde65174fed4c028b1d3d4ad72028dfaf2894697f4dbde797dc1be6efff575e6f5754bea75b1a3f75492b81b4fbbd097a8351d4fdbababd754dff07748cdb8b84dbde1fe68db44a50c452101bd3fe87ff1f71d39a30613b31ac898aa1ab4a3178e39d5a248342f79b363bd0097c585af434e90cc5fbd5c8f06c80b595e46118c757ed8188cc7a72799fe394e22bcb339311aa570739a62a2f48218e9047168884cc3dbc4853bdce320a27b785c29499d9dcb0ab4ca805d8c1f0b0d8d99f3a4d6e02225ab44817ca683a120ec58197bfd208797831830d406cd5569c15c0e0e6d824a863ecb91d054c2e3864ab6a16e2976124f068b6ef3ed0ed10fee4ad2225b55e3c6cae4729ec3a44628f6310a815c42d6c45832a11e2f2f6ce6e5a83d26e5dd0bf9fa7bfa23ead775408c6e1dc96d6f48a0f95e4ced6978686b84bc5b7fc0eb139a3dae2a349cf191202d6d22924233d6b0a5e73f9363241ee2762d01c63d91246c98334a9100b6d8f9a8e382dc92603b1253e1dc22134916c81715c41519ac5fd381de4cc0f7f087c37643d5da1eeecbbaf3f456dd0780e6751f50c876797efdfcb537e38d3d02160ae5dd870ae1052358ddc97e7fe836564a34a1985b564dad9a735eb8341eaa1bb710496ad8d10aea42b38aba1eca4dc0a951edd75f4c851371f5242939ee8702a186b980277831c218a36090fe52376de6ece30e194e280ee94d4db95c9cc9af254af37be2f67d0d7857b5db7709452a467432e1ac9b320298c4589af05cdb0a421e4caa45913228fa2e2b8fa3932d3888fba0e6e1fb0ebb6bac339a312ff5e33296e232f255975a1aaa45934fb37352c8abc051daf82c45ce9c2318d0a634b77c4f38691e11f051bbf20d3f01c254901c4b724bb316e3f2ec41e8483c6b5971380508e4552fa84591e06400cba7910c5be600a50a1183a363531051c02378fadf76cb7d78eec12808d3a1634fff4b687a31c8a7ff35c0240d140c128138bfc4e613031dc7b550af807748fa9fbcf693e12a6f319d65c7d9ca196abc3006e16f51ffd33bfe6500a5f8cd45264be924d311820a406d3bf667e38e68ddad952af704065f294a04dca84a196e68252d6e8c52d0378828858033503db5a2c4418371c7b9e11be80d84f7200485e2598b63323c6305a54dad8fdfb30c3a0e36b53e7ecf32e838c01aa2f267717f4e586d44e1adcc90cc18743bc4647dfb3363d0ed1093f5edcf8c41b7231d8d27072c597ce1a5ca00cf00620d85999dcb049c79154a4cf61f3f33667a1c706b32dc1061232de35b1910cf32e838d8d4faf83dcba0e3803502c60f20e8461f8c3c0388351466762e1370e65528589b7936823bdfca80e86b468cc52686e3470aa0624d0ea1795f9ab6a386902b0ba70892efe7f208272daad19ae0fbcccb217343fd30017e63ee4387413df1a20f7f5872f73f4fcc5206c6eb20a24ed999cd39299cb992524df6d7af33265d0735d95fbfce98741d882a59e9bbbabe37542da2f176a610674cba3a68b2bffa9d31e9eaa0c9feea77c6a4ab83af46c70b2aaebea2a5648877204295e2cc957312ae7125a526d7afdf9946ba0ebc6a1cafa0b8512de2ed4c88ce98741dd4647ffd3a63d275205581a31714f4440f66de8108558a3357ce49b8c69514ae9abe1b85336f6742d42b33e6a246d3d10707d0b14a86d8be9e6dab434bc18971ee92991934d9f6deead312f245911bf9ae64399d1b8b430bf13fe421f2d7dd17c28d311834fdedada92c75c2c7f1d205c4e81a2099f8dbe025edbbe70488ef14d91338f0bd33491456e8c4108af407046e96eca0c55f4886c00414b7c506819dd633d33c2dc8ca81089a2d868884442a5bb0e0365735ee0c63bfb75acd8b6b50fd61f68857a69a0423acdd13c09cd68f98e59612dce25aae91f45c556e7fd034e5764d9954ace6b56a8d437c93aa1f06ccff14ed09d0c3b2672f136c4843f3cbe278ded656697ada86892bbf0edf79bbb609187049e3dfecc2bfbcb43f60ffeafd06e9a81242b4b6c3fa375d9749319e679e1c743c30d86fec70f63a351cfbb5ee03c496e7e8a0423be8441f5d36c9fd93ba2a633110b27b88bdca48b0461b349517b8e37c6522406b2d0b0482e4cec24a093d510e412280f82b95e5f94b0b1c230b8c29108ce3b486a952a9373e7faa5b0da79eebec85859d01a083607b79fdbf104a779a777d7d2f7518ed29187bc37e6358ae86b028fb0ad31f7e2fbc78050b9401566fa4a5fdcf6122b37f1bf6497daca650c51ed9011a5bfa437a15c0e8366a93a5522a63b3a15c8e94cad86cf3d865e4f2b01c5a731316e9151ade287d95776c28e64008134d803ac4cc9c98e8b2d6bbb56a0334564e0979ef558ab44c71cdb28fa59d26da2377aaca6fff4128bc69def5eeb7c471745c1aaa3de9effbc88706d836821db5df2192c9aa1f63b8befe4b3b894614ecec3094d6b5caa2d66c852bd1ff7243003089148b2aa885bededbca96f60d1b01d7b8ce68cf7b4eaed836812aafa6a29c068340e24a64e36a2c4bf5ec055319bd03585e311989ce7cf8d9fc7794b9ea543cc7ac247f63cf6e5a99d33750fdbf09115623525d57df4b1c4741a96bff8152bcd39465db448a4c6138cbd783ff8eb38cd6b93388b5ec68495ec209479d7a09e7ac519767ead99962661b382f46606e0a581681d5875ad0ddbe252f5eb59ff25eee317f6909202f41630757d57af634fab602d4e695d8012611d753861e1df2c882841920b6bfe6e02e54bff28dfa19ae8b4d08ebdf49e67b756d3f908aee9a7f7dfa2c713c2a5372db6198db820c473758cb9df134f25e0c25f41b48ea71771657c86dff9609ce7111490ba5b827d73112a2a9202544ef35ef6b1e9d177188d5a93954337ffdcca79ffbdba0e847d0c3264eebabe668ad6f6e33b54e08403750748bf72c5463163e105bff4efd64cf325207b951c7e76925591a2b4762d2798cf4f4ebd9fa2de904a2910db6535da4de0a68786f03e387ea5c22b25d8b11bfd5ae00df5fc54626b11341730212a34599ec15c949a9f3de18a037d4feaa3ef1aeb143b235586780c09ed312e95070d380f4419c15ba289b7e9e293488c6bb01870ab1ccba38ce0e87aa2b78ffb2f92d23783ea9ded109d8e973e3018b4cadfddfac0f4e9a96ef3809b5dc5ad51182726c71dbfdf46a1b0a766684edc63704f21bae6e312d62e4aa648acbd73363a093e6dcd5ff0d02ddcc313b49a866c72f6a27075ffb514badea06120f63edf6b10a4fa30feefd4acaa313d7b4af86108dd6df36a5fac1e20a82837d05a2c9c0be640bb22ff959118c9e64ecdd73786d041e60c9f821363dded59d7dbdfae7456e97a11fc5f92473cce19d6e903fbce13652752f30cb4fb6daecade13e006dee9c825afdda628e6901c126abb0702c24079980b4fba1cc50e876d67bdef7d0c192277cbb234adc321cf70153c5ac0589aef661c5e9ffecc2ee4aa9c5b65e43cdfbc7bcca81b9edcc50c033534416531f76f631f1a786d86b7f41eb7f00abdb6fbdb4bc4d31532a892acc80b3cdc161300b3750c58c277028f3f71ca6f368b00bacea4568e3a702336bb671b8d6495044909e5ac53c44e488ad0c072631a6e23ec34bac9c7f4fb506d91ba2b4b7a09b7cc00be7e7d1abd8ae6d11d31c2b939e6fc521354f3a90a3021742c54f65bc7d66aae3daefaa704186d3a602cb0cffa8fb30a1c0b5d50347d391580b7ac9c2d04bb635d2153804768c99142ff68a9a20909345656cd9a1cb74039d754593796dfcb08c5941c77923f3bb43ac1960c78a75d8574eb734d901d2eb9898f78fd193a1db89c0a17a2fa0c9ec98ea0d280b7b1c6818b48de4fac851aa04c91867e309fd6143ff378c390c48ee3f6db1d029335282d98027ca21b224e5c5204618dc466058df6e03aac97644a54104fd8671a3ce4a4a6f383339b2a32fd5b689350cf81ec1c2184d8ad0822cb3c83402d33061816a49a689b047deee2d236dbf15364438507abee0e5082a9f15f9d026206f605cdb548dc54dd5121c0677bbbfab4f661b75123e526facc77654f5415b5ab46a709f8bf21105788afc0d86e907014c90fc0ecea730d560af8e59e905497468a2db4d1b68bbcaceba8bd5ce298f3071afd20cf1001ee10e1024b40110a6b7301d5821e8d1f18198896fd81c0dcea804b3cd6fd034e3792c198c46ccaac79915f9545a615747baafc2c6860aac73963f5cdc9b888705a20bec737b802e366005e5fed1ac8318ed535377e1607bdbd79ad8358d03d82925489adeaac336153d1168d97e17118ee2825897089cc8897ed7965591f7a3772561280acb75aa71a39d24fd5233a81725f14b41815eb686e0d8887823bfc85f99aea4088fa579daffe943e8b7ba1cc4d3e0f3f578b0d4748029879d8b394b04c88ddb27bc2aa462387242d516e40c3a8d726b749dd26a08a0937edff11020fe0a66e16536fe06119d186aa41eb5adfd25f54c18fa3b31b1adc4b744e0d251d6efceab144e55d779d0f25ae94fc412220a66c102c52bc065be9db60dd5bb2d8a2c32679003734293a7a7a7d141748a7bfaad96ee3921807ac0bca67b956461c723de6dac9d12282752b9dec2c0bc1618600f600359ffd82236f4bf2477249ba376c124ea29a20f2c0128469f0691e6a104d807f2c009fded0311d3d05544edc93088b92875ed9030b029020cd4f272d958f2043719bf2b9ec3e6b01a677c4b9596956ed4fdb5cb3262b301b0f4f0b864f84962b2f504ffaa8985d04eeb96a2fbd6fc5b8cad7e812d31c7a94984bc37906db42487c4a494af9c411c51ca6824b1965c099ba6418c4be46947f0f69604042efa42b530f7fedadb7f35a2f7b856759cb054f4c02f2a9df0d4c439c1b22db18479ea7b8b80966dce11ef010c03ddcd0bd6704904b3f4a508323b3081577819b9468a5828fa413e2ed8d09536804049115580dd888944084613e9bb12a51d29d24678c7fd050157242174b48cb8bac3ce437347c85c895ea53d050a8f8d5df60a996582959b2284feb37e48afeb83c285a0816f2bb31bdcaa2fe25f33c804bd1edc6cb1571344b8469051d07758e8d3a5de8e0bd1a983d5c1d4e671a15ca12da010735157ff5f59879f04ed2c2c1ec191f593eeb435d824c26d52d679580606972ab5ade0b156a78e2d1770f032b69063ccf0b2c2510667dedf5f45393999590e7ebdc3e955f80d38e736d3c13fc720f9f7274fbe0a02a360a603da14df73ebf1a5c3c973eb5cc805f3f454ee21c5fd417695ce933b8ef10b0aee14df28c0f085b468cd7bae3044d19f589ea51746e475bf50a82e03d07e0e3f8e9d3802c763c410fb147dabe8649dbfd7dd24c46182b50f130c6e640d6c46a77c925488ed27a37c66322062120820c0255e5b3054a2526212590ff5bf63daa2d3f65141190cd025edc051ac3553cdfa5029a5b6efb6f5f8a619d249b84e6a7704b833b238a13fd302539d8a6f8bd8371f6365392d49a65c5539db8353be24f02ecf13d0a211d1aeb381eb372670543451147221c3e00e60ed1806d47868483231cf98048a9a6add3d45c8c2e409e64ed4e6d7e0358dc3e9134c36032977a24fe3c7a6b0d022d38291489876d233a872b574ba921d40d7c73c3c446fc4fc4a6336b63a8be85e9db0dd53f4a7956225f5b493e95c8c5e22a9c9886c25fca8e0f822e86ae8da334ac60efda312c068588765fc74806111c6d84c9e3ebe3c300b2d78feb9864617695f761c53b997d1f67e71ead4d15029ec0d25eaa2a12576afea879ec7ca40311efd24924eb27b2d31bfa4cb608f8201ddaa430a1b51aac578ceb64d8240a44ead66b78a9779dfd0cfe0afe1d7c0cafa35ea1b5b29b542c41c1d4f3085328a565c970679fd8d2c58dcc3df414b7388ef4c4fd2aa82c5199ff65feb9604032d20a4515fd3ec7ca6935f3533a3ed1082d5da5ffbfc3a78dac78916241660067d125963bbe050ae8cae3c6d83a78cb68405a58b54d4c1f92112b44f4e8498d221ed57b204c99ad0effc47efce413a82cb9068dc5308c01bb48202c44a13103258ad98b384aa2aa19f6c11ea40a2e10c72a016fd518748347cca12f86b0945d3b3ac41bf955034fdcb1af04b89a1200817199dee950d7ae0366bad8050cc80e3e4c23dea10133dc47534e59b993560298739e183c2f625df4010046e8af325ea7a0e5c36e82b888bc6a75c83be83a8483cca36e83b888bc4a36c03be82b0483cca36e02b088bc4a36c03be82b0483caa6c09820763c70ba41b3fc2825231bbb101962aabc28f940fd65d3f9742c02fb7e825381c445553c5edddda4a3bd312ef20342c540c3909751c9c96f80c38c405acd991a7f9171ea68553d5c8b084a0aa5477c27122a2f27a001afd7474f3bbbe3aae5a313a294413bc19bd46272757a53266aece009d6a030405ad1adede116ca32637fddb5be1023986ef98521f8a1e85c2b4742f00ea86450c52e9f3e006e9df9501f0eedc26d6fe9d7dd7c0dbabb1db26862d16cb44097460e1fa953765ef06f6ba5be22c76247bff33aa338d2e1ad5b9a0b229735029499c4755de837cdcea7f8f13d430163f8c2a79b3f3c0f5b8ca8675f67945fb15cdfecc231c6cb12abd0c3da0aabbb6bcadaa2c5d5128ab0e75c7d9986e39406b073cbd6a8c80820fe123684c5a7aa7389daebf50e35b01a72bcbc0d76b52a141422c000ae1f0c2f1a7bee38564ea483086e2d37baffb484d814b5dc9e86a31beb704967e32dc5e66321ad82fb9b9712f12a2fd62ce5b06628e91101806d78035a7d393df7e924b0f7b82a45a8d6f3c007e93c115627b2b89a78dd94b692666fe62f776ef0f7a88eb204423c9a6e3503909d819a8bfaffb0baac1712d2b427ec9c88abe32342bd0458790cac4e02cc1da3ff022ab2b37e959817dc31ffe62b3caba40b49108816f6fb29075602f37af2a164ff2b0f0dba109738305843fdc3e1f60f3e5a5a913e6a4240f839ba883264b318005b3948ad900d9ccecfca4160f9c322e7033456f63dc9a2fec3af6cf8d4f0b47d884d661ae517376ced9746fae7be832477fe72ad10136983bd04d455f800163d2d39085340d0bbebf9bc0c7e61a6b7aa0119c24fcb5f59c3406577a70f01e9fdf9fe3becf69db73d1790e53e7eca930614a8cb9c3ca8f173acca084e3a243f265fc380aa485781af9f46f1fdae74d9f295487050468943a64e4454bf0364ed24bfc71e252f33cdfaa4843c58722c39120c1cdb6152ec9753f08d97c31de248a867345d53599b862d6423c22d0325068062197bbff3b29297ab95f5046ec923fcdbe10307d4440a467ad09adfa83a480a06bedea1855be448f672e6d70938345eb2f598e5a42e4c7ef694396badfb337e695c7affcdf59afef75ae0f8756a237f3ae4da0d6a8d06e27f0eabd1f28a8afa3f01e28aedf765e32db1086e827487d773c99d0ee5bbaa2c858dc10b8dab2558d22d2ed160d5bc9d621026aada2c3ec04ce7224644c653c49f433788b04ab651f3b8b58823357de67d3f3d614f691b19cc4d1220fed2196e686ab664ba3222400a934c87be74c62559225812b7a2876f15620e4ca149000bd2c66729609130e51b7c285ab65318feaa2fc530f1aa80032fc7078cc695beebbd8576213088c4e118b84cfc30748ca750ce82c0620c51457356b7c5d17a2a949658d6a87889598345dffabc4533bac8d8e2b6711a55678649b4253175ca44cbc1a9286177373a6f0e6cd78363df3c2fea28932c1c7e7250e7c75f24b12e48113468d11e1143168069593ae6fab39fc03472c7a9e8782467925fd2e939c70ea600d47e2850802409751ee26ed9504a79770c1e7f7868117bcb044ca3f3c3b8584d90d6434de5eabe4fee90dda210e30cf2660704d4d781517e1876db350ba78f34bf8686810c07eea5bd148e9f414f979208107b2f1bdc438aaa4a2f25aa5792605c3d24263ac7b412e0c7ab9233b602c10562c341387cfaba96adc6a60210ed4673b30d1ef80f32f46d7bbfe0541eded86919f17f8b032947f5329dfe017c100e0fcb6fcb2632a8295f9d60629524194e619d1df24a0e8e2a0052a38c7090861b901a48e4f3ddb89d368fb03f1f494f773cf4e671f8123042bd6fd836e210d3b7d4687c853ae5ba812656adda2a0c713d2a4e29054b6c3079e5661e63d4d2d2f232d8f69fe665f33e1541da8c47148b090119f0a416803c648e93d7246ea2acc89910c77f3d5a391dbcb612ecbf82993ac2484f6a667d323764553b0d509e73e3cb9a1a122822f23668582fada1ae5f78de31eb2b4ae53560d948886bbb601581ed54c332c520de4b0936a96dd461acb02d7fe245bb038e72231b59c9df74967748787fb72aab6a09fc3ded95492e7af891ea922acea134a5e9b3931713ea7ffa1c12a4118d3e2602f44cc5837679492bd4aab2e5d0db5c6a0d28c85801e0ccfd09eed839d8855b8ceca5ba0b5e450b31263e8e667927750f3ef8a24a5d9eaf0a4e2b07c01f42e84c8a40f2c2d33011c9683464570a0c89fe6f49ded43fb2c7224e75c91666ae24d78f1e1fff92451f57588e9dc68c6f370b255aa72fc51c0b6a6bf4013a4287648a12a818df144e7ecbff957a8ca04b2074042fe85fb4f374aa14c263078746334b001980e412e4f695598c2122d800f391ac0455d1b208eb7909430e0a06b2906144ae38c9e8f00d6707ff8d98a11b12800c001acc2ed8d5cf2ee552c3ab3f166de6687f448fbac4946e20650225e26a34f461537255c022462b99abc7773f2d27b683e3495b1ced299c0176493f3f5d8f5e81304451407dc60ddb5c4504176c4b415534d6905e1ea4c771a521276b780bd2daf1791d7803afb5b822697d1c212a093349b0f780416a956085285b7f3b4a422b204cdd29dd9ccee0cd09da036830b10e5be1f5f674143afc4738fa3078b90963c31d541276d06a6840297a58958c263ce4633bff1406aff4f0bea3507f34d1fe9af8f53172a90a0f8a2b14dc1817019026ceb4baf32129fdf97517cf5a712d0857d222cef930dbaf774df78f1daf8b2505d2bc3e0385eb8a62cd665f0c19e41a04673dc9b3bc70f29bbdd9867764455f258da4cdf0fe82a616c910435da234a0c410339b278387a9781ad60d40eebb029acfeb97a26e5bef9f3acde8feb001dcb6788f046cbd4364c9138b52a9791fdd55afee151a37474d5e05532614aa52e950db39434731de48f9e853eded2cbc30963ed58e83dcb47c39c61a20ecd643cb3297e2633432ce6431f4599c1d0d1be1e3779f3c13f78535ea07514892eb0eb9f34196f90a164387ca4891209ebcce202381a903db261032603ef3040ed40a811128042bda7a62d9f812f971a852a3870737f062daf717c5c457bf003b20321a6a67187d9ea58489c07b85d01d6d4689c189b1d3d3130bdc2e159e6ed1e02410794dbe6e119f9a8107d6b0a2d3c6e6cf1af85b3427661bd00a1b99cbd680dbeefb09a1f8a1b45e824883c5de2e08a5bd143454accd975453a51678b0705ec838f8cbd87aa098ccf7872b887074330877ed59a67a683e5e44919e8ce7ab73dd94d6337f29f5680c2c0865a95318372488f8f9e5a1e2d2efb572153b28c928d7fc1791a40f780341f6dbaae3da667e16ffe6451bc5d0a5c0bad3097671b893aa8b00d1aac7dd2ec7c82c8efee1630b7c9b721871896b1fa302e9e1666c95a56b30c3568016efa5f766810c9461cc0448596f4774607658e702cade6437271cf236dee0afdaea952d5ee39d22ba6109b359f4366701f25801fc834b52394b20916c37465401e8b3b126204d8b3706aa995019230684f00c2e28eaf06c4968b584c57da11a050923bbf6fee016e22a813a9fe3368172c28ed9cbc990b394a3753b52206557a7004aaa613d5a7600f85505a40456275a119915518e6816fe30f59ba6b358455bd84db3ef86417157360ac62454b3c96cf8c333e4d0a7a7cdcf434d058a97885be16ab178e318dda22a7b388b4b8941016c768d5a2a233389de362918d59666068320f32bbc10a5105e00b504cb1daebb680e87a2e9d418c6d4ac514a86147736289a9c77c775526e02f27173958695d65f731e6b683955847261dc54d4a47d0c408f825da72cc4fb92eaf2fc6c3bc5d1ba31ecffec89d78da8c41b63a1a76d9ac298c707c85bba7980b933761e3a391ae9114592faa99bd84a2a25c529a3856c71e23f4164126b9e1872e3ea81da8993e72ca5d1a586e0637f61cb23f5dc74323c656f7129d107ba87964b5dd8280f510adc8812eccf6cfd7364c392f7e77597b0d21fda29f423f11787d6bd3625159498fa0cd0fd0f881ecc052fa8357853857902e8453b6d5a363a37441c54623ccc5e169a27a76d4518b8d8e949549c74176235ad840a134ccdcdb71170c67c7d3f9e156d050935f23fddbc7b9cbb89b91f81cc4f73e2e58e866fc615d3281b41de513b6f2136fbf427d0ab76f9c5dac93d8ea1d2f0c57582d65826dc578b64b5dd3aef83047a51b57c7ef2cc9b167e23b2eac7854f37b9d4313693e559f43d409968bdd6b5b633bd54cacad5b34fbaaf1a739747ecdbc860c454082694d5ebac4bd4b0aa0cf0f8af90e2dd4fc09201247b92a56f9ebc4d67254cf92aa4756e3fdb89c305b75cea2c65d19302d597001e029e14a10cedc26d44f8eabdb9b02d97058b77b5f55acd1a468981851ab72608e3d76334745196a9715b92aeb44d19fb87c8749e7ddf824a0db72ae09ffeb601f9c0e3d24122bd3ade8cd1333d09b4f714773bd51dbbd11f2e83d2d7f8a9e0b9769628b0ae27fe5f8043e361b1321b816028fb743dbd1d8122e55df9edd2582a01c4ab3476ae952d2ae332ffb30295dc01930520111c717c9af4864e409aa08ee873b16ed3e815e8d90dbffc85d0b96352e2baeda7c217bd89829a5a45e7d73f83e2368656bbfd13b80ceeddbddc4c08611bb28f34e07540b92c4f9821d36523f146152c1985eb2e69497aeef03ff2e38e553abdb2be1ce7db1f611b58d93ac55671cf715854e6eda85469d93e19a78d4710caeeb7529f25c57627000f9e8b266164ff44343f6c51bf081d75e3047efd6f267ffa68dba400c7e7a590ae8bfd2ff147957149f86ee3b0edabdd6ab236b80ede9b0f15a6e0fb1ca3534ae41b0a26d6d861c6b065ce40d52fd87b01099ea707866053fedcfc12ab8d765be84c10cfe80bf4370131a2454ffe6d2df2861cb1eb6829c4d70beb3527736df7509cf89a04afea7d08f9788d7495a240cabfd57712db9e4e529c68a505149602b91291e31c8c08435f0fa10cdd1442db9067960f285edfc9f026bbf3f071988cb31b510194b741eae841c43c97f6895c4ce1b670953b6361d16158d5be531e354165aceb46c9c7bb635f23bf36e58228efaa909937c38dd1affa6cff51d8beffe4de49654120c5a54e7e300b4eef46966252ad1e0b0700033b01d05988523885df9ca68682b7c911ae70cdc6a0db0ecac9768245218f654e24aae480635fe31fe25a056cb2d91fa147fe07e82ae305a6c172ac2fd7e472f92d51bd41082501b2eb43e37d4adc18fc46c20fd298876b7c47d7551ffe9b4b1e8aa733e58f77bbb144bae2026ccfe7f453630fa1103f6600da090aebe453307192fe70a4f4634b11b5d17563c8fb906f2cc325d18934a2769f18b922205f056d0bd10b06483cf6f708b32f635b7c17197e7cd6f4fd19fae5e4ef2a3dd724fbdff66091c89bb9171cfa00b75274aec2918a04b6786cde71069e179a9591acecd0b7fd5bfdccbd4029028e2f85fa4ce8a2c70345f2705925701fc022ca1471a511b4504752ec1876083f3c4d411255914cc92b88f21cbc692715fa3f477c1a9f83a8950a4237d96a87b2b8c779604ee3ebd48d97bc82539a011ff127736ab01de4b85c948bc5b44c50dc84f7eb6ab3d4079efa56a572577f06247d084935dc294df5c5514f662e4a8e1b8e06e8e6f4a90dde3cb2ab7a6a8414d080715c796fbed7f41f631b081894f5b765a2e297480f09e79b17f9fd5b76ae530a3bca72a8b7163e79aef41476b0cbe36cce6c80bb29dd8482f86f255c79320ba1fda1e1bcceee26e3dbce66d807b50374e2adb58305ee8a183848035831fb21aaa400be5303808041e0707a60d520ae859821cb03dbd4749db095e20250dd7476b25b0c1e5b616a3769a7caf6cb83c0b53aac5a28a9b4ca530fd110e078ab45f3bae1608661d7a0b3398781d4f5a6e4ae30e1da694ab36748bd960a2fdeee5a148e0af12c7d6574bdd8a01492b9353b130dde3ebe608504b04246c8e4d2a0a9867c40aa7dce92ee9436fb76a1151d734640d34f877fb183e96dac0651aa518193293edd707bcf92b5cdea2cec32c6c94a312cdfaadf36773e8a6ae4280d50748557456ff17f31e4fac4299b8fa3550138af425c780b616e6dab3c5917f76fbe5819ea74bac3c77c9590ea4623848ace973b04f4d4a5e01b3cfc890166df3fb35745cd0031425283da6c53be8db7ad972dd8e20015f988ca7d03b90fa16fb67b684257c7f815436b64e57853c6f9d7e90caaf7c3f93fb657c17996ab5b72491fb63845684a67864349542cb0f4b89095645ccd5399553f050cfd19b910e0759ad4bc520ee2e90087891e2befe8815b0350ec931bb1c9c7b4fd4fd01a3dd61869f9ccb95a861e1421bb5767960f24345861ec8509b5becfe63e3c829e0ab2b7fb55847337e168b23d0faae27239c55b8b7491d3ccef322f1e6e9e064a707ac7e84bbd391f633ae8cff2c5d152078d673e330448f6e01bd54c6d8e1aa8f16adc8cfc7f584962e60375bf6eb919e62d21d6d56bd23b48e36509d76a58a1d0d7d54464de2e8493f043a9b9549a9b55c56a29165da519b8c71ef78ed531aa1a2e90be9a05512c499b880afd5c7ec4b695d8c7cf147cb86a683528d5b2e293061a4235bc1220ad2ec987ad72ebd214b751b48a62d7107648133b8c2f575f63f8d96e8522f8ab459bd2b62403dbf25d0c3b3311dfc55952274901d0759b862dc1f0090f1eafb6ef07db6aaa2c34abded1c00a0f39e609e86ef0500cad57a77681ec0063d999ce11206f9e500ecbf2241eb8335cf4a440368865df3ea6c92316e67e1cb3fa6121904301a49549d09017859b950f4f298acaa8fa781be556bd285c089a5cd01964118910291d0a38df8012885600d70ba414b0a898c42c0b4eefeacba7cc44f84a12dd60e109267c32ed040c6782a40ed02e345376823d7851e0076031a8ffa0088d92b41002632b4b91b2f699db78fc6565773b6b569db11e1161873cea38bd9a9ea416248ff9c7571c45dbd8b9cb4b55a69864934051ac100b55b791f9270256da3a593e4ba21745f7e43882dbce6144ef5f7cad15c254b5849c1348d8e16cd02c07ff38f60df18f86910fc1126a5ea0ed12d6e3f4311a6c5fa3ca2fee3df50f27f625ae254f2bd3f5490dc73615853c9be8bb092f0d0f888962d59a7e2e939980eb4b2ef4459042c4fbed1d43401e2baa7f95f2a5f5a08ede72f70da5d305c7455e984eca872e74ba0120d7e670be92db15d6a62841abcf842993e3e0630617d7c4e0fc016e81952eed3203083809ee962df03ca64b75e41da5a332e907e39b5262b177bf64faac97e008cce740fb29c9d12444cb349c1fac97f6a1443175109f0d03534542ef35ca693dcf739d103e6093c87277cf94cf017fb6822ff021c7a6910149653c2647b7e9b68ba75642ef415169683196890370e32529c31a5f6d7536118e516a12edea07f1a8f6bdca9bb25cf40220d64cdca211d812faa907115800994c5b04dd72449d3bb526a1b860524aefb439b8088a1530681be6dece61e32179bb393b14dabdedeae6ae15e3475241b7dae1a9479d94f87aabd7fcbf1dc3d9ea0469f7c704e67ca5a5f6659663e3778355f7185e2cc50f859925f93734a9c9f5f701e72cc6210a2bab5119ac52bab387c5b6d67862d07000c9b2cf3346cdbef8d2503f281cd1e061dc46164878222a8a705d46ba91426f90b2ff467aa1a748b949b4613d0b7c6c79063dca1f7aaef99139492e974018cc2b4deab0db3e0d5e469dc6bf2689759df79a46d28d727a5c54a9c95207f6c88d29896e0ecef80ca1a091f9054dea1b352f05b6286b22a49a8c84cb19247476cbda53e6d25c598d39ebd29279cdb3dbd5a5528c5fba44825c47057a5e085138c7953997e61a3a4b8fdbb177b116badd75da520a717b2049069f913983f3e4c32cd4e9dd059ab1c97b410e184364ed665ef3d842a20cd3dbd7dbd3edfbae6d5902a31c574ac355f402312182d45c877fa1fe995d640e5e888b9a4e3cd467818c628f9cca81e0dc8d7fed0ec4e860ddfc190121b21d9c3ea1ed7bf1d1adb79ec2652e2daa19f954470ed21cde7aa815078e548aba6c9f68c2fc31f5d7cfcf152c053bb1d3769d2970ddaa6ca46e4467e4d0c7112bbcea0f45e299c61d90172827273cb8df348f0f442e0702251c7d4fab65e1dc5b6d1badb30a47f05b6046a2b1b09495dd579754caaca3e1d33616d55c306993a84ee20e868a3dc3cadf3bbc93488ce9e8b7201a7d11c8beb19dd97d507f8b4e4c6c7fb88d9388db9df92b2ffcfdc99457e0dec5224c792261e40cbb04238e906c009426ab11767fd46229ca0b5e7971f4b92e63707ee0a64507af23e856b93a6400b39e41fde3b909cd864b899801092131191c11130497aa2169335d570ecdeacc1c169794cd11862048b6a8c0563d4014010a623da50037a61501a123f5804d296ff087b98554b5b7f697a6e5491d19e2b690bd1ce05519861a499e2296df5687a466d39b140baa43a02111c000625defce31b858a4b8caa57a0e1cc103e74e0568d92636ef31a8f05a2b0af54a1650520bc56a3b006a6e2e788f79d61d98e05b3b98fa406a8eec35a7d981c853ea68bd1b84c2fa55c38c510dcfa8ad4d7945244d008acf829bb99f03709ca6a1ded6080841464cdce15ebbf563b458ab028b4f473eb4e7c424ac97540bfb456634414fd5e73706ce22db2c10ace789c032d036ebb88b79cf62ba55be71050d6878a6a3b354ab270dd6c724ab3f0565ada4443f51d204d89b18816733b057ae07182681229785b88ca6bfead6e8133b144c6e8af36c467eb7f090a29b6d9d36d6314ef43d540e0dfebbc18a46df248ad57a9d752a6ef84ab34e32aa7732d93849c5eb73a0f9e52cc56c7338b0255f10ed8dd2953edb1ade6e2731091313b47bfa87728c8dcd50508773234e072d09df6b69dfcdd58eb964486cee74da14e5cb59c07c1c9cdc146d78278bdce16d6268f17e7c376a7122e5c321fea1b3779501d1d14cdf96fc9135bdb5611d761da5c324285a21a74092287629391baa46a616b1eb81a831412a1062bc28d28ea22e428b7d168cf2f3fbaff089c205e92d840c5d16faa5cbb590860d389d08b8614207bd5e742456740b81819a27ef706c9a31438dfe1a618618dbc68120e4fa9c168ec0917093a780e9bb4a423c209c80d5a35045c8a5f155a01dbc8b8d695218114f9387ad5075ee6bbd69e45fc09047846442064f5c11d6b474a5c2fd5a3a8f96d73df19a5f7bedefe8ee2150395565bec52a897b8aaf43a9cd397dd8d442d1ed0f66d7a09d8d95b322e24271a43882a748c7c8b86ea1f926809554c8b3c961d92bf2c918132720baf2ebaccb244ba753938f46af3730cacca7a64f229c0ea189d2defb52f054e6a6a1f6a8d281db4c7dd037692968d5120d694f2c39ca36235841395a458f57b83ea88bf27e248c730c731f0a859b31610ff3255152946ba56e0907cad883d0142b9078481e289fe6a524d5abe63507402203e7b33e48fdeb3473919a5cc810958c4141a560412e017ee91988271412b530c3471daa5547db54b60e7e22140fc45fc27c75c9b61ee4fce6ff6a1d7c28d55ba833dc2e5c0f456cdc82d87ec8ba2df09dcb13f9b08dcdc850e1fe45515b3d7125b94d61952625ce34beeb335362550075e978d5b3eca89c9c28f0d7a6b0c2b804ab0816d8b3946532b80371611c40a5b4fcb554de9656dadfb2c316958c20f1d6956957461795f7a6b232727cf14b73fe5871cad521261fefdac5ce5fb68f0ce0631fda0c225f2849013e9097e1600ee0b2c1bb2fb0c6562c2c0d9144100d50a03adff1e77bbb62904c8dc072d1a5e30357eeba21a5572b736929589a790f954dd02a314450333429a199696e23b2d4ef4ef15c3614fa6e53ef2c94f7b9555c50f33483b483c503b02898c37ebbb96687921d24172d6482c97d85a287464a84c39788f14af642c456e27325cf1186007674f8328c1170987e73749763e3a91775ebd46e15caac9c9979edc6db0dd8e1f0a08c7295f3394e7ee822641cc12edccfbe6e451a8ffa3c90fe118df231b0c4b4dfdf30902432a2b52582610c29b47c9ebb396c0518f02ae9fd7c8a9f9e9f51423d07b893d4e0e5df8d42d2aa93477b918ac00ac36339fe0d3e932aaa925eda4b772971291f04ac20cc908569c12aea4a6e7e14ce597044f4c56aa0ae857a9ba68b7db87d9f1acf100bf3fe4c94d4991d3b1bf2f7876d4d36ee09c94fa2fdffadc99ca4bc3ac08d28b5c93ec7fc23aa35323498b57f43d039053b9e41d3004044f7898ae0caf78a3ce45ce337d00d220b8479089fd950d22666f6c0a94b168f8085d4614e892a429e79df9d1174942be367d4a9c3a0342c880a510ba8ceaa4e054e6bec3e92d8021cd0a5a5e7b3c1056861358442e645f1416fb46dfc7e416942802445f90fa3e060a1d89c67875764a15f383bfa400ea8893d0d6f8f81fea7492181390e27f296329c9ce513c3089530cf5aa0a93dc205431717bcc477b77556732a74f089b49f878c4408bb0b32e8f9308963be02b0178540c89cb9e4f5e22de3ea7aa9071a27ebaf2fdb539ac3c5d952c10ac9bb36cf1dca2b66b91a38132228d59af4fc371e3533185f179b27920db439ef1a9a7f681c55febf818cdbf864ece05daaeea3874188c576fd225b6c651fff25c2745ab92b0019967b12ed7a190eb1a4e19c355120dbf1f666f7baac2cf504c5f88327cdfe628f27d5f7103a3c327ebb09fa3039ad2beef8773259a0837088421c59625059474dce5d56f2839a7cd5a2e37d8008e089519165d3a94df3efeb215100ec46533eda1c79827e3ce2363b6b3d5424bb264ff84a3de20c465a82dcc69f97a3c3e52927f1d47d583c2481e814dfc0405e8b35d9838a3279e7c79403ba5fd001cee91a6147a28fbd7ab0cf92bfbb23702cd7e66cd8f0605612d32e941ce84f5e3d3fcca56bfd225d1d35cd86e125d2bb7ca8c072615563abf8afceb42465ef381518d6230b0c614134157f69534d62e335d1127c492b12af7a095cd3d4a540bf3e69ef3ed7309c4435e7ddc87314c7d6098128799de872a2d43280e02f40bcb393855dec06a3d685a0805b78967dc21c3ec81d63149a9deb9b1a1ba49d1d03a2faa7eec9f067be68065486330ae750098f23e4a5e89b592d7031d25bb6207133d284b6e6247decb618519390a304412113678a2317c6bf1b31f1b764246ba8a2c0fe76a1c890c2944ad34ebc43512b03e6d59b65e997c80fcceee6160a678dc7e916eaa915806fb732432e556c5044c9f8b24c8521756409348429925858e3f1572bf491945aeb45b0e44b81203933da948b54c9f1f4425b5097c20b5b454a3e3361b88444ec2c59b2912e3809b3c92fb652ac599a6b60124f2db42208d0606c64e4a9df37499d58fde3c463c4415c52a4bd5024cc994e34394e41f2243802bce5463c407a5e3798f940c7ae58d1893543a20bca6fdd78c082bf61877ea383d651b6a87af4e447c54b6787ad132488534a6bf1e1feb9299eacad7259dbdf0c499de451fdf198c4ea840a3811bed596f41a1a8b38d6b2879124eea26c0ad9f858f1e64e4fb2aad1882f8154e1e20cc382bf0592c6147b82c750914b496ea950f16ef394ed4ddc62d37c86187d281bea40b2258b1b83f725f19750fb1024ca9d1133816c92910251329ad85bdbb67fe01798688bdf0f1f9799cfdd60131944efb80e368965dfb9b348d9ea0da1551c62d5f2caa518729bb5f46b8efda829478e548e2f7049428d5e064508809605ec0c056fd411789278b59324e08104411598602aef2f1a4e44107fc01f01f67bc26d915e1b8f0da6fb217140c8f1690073a6458eef99dbabcee89147585d422c69912803a78c21c3a8f2f1ed0b13ff2295ffaf15f33f08b1623f8f12567b30387dc6b301ca7504cc407b2e89cef38691a9df160118e966bf4f31256643b5e2c3044d0b49ada4e3a5cbde61f8bfcc34a9c806cf11d1094264da88a4da6693baf6e019a813468f83b92aed56c00a846d84d3ebdc36d23e82de5985177479f946a0f55860e6a973c91fb2d0fb1500fdd3d31eda45970c508995dbe568c6a13c938b2d3613346a78f1ec8bf8d14b4b59342ded99472b57a588ec13af0d0913316cbd0ec391e3620ff6d1bbcf46b9da657b01c02817e6c3e3e9600562a852e4b4951d86371e4efdfeea5c171b9af2d395cbe4a7a3540a6739f08173e19ea64642850733356c250d087125a7fdb7270f8e40d15889ca1445c8ea72be173c9aa3cf8163a594c95b17368de4aa4e2181ec5feba79e20f6d85aaa42c14ae4058decbbb3056926815498f5f53ef1a72448afb7c0bde0c40b7084d8aefa22b146394d6c058fdda718dcb8355c54a5ba043ca70076c2b0ab4db15854b3715c4a3044af8654b316d46d8183fc75a50d4f250d0e76aaf99764a939faf56326840c62c180d4e9c24e9eb24188a978a1ea951ceebe49829a97a9c80f9e93d2f2dde0fbf659c97304548456e2b90bbbc259833e6034ff47a164ab502157cc118438f6a29443611244c5811c5f78c140e784d41f90abe6e9d84644967a32bc0409b4f4e02a98930ef65037945741838cf46b2c014a5fc7d423ea7d2268aa62ae2e756428c581877600a3db45fb9bb80a19823c1a000daa456435d90ee56dec1f681db209441593cc50f63bfa45e96f53a81807c4f319151989449708f35f00cb50add2d582c07df8b83fe08950e4ebcd28bfd7b64339dea6887c888f8fce9016d95201da405448e30e25b4c9c74e360510227be4b0b819d614b2da249432cb22e143c83222c4bbc08dc3669820afa60e8a6f7707b254e1f7e931913a2e2054dd2b761272d8c9ae52d3a1d1e500633e2ec8cd1135bd03ca77e65395c04b470d73edbb8ec49cc25bcb873123017919b25480327b9824811b32a37917aa09411937a60b9951bf60af2883b54a8eb623e0af8da87ff5029a0dd67c142c5c01f86faeaddc88b72c0af774e947358c53c1675df40d8aea9ef7563835590edcfc602c090cdfbe2b10004642bfea3da6e0d67716a78be49b0fda4e03d6a73b6166cf2dba45136283fc2e794c221029f745abf5724cdcc1c072add6460a9f8a8044caf1422244e918b0ea75bdf6771194030eef3ba5feaed7ec1dfbafd9fc2b69a2cef8c9fa732a73e11638b3a4b35aac044fd9cdb10d609ab29d9213401c432790e9b15fa3ed801c32426d7ead00558f0dd906db151951c34f3bbb157efb11501d214da9712cf7e2826ffe01f0375538b16f07f693a3f3719609a97bb6bdafb600b1ba518b00cf8751abb518fde78906f47245e09e0ae52318f5a83e724eb1073867209fb456bf67e436a948efbd4e01c58cc43cf86ca148671bd3da5d54933d44b6fa9478c3174d210b8a69d26d9b970eb1bda6787aab038c7622c71382e4243c42245b6718b84c09cfbc8bca6da5dfcb909dacb14080870e611b3d51c4ec9513351bf71b03b907efdb35867b78f21bcbd671f830acbd1cf95470c2822b05b78dce4dc530ab692973738e384e3b8e184f3b87a6eabf3baeaabf7baea3f7a7fafbdf67cbf3d067d974d265997c956937999648cd59749464077dc21d011d551ff3fec96186d5b0dd133f326579c5ffc01b34a15bd34e86cd1a5a75b83ce161d5a3a354892e38db327809b4037006f02b8097403f0f43849ec09e026d00dc09b006e021dde93961b5aa834a06a41a105015163ac1a74b6e8d09208be60490037810eef896385160444776ad455a784f062e84b9f2dc1ed4db4aebfe3a840ebbe3452008c0dc1fd3ea18667b8c158c9b59d68a8659b4e3c54be9c599f033bd2ef06e5378e44155683dbdefc9cf2fad9d10d62af6afb83ea5dd7d71f772b06eec61cce7cd1527b61d173c078d013d28f27c0dfcb8821ba4d8079edbffef66119d17bd957efe7bc6f9992a1506942c142eaa0a7e5e973b305720f5bf8e07c5f27a90bb6ce0de8035db10042f4c671cd7c4dd7e6dbfd91790747bd24d6917c5b5d52d03eda3506622b8a574e0ebae63d3b790c12f68d02b79ff487635f383ad68e6305dda8639ee1ca58be4ad07f3bbafed16401794b20924d5cc6097ba7496519fdba50d584df6211b6dd62eebfa88e931fa869b629e7d04f1c9ab6b2af284585094bf6eb7eee65d5dbcbf965bb0c622a50c6b693166a613422b08351a79844019cd372facc47237c451da004bb766f86019551800dbcf986eec20b1858ba44ba7828ff3156025cb77a5f3aca42707e5dd1085f8dad9c5cf8526e0897cf57e2c085d7d074e9d8110b9717def99def106fd0e87befb62b6c8bb1ad75e310098592db0e67c91791c6da0b60448c1d5946f88564d072bad507b458907b3b1e79ca092720cc79178447d0c45ee985fc2442a72d40de649731a5541e14304cb3ae11656e10c95bfaef77df7505d35d6324b7c7b030e737f8d593882da94cb9f8615c5d3b23e81be5c9da5d91d461a0b3017db158779f3a7035596fb2182024b6e95a8bd0793f2e887459e324e4a5eb424c7ff8d1025990d9a47e9f1f744fd9be1ef69fe4339a0c672ce58490958a24f65d81e6b6f8b642de18af57aa0a4aebb067ac36e19800e35f29515162aa08b4590fcf7a6715f314d2d082577671c72b10d74684934dfa9738c948f90a2fe834c82b2bfe564f90d56449849730aea810af3ce9ac88ff8f7281d7f440d754441cab1e4dfd400b0fa28c2985fedbf87e305e07dd7b2382cec708817450529f63cb817ab5eb1dc8cfacb31583ca9fcedf5a79abc5e21f749b578c57445e889122ce06bd6ca45c56dfd21135c54faa587b976c27091b3586fc00a28d6676c36b63cc55782556749c8a053831aa532272d0d33707f146468c72ea51302a17dd6ac2e9d1dc73063a95e47a1b83069917dd0e71d7375573a601512b0c0623d3bd491caf91308a31b548118cee262770c523c140132e96b9a51d81ac138680b5a1b7931053b7451dbc1fd14f1f949bb28d9f5948fd4dda13568d850321daf4a7f6370b068ed13d0b4a62a2b4a2c2a6d7725b83bf3d73934d954145af84054b9edc3a1620191e993ede8e1a7d82d56671690d19b5852b22dab4dc0bdc437ca614914d38803c2b24ff453605c1f0d73c13bdb70b8fe1c6d96cef5dbbef897cf3a8fc7ad253c3fcd68942ae26a9992ea43dc039c74c8ce9620b0eb68caf78163a793af94dfb36a87028aa098147106082091d791f2ecaefdcac2a1807ffb66d9357722332497551f5896dca3339f6b6e452c4cb37167f84145ccad9b8bc0e18a06b1669fff82d36c45178c3c0f93509c71e80a6695d616529c2ced73aa0366549ae91ac08ef77ffeb8a2cd9499da771b241ad6e222e199fd75d46381d6d027c9542747202e1c704b4a9e2d06e7efe06599e8acba04515fe48209fb7188e4a143e79a2642794dc654a4055b9559028285b1b390493fdbea089d08730cfeceb233a571650d4e1df5b7fbc8f2d60133f5d82f7d6f9657d9397976c1acc56327e8b9d0a05ca637522cf0c7429aa3e9a054d942c24661ec4e39ce4f44c76c40e4c1f742df42d40e4b6c1ea7c8493a1c90d3a2181265e6216c8fad38808b6dc686b696e5661a38b20522fc3db10436e84873a978280ee02a455881978a5dc14e713453c0c24e0c379050336f0a71c8333a091a3379038c83331b008c2d7986313838e558681fab7ce596b85250038484de4860128b1fd1e99f88e9f98df3add125dfe7341069dda263624d9812fa752aa3c042760edf1db4e0fcdc24a0ee402cb2935d05cec8f67db8b4e070efd637dd71a4d9f47823d7e1b74e3df6dbe1905e84b2ef99c2ba748fcf9157bc65d56776b1878c7dfd0c6ccbbe98a6ecc37a2bcaa74b33c27a1e52c1673ec7872294193782be5cc7f69f56ee3b4074cb1d1ac8a2f741c3ef0c27e2b3ef3d08b9a836392056a63bd9c76c5bd2034576a61727696271c126a998696ce9808ff023fe75726008842d9317660e4214138fee532048f2681507ae13e9fd758f99e78783efd8b8800d7a9d0679f794dea7acbcc4432492d63d6317108a0cf7984995d8e132f7a30bc36a1242a19bc48613ba1992cb2b9260ebab2129e7f0d51cf066445625a636a9a8c528a428335f7f9b572ecad3c656918c59367d8fd383b859c77210ec944b92fb9b79bb8e7139320ae67f2f997fa70813830bc3b42d0b5fce703546e002ca5eccc75e9032bea7bc87b1cf12ee1ac04b90a2c0642a2420ec8a4b78cd253c10050c4649165361b8f7310b7114a000ad2cdf702038fccc5edaf111c468c9d75760871bc9fb982e0a088d93239152f1626d4be89fa5e712856dadb7b9d1cecc499fced291a6f1e6d361b58a3803ecc720463e0182dc22eb54dd8c872cd9a21d1dc97d8f8dc0b6e1844ac23957d7279b784e274035448bca713feea6dc66a934d4a9a64d608e3493309e422d1028a2edeefe8e202233c9edea8b27a1d0efada19c946b3ab1b8cd6849d3111f0e1d7511db19acd1cfee31ce20019e372f69e8c0316b5c73030bbcea98ca0a4c9c4d49bc6301010d3834fe069c3358bf519c63000d877ef7c42a00f8ce7031af78e975a3050c24a077a9a28730b5fd0d3ef9e8c9374edec4ef2f437117a8f7852c2d9dfdf1ba47cc56fa6e8400f204d56837ad87ce4a7234a1de41af580eddf17f5b2b0130b420b7c92cdc9cb0b3d86d6362209d95bee2df79652269902e708250928095e358ebb1ebcf42aaf296fe59c92fd18051fbb8d7f436e3e0581b09afb51ccb90e08f495d7ee878dafee97721be72ec826f386b01f2fddfcd494077f048cb5f853cf9f7eca7e4a954a39ed8252d4e67ed4aeee67b10ccb289675254cd7b8db8373fb369e795fe62a958d63abfb0df9954de75957424dc79ff2be94b3af3ca1d4b540a0673fd17a436e74b2cb83f38e310cc3bcafbdfa8d27d4de79ec8070de79edb81c261673a1761bffda6b3c3aa71cf31ab75979fe2a0c5379ec825429cf9fe3aa070d8c56254c4f71b7521ced9e94b34795d894a72eedbcf61b20ed9da73caaf3a3f39577bef2baf26aee57f43529ef0bb2f195f7d95c1ecc3954ce9c23e52bff8929af7a8d677d05b995ce0f95739e722e7533ee7adb0d744c0539168479824313252c63407d019eb19cc9f23840e90e84ec3a59e248d3af80f4bc848bca7f50e9a1eb78c692668c875d108e18cb2f7970b2b01447098b790d157e62dd86b27ac3a29063caf250ea9bb6b9b65df8a45b5070b2b0fcf331bbc392f48283ebf97543197e3dbf6e40fa1b9cdca0e4f965c399ef189e5f3588f9ca5d104e18b63d09e78c6d2aa5b49aa659b7b15e6335d949bbf26963646ba357736dbce8d5d8d87835de47dfaefca76bd5624de4ecfdd829bfe60dd9796ceb3cbae645af9a16234bd3be21b5c6b973f6a0e3f0783a4f88a7812120f08854300277ea190b5f4b17d5f4960494524a5944c509a321841ba59af3e6cda9694e3dec6a5e9661d1b538a184b16127551c3170c0b0bcb5511b497b73d1b451b7d871c058ee3bbba1c32b95651392092b6b3ffdecb81940b04e2befbcb6d24bcde4b512c4ce44da56f8db49aabb298ff763556e95d17865729541df360f3ebdadc439a67b1769ec7cf0775787bad0e69a4b875d50e749e7bc158dad28d672fbb452168dcec0aa26a7c12ced44b3ada445b11672a7a857aa919941304ab77e1aaa7bf8a1ba353bff892b8f53791fd402ff6b25a8aad5116acb5a086997dd31ecd74a23746bca9a1a67e72e88465af3d35817a439a669f7488903d55cee1bd4b973237c3f68f4b335b36435ba65a40ae91ece2eabba900a39ceaecf0042a8d4add992fc135bd5fb18ea339f3e8210233eb0497f21fc7cd824fab452132b73b6527cd23d7d61137e1c24ac93cbfc9d0767d83cee619332306fa5e973cee05006be317dbb1f9d3dba09f6747345c519a3a6062529d3d8e852465792a9fc863fba93d9ccb32ecb325597659e659e659e652acfb22ccbb2cc3bcfc3f9c2b6ab344a69f58d53a9acf35be7387badabbcee7ef4556ebd54ca7fa2caebece6b6db385ae9a6d16c87aaf1677de5ececec296fa75b9aaf3cef96e634fad4dc56bca1b9c6ad603f1d994b771dddf3b142d07abed608ddf3dd90d03d9ffbe89e956bdedaf19bee69d79ca5b94ae29859d578486adc66b5aab1a9a9a9f1d5ca6b56ab9a9a26a4c9c5886552ce6c520e9b3eee4fb73c150a6c7b7675f0742b6231a201148610655eab5b31ebb193d96e61de90ea3167b138ffac14918fc52c8b23f808a2516dbb3a5aabd5ad961012c8775a359bd9f4c13f6f9c24489f9dff4479647bb22c1ba17ba6673dd3339decca6e452a95ac4b9b010e49524a99c4ca18638c2d77640ea474cc43529d63aece5f7dce5a9d3d783fca0d2114549a4d73c299713865ac13274e9c4c27599c387102b32c5951e2e11dfd1dbc7089a5a59a74a844b32e08629ccb46ff6096cd61162ddd339da017319b27bd8e6b8ac5ac29bd1f950db3b0aa95d262f749b7a46a054bbbd51a76e5c74e3fef0795fc3784a1a437c12cdd928e838475e8a45bcd9d10ce9193c4b6975171a90169ce285b4a393bce39e79c53cee973ce39e74c63a54f395bfc2461a82c97b0b25b9086d03e1c8d97d51c7aa669da3de29c6c5b17d4b40bd232582bec82361f12b439dde2165df334e0a1d02d29a40ceeb6e85a1714bd6a518ba9ce07ff7675a20b41cfa89fa07916e882a8ec96d411a47b388846fd27526aad0e24f6b3990f61bd16bb20cd6b9665da3d52e240dce516840e420d4aa4063b78e10cec6769d5004e12f6d301fd7f6e08dd929e79527a1936fafdf86e50542df6b3cf55a7dd93eac14a1c2fece6d12375cded4dc35a99a7c468ad1ba5d5d3ee47378d73cc398cca4c62534a21c4783d2ce7885e7360db610f7e6954a127219cde102c92104e51b97da475524dae6f4c678f1d25c34a97b20b2bd3a824842ca514434a29a58ff18273c81b63531655c71823b5b66b25021520a5f44f470e6c74c938ba25a57361a34b17a8ca3aab58e52b67cd6b7938a2cfeaf25caa699aa669d6e35bcd3f762128744f3be638d03c53ff76fee3a7a7ad254fc93c65334fa9ff684e35aad133af51e7c1d1aad13d3bdd3371b4b09cb7751c2facbd4cebb66d9d73295f7948565e1374bf213c352b4fa5562bd73cd55d79d6aa56d6e37cc571ddf56e6ddcfd767ebb4de38a8dedd1e915824db215549658acce1612c46c1132668b095a4c6c4e0c07585e80d23205992f110716382962813cd9fdd4f36b05aeaff6b8b2797094093bf1705c075532a854eb2c61081763f783bdaf107b7f986b9387e210ee2ae7d0657739e934682c618770ce1f778708b1f343cea173f0b72aaf10bb94fed31cc7dd6fc8d7be69f71bc2fde6d43feb7ef4436a3de6eec771ded7ce95c0ce7975ebd23dc694ad2e39c7daa1d78e79df10a2e721dc37ed1bf40ab197d0ce57a83f9a7278394f7a9cf4ceab1ee69cf7710e2f51bf746d7a959e5075feca5d8fea9b4befb31cf71cf752e5dc3d5d773fef3ceaf27fe2e609bde67df40e21faf6a2a1f8f20e89ddd5d791f7473b3b77410ca532556e28dee16be56c62f4d1612b61341fe1193265ce403d6d717ad292c5ca52968f541a263d79e63b65cf77c3754bde89614d5cff714d1e2ef96e824991b9cccebc7250f298cffb8222e6f9b953352819ec1101379eb70a639ccc9c795fec46d7e6755efaec0f345a628e1c79b69cf2a2a1096bc9571c7b96733cfd57e3a582a6ff583558bc03c26fc1c5020cca478c1909fb6877c83583990042d774f80ed5b8db01f6620c17e642018bfd74f8d031671933dd8a337adddc022774ab5e12da157db6ab23de8851d3e1fae8639689503026a91830b34cc5c0428f5f4829274b4ad95db424da112a6fb218638c319ae11a5e7b852a2a6c3b642e6ed01e9bbd60592bd53c0f07f03183518acaaa302a1bd806e2f965a5866f1c9e5f44a0f9d6f38b88283f88909479fe42200396af2a950d6c4ce2f9b56483874ccf2f2474781ccfaf239a805d8fed89a71f12f2ec3db63237fc500952ff115df18585c37f444838d42bfe2332c115f3bf14a8a85242018a68fa2f05a5a667ea723d739a677ef64e411d82df4c4defbdf7ded7e6a6135b7e7679e87572f77bbdd03cfc8a7480cc2e42f12b32030e719a34694af08014bd5764069a87ed5d1e7a44ed403ca1f6d2fcd5f9013d7a0fe8f112d5673af344fd45e0472ff23e7ade37517df6a209a30bf0c2afb09d3d2221614603cb2f219c3ced81f9e6dff4cc39af294f27e5fc99f775df21d517e1549e4ecae15baf926baffdd5e5c7af3f98c9e5b29e79296f2f722a4f3218aff222e7e0550d7966124b719e794cc6ab78c296a9cee3775e9ef3daada79a2c9439f548421112d4d9a1ff68e6011d7af62373aaf3233ee7f1b9fb155971b9daab5e5554d8ea29affa91af5e23175fe50dd8cca7907d917e0e10815f5d76412a275bbdca8e077b991142d9105200a4aa33b956f894c7f375f3ba764e644884da39d75f7ccd39cd89b0e79a08d7b5739a0fc134dc91c038347686d86a5edb2d79efc7cbea560a6662ba8ee3baaeebba8e773a326addb65a37d7bcd65ac3d0344a354dd334cd29efd09c77b42b646117dcdd9d753796650e3d159365b2d235de1144798798ca2a2b56d58377b018b11839462c73cce33847e651a584e5d714343f5d7e34c33c6b17d41efc43304d6536c1438f73a838cea1f2f6544ad89477ce7975951276739512167395ca55def10e7e95b70a4c55fdc822cf5537f5e8588c14d38ac0ff6011f894c6e8f1fad32b441f40a1471a63a4fe13878c386dad69d376a8f274a2439de8ede32773e875a5448838100879ea947b64de475d285e22435cc6e57aa29adf3c4622ee3707c16b448644f8e61cd189b06f22d48930201878cd3f1812e121e7188269becb8c2376c7633aa51ef40cca9b69a9d3ebf476a09a7985cccccede90918743f1a1b30fd53892e68bd0fed863ee826611fb43a4ebc87f43199a23199a2369be08fd34be9fe5beee3b44a44876839aa87f736cbb4310cdcbabf3a3bb20ff8959f48a3436fd7e43461e6646babb878cb0c3148a9ebd339ef2a3c73b644483189a6e69a08caaba623bc5af294a3403f60af74b5f04eb529e7caecc0f655fa4a6e352453015ef20025d3f24c2436f97753d84ae17a342af2a7e9ed78436e71c3ccf8efda04e9dfa4f6f75e3a139845f83a0e6c9ad08849aacb1618c297887e2ebf0880f1d5ee71cecf0a9a75d21ead56537441ff37ae7ca61a78ac246bfda850fb7d8907140ff1c5084c433e380aef94f1c32f2b15d2b21fe50fc08858dde588ec7bc6feac03bc4e4727d011efb014e1fc07f338a950a976c807710e1f923f622b6814367bed83562210710e64a6c80a0cb9b974e838616fb0d799e30418c30c7623fb824cc4b37c26ee30d309e0c81c310494f2e1710e610087a2ef9430c2d58410723808c58c801045d890d10bb110b0d94b992060041c73c250d003222c504e8468218916242261d73788d70182d30711445031fc04c01c4405c94022d46dc70c315a7295f003110fbc76382bb5c40102ee99e0134913954e61d1f8f6f3fe5fd00435d2c5ede8965d2b3fb01ec7e980f894194f9793fc050c41b3d090593c7ee11ad25f80ffa377d48d193c73ec000a3a5fba9f0f1030cc5085e62f7030cf5f336211d71802e49c83b05e96b3cbfa6bc706484bd04aa3469d23c01d25c385f824032c6e50282472e1b30f030031422018002441617110818ea8f5c07e89284ab08038c96547031144d80d8bf11fc74667e2525f144f08f56602820edba180a88af11f6127ce0861ca83882c665e47201b17f467ede8f5d7ad1bb93c001ba5c49238115982f2e2803499a3440ec3f1dfb881ae57408333aa79d13eb24fd4a92e1591efcaea2b2c7c8e2f156c43cba8639c5a247568c3e1b86c65c473afc7e1dc924c324e7882d79c704a15b3309c9f3c48faaae508f3e9b4f6f459fe93a7887730eead3ab67fb06f5cda37d83e6d0e8c3ea1b0cf51f083f3da776fc4a723db6e23c3a104d5fa35b5427f3f8fd3ad9e557520bcfafa424af49cec14b51881aa5b7104ed4e5900a462b1c71fdd027821c9091e6314fa1e8b19bc274efe90da1462b1cf92198e653e123107a3f15ee07e1639ece8fe8d2a3cb2f7e2b5133ef9c79078fa2ff38a72e449d9f5f40a0f9e9b577f06bd534df3c86fec1e7fb6995e3e07be5fca7b97ad4e392b09c57dfb82ba46940da35ef9ca717230d95554a56f2e8e099cedaf20d3443f869e73c52992133dc40656cc5754b768b6f7c8910fff196979e6119cd74647e42f7f00b88a4cfdc02193b6531d0c135baa7bd8c093ac17ae2b3ac67278b4154561961f93585cc7ff47b313d7dc721b2b5439fbe81a4079a6311fe23b28d3650582eca43113885435bc6af46976226027d2ce2db59bdc37544bc191d84700aa30a0a64d802883d585d9514db7ac1936fc71102a704efeb054b1e46576555119c002aaba6d8762e85c34bca0c4539f0a0823160725842071a0045d92548c656b25b44f13767d54cd3b42cfa4d855d8f38c46f9e11c5d7fcabc7bf79d673c181b86f7cf26b3cbc1fe610621e3fd1e43ac6561dcf15d72df71f82f1d9a1657d74456ff18eb8f31387e8aa2816aaa44c294ba24c55140bbd53a8dcb53257146970854e8509490b0c24179dbebd863f7dfbceb7d758e5db8a17e2e5d9683689f2046329276c00a4d877f095d19fa5e40381faf5039567d8e5871dfe6b7af9e03ad221e61142797f408f0d9378f9f0e4e7f3ab07a6e71a24282f0d4155dd60bba723e4ce01452f659012c7113280e424b60bf11d2ac1b37fedd0881e909e5f3d28f9023cbf90bc7c94185667b79cf68c3ad8e541bbe53b9286aabac146f945a7b104e41e910439b17629c4d84fab5c60650f4acfceaf7a32548297ae81ca1da38c32461939f6ea0b89ca7f962784ee892e40dae1a3df4417fc078250bb942b6e1f0682ce41f93adaa1fb091d8c9e5f2a282380e7570e4ebeaa301f52e686e594484a6a873084b0bb7bc6c842ba0599c5f82001ba947402a0d704613fc8d4b365613fe8a20121d337944f96e9a547043e3bbf909a3e7afc3adae1b983de84cd50312ba0af1c8ad2af3ce5d4bb23129439e7b5a69c6574fa1aefaa70284e9ef30e4a96b7f10e94528cdeac7e4e2ef35853622f987265816ed1cc310c9b1ac5b0396915d9831f9352c6d5099bac73ba84104e6821c424cd3cca59cad66647e29c73d25526a5b794734a492d853286899177a6b3cc6e3ad822314fc2392794b03d1aa5c31861c490e42a478c92fe796a15a3c7c85212f54b4e72bce162943246c9bca23ce0476e1ab0582c966461538c97335ec45481268a7d7e7d79f255909158cc32cf6846e991c51e80f1cba29f2e8b38d86197a8e5c32f4b9e5f5fb6b09e5f5fac3cec7ebcbd31826174627da5cc6cd0a921912452f4e924a9147d4e487292484e12c94922d1e8241beeeed5fa60bf4e724f8a8d4eb261c3868d4eeab1213bc9494a29351b3eaddbf0b2fc6451698be03346ba355d05c73cba74e203f9860d2b363ac94612c67de01d04fb30dff0c067f71311573cf0af9968a876b2e15f7bf9c0860d1b1ed8b061c33ba95b54acd8cd31b73157b65b4b7e7ee03fdd1e559893c572efde520e530e31aee106756af80914e01dd2a757807b3677ffa8e79ffd1aff585fe3cc3e19df805ee39b17b9051df3a8e7e54097fd10daf068bc284786e5a7ae613cbc520e763da8432dca968484d449ddd44e6da5b5f496c9f43348158a82214924a42064ba94ea03ff20d5b0ad2c31759207b45b9b639ed0074e04be0d0f4202155e9eaa9e74cb4e7642c5ee746b76e0d1917c3c9f2e97b2744f073e5d3651e99e8ec93fa92535adfcc454124922c9283209476e39fe75127529e50dd2ad4942b7e607369628818a62a28fbb8dcbeea13e5d2a893e0d65bbd33d4fbaba1d9c2024c827d249f4692850a493545369a51d9ccde56ff723c163b18c7bd14cc6d44b49f1c6f4e042a1e17df0693876239a1f2c741de7ba35c3bf4eeaa4ded24edda3e3d3dbcbcd8dab6ebc866764625d27456aa35392ce55a15bd359de817f7c8608984a79273595564a714fc3e3efc0637939de913b8e37c3f388401befe332afc623929db0baf6b293fb883e7eb3586badb5563e0de00a9a570dc8d822ba8e2d11f645051a235e546879393dbd9cb4581fa0951a78f91a6c7996e2b98bd3337b8fa9bc03674c927129296298ed827fb0143a41272779b9c22708063a39498e4f3c540b03abbd9cacc40d6e2d6d3ef10a130566b147d8891834b5a08ba4294530018a4d1f010b443b064d309b402d46d826223de2e0f942f0d93c02f1af4eeb03b6fbd5881d8bd559b644cad12395ca65b6f4f47ef0e9f4187bf86f2ee57675369f97db2ea5de796cf222269a712d71b24392952c5b9ec8c833fd465238293b2098cbfbddaf290f7e7331f39c6b1d90c8d4ad9b1bb378fc5a67a5b4ec8288f4e0dfbc47bfd6057597f9005f05d24048f0d56396eee1803410ec46a64a3dc805eadb61f700d5c398254ac139e21d8231cb64c870ce94948e79714bb7e23725d92f367df4b8149962130a04161bac74812e2c474e207c4146b7cab93bb7e6ce6701ac860be13c560d0d7cbc61160a1f2ddf68cccc15c62a51cb7faca75560f8e2a2428321a08e6a6825a474777bc57eaa976e65e41d3c1996653609fbf96799a53b2d6c6238e0b1a4a5e7642cd6deb0a4276515feb29f7dc992734e2460b7b0202b85fd588fd5f09dee91903308338835d18cca0cf34c28cbb2ed4e4a29a54e29a5946a9ac603839eb3c6b44bd8cf1dd27861180f165e9e00cfaf2d494e6c81220333cf4f30613f90dc8404b4f4052acb26fbd99fb0a32441b78dc27eaa6f2800507bf04378b358e88c801a8f9840e5ce3259f9d3254c41e5779e5f5268c1dab31f725ea199dd7965b7b09fb648d825a878b23f546c8b1d3ef952064fb4b0fc9a424c9ce2c98eb1fc9201d4ff4b065ea4d0f2d26b740ff7803e9da384505e615e5072fe80649b45b04aac126b03a397ce03c44beec1bf90f90a1b97be65df90f60ae84d44c53608e196dab61464f9e69a0f869cf705f9aa524995b45e21c7712abb79f12984db267d1b1244f3823c6b1bb76d9c4315c771dcb65aad562b95f377f67eaa2b9de3dcfb823cc7f987d1c738cadd92db8d672445286edbfd8a5e4a74cda3a1c56e0ed3fca779a5d463f763bb47361ebb23250e64734bc00324457a7777df786b585029a5d652e95cf77c5028738a51acd218638c180d6b64a3331dcae8cd2ebd4313524a29bc47d0e72d9a50ae207912b5aa0c6e6110c3aece8ff65ba45f5ed9577210820c81462faa1c4ca2ae82060d2d1ddb930e3b19c2af9430e9f0d07f1a22f1b0ac9d3d383ce7095b051379b398bda8f49849399ddaa49f4f146182213c1eafef743afce73c9386ca3b18f3134b7ef5fcd202e5b93323a58c52ba7df2f2e5eb091f5e4a29ef1755377835bdf0dbf3abc9d5f48aa209143ba8c2b0fc8aa2cc2b0a28af28c4bca088e244fd47987327011180b0cbd2cb4b4b93567da1f222429e2f2a2f688c6168318210420821e438473b61e6e50417af52c2b6cbe797135afc47790763cf2f27a09e35465545692f83027b23f1473c8f0ae6f38ba98c6a8c9403f80f7afb2c9a25789eec519f9e91973e63106580e87531144d7e22e42805188a26400378de890e6d8882838827cff9f4f65280dfda1582ae3511c839a613d11fe2343c38dfb6af3704accb9fc75648e78858f29c6b5eebd49873b473f74373ce7fba47565df3388f1d10ea10f6859c03bae69532069b0b4884955e80978eb9d296c73c0b72c210ae08c4a383b9efb484a0a0d46402196165e2683133538f943b4148f77cac1ff8af21acfc7410787ede940082cfbcd989b09dee9944da89302018e8ce014538f8763cb48e842224b00dfb60d163421ff623bb1f091e7e7b7bec6e6f77e89dc1c0e9316fde1cf98f3abfa258b1dd738339f58f04697ef491a75eb95df47e45471e96a166aaaadb2a752efacdeb9c7a455f6bad3ad435efaa9c79e91d18ac4aafb508729ae60d19198a5f5d555d480748e6d3b35406244b65dae6fcda767950d75ccba2f45268bac639f5e06bdbb65da1e99f748d2b417297bb98ca8bcd023302209091ca59604600e610e827625e74d5909197d11b8a40b42bd4b9f4aef38855c7eed779bd3ad5339f40a47757a75e20d431a78e6d9e09519a01a119d5ee8779e55c47c33c1dedf29830407a29b479bd1ffc0f738e730c3ee79347fd512f730eed0ec134f57e9b635ee163f0e1c39fddd3fe8110c2b3f302fac8b3a778746ccda5a0ca522c738595a748e5c917559365666666662e52f3ccccdc41d4f6aa0af274e6848c793ad3e1678eada40fe0a367de58638d65ec8dd1ebe519f39f3803fed3d123d22fbbe113757f7713f5b7081c5bd8228516e02049115450896208208e7a75e1e5c545172b1350c0c8c9131d62f8d2022c64562c6cc1c511ffb53e72614407b8e0028a1ca2fce0c4f4e2a24a94550b9c2606298ccac8e1484c0c5a8040cb1351395cb14213a8311058255925e12923aa051a2ccc1bcc20c382e4e9c59261418b4522a594b21e918a4125e3c38a4c0c90a89e5f5cb8a0b55006940dc99c733b41b501c99593cc918e4c0c467c05cc1520ac70d2c59530c49881610b2dea8b2bcaf02e98ac10020b0a565044165b0461b7b8e2c39c734e2569c22862081ea278c10b1b6c01656ec1c312bac50cd8162c60c18e31e3f915f5c5864e0a38790b232d5640868c526671014a97364a295f51585e4a69cf74f0fc8a92f2dcf32b2a87ffacbfc2ec48c11463609161cbd10b3c3c39a0946767070752ee145121f34392a72ea6f00225068f1862f088b103c7681103c68c8c52460b86b5cf2f2d5a98f2a5c50a2fe54b2b7d87c6f36b8c98c79e5f63aef8cf79ce580c724d31ec7e1ebd81c51c5e2a31ec35c60b0bd60b283b3b5f48b963cbececd832354d9a9c9ec494796a8a3eee4ddee44ddeb4e3218080c3ddda2ce48f00bc7cead666b4d178b5265b85fdb426df5c659aa05236a478484949554959f9f6d4936e8cd491940b2919521d97ae8a2e4c17d599f9f66e4b1744474477a563a26bfaf62ea983a14b416743c74317e5dbbb25dc18ce0b6e8cee48a7847b714f705cb82a38262e07ae072e0822b82532d8676564c42531e26030e252c03d414305fbac8e8ec01c8d39f2e28c5315f65935d184114dbc9a78a26ea932541a6a0eb587da648bdac0d8c8a849ea12324c6c526c546c60c464e1815d8a5731c237a66fdf76d88e6c2eded150583458197e73c192b19f3f5189c61acd1996b4a6a6a7a6a7a6a7a6a7a6a7a5e8239f9e969e969e969e96a09ed09821f3f4c4627953d316344df6c97e5ad3e6722d91e99ecfcb343d4189e91eee1e36827d526452645e29324fa4c8704991f16245d2c03e2a264c640e4c7a601204132760b08f6aca1432a6c82453240c53e40c66a4601f15172e547001c3650c97324d52d847754675a68aea8c11aa332fd5192d51a20bec636ba821ca5043a4a18698430d4ac2b08f3de288a823c038828c23a0aeb08f0563c13061c14861c15061c13c2db50decb33232e2c1488a5115a36fef27aba3a33e72d42e1cb50c4767b8b0cfaa8926aa68224c13514d98d91204fbaca2565144aca2aeaca2985845f10e18d827b5945a8229482d411b524b3ca496a274807db426adc98b31e0110d8520f6d9e813964b152378ec239ff846f77ff289a5008b80ef1b4f4f4f4f4f4f9bd1e6da5c9b6b43a2643bb2b92c179bebe9096a49479fcd935848168a536a2d8be5beb99eda1b877f6c512b76deb8b936d7661425a66a9a1800693ef919e6920c4ad2fbc52528da14256da24dd187c61bac489b689384dd126deac27ef0a9e99b6e81ed2f3320a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a26c948d2243268c97305ac2587952ab94d4834bba2587b2c63aabd3e3657800cca5379540296f065bc9cbeb0a32cf2f305e5e609ab0d06be6b0a33ad8854d5109695fb0ad6e592465b2d40c9c37b4de4ec43b54deec93e31df520d107e736dfa08eddcf3ecd79eaf27e395258694afa3a6717c471f1461074d81dc2f34243d2bf8893e321c971234540398ee38d20c757355ee33939399ea40828e726b1f19a2b3dae3c7ee9b97794e3aa9cee46efe8c66d6eae0b389ea4a60607c76b38094e8d27c1f11b4f6293e3496e6c1c04d127e7da505a632d8b3ffac7f335e352469d771e8d2b96f3e99c778b398f2e392e0bab451f08a402b6e4270e652f69b7dabf9d4f0791d9337a4717723c094e0e4e8de7b80b379ec4e6c6c6c6735c98e1496e66dcdc780ecb93cc60e5f80c1ccfb92eb08092e078ce8c1716674078c6c24c8e87e3cdf06e3c59e34dcce19572ce39e574f9024366ce2597eba58c506caf9c54eeaad31e1949e6468a8032a7de08b26fdede7cf39fceb22cbb4934dfd87b462dbb2e644eb3cc69463d49129a710c55fa8013360d1a2ffbf0f6b55858e95a9c40592bac0ff68bfd627db03e582bec9717165b2c17d05b6274e352b60747a8da62392bd058d1c543b71c851076c47922a59413cb9942b92ccb32aae13051b96ddbb6ca6d56a4b8aeebba940a1bb3e2acb5765553f3fc7aeae286b3b1b1b1b999913a8283838393c3924c68701d74d0410734745628b0c1d5e882600daf51a3eb016d7443304d64ef69c97fdc4d0796f502b3c3b32227a56e1a97b2c9810dc4844163a74ca1d261ce09676d628a13a42b49c250a1420c149ba483941e9db220a303312a7821cd1493c51397051919d224e0f96545118ff3fcb262078c69623df8b17b5380294f5c3b548912e306ac8516576c68c10a9498a10646f2a70e8ffe383d1efd71c28f9e0e84b74db0d9a53df86fe0b59f0e107e7c9c0042f7448f5c9ce8220397142c9ef0299aa1e94b9613c0408822a6006a77f629aae18631cad8c2c20a3ddc00d4de629f08bc104594255f6a50040e80daa39744f7cf0829bb82359c77d00564ce0e00de814daf617324e0790021fcc41b2d03c03e36a6aca6b98dfbf0b1aaf1e363041fabae71b95bed919ff3a14263f955cead5cebb694cb2ec836b7e326f50cab4dc763753ff92baff10efcd3f191e51f023ede789c20313ac305d4f00ffbd843c33fee3df0cfbee41d371eef3724848fced32d1d2e7b7550b151c31b013c40bb0e0d0fbaa051df6096dec1fd3e60dd8fd53917e7ceb870899dc18d47875b6ebc1a24ac0843e8d004040e82b8020306b8be904114292c50ea02b472ce7fe2db78307c7b8d47d42f8356d2a1261d4eed990ae76813a89456a5694a98594245185b3475f1c29f4c10c3122d30bc50a52f4ce2920414a45b3cb0098f15176c40854b18170bb46034415899c2f5430c4d4aec850aa2c080091214173670962852b8d0fc10852b8909dd6acdabc72c59bb4434ff215ff3e072bc512153b77aa95b2704814b678c2c59824f9df4c3c20dc4a0a14c0d68ae80518482133871240b5713942413988041e6061dac68010e1ac0a4cb174834d4e08b2b959b7396e0d207f90ccc029bba7c432adde21dd97b10a9c79c830f101df322e7588ade35bacc30c183e6ae6b8eb01f37c1a56f874fdf3d917d8a9a70c1e4053d3009c1051640ed300bfb70513110a30b1ac6d8e10ba076d8c43e45365ca1c59525474694f104503b74629f0ddcd0022e4b34f9410a2480ba46d7f8a2620e67779cf366cd1d04386389e3a5774b3601f142f80c7c884587b11f3f09895e44bd990178b6f13c837ba8b6395c80a4dc92ae791cb7a47ce9900f30e3fbc0cac892caef839f5e19f356f409c2b524a5f79bf171de1bce61359ab56e5e5e13301e2a43d937a41175c9d18f30044ccf3c162890cdcfd54fef3801d3ed0a56766b666ca334a005d80d46e5ae448041e259605edc81ca8d695e390e7edd34cad9176a9a248d38b0e69473e6683863dc22c6cca3531a36c326c6942d6522ca444f6b14bab579536f48b3ba4d2935ac0a08214c017e8466ba3b42304c96b22ced29c7400823ec55840dbbc418e3740ce36e4d9e2d1f4a26e2c92dab90114a06a2d0a8148d9675392d19a2110100000000e314002020140c070402a150389ae7badc7d14800b979a42664a1649b3288771140619630c52800002c6800c88080d4914315ef03187de03a03f2f0d9748d6e01cd21bc8d4afe3a64f285197da1c8dd41cdefdba9f2a90dcfed402ae82298f85ee4b3648d1c27664b8f15e9a58f2ff066edc9e4a774424a4e09ea0192b37367654f081f0d4146c66b7bae67c4463dde96b90f4620b9ec4b0410bde2b3fbd6344eeab2010ab2db942730517712fe346573fc56e87f2612b9eaaca194303c278a59935c1b8df14d310e95cbae022f5b6976e8dfa9e31f28d0c56d53013b3be29636f408c18f2cadc74f39065f1ff7254f418d70bd71e2bc91e848c0a77fc5e6092bdbdf3316f57c83bf094d7bdec33854497e1f30d92d9e1a48b111e992a6902097018a598bcda5468e5e4497124618cfdbe3278c26e4ddd4e190d015ff0837a5cacbb93c0d0f9d17ae7b40a379a094417e05fd1d33ca9d6cf7b2b8aa83f23d12c76f3cc2beb0e7aabfa2035f1c848e5a9ad9d88fc572dd29974c8c3ce980f90a73b97a8886a54313a396e950894d12f751ad31247417adf14494f15ef26bac0a27cced7e68460bbaf8404b791712872a4e5d945e58d77971c92b64de0be7b15395f5454460c6a8d875386188329b360482eb71a5dcb5744e17c32d84bc8df8c3251fc5d7d3066a4fdcd7500d024fdfc02ef3cc568acff810fa568829f71106a7c7960bf9bd8705a1a3ae0634e130b9110f98240be85ffbaf784d30478c732a0e0e0c78ddba4d5dbcd6007a6ccefb0de5688e0114f51fd0383fbcebc96a6788ab9a9936b86f3724b67cf2bfd14b6edc61c06cbfa41b018af34b7de414e3fd9538e729be080de4b50b4174330bc5915e811c327e4f06faa6ca635749c658d94ed58f1715f2b5ae693935688697b25549bebe16f3f0faae633502e9d69bbff000ca0a0ba0592381a9a60677876c1a0d2a51dbff118532cbff7a898cb237c84dd0571960c7989e44151b16c05e02501baf00bbf25f001b4b176a825cedfb2a329108b444160372d6e62683dc1e4badd76007bf6db6e13741b161182e9077498e040fca7f8241a89eacd283060add615457cda93ac7b3f586e75e8207875dede6357c2473f3efc4a10671f1c93f2e7cdc6e849644dfc36f9a38a9ceacd9efc7f5b5d2a2f7b39844db9bfb05bdc548c37120a9a028cd82f647609de3a51be5eb9b58295bf9ed298e174d32154e8efd4dc3ab2b32a375338bab2c939bdfb1519f8e176f68c63e37c3548b516d4443758921531abe1ddfac7d6d0aa498fe0bff939c69ce2b950c7437012da82b70e059e6387b6cb132f301103ff8eb939fbd311ddb7cebdf3b7792bba7072b3343c1bed0bb8b767c9b6c391ef018fa9e1cf2ca72ccaef3177e7dfe681a37aa751be458e9929cdbeb243403813227c78bafbd7af88861cc80f3b52dd7de13f3ac79ecd093a6330f2f466a96a2223b551c1e65f99f06a88c8570c4553397295d481cf1c85179e6989bf315734b1b927a55c88b5daf770e1419fa3ffd5b03361f8760e1ec619c137916dceab6bae348705962838044f8d996b8d349e5827c283923e2444fe59791fd54c938f0c4d8b324192e5a7131fd8701135743787ea1c4400d8813cdf677000d0666107598a7ccec1fd909750b40b882ffb261cfabd344dfe8d62742f72685a342efc835594a30f3d342ee5a7d3174a4b7ea2135f1cd8f2ea795186407143b57d09d2a8e5a763e962a4e7caa8a348a1e38128982c52c7d5330aad4915d6ff40bda3016c4bd9847f76c6340b1cf0da26b13a27b3658a25ecfeb43ce9ea0d99410090ef36387a3384607908cbe184876893f2ae9672abfcf01c1aa05d4870d4833c9cc4f8fef869ca34a90045c6eb2ea886e3cafeae3bf2cad680dbd02678ea322624cfef0fc31b7af0568dcbc4a68dfb25e2fb3d6758e1c94130e0f38c0262c0f27e009fdd9ebde5bd579156ab2cf7e054ec5b13ea8ecbafbfeef8e05a4d6537f48255a5683bb7e6c1b49f0ac5dbf7a16ac4992f9128ec449ed7c494057e2c7d5576112c1c049cfb1e3d0f1a55d512f390f0626f2f739cb93578d83f0d7b93eb68271b165c946737e18b1c74d67ae87432b56963e658c74076a59f43f768f74dd2bda12045e5d415d455984ea84186ccfdf7b7d9aad2b7c952e13633a3650f242e8cc23200a2b0a0fd461b419cb92f26c637c94f812d1f1943c1813de5d50c873b0e21fa4a45acd616160bdd8e73cdb19e7a8d8f128ec58ff6ab491ad043c7696f521b8fe4a5e40443aa293454e94789ed5473a7b3fb3ce530dde4f00b623a74b6ce8da6448053034b20678dc0c18351c74458d2eff47731c1b8ba5774743de3472a7c45e71c38a95a8880fe6baa578a24a485ee12692513ff9189f7b937e817dca49ba456d60753b54692370b95f6b61b8e328d46f15e18f34b6f1014de2a286816d8baebc776084124f20c11ae70384e4a97451a0e32f8cf21ecd5693071bd61dc3b91845959c46b21dc77a982a6e8905e73fe2e934fcbba40c6b994735fafe99432387b2bb8f93845a749434f4415a5cb8ffa91fea03e920ffa63f1517cac1ff547f2a37ea03faa0fe44331fd93f9587fee9ff9b57eee3ff3b37edc3ff3637db87b666fbd725f8df79960ecc6637380090aec9d01bc3b907704fefe00df19f0bb02bd7b00ef09f0dd01bedf027adf0be83d0fb7f3feb60e1fb7862a88bdaf0344b75694fb500d5aa7d49cbde240c1a69ef71ea9268645b0b1ecb6c662f2c3d83ac39512b6bcad69403dc8119f1eac1b0e79b6ac2be2b54d9b82001e8545d86dc4f765ece76afb76328f68f52aad8969cc0725cff105d27c9f2001617ddc1559ce0ddf8be86dff074ca9cf630cb10fd15eaf5ce7b9ea989a560a642f586cd743c1a713e9312e0c2bd6f6cf43c4052a86f841e2ab2e12a2e53554d758498d39c112b2295b12ad22dc9d467ff34399306c7e67f054c5a6fda5f3125d9786b6c5a42cbbad46bacb2d9c9f275daca663d7d8793d5cebf10ee12b5366a3aac1d2646e29956d210fdd1ee481fd94b6dc36c818c447b5ec9735254ea22cc80778d4af6f3d98bc8049134852a5c85322eff41db985e58583e90a8f44eff84ef29ba471a30d9862630b25f4a3f2b841152eca1d3c6fe108d7ed15dbeedeae198517c946bdcaaa2cce402c2774f497f50237c1fcc4fa4be40e860e47094148bfe3794c4064ba6106b803e970fe17c140c944956d29575933cffce5ac7b554f757bc115c25cfa1b5556bac847bbb988953ec66ec25e71d94f5000feacc496348f825402a5a9a51a1fd94e2645aba5456faea7bb1973b0c7f70da6f7e9cd77184428869b03333059f8a67704cec26f9f93ffb2a3686bc45828936d79b177ab204a650053c7c2faca6609011c4b0455285df2ea7ffde6bcd3e06b388d09923b846f07cd1d18375de12b4288658179513607fdd24c579a4540ddc54d28be2c6d691bbf953bc60ef879dd9db11535a438c0ddf9be4e3835fd563429ecc8c430de54557d7b13b437d1d164dea5301bd8e3ba25be9e4c5ce0d2a8f3c576ec79eeaa44d451e00716ae7a2320450afcd80d90aa1481d7a4b1e932354948347bc2df2bddaa942d83580822a4a72aa91fc99383ae9685a1f13c6e088023a7f6b7e63f7bf7469a1744ef1d5df09052b1f62e013bc81957b347528054d9d24bf6d612cbe5c09923f5cc09bafa8154398e3b82999d1fddb3354220b640aa74c909ceb6d28ad7292c0e6299af3b68805449d6c08e45e8333e06a75000221491c7a7b01badd3f6bdebbba2c8fb3e864d846f6579bdf5e5a4fe9fd9335b9b8973ff838d7641de178b44b6d52f72b5d357accd54f07b814664b98f01ba13d0e8172f3208b0b67c064c973385d1669aa49c69b29f8ff7b10eedbac7332d63cf6a053ea7c97f81aeb23f9235d7ef3a07f79a479b6710d367c35c0d8a7ed4b1959cc117019d60c4ec454f37d05c64479d2c1c8a7d928c00c2f0e2c3850ddc29cbe69c4c6e43531b001c7a53e0ff0d0e66abbd1c73a776aa7fa48bfbeeb87bc710b02ff2d1fd40673e2b7d22698ca69683e6f83a6fd61b81917abdb4cc724fb1f54af10d9b4c082ad1d507198f83e3f9d0f11e7cbc0e8df321c6e3f0b83e749c078fab03e37c9871383cce7930384e1574c4d333fb3b20623e5988067e77a0de0bfc5d02793fe0f70cfcfe80bd17f03b02f26ec0ef7b019ef7037e17c2e9bf57b146c1ac584c51667a4da92405d6c41e9a38067dfbf156a0c70b1a2b87f6da556335f246d5e81bd1466ef41b9d379a63f21cb01e087b8f770dfd153d5a3ad8056de7503db3f479f60e167ff5955ce21c6429de10c51281345a44107b578af4d54919bc4c766c9b0619faf2fee25349e92543fe4e7967fd74a6ecd63c5f53c65f79ba50be6c98df2eef2d9ede94d831e7ef9637bf028f3284bc1789085f9dec09e0d5b1b818c8ed95fb6b9e16caafcde6fbcbbdb57cca42286927dfc30120eadd255a8b13f836cdcf992ce5a98a2882c7aa279177363a9aa685ceec2fd8f9b22219e02e6d7e674546eb82ed76b8b395b9fbb0ecc51c7727ff8f78f1477aca26fe7eb6397573ca0a7efa7684c048a121dcd6cec412b4618286ea80aaf2c7dc7b08457b218f67bc0ebdd3d0db96498822f77d51d514463bb37865bf87cb015937a6918bde51f2efa30bef9e52630a2de695a81c0f627f81c202abf9576227fe52289f0b621251028729375fc22a44cfb313dd93bb83693cd5f6bd927389014cdb0f58f462d61bba8e65c622a7bb63a0538d05a0776fa6ebbe12697f0d4f2ca1b14bc06ae44870a828f75ee017434290b89486ed1320da55299265ed44ab90effd212bf0f384cbc886fd0861d6f37a668833171e705c43fd9a583b35ef54540d368d4ba42b8a8c1f6f0de64fa98eb0e3790cc873b9de3b1650641799b5900a8f4420d1bb4197f1c054ca07311214a551b4f1dd9fa1c057fe0621070d280cc6f56dbff7d68751a335b730c4d4c7b78cafb911ffccef4949f10a1098899159767254c1842a857f2d7f4a84b27a8f2024577b7c9fba41cde0a049cc74a5f98e6fd322377a70859503dd3a937c07aa146791a335b8e9139c7b918bc9528de503542a27d6a010ee47d9153756de8df6fba80276d41c25c042268073bec40baa6fd1d735c8589a4aaf54fddadc60d5c7dd495283dcf86340922cbdfdb5f6e3c3e98ebca6075c2fc08dc47d5c9d612a68bf04daa20276608adbc8cbe02ce3c332f4fd9fd8a161d2656e05ca9198b45304a29d8ecb972653411b602322bc1c91cfdc0d6b3ac72b5ee50be33e627c3c0cbe3cd80b3d385e9bc07a666c8e0055b84ff8c03dd081db370c08031ac1729287e5ea609c699c583279e1db07835a2f9e6a0d512ec290a3b3f7636331d2368e001ce512c8a3570d4ea6a959cccd8a54f3b054590a35190e649a5096673ddc6ee0bce0382fa8eb5255829f38136dc4398840c2371653630e6257d206ca475e9c2f53178e5d6240df5d07a806a7b2e724a7bc9a0e538436d4f91affe8a764a06db313b068e9a0b88a823534f6b5e7a6e2ae660300bf7b4e0717c11bdc46e0b04747b867fafd985baa86181b1a32796c364d2e550539568d4c9a7fc3968ce78efc2cf293842f52be96a9a05b7f2a4fc9b02776591a1fa67f0fa3ccab8ef8b1f17efa64944543a5c48f560ecdb2c74ae613112db5f916ca0039d8e056a8dcc4bce1804b7607534e8b42100a0c5121c3fbb933977561799d1f9a547df29908c812bf08935016c4349e0b279e7148a850458dee61142e4dfcb24725f815e711a7007305e7fb8a6f3f7d15e9c31cb88049d496af9485854670c2457d0db2673d1ebb6943baa6186b6136cd59b4e9aa0d9aaa9ed18f77627095a3f0456ba6c9ae4cde38f20977e692db69ab5839f8b4140533074fc51ed8fc9aac5e238adef59fcc88d16216512dcd77f5aaacd501218e4a8196b8b70851a20b2ba9237c5db2ec7e4c8370ec2fef494f9dbc40a8cfc7a7ae4f97c743c29d0e0868c843022f0453a628d280828097d4fc6afba0f9f1b1607d38ffcc8920e05dd61c8b1033f1154f3bc43347ad66e90811f28730a7b51d1c57b748e3a3b013160dad7c6d7d0a2cfdfa6b1e07aa410264025dffa50889ff8bde342f614a746648a4512408f7eb0d14320f1c8087a8ba1c91da7e931936ce2c382c93bb5f23594f156440eedfe35e32a9664be83674952e00159dd568e522eaa538b1fff116ba69eed753c003f6bbf5a3a551f1a07ffb6609c05b6998a019afa5b1404d204e84ff830f4c4037c1183abfcf8c5b169c4af3fbcba4811472722817cff4fd38e5c99de54d523d92ca71f19f2c3afdf70b49c75107fcbad1a1944f86c30cc59e562d9a2ac385ff8e1eec37e1e3f87a15cf11a914e28b87603b9294e56f07f23833eb0d3339f84d836e488852ce84dbc0c539a03a505f3d5ad42ca5280da682adb67566b546d77569640e8e339b598035edd52d3c7f800f51e0b8e4473c2ecda320ada0a17e044420ccf7211b7af396ceb29fa17bc7a06726791a201c175a4a81f578875a52db03892258133688901531c144f99a25949a2f8bf08115816c874f303855a729544e22e39c940c5590110d0ba3a3ad6a9bb9c21e8c8599b71108ebd53e7b027bda9ca359350f206480a144eb0998e2392cc3d10f5c2663f02e1383b4133b37d075ce8b3d79c355116815cb311a8cac8dbc9e8ca836e9492c67109dd6884a7b67dee440e68af65cfef06ab57617593da1c539082e5f26c37cb5cfaf2536a17c688c9c3dbc07e66c378e1ffcb1af68c835cc537db193a52010e5f56099f41fbae0e02a592ae077ea7c922a3b075f9efaead6cb065ec17c5f793f4ce7f613ac4d5bceef8d03be06155341f286659092374cda6cf41a1f8eb90f224dfcca6057ed0fb667a71fd6d88347f0fa0582ab90cf8f32ec427b2fdf4170b11c2de8bf7ef7f604ffc02c1aec7069116480afb5b09016f45298232852cd88602ff2859ddaee98fbdbcf900d4bb9ae4439457e4252cbc6f4ffdab3c8c6d68ff58e772082fc44ff63dec85a1841ed9d567abc30b26d6842085bd253deb26a8d43b33ac25b4b3d4a3c3d9b2c5c75a256b87347748437b14982c3e83a5ba00a4ccb681c427fbba5911043bab22724466bdbef6ce3b306d0c0fa228d16057b04d5725f51941d2a253193ec3d8a6866cf348751f6f7ec60f0991c09c37bae8805408b2d4175efd41adae991e8fc30c230c47ebd2c4587f1160368d95ea8236e6484fe1e54b51f8618e74a1c1c58e4d075aa3e42763bf7452cb9ee194ec069697ecff6af3e4ef9e46e9b97a0c86a40b9091ea8461d74ecf9a83ab2af13cdbbb80184d87fcc3168cfc1deb264be55ec042bb17856d233a048aefffc094a4b2555b41c0428fe6caf9379b66b32c0bd65180599818ab148db5e0da1b4b4fb74ef9086fc2930805ade4de348d0058a9c8c12404460976e4cc998a778cdb8682dbf2cdcbbba9595ee25aa709841dd5c38693374cda9bf2db2c69d7bda2beea10b96eb62140d36c56d36e4de5aa8f0d4d5f445425b5475342192c7d94f54c94aa9300f70279da85077062a64ed0bc1b289e689f42e1e057d7c9e2b10069e5537d9973e14ae14599600b9c6cc5d34ad06069cbd38a263852c69a21949e8095f10a5b9d12aad776e8a383c0315705d860424e227e1bb111ebad3e21c6673135264a63fe9911be20241fcae88ce6b180720de05bf23a6598478ec4ec14b531521059df0fc80d4e2c04a8f76d480352b939bdb8a2950e50fe3571a21c25e33bf4f52aa24382df68d85b6d83eb1b45134673b0cd39a191b9a436d152c75c05926171377999b25de16ae4318d3d41d830f27e2e697eff908fe3d8b7d54e85e33d9471254d3ed4ab78b61a679501eb69008d474fa97a75f4873163ddedc73d54f2e27177287603a964f5340b281f15a5629973cca437a9a4590d5be4de84945277afeb87f7a06bc8362b6e33bbbc25c88f9c001e928d489cc5e5c4f8d4ae7ee099099701eb24b165e1095c70b0504ba81325d4e9513c2d618129e912670a232bff153655cc89eaa6c8b94dcf624f934b4c14912346bed8a34cd644a0528b9d07866146b8d5e953df197775ecff88486ee8cac7ee44d35f6797c7ddd73ab937e5fff1bde55caba7886a3df134455b034dc09725cc744b6badcc0fad6a932b818c01bd727665e2bfa233dadfad57a63117c00e72465b15a356e554547708234242ef234ced36c45e5dc5cc484ad26168673e294ed5529d3040cd07cf827efefe2f60c74cb5e7d6292e633f28d16787bb7ae3ae108db60f9888b92a24096bede894dda1e71ad689e6c0541e07d1ae98a777a4e2030e4fff6be7fafe49eb8d1f7f65198449e0334866af679e381c407d8f973a788c4fa4038a613189f8bc798d2507d2108225966db0dfe126890dc1e129cdf340042948da38cd66b083fc96d8bf6313da5ebde8ccce83c1ca6fa09017cabb6445ee9c38466e2097514590e83c312b23624e29b95a648b0d3f5a09baa56223cc6d5f7d02350404286819994a858248fe767917c48e050ad1397983a198e742cbd74eeaf98f83dec20548b008c085f8b8004fce189dc1d904585b2977489f41efa5b1968676c463950967413b908aa0f2d92958d968b400f2dba1c97a3a8cf9b2802040b1d421485926f8ec02d5707e2abee4d1a8fad3756aaa218e7e0edf5bd4187993387dc548b3f5f409005a9e89c5dd82a304e8916c9d03a332695384a4d734f2e0b36961859a1e9c9d9ef3a30ff53efb80c811eddfe0cb52158193ad93e337eda20d29b57fca98e399adce51a24001bc91221319f8ab5d80bb523a00ccaa1ae00a60dea0c19ad5a32cba5c7b21f9aa75c947ac39143c5e481daaefc80fb652638944a4786da14887da38af56435b7488b96c07f4b7d9fed3dc2ca5d94feb4f8b2111f80c0f4064d854595422339a608db78436b680de27f32169dca44ca2329885a9cd206cf7920b18598bebc7ca8ec65574f3c7de932eda1dd89fecc4ba88efc731febebd311f78ead2ad51c4a4f37fb8abb351d60e93b96e8f9864581ca5db64a6f2ddeeca41240531c6d204ad6c9297dc31f16de826231e5d6f835da03153885f15cc26821498a89435bfa50e3e43f9f8a3fa7553f4def3931c8ff9968412e2cf1afec8e681d81e0c59a9d73122e40ba350256fc0d082943aa42003f1d4052843a2870a241200b5cc4d4e896b9586395926034006a8284e0d34890cd751c11cc58451740f544eb61e5ad54738cf17b46b2b22cab8b08db32debde28cc211408f9dcda8a19a016fc55805eac2568f0d42218ee12ce6f2388428c89ee562b2c78a24cf6e003bc6185734a30ecf8034786444d0f36604a9b4bf2ed02ff3de2b06df28f5ce53735044be7615e95d63ecf0ba9d8f06ebeeec7310993621d1538c9c6aa2df161f96c8d2668eed2d332d6d9d34b7b0ba7a82d37301b5c55f66d231b427c51eeaeefe131c391af39f1d8c42885c439a077fb1e447d9e185ec2d8967b7e8db9786afe3ecfc1ea94c3025ab8204b628a0c685856e641af3db0434beaecd4ffc4cb2d667c78dcec7dd16e91147ee656ca5230cb0813f70a39b6ebd521be11163adc648173d80705bd8a2588a8392e4707bb257f5355163b6a1f829ca8a43fcdb04fae2b5278073bdfeb745d46a075533621afb9644654dfc3e49a1082664c82d957f9bd025d5f4b3be30029dacd52444c90a0a339c5b348982422713fef0a74304d960394769a9c600698113dff8ab4b107859c08a9de9ba4492f56f131e57071526b65feadfd55620699016b328f19dc68b913b0fa86cdd6df0df26e27153cfebcbaebd4d8b43939ea66684873ca138c78735b9fd0931c0335bc75d8ee213c5b1315cc11037b653a23b0bbe505ddecd13812fc36a0599cf24a3e232c3fa16ea3f8b6e727d90913f61be6bef4164ec9dc316f602847ebd049645d70cdfde9dd564dc5793630ec9b866aef7ed8d279549a7f9285dbe2984381538d9a3bbbd90758bd99a7f9bd0f653c7a9e4a7f6a554f2e07e942837bfa2083df6168b4b1e1871f63433fb844fe4ef25c6a86a2a5b080bf3be7e313de39287d8328b530a85790a7cf53631a480e00067bcd325d06e68989ca4092808929db872f5b9bd017210cd60e3673e48dfc910ca7704a01d739ad10cb80691c19eb0951bdb7e9e546159dc547fc23479ba25abdab0f0c724db54c390342522ac456e4253934460a57cde8e9f2350e89efbc52684d990bd45de281d70bbd1f4a15eb237934fa16d155a8e521187e448827c9a58af212f6bf2c234b9d0081972851c3381ee7fdaf3d12feed6e82d0815bc7142b1ebf9d6770668d03a43a22130823a67b09a4b1bf00238f469e5d8c4fdd31e31b9d221fce4492bf105d39e8b0e1e58f0de036de3a892fff0d81f0884898399f9b75501899edc4e7a0b3f3f9b55f580a06d31e099dea27b22d0bf55e17bd5ea82f895310e76e2f4f8ca42d432db81d3b62233e772cdd0e06a923153a3b748fdcdb53e3827c291201f1a42e2c8d390fe095aed57ebfd7d747a370492322a17143fa191de877113dd233fead29a1d431a814b12e8da25a2dcc4dd9d6d4b8d38f6f518d30dd251051105f73ebb980f571ca837493b6496001051e3e37a411cb1bf1631399357a49a3f40aa146fe2b05ecfc7734bb83bb79cfd23220140a74ec8b47f424070a094b0620219e1ecd1583d8331a18acc3523262ef8fe3cd52246eba2b650f99a1a77d73f738d1592977667dfd84ff911fe313678fa9524cb5e93d69ffe8c0e3b23cd74dfc29f629f6ed6480d75d88535ec112a74d53ea1a607f3121e9dd1bef5ed3745ecea01e33d4b66779eee423f027ba438a774d6dca9d87c87f5aacfd8fbedfebe16df02c857e0f96a8b2ce7d7d44813d1fb25d55b410732a9a5a0838c963dadfe5ee586b46e6f426bc4b1a0c356300f4c54a77ef46cd38bf7ac234c43dc9c56e857c137715adabad5af331eb156a022e7c80fd3026ea32c0880c2924698030f0cf43999df4e0760b13d6af1a4ce46b3ee79336f3f97fef0f0cde22d6dc2871f5aea2c71487edcd50e160d9a5bb3c8a8bcbb7da77c9dfbd0efaaf0978e8465b15a135408a9b713f32f8b4b1bebbc598381c007630f477d4e492db7fed87b0156b3d02f91e173b1f7b0d52cdc76aa16e8c8809bf98ad3cec59ac5e1ed0bb0808c358b8897ac26afe5d5b75c1a31347aac5938e056bba1ceac59189cf204735cc1e1a2257ca9bb8103351d5d91fdadddb178592ff171914a92e422f34136648a7b430daa8465f9fc396e7de3f70873769b3f6338730dda2a5825656e5093f4f379ac20fbe5cf4e17baf139061a3b33851687fed2e93222d3900c4e7b3eac3438e8c12389abeacbbd5e7b6f8c017631ede583854496a01cd990005c19374c12244e52abf1ffb532cca88106700004d9d25a02e6ce931e0c10d90478063398bdaa895160d9573810136b24c6c46910c6621d75edc0c39452b91cfda227677359fedd083cb98b0627137620e302c9e942efd24e2881f5bf7cd58b3738200781631298175ed6e904d47b06651ea77c4cba8b623ee61cc7e00dff38f64dde731ba2aee064dec1e74f132ea1979bab1417a4fc0f4a8a88fc064e22d5d1c3952c80a45ddb4744c73a0746e6481b661f68d16e8dd469baa34e1ce0e6801d95ab23249081f88e57d64eec1c208e8340e27171dc7477fec8cb8596cdc560632860725d0ca13f35c2482ee00cf87d33a126fd938f852d6404b5a5a4864d1033463c00884af044a1078497b64fec0521efb08fe67d58c659f374a495973c74386747e59243857c79df5e8126502c034f5eecf0ab6344fd9eb3341f895f293e558c905a39f6a3cee988ccff326a9f7297c813a1d2900548a26267493a5dade8a916a350eb217f8194c41a7a6b186fb0c59310b0469d59890ef3ee6952bcaaaab755a74433d87cfdf327b5772d8e85738b5b02fd5a43db28159c98f66b35892bfae33cb0532735c5ea749ea638ad1a32f61f32b6925a0507361e6d80fed02c870346a695c8ea2e687e8f421139f043a0025d34063e8c538ef980c0778c50ca72be47d5e103903ec79735a9a2ce7a710b1ca08afad52bea618310251688a1c4c210f56b83ea6018be699db604d74f810dcf5b36fb92336757ada61519990d2fadc31daf8cfe062476bff31cbb628946f0868035c1449ea73b4583b064f1ff6ad5cf4052d1fb0e7a4a79621a844645b40ee6a0867656016f7f80042fbd399b2673980c54d92bb404e823e349fa5dcead8676d9d32e162c0790ae29f5f5978f4845b54efadd4a687a8c91adf504e6909e857069f4069f7fecb1b779acca44e8ca0e3c0a62b73e7724e0e7cbffd9daff2288c694f5220cf66c12b5e5ce32707d8abc56876e7edddbfa070fb869485d458217e8036c844c33f58d5c3c8b687ec1f67151ac0c5144fa2e788f3ce4c1a879a2857587930864f50afd90087ff30cb654d5c3118605e837a4754f736b61b1b3d4327412d830e764b97f5f248a25acd9c14380c512ee160e6189c482ff21ef206a55772657f8aa89602d6cbcae6ac4ec66478b02d739a7359b608a5280311cfe0bd50a7270714bab5ee2563fd6bb4974688713b9dfb19b5add3c3c94d303a6946548ad86ab4f50c3e3734a42316096da87793ad44855371a405aaa526756b111446ebe58a953b810cb9ae411b9e26b2d96488f46a3812fd0d7c2cc54f4d253cb90a7cf57ac7a3b114809613e0e41444f3d86cece1fe3e4ac4626251d8508a1ca32df9e7a2f45c04960433479844ac4c673a062e50189025a24275ba16ee423001c0da587c75b41049eac5a4657f1b5da474081932839f05f830b4c4252c198d31c76a8de13e1ea92c9607fd068d357e98faba2b8eb6dd6c851cccfea49e3e82e2404d01ab62ed2910dc0dd42f7469df3ef950f46e816c41ca2b257590cfa68689f0e02a64cf89baf5b65c10714287d00030018a7b079cda7e549f773be083de93126e2159b8b1db9d3c22c8dfbc92dfaed99ca9018ce9a97d93c02f2ecf3fb757569b5d1214c3bd408ef38385df5e9c070f2e80c7822e22d22844ff03da7d6acfc70e2c7ac9842761b4e9035734e556c68943a7ce9ae23a9284cbf3f6d817aa1b2dca4cf077ab404a600acdb1160eac12d1d3de94b70652e105e5bac0a1f1beb31a6b2dd04203ea08730d6386062d76adc4b9995b6a450e088d45a4e59baa9d2145583d71bb362d43c89914f89dd49a9ffc73de8b256c0259263a1c27c8b0f2a633c0eba74ebcb953bbf013f143055e477c9be83cbdcdd70f815f11b499ebe55ccfd491dd7d9a1276772ef4b23a5e383d951915bbd2f7af89b4111c05e3dd87c6d1e3c497aca5a2007ada7727ef6fe9e606e92768462712430c663c50f05cdada42a3c0237ef3a180ab8d3cdb9729c7cb1d4481b4c70d8a794c8a8393a8f753011215c65d3cf23f34ed2f2f7de42eaa415b8d1064e20e7a6f1790fce533d10346fc359140dd80aa949d3c7249d8631edc66aa2743845108a14d4ffeb0c3d1b613375f988e7c5cf5caf0fca6666d9421ef45aa83d373d27d4c50b943ce6f2d8e0d4f64b65e1c6f4d4949825235dea5df7220e724c815c015f91d2bb76f1095e1b4fd0879f195fd1bbf80cb7d4bb5278ce10da36d404f1038592dde6ab815fc3b53b576572955e8e8cac234bbd1bc5b0208d439e30c2aa7b840ee6709c90b00f49bd1b2b29074d60bf34877b5f7b03fefe1be83e717c03977a57a41d03bc7ac0a318f4b1dcb40581677246461e7a2b3b09dd102c489c4c4aea8315fc80c7bc80936c18145f1a79d3d0ad863e91582f44be413874de717d04039276c7db09ae17501b74bc6a88872f3da77af507fc7ecf718b600e8d7985efcbb71bc8e5efe6daef6f9ebf93f7b90b5a851f668b681501e7136f19f7fc1d4dfbbd2ac60ff7b4e95646368cfc2a98214b874bd3e29285a6a353a1e3f4775d0d3d786583a18d5726eb8c4f880458b1f477821cfc425fd9df2d771070c6c49d32db286cc25ac29b028062e476d327ef6462bba0e8310ac46e58a8dd85fd59898562a6cd77c00a3b15f38050c44df31ed6b379df85b63bb53ac04b823c35fdbb5c084324c2f8d30b22c1f8a09b1bc390e4a253472c58e076bd84933d75a34a04dfebb4a75b2aa0128969f8e7d17014181872bb3213292fe14bdde58245f0866e21736e4c857cba9c8b12ee4758bd1ebaac1094a31989795fa9fed309552edd9e5dfa27ee65f533a4c4be5480ebc0fe50f09fee442febc1e7c3286317c15a9f2b68ec3a64939c665664d7deaa0c3535eeb6e4e8c7fe47e1284245f06d34b7600dcde5f043c533d4525eb62d5987d5b9ef7ceb664cf3bb6ad98a3d158c33b2ec335f3fdac9c827b027dc78e9badea484cdaddbc485ff44fe2db8c8930950528d5f4092976275afe4db2d4dedc8dbc33a410bfaf9e509268e4552b92b412a5987b65d314af04b162a0058fc4707290c522a968c194cec858e551b8d930fc2dae932e576ed84c576006f99e8c3ab1a2bf9019eef78c175c4afedc17b34d9086f2debdd9989ec2bc1e20cbc6ee9eb745de611f779a93d83bf620c87a55045944309f78dd9d7dc9a627eb3df7817b14ca05de036eaccc79a7dd91eb4a40efa15d0bfc48156be6790f48d6a591b11d8aaa05b3455f7460bcb03efeceb7f8fa2bebf329f2bb9b01bdde5e1142bbda514209c562cf2f9cbcdaee96de54c4c6da9070ad7f4b770b5c2f25d73357a1fb17fe6708bbe978823cbcad0cd53e800f8d622eaf0c4fd669b0d53f3e861dacffb0c0adabf57db64d76c56a8fb167d36336220955b5776d55119b33489492b12700952d179a5f2c964548aee133826e15267cb5f2d828075b6c068403c048773046fa790499ff49a3bc6ea255267a4f602619cb8056763560dec9418b87267034f2029e40638887cf3e9933bdf6b6c51fc000cf80e1ea9248a2f8ae10800e1c4f18615bd30afb7e4eea14d9fcdee6f4704f98db08238beb6002c120246d86446c1037f97b80d78d694fcb77dfc90c54d664f5653b939859ea1d7a8b20ed7638172ece1fb75e32d365b417f03c503be98d864e4c91681129b6a3c0d211cfac47a5d200c78ac386c4b1c8c78c90681536257ffbc6c25fc9bd2a63723e070e697555757268743ad4d375e6224ff10bca46201a8f6cbcc7a84714fe78ad10babccc163851a94fe8d3713419d68934595c322c11afe2787d8cdd4f35847c0f3a1768f489b94a9487102f74c8506262ec3d445929d90742af5598acbdcf11e0595f6a91d8c5e77659d472708725822e5f51762e784be27606211075b10d164a278891df41813c79f5bfcd38ae93d74fa28870b71245a0a02931a5072e9a751b252e714d8f43e5c7cfc234bda6fc430320312fb644f83e32089ecf550430e0e88d0e0e7c361e35fec0248516fc30ffc64377e93b501bdf878942e2f58c76af7bde27630189f69b4c8d97c1b5431592cc5d9ab4af4b6d79ff115e3ebf43f54319321db98209d180c3833c0558a389ff244794f58f3b76a73386c1e708378bf0cf1a43c909647e556994264a50e2ff0fee7606229a70ab61bd5bb981e4563de7b95cc14c1ef3cc4d22fcb4bad2e506e73713f6bc5e4a44d84e68e843911c0adcd5d84e4ba50b2ba30981e4e530a2f73b2d9ca06362ea046cf7413fd43cfba291474fd943da72b4787336c16ada2a52b77ac0afa25eb11fe6bd5563cb91288608ac341b76f33bfb3bc31d27ab1bdbfb7a1661638b9a4775e3156f34c19653d3b51fd23c31ab8d2eabe252f1d8be6f8d819b4b5176571038549e5bf9db20c35a1f188aa7291ef5843c2125b2dd5510cb2a48a987b4c9ec50d0dccdffe9e89dbdeb4b3a20bf26820d24cdda5d1d2aa2e94ca1ee17ad6d1ec690d533a154c401abf79dca74c9a4ac4030a6ea0cced1ba560bf8567e8b3308c45350c2b3e2d377c14e2508933fd0ffebf03a5c6f768ca9315903a0ab45236951fcde83f367ad91adf88d8844a0c72aa76870b9802115e3e4278158610e4e53263044f4eb7dd93c2639c632907cf6f40e2cd25b2fad47d6373cd6d5ef2df94016fb9a2f3571ea869d81fcb8cb9ac17fc5f36d4919f133ed41ad4311475f2ef5c16d2614e516d9d6903e7e5f2dbfe60f7e59b3e8a3d12ec3e26b271cf02f411cfef6a4b5d3fe5450e82242eb7285fd343fe1429da42830033c41b860875549276e381fdf77c5b9e73a780983994101a3039024d01791d2002bd4d107fadb6838004198ffd61f4abad359d5633b8415c1517c199b43b3831b6152c0bfbbf4b1716523dfaa14cf8f5043f219cdfa5ce0c148c7680b8e345fbccc46865fc281fe53dbf72dbda2d14bc015d4d4c5bd3cf084f597f0e3663c3ad528d3dbb39cd940e7cde15f521ed431906b002d28cda1fc2d863df1b9372410b5b455b2ace9f825f071e45247769de663b7914efa27de7fb3334920bca24fdfe286bbf3a4005ee90f8c70960107e719421415fb95c8d6a6f19e53676b2e7f81b2e90c98cc2aa937bd0d81a35790bd9a5e8652fa945e529a083208c546cdbf5bc8847bd51a7c3aa9bf38bf7a9429db61d080bcfdcbbebba1d48fd5657ccf0a748a7c6f69611caf2aad63d10b09cbda7ccb1f6f7bd5e9048ad611635532edf6e0b3b4bb3c714057874ba0880317e0739ed480308fcd3a877f8f821de631e13535d5675f8388f1febc0f5a86469770a155989899338c70687f30de572f685d3b403b3d8ceedb8d93f96e131f4398aa95720df68e32d81aae428a03145fa47c43aa09103ee6daaf18934d2a8bfd8d92de8c729269406e4f252700b59c7181f81333acac025ee1f55be0c0e1a4d0c8c100828230e427ac3bc7301c7e38ba9ea79232fecbe1a34fc6dd2070c71fbe9bdbc43683fec001bf6812d51bccc2aaf9a1737ff5d658b90383881c4e2e6a37cb70a2266d1d8f2aa051bee25136d7a193075ff2192c5280f32d58457e983a6475e1a5ca1cf7da414ae5aa44005000e6f6969497556e12b0b56729d7362b96cb0711218da66b3d1f39b6113d1b1497c8ce4b6b69f5be59a4ddbc7392af3034f19dbbaa6ded1c09e8322f88a4640ab84ac8545f987af5352db44476a4bc04d3706936b40aeb72b668b96d50bed8fdb22c0bc1168191ef40817f192bbc46ff859ed6475e60cf1d3f65ec3248215cf90fdbcb2216225fda91d4a5f76ba7cdf72e05bc6f4f885da194c7db121c01e166052f6978099ef837ea4a012bccf94f9ac81ffc0cc723e9735347ee061fbb38900268019513e4078a24ca66f8f37dcefe30071b1c608ec704f8d58b5d18387866a62316296eab87cb29a06d849009f2d47ffcde45fb2d491e78024e1d634b2071a606f82fd77feb9cf5ecdee37f1b9c50c5d66d615e412bc4f43a3ebcf95bf7eb95cdb8e5bd24a4e2d438560e0966f4742185bc7557524e8b98c49315f5e1c11f4ca5f7720f3a346e7635405b871d9a24a483a8a130c560be62bf2aa1c041429082a79a7350abcd92beaa875f9debedddb6defbd04e8b638b4fcd4169e2036b0f0b89300534a4dc236c80e1895c9b14bcda46cc2c8a031cc5aaccbfe5c3a2deff7d9183ea906f12a930b74c6ccd95022b36ee7cd09645209476f2898462a0441220e3a53300c93c7219aee931ebb68f821149ad0734cb6ceeda88569f0d75061c5dadca662d991d9c783845e7419f4d5a14e82b97b548fc3907bcdad78b229c293450bd2cabb3ffc537c21b59430b073b71cc05993f8f6525e3ea8a670443932c2d662b9b8f497a5478464288fbd5cb8958134e659988028e3d6b630857cf3de93a46dfb3296b20b22ecd9a6a790a1add08d38e8f16d8cb5cb3c1fa69a979c75f730eaeeac315adcbd2c361ad41228640d7973649812eaa9fa4540a53343ca4d153e23b56917df58ee4fb832e4c80f309ddd5d973bf4228093a7d24840100221a203b49c4695ea11d4cea187c2e49eed1834a21252f2d447e9c6d47906082951b1c1d2f54abdda558211d3852f26a08f153f4c1ad2066f3ad7094e978cb183a8447616232ae9e73c9bfe96bfd51e4b269352acedb224469d98b205004deb7617717ec14c8a02d35370c2a89676759b8b6b03356795fc99486ed87e7d40dfcba901b546f980a8dfdc020839356284b086f9400b66d174701e5df10982a92a1cb73e561bdb9572e1c7b88555bf0d9161f149b31c01e09c5774e54c1d6aa49a0b8c9bb89e5e18a71c9b22a21c94f6e9ca1a1a594f74323459c252ca0858cae22ff9b33a7e5285e013de49e0a5814be0af54229ce32ae11ca93b6450d1345cce86b0da0564b9425d308fc83911c859a6e6240f3a61246738dfe38e550d0893961b91d2205877c606726337ff1af072dabc2389e3a916edc1c82a17203c12856b6815f99530545a1f944dffbb31ee6c7a0130984cff3b5ba27fa9a945de34ac627ff5f2ab833e82c2ef7f2e4ca75e2f4654a32ab194de8b75d4e94e44e8b8d4119ef76356f96a643d509799238c3ff08418d68a0913dae525358436b17eb3f1f277af9a81301d681ba2de134180af6dbc270155f4923c9c786ab08514817869f15c6c8d86aaa42becf53855e86b581d3d2e3ea94fa9e168e04bb71752af5c468720b6b6d7a623d896023951f423224586916a88d17f65c7d6ec1d3351f49961c3579f8453143481c4748a7b8238d621723039b89aee8eb4bd90bcdd6302aac59662711811037e4c161c14c804df328a7bdeeebfb0710d2062491ef1fa6a24a790e16b56791112147b217150e855b9cfdee7fe93e9bb2531ec3c726b58963e21fa2be2f514ad9f416f8b89b7d5b808bdc9a6e639c874b42fb499109f8ed4ef4aaf17008f3f01377f2247aac386da1f85a7b641989c62145b725a9a28732b5bb085a529922fbf5f98957d10911020edb9c247ef8ec1e8f4bb60a223054c658f2e05bce077ddb22a99ffc02af330dbdd7cbf942f2afedae80e17533059d59821527f5e0aa515b3cdb60c2244306cbefdff37495649360f9ac2204970bd56526f394476379fba68881016bfa5056a043c78dd849aad292764518397479571ee773b108cca1e5002bce05fa4d8229db1b72e2c1270be26ba2da001d121905e597381c089736928bf5d1931bfdaa949ba5c006ca5b897e72a45746a96438ad632e955a951bc661be1b54d71223809d2cdcd22bc766b143dc364046e3c20a3e30c4195e053b5056a61e2812b397ebe4a36197b5cfa824bc88f016d8cfaaf1122df4d3eb9de36c63ca147cbba0cdae56917110f82735efd3209a27dbda2710c1a0a35b84aaf2021ab5c85506c6773e045552715cb4efdcd1601eff097df21aba258127514310e47647d073d84113a583e65f3ac0c0571b3b06d6cde898e8981003c2cfb3789fd9aa82c1777e5d6de517b82c9a2653c4dc518ff8c85ebb4d590aa61889a0b037664fc7f64219dfd46f78ccfc60cf382bace7e5e04c58dc8f29fe84e8a3f9af43b8858bf24ab47a8c4b4c2660368064c3561d3abb1e604abd5885a048c1ce8b7fbe47bab87c3c192a19252ba65f72e584337471e41e87c3a4048a64fc5b3250919c879797a752584ddca1f2b8c410cb94f8672ffdca56f14e6f2aec649f6d96c9d3226cfcf342e5729f796c80043ed08229ea01895b9587135cc2aee1aa2e7f52283ec683a4abcdc4765b9ae8e29e42ce0de3c32cbb1bc512a342c075cac52d318ae17066bbb6d48a6b4fb259a54c910bf63252d7e2e80dacfba0ed6bf652719eaf6c4e24ab85ff69e549ad9bbba69c20799dfb9147adf9452c5c84f2a517bed8ab7cfc1170f07a124c264bdb90986ec81dc0245c0b2de2d18c3ee0d2d81a5f76eba659348e2ec1b47071edc103a5569bcfa5fbe7dce6403b56b113f074618c691b8866e77b4515b4b0d8eb1a1b110957e6f3baf4ae33d255dad6a5911998f8aa0da00bb522e7f1b70807758876d88d5e7ce584f0a23a900357c31d069dd625bd800b1ef2bfe83d681bf8d9d4e284fa58faec4ef9db3ed5434eea20d920d0b4e9439f5c112f06d0b36bc9fdb768eee45090d79443980ce172a522a4c817d77d4d0f37a867ea754de4b352950839a7a03ef82c22681c1f92b891c43cc3d95723dd181594fd27789587810b79fac780e82661ef9f0167f63e9bffad8e3b5748e76e90b0904d64be24076f29c0923af534f98bd4dea18f7048d3299e404d8b530d9be2747e9f7d5c8b5fa4ad41b7386df8c657642649b8d938b50b47e6f45a5097e3be3fa1b6a79807fa085c7141409bd5ca24da8d853eb35779010f0f06917fe7bd334e08b405f398771812382e6faabf13c690a7f17b1d090e121d1a853a005f1210acca8021ea28965b48bcb1d2a002352f7136c679295516403ff9c49616b101c0f93b28093339f3d0bd2768b3c8b1587d6af4493ff00bf2fb09dd32965690e38057365b3afa758037fab58ddbe37507d8d22e4f00e0740b1e9d1e1d3459398982bb9bf427bcc2d94f700ed30de927c38cccffe6963180339a693b641ea56ca71a0b1b4f5ee599fcd665f4cd6f8b3f4e7243e547031dbfdd7264b352ce1bef3bd0f939a55c611eeb8ce5c292f464e2a01da83b6744b0ab5982e7e5c04e4964747a3df8d5b7b9386aa8a96e7e47bc26605ddd274d3b2bea0e154950499068329d508632bea806d53d9d74cb0a7db2b6e85e80eb68a42c9a14aca8f10c94801c7feaa7073ceff753d61c9332c07aa14dd1268477484e4192857681a1fd23a4929fd68685104861acceecde826124842814bfe4d7ade5095c110043df02341008638b76177ca41d37da66fa33bff23f7bdc5d4af8d2ec110542c7681a4f8b97071d1b960bd4ae9ede4af2e6c6ac6abaa58428129882af7c2d0e0fdd05ec54a983c4555371e9016be4a03fcd3b101aef2e6d72c4b730c46256e8e3a6148bc1a366536f5e67860f622a895b1d0a1b7b88542945d9fe1d3dc7a8bd3c5e2291ac4c1750736abe283d472b1849d5980c2aacc4289a8302b240535ea75d78a6c4659a8645424f9398530c8f55cca49aebec08b401be6cac4b92cf2090e3c20da7bf8c1ce4d608dd96e442a0d93d749f1c8fd469f1cc1ca439236ca8939d13f0221130f48ae605e42bb4a6ada107293600e7ef87d20cef2553778a4304f3050e73d48ab7df927832938af76a9130fe4522ed5fca7f00ddb6dbda678716cf44b2105e6ac99e463c295e96f1d84bd599e30bcad94a4058017009eb0fad67717b34d8f7c793bdb7bd601d00ce91223ba8f628422b8befa8bef93a330440e7d4a5fd328121aa72dabd3a51cf688b502c82e7975668e8f1a8cd3fcb92597097709e153dbc5cf47c26e4874470a70b3d8c823ca00c5437774cc28da19760dbafda2ee83477bb9faf22c0f3eb969d2ec0eb4e34d375d5384f3e5a3f4289c82e984f18f942c3ed56f7b743071f6dd8e898dfa9192ac2c6f1068e422814672e656d71d189ca8d481b7df591e1fc82229fd8cdc78f208af4e038a42f64d829f5ffe853939fbdc15b4a641708df3e5a2af6ccdaacd3a16103d15b88dd407943c7446b1cc7357ddebd6c686b70752e6b4d651fab50983ccd796c3bcc07a2b36bb4deeab022479a81a16955ed61945f6e708edb5de3d9ef471e4df594288181f7fe38f0fe3afcb05c2c9584b241df60e520066b422df223eb1560aef315d7777b1cf164f7cc34a4084c8ed6a45902f10a032d7307851ab3c56ed819b97507bd9b5b1b117c31ed428dcbc0a1be779826db062863d727629803d6f1c7e08c8762f600f067818694696c09d87fdf12cc664cb48be2146690a1d801cf797f42dc5b709562854b1328f8d581f86a4a5b95d73163b8da0716a90257a48030d4267b6a89631960443a3f5502523a5c4eaa693d5a5c714b44ea734851a16dcccc981cfffada716f9f82fe025425d3089075b551eadacf0ef7c19a581cd85c3321d248db5f14ae9ca63b3b35f4c689992033d460392b85709281fd4fd92982c5e9dea7b20e4622782f8824146f637389256be2c340424ede8769c42a810c9be8e115d06cd4cb2485124038227f61da659ca30892b2bd8dd555af1318ada4702957d0aa679c84b5c4504edd050f423bc81de047c0f168cd7e1338c2abd6fda10ab3922d56638734d7c933b6a500e52ea5ed333802e8374a33bb8caab844a78d9b805647c14e3f4da98339fe18baaf23ae02d57390dd93e8dd7ceb2cb899bee516f627cd5258b296ab98145aaad9b09336d804252e0b7802150e8c168f299abe79ca8f7aa019728b7c6e57baf9c89412586c8036a3480819e2cbe9654d22dc93ac971f11fd29e8e4ab1526e59c7b31008d75dc78a49e9d3aea1dbec2a1a9f4df43c58b8f029b33511417d4fd13769411dd0da9d043bb4745ccc86c1ca0dbbb33dcc2ad8fa4d1047fc6e50178890d50c066393bd83bc78d9155dbf7a466280f0e6821aaab6abbd17841405cbd05bde1bf57e1c623b9cc3ce99792e321332a634c1ba0dd6da091e69917a6ecdfac90c9648342781e2bae99da535e6dc3db2574fe03ebff83f990d03e75c6bb1f60e85b404ae9547aa946ef07d2cbe99948058065969df03e235ec6f2afcadafa3ec9a421a4ad11b69b70d6452556ee81f11bd4708b9a4732c1ccbace6c7d31af613c6f2673411201edc1b5ecf50cae083c5f38b1ce9f97b3ff742dd6a3828d5e49836c8c0cab3272ce29a98c43612d0944400ba85d80d09a83b1ece8c4234e4d69613be9a42597b7d1530b1e057210dc55a5121463bf51d312c2b79571264814576f458bb567be00d223f9b47592928fd2d41647fee9a7606160d746353c71629967cce235b44a06b442e6588f92b920ff5129f739ae5f3259aec35c41abdbf9836031717e9ea10aee08f3af0a78aaf08e7843cad1d229ac9c15bae0e6004af8e215ec0ad929706c3412036a99c544bbb8f82c0cf823ede1aa5310da1b0c44d983311f58e879a02047fb78cf5f4cf5cb92d0c8283733321d65c9eca657fb2b113ec6900d7fb87328a7a3e24114250103f6b829372871727a7e1c3d54beebce544a80c3d87ed872ee2f0d99e1d1f04c4321e0dd77421c29658f14c64525b54de3dce2c848e4b2010ea06fa8919336d7b8dbc75466ed42f7cdad42fa2596ec59f55b57ba27359df56cfde9748d4ed2697972c15693c9589334f930ad1323505964c18a9963102f35842dabc2a64db9cda072a770cd565e446e2f1bdc2f4e4427d0d8c28884c66a04829c5293dd546f223c4c5436246a434a8d528b89bfd8dcad0eeffc4f56ae000e3100164ff9c4979b1f78a6b26f0ab7f6f895d261e0c80e44e3eb94600dfcbc7b19befd067da6ad5d384da106bbe24855e77dd44b9dd83fca49d7bba228bf5d7b7cd37dc799799df8b19686911934aafe4409980012f202fa47e0c0c68f747b44b25e7de7d023449ed1acf59d7821e9342249cf82ffc56b0250a1d2d3ee8989d0a5261cf4a9e368caf9ec79410ce17c96e48b11b10c078477458c7d78963b764b2fbf844fb05ae50c52cea60aa97b16939df28aba27f6b03a8761e5754ff12453d9f6d114eead388896e133ae20369df962a56d3c0955451b303a00b764a5c10e1c8fbd549c487a445bdd14f8794305289854dda7ec95613af0a0bd3a8a147319c40589afa89ff8fcc1f6651ecfe9a47093e476955e48d095b23e2ebcbc9f0c9e0662136209f87ee5e5dce9d97e88e4ba1bc2bacfba7e34c4a31fc13cd0d4d3e503f5bb25449e6b55050e6467357711cbefafc68beb21c0f50ed6f71cbc89c658f607ea6534413caf68eba549ff32338a5034072f4805a8c0992dd3a2938372a1e29bda41c623f843648b524a96cf6ba1b7733db7038dd865830d59e349842415a737c5ae7aa7a6fac46049e14a7af0077d7b28c51cb772250e4e4e2ca3201874dddcfb035e4863c854becfd793be737ab405c2115231a402a6547f572f2e0ae0a1d479b26b31f2a58d92b398c08b39443a591cc13182abc63a2c97b94f51d5a15106a192eda2ed4eeccfae4f58b09de6d30f5eb21ec95ae5edce5db01ca4d19a4b5a3a7031ca01300f23599273dc8865d248ebb00354190327b99a7ad2d8ecd69f2b5b12f99ff7a48bb947d88a388524f2b6f1a0c7e33234b9be45c2190f1fa6766ff8d25d20470ad9a51fa38306e874135ab133c6e5d4dde613a468cb666cfba71904c15e7b15eef85721953284e6327c536cecf42e5d328843500b3c8b60ecc807f46d8605c549fd303bd82be9e8a6b3d0a0416b8471a1e0ec46b7784c5aa69e7bb36e1ee438a574e0e08b85021d98282505039dd6af843a0d8244c9adbf86306869f90de022ff3cc11dfdb8a6497e4571663952e27dc082abad66e94b012399fd78e4d574f0dad7caff54405c23e4b17ec9ec8d303dca812c009e1ee9b7a035dbcce517f6af7e726fa32a06404c0cf03975373dbfa83a9980a2d11a04afda62fa6b5e961b23ae1ffa9c9c680fea1320050c60418c63cedb7dc74f78af680762080a4c8c7e102a93f4e94cf89d493850060324cd65e63effe2020df1be11e0474db9e98af98c9a63117a09aed8227eb7b6f5e6795a69eb8aac0024e4bbc86649169a8885db418a69d28741011327f46332472dfca66c0862fa428139db539b18e970957b40786ea415aaabe99e3b4b675b45630bb013bd6be3f78e089117b45ae965cb1b58b405f3e0377e4aafb82b5fc81bb43e5a5e9ea5664dc29ee1303a688e733fd3a79a541dcfcebb29031a455962f047f983658ea195c52317e156201f89d4dd6f5f5ae721a298647ec6634d7be5d6c30f772cea8dd435efd606af39ce8c4807c89e89d080209b38252d089eb6f8051b9e0dff2f794ee9cb7c1961107a6def2d77a0ff186bd859d8e041e08b10c32aa6e3942da1044391c3482d2810fbf5bf35ad9b6cbd83aecdab570399b6f37f6de629bb6ee70cb2e6011779602d312225f400a6344be0b3c5c1969ab369154580ab493e2b7ce4db896fba6d972a015133e8e3061e1a1190d79d2e13c858d2515098bc9db4f431d0f8c03d888c1a67c4525f79ce9bbf127c5dbfc1a49163c4778e758417f56fad4245dc1fee27b8a1acbc4f79316d6518c405cb8ab3f21590cd9af6044dfcdd66382d8794b1914114e77ef01d31db701a49ab6e9df627e5f9c509f713b5493d542e20abb19b8ec9a014bec8e7ef71aa5700db404be165de1571f187771b983bfacf5b9d2539049eb8f6862bc914a2bd78ca3a00c3ab88d91c4de99225aaa48e8d8d58cd19d0b17159b55281355021b5c631d9e91ca0e86dd76cdcdf4ac66469a0b6a4417a2d9f4458632ee5fd33bea858323f2544ae2f6783ed980115e270b6c2ba26f709428ff864d4d44b553ae83506281b8959698746fb496d0484fa5773fd89a54cd4c98a862c078ca76f27daa0c7e5b7f6ebd68a42b778642b42111e8669cef9e8631bdd4e59acaa464f9ef29c772098ded8ca88d95c6a3bd36e3f3c538f201aad72daeb5eddfc16f3cbba204a78861b3f1c31a0d6d9d0b6c53acbec84166ed41601cfc8e80684fe1e7b50079e8f090f973238c66c23fbef087899cbe2b0512b1a65c16606f77ce0be2df227434900e5fba81673aa42ec2cf0a2bd24c89fa97bfacb6a6a445f05d1cc4503a3aed72637f732aaa1aa687bad0dcfd92dae3f0f816a4ef9cd6f453be9dda3ba1d6a33d0c2f6716314a2050fe058f5c1f27a9a7e303e8eb5e06aae5297916f47af2e51021b2abe4d1f33b1543d5e0a7a32973162ec8ef6d31d5e4367342fbd8b74a3dda0e599756157951d2bec7c122c3b99c20967f80970a935f3c0b3d8cbad9bdf152b946254f46a59d3bc24bac6064efdf385c646f466d6876c326bb09fecb3e94000bd6b8b803d5a54690e65070f04de124871076fe12c71962bf707a984018b07e87e99bf9804ccb8bbc14ce58e476135c39e641ce5e66a3c819877c97a24eba1b2c61e4ff0afb97a08d98cdd9969959c72c260363ee4c571f63c477a2d564b3d0317e2e8b718925ae0eb3126a0097184fd1e2cf3b4b2b7fa22265f3329a671fe6cbf792d045a366ca70594d2d49685c63223d7125b117f5388e0572e26e05bd796dd45189d43470d8341ae7761336ecbf035a588885d450158b74d66d7797fb0702f0f740a03913cf83112d2dad1520375b5a8a35e30375434e56c6398a200d9757d88546831e2c6851e57769c8a74c0f41afcc2c9e3f208b34086aa0ea4760d365e036e8f294df0bc448deee5ec5bfcf144104bae6f2213584d47ad382438519c9497891aedddab64d68ae010ca78651173a1c69c3a2463b319682a07142c9785c79ae928fc7e3b5aa08ea94a6ba011cf043d323e8794331ab220ef411110424543cc610c10dd26dfef937c9a7639a2645bca4a83813bb208a8eb6159a4fa73129e58cf8e6f6bae91322f4018e1645631c6b8b67d24bcf1d4020d38cf55cff7831ba142f35abcfc7faaa569b71a8d98a6bab086846e662333d2266c048bcf2658e9b3803821760a219d0f989971614070dcd80d07d5af3468188799447ace1b927f196d24c60e1970da5cf18a18bc2ec3a986b46882f0cb40ef4e0c98b4dfaed411b7be2b287b1b19d74d6e5c66001c0de253d40d976a08eb75b83aac695dba02136c4408e9e7ada2f6a9c131b859b91191a072a11e5d36b619db6d667d3b05d1633240d8869d1f276341c38b622e3df5748ae263d187918a90a91bf2f2a33a15985285042c700ada824760cf4c8340d26254f683ad2795a74b685e22951043b9a7c2547ac0ea0c75dd8a5ae1704a63fa82f2403f1a4188640e0506a45fb8b87229cf147a245580b771b5089e663a58e942cd70e016c875fa2047fbc13a9afccd46bb192434b1870814a13ab966e7a1b0b152a4230e13dee9f30d01ddff47f9f9a074405e8b20987c695b4c6a66518cd02180e061163de852b1819f58f354d9f5afbda7b4551895ec093653f876a7ffa3a47aaec9cc36815320092bcabf678bb061c7608094f750a2c3c0dab50c617b42e1e7e43b29a86b3610d6b72c1aa0b5d918c6548c0022852b1db8b541c516e9539887f4d661ac808064026426e08473bf1e5a79640c07bcdac4ffdb8438a67480930d028d776ad98d965433fd93e94ef1061036f62d6a1ab0155620812ba66b6031568f5023f467b7e486f1236c33ca04c9eedd51111ae7e389c2d1bf38783d23347087f80718e9daf046418ef4e177fe00d232712de35efe9ddc20e28c821eacf8b30d678022f463536e042d503acb1724ccb7e0e3a75ab11244ba3277df610ff008a5448cccb835a4688623ab05d3aee5f0c4e7fd594ecaa3a00dd363b6bd42edc605891901ee8788ed438d308183a300d05e4e0531b08ab610d361ace6d45cb0549bfa4aa15e3020f656e29cdba604b03f669c62fa1580a0fdddfd26cf3a1bbc051895e45461725b653191e5ab6c0b4cdf92db3c0b13e8e56a1068c80d36969e9d6e4162a2f3fc45475c654803b808f6a1420f20506d74bc07ade80cb929575de44339181a31fa703812f8bdbae8da6a1190f388e47018880e00b79c4304209b2f04e71f633cbd9977431d7cca55a2757bd6eea04dcf314a79eea4ec7b82faec2931ec63a039b4e0fcabc5442c357cd79d26749da3e8b192363190a1181763f87ae2c0fd17d57cc5dc138fb9e6b6bf253e41514a8aa29ef2b7b7723d53224a6eab1d27c66087c617071b39485bd0dce86141f531353e44b99f69a466c19f52646cecd9faa30a6f0b7f772aaf763d09c58bbdf9c8f2eb76b1e40cc6c5f298b4176b3da9542edb89573517e83283312a682173415649aa99eef3e1eebd60a00ae08e84206744a256833a009944c04aef95da56203e73961d9d36bdd44157a3563d578541a4578c9d42b8f2fad36e7618abf010c283be459280278d826a176a63408978cb300d2003947fabc095ea582a1dd28939122d999d0fdc9a87effea2bb811ccd600edf29fb87ba0c3bea4cfacb9eae1001b6128a7e5996261e6e34b1860b5f4a5d471de08bfc66ef5691ce41b360b673569d81c52bc70b8a27e90f140954cbef785d709b7dab37ea540799639749563b9a5f68fdb18862add0269ac12594d1e83fb3b5370f64d4d2aa65469357da3e1244297c1aa9127fdf18cb5cd9caef1afc0d1f18685a0c630c00f71679968b6600c9ac5a3c5d15d38566b915224a3198aae319ccb328bc34bbc6141808e21603a7c0c14737b129b1f90356ef45a47a1f1e6c4dc1be891d65d9211997ea8300161d17bbc4839e87080bfcdb0ede996d642b6f9b43503a50690527142419060d9e32dfed10e5d19c54ba82e1d9411f3207613b42945dfa877dff9f0e7153602714278cc4f04769d73a7dd41eb5b686d4cb26b8010836755eaaa5de361e7d841f01884090798bdc1d071e6fb6535f69b94672ef447bedef566c41034c11e3bc703c3251f41e22dc5ff457cd762117b6b5b3047ae8543e8e71bdea4d515008956d099612bd321f2528dec9a380f097d27ff767240c04829af45b718e6813fe3ecc2f2f5b9d5df7e239b6768dc00c2c91484dd5364864d3a5a6c91fdc2b0db938c6f9f1c37949cfcef4f89a80b03417bd7b917c3f37dd0e5c4f80061581860e01e6853bc2801e033f68ba0a4f8c45d2a8186869f9e4e25c84fdd852e6a8892aabcfb3fc8444fb731f2c2827e6644386364999a489908a5aa2ef7b2e780f756f2c391b06c8dd1597612f38c86da9f1c8b48cae3dce436d3c909a4a5e03d45437e3b06a703432d5c404a50591fc6de86131bd2d4e5ef72907c16321975d5eb507513fe3d9a830a12ed50c1e3be6abc7cbc62d837485a9413284cbd01baf31fde0a58e265f0783b00b5c230dfddc131d4e1d3a9a68628ff5e1358fb326f8080023f5ed455d30ca724fa50132f8de26fd97acedd606f5d8cef75dbd14eba6e89541573342b131bc52118e2edfce86057f5bc0b1362c508b6bc31139bc7817d891b93debd36e5543fe312b4cd55f07c5906379c39265e017570771d75758a69c50673ba8eb29af674d11fed3a0ad965a2521882f427928070faed159d350e18377e34cdb1804a4d4afc5cd5a6003155c98fe22a145b6b56efeb7098d217d9e3c199ded251aa871c57bbfdc3c6a5dcfc108c53aa2eca6870a820a069ec8a15f1ee5e11f6e6a08908fd8e447d727de91eecb05442aa036a420b19f6733c2e07a6c5d982e7fba8d735188c5612037d143b258ffcde265b5a07dce98ea2f2b9cc189c65cecb42f88e3d9b927a0aa0376ba7e788703ca101c7983ed987a833f563ab625da07dc155967a2534831ba7fe1357eca588e663e38893e10b5641203a3d43e191898815fad32f24b66a1f089acd5a9263f7f6d7ddd7028067fed99e4ab40730c40afd80e1b76c700103047e477a41200b30102d9ad286fd7ed12e88a6370fb061251dad661782e353b2df4f01842a1d1713c84b777d653ec3a99e0da59dc3fe66705b0e42ee870fdc67fa1467191dce9e161766a5d13ce15ebdb2b893917cd6773889e10e1d054d87e427d742060e8c9befdde8927323849fe651ab4a1f372abfa2687f80c97e0ef8943693dd34145f0216a8692078d5f3913fb8f43fb691c7626fd8f47a832501d0ef4bb0de500a7a0b46e11bb237ec09c4c6bccd2f84c0566fee19c6c63f1248f953e9d1fed6d4f075652d2fb147067bae636179e953bba075390c817fa803f99dc513d916f780a218684ee5cd1b7c5e1c4367a5592f3ee2dd1ec11b10cd2b10a07b9a10352c98b6d42d256c76c65d6ed11c9cc6b7becff1671dd923935f59016d6731444a5072c94a8818b8d4b9c80a630cf44e8c8819e0c61f9ec42d94d4cefd0eb3b33b3f443fea84c832c1d1108238c8aa4028ced2674e57afb094fdc4ae40849af56acd688fd41818f988418e9e52e781bc5990bcdf84edcbf1581fa1848dd98c24323e0e351052977efb85c4e1f222da17173d06da60325f095234241f8f599784b74d3a782d417812666d1a0e3dad05897080380940c56e6b9bb0a28f15c1bafe1a51d4874f94dbb1f9e710cd3df67d8faf8688e1aade3980432b03894a484c68b6509ea5251e22079a6f1175eda4267194ae59cadc9799a48667558661228825fca8667a799a5fb794ae9904ce28697a1e9e7f84761ae03de591e9a601d08b9d92d144d61308a5fe2501d71b514a0e633ca5cac0317a21bdc8447abf7cf3117f81e921b5189b86d227d310647a15904ae601c8737c44dcd8f68cff63a93936f7ff3fe9de098d479dedcaf202abdb5268cf6cfc619ba64a69950291565a209a9b141984c270472fee4ec4d352a3da13176e33dba7df7c11931fbc756e3f11d8b59ef4433d70a56d238a7f8301dd2d95f1f7b9164f63c8e1837fff508bd31ebada211036fd0180b9789e9d4c44546af24f15e9f9a4423a6c01033cd108f413b28c67a4551220226e864a2c8127249aa573227648f0f3c63d11e42188622fd5295d91a04fb801915a65a5a4d0fa6292674b519c9e1605dc4bf1238d4c610c9844ea0d2853184b412f78409416dbbce02c7d7367042377bec31cca4376fe2e245136f9d004080d1e06886a85ef6965d2fa41f6e094028a2e2a74d50de4247a5dc825460ba767ac35efdae13ddace13718be8deae1d7ab9531ce229db67b5c3a000d4b97604856e36d7e6fe1ffee72dc1f6289de36f8e4ef9453f937e6f1ec38fab9098261e74d11898af14d917af563b567e9787ead8aaa0404a69029f51c5dc85862cb34ecb96ff07c93f633c053ddf949d04c2ecd29cc521a1205a6111b2bc096d0c9289e01f307a551a68495a81b6b5f7926e71cf05240bdd2cd83cae762b7fa0257738aaa9a7e856f96841c871a9e92a1529482238742218e4a35175a8514b0f126d426ba5109db2b4af27ccfa6152a6e6cb80a6b05e819d63646001bbc41a3238c739da046908c7498449b1964b5ff1e0156072c73295908246013685b559745184f3607a9378817100755134787ac3166b9b8032505402496d89312278ad888be802287451359738e504bbd9302ab4a263d98963584bd6358101151a21890945f3f8fcb4655cc2c5749fc1c627ac8218981ab7053353688298e3efd58c023c5a198180505d9f4d940b8a22f23f5712753c44f11683c626002e83920876f85f14588e2f1ea1c70fe9c92e8e2f658212f8e4717e48c74e1637490c169c06d67ea358bd4aa22881dec2bb7de24312eb548979e59ffdfd3adcab481fcce63b4435f0b87cf29238412043a843eb583b4b9fd0e14810a4bf517c6a702c1a39ddc403bfed489896e224106550095c0e032a0ea6695b30ce424a070a8297257e65b50af8a407ecadd36105c916d561852fb6ac1e1c85acd187dab45a91ac3d50a0047558db2b00054018c63a00b21691b1293715a2dafee424915dd0459c5c6d7d4c6c24641349c8de9b1029a59449ca149f06c4061f0650a4aef8fe150411223043313049528317322aa882498f0c23cbbf4664f9ada005c9d7cafd11c12167b93f223348135c2f26e538c6735032b089422f8e8302151286a61953048da012102415c53c47fd1cb04776ef38f465772382b42f7b2c007bea4ff915a7405f4e2125fbf28552a05fdfd6f9f15d1ab89034495e9492e127dd88e0e54604f9f443803d9d9c4331d61b32555286aefad407f141fde923d79b8f90fd1bc2f6d9671805ceb39ed53bde2139bb822fc764f8b5c967bcb479b9aadc6ff6b3edb32dc337f14f5e1c073e7713e1a7706c128de0cf20f3b7cc3ef71c4661f5f6bb67e3ea73df3dd947bc23b69eb5fad6f7e653df081629b9a13fd4d3fa6c7641e2fba8fef4fe417c509f7a7f134410ca5e7bd58b20b4fddd7c563ef5b90781c83ea7bd7d0edfc8b7490281e3c05f75ed3833309556b74486cfea6e2896a50c7f5e97e304390166134c081242086f42109f1b1150af7a1546217b54fc203e3722a850d8b88f78c77cf9abaf9fadbe379f8d8badba9bf8433df633a91221f3d95ef5d2c7e7e2c637fe29dc8ed3bdcd50dd8d63103a6a70c2616cd71e87e0a7708766b450641d330b7c2b187d2a3c597d5995e023cac106a6167c44357c44485be837c48b0e2b264a579f0c5cb8708971798df182a231b4201a406ea63148308695dfbadbe163281923c98baca33b54006cc0144c6170891900e6b8170174752500489498881183441163c4608c17ec18474473ce39d17481030ac8605a92c406ff624d9ab9660c2340c8356528d39a33445640fcbfd4b0a0082a5d4a17e342bcaed695fe4491268850355aa8b8acbec9708d18355dacaca8c16105354d86ac82500325cbdc4c6a76b002c62406115318659098c4a8e2673c1ac1345ec2a8020619309aa694524a29a594144bf970e21ff97ec25096f651b4b68e4a5b079dad63b68ed838e8f7a8d4849a51f361afaa5cd4f70f54447da456fad6c33ec49e853fb447be96584c086b63afd71052be5e37f1e1fb13545e54babb276e4927f662797bedb1b73d7ca0582621967fb447bdf434ecc5b2f6ae6771901371b2ec05e3f6d773701fdfc579da57eff3b6614feb3c10f24f7d7ba3b421ebd72a078a573c5cfb5e8f892d06f6e5bbd4e6e2c51c3911677eb5f65e97eb1fc790726ce188b3e44a747eadb5d65a2b5025a1c3e4da61605127a5b3693ab27fd97cabbebf67b4bedff58ec2df4199f1acd6b5f918ffbae273accea6fb088bb07fcf3163f5f17b43d988537fd5dd584e84d54f751388b0fa5be741f701088d6327e2d48728dc1156232bce1eb2fade79f0a636ee8afb36d5c1b4fab07e561fdb08abd8bbb0c69ab4d1070863749772cece7bed58dd701baf70b88d3d4b573ddcfe996abb45cd33899aa7f6efee6e1cbbbd3d1064e9a82f62b02515d2286b4ca1bc5a22757cb524dea823bc6ca0d0fadf883057e3e82fe12605c996666bad926648524a4f8b2f78b06a72e1775bb865b5c4cb40870b7f28cbaab964b9f2e1c25f2d01da4922fb53e4691d5bea3d58ce20e6d0ea8cf6ed08ae7751efae98c7978f10808902c62803c53e88b0d4751cb89d60de76767854a7da8aad9594ebc15059672225fb44be47f5ce7323c3de679403edf8102ac1d1132a19a8c3e413ea8455cd05ee4418fcf642afd8a53c3d58f6c071e68ee370605cf95c0c2ec7c5f5a012a824cedaa462287e13f1f5a6db11d6c45d71e77be0b3fae16a60031d105242f4e263afbff8b683e22059450325dc153746575e295daf9b4a088a3a9e4d22527a12753ca01d1e88819a4b863ca080cc980cd463a806b6676660e1523dc2d33838d819e1e504e895e7cc81bd96bc9437b21514e83d6917d28bfe16d2e841327a9173ceee7e971f757dcfddbd760c36e75c2dc964756fc19933bfc81a7e002184b0fc01502c43f885a7c364b8d361e24e8fe931123a113b39feb4f63be75b4193e28e1fa5843d5351ee5838a5c862cd25c71132fc160af257ce8e1d189d2f63c7d85cb01b713cdfa394d29ffddebe5ab29a72e15b91c9397b7effb417e479be941a5831b9f0e5ccd3218470554392975186bb7becd88d3bc2908a98bc6882094d1a26341f13185c9862806595443a31862906494c5f34317db1c4f48512a62fbcdcc80aa385bbe088cd10de4516b984f4a552917911a57a71e48590ecdd975ca43c23c585db3ac345f6ee7fab2254b8904352131fbcac69eaa2897566880f938a2776104306055300c1c4b9e002c686c8431738acba9882449a694aa3eaa285244c67983833c497638ced124e68bf6db41fed4b7b5d52c7bee7ef31c279436679447ce949f9235747ae94508b253c30715186852423883035c960668b2898cc6c81b0bb1b0617ffccd7fe64066ec0612f96e75d8ab13140394039310d56a04e0dfefc53e779f6ebd32f41d2904df7ba3c3d05cac9da7b4039f9beeabd58aedafded3d99ebaf3ad7d681f63f177bb06e3fb4ac3d5cf21c35a084df65a09c7c7a15f66299fe26cdc00db4d367589a69caa8ae27cdd3f6c872c5d20c5400852ef85222acc9059c68a28958d21250c4980086a430455da0146599fb831226620f4a2c45727ccd3fa6f97a40e3ea5890524af93dbf7ba253c0e565155d9752ce3f61c2333d6491bdcb4399ecdf8a685ef31b4b396128f7d04981a11cfd67d7ed3817c7ff04f8f15945b77bbac7bbd9bb47e947fe09127f4000193e7c8f2d64b05128fb8f3ae11fd49f3094dbbec7e9ee1f5da22aa5734ae91e516f1f66d457cf4af9bdfdc8d991e0ed84cd1de1d2dd796022bb5fe1727f3c60c9de7d120439819a29565012c5902b7ae60b575817c0309f48817a6282d3132df70995d493271a2bf7c7030f2716b82c4f6070159973cea9c5cd13158a70c13b3479ede0020d3433a40a6ce4cb2edc101db66c9f0e59e694ce6171fae40b1e60d0c85c21c361e998c5ee873fc4eecabcfb917fe5cfadc784f827bee31efe43792843bfe9111f7af7c37ffc7fe47b7c19dfbb15c9d0418a932ddc115c124e8c707285bb42c689152754382dd7fbec9eeb5f1f731d7bb57b23cc65d7248b9326d9eb1cbee4f81300414c8e5fb8ef7a3d467660033c2fb9222ea51889ebfdc776f88ab0c82171e3c7288378bd8890f26584152b56ac5881dc14215a6092e4c381480997246ff0426e1912bb60fa7248fa702882a3225df872c0d202e74300727f3740714313b01d42d83129b7b50c5bce0ae7434ee976b76333b118f783b5b1d78b8b22e56b882db82162bc32c6418971505ef3ca778314ce09e7c4d61ef4bd03215a67663ab23b6e10bba3edee28866c1c9186ac5556dca8433de9c39f7e8feb7137a8743a468f113edc20160ea3437777e9442474242489048f7477777777775397dd4d47907147dc1177c41d7147dc1177c41dc949ab3d592f72d26aeb52536c2227ad141a2d35c949e7929c121a49f77a4cfc18e35a80fdd17af96a20f3c2edcf86a2ecb9d24c2bdf92344b60e05cb8fdd510e6aba1e8abc1cbb704e9643924b59b4ee9dd6dadad30c769773ff549466f5d7921d13d6548742d47742b4774294774274774658644d73344e2886ecc9c0cb99f23ba9023ba9da18cced13069d53824dc0c969b417aee1cd207f28d22811d3821f453b284915519dc928eed9c92db0f6310990adc921bbfb364c9f22591c2d9c0d5c025e168e090704c38261c124480122c49bae4de864897d2b923d73ae18caee3f02f2ef7978448a6b9bf244ab2f7b11844c615b9fd1d61108a1923a60c193163c4c018dda59c517329e7a4b45a69ad4768a53629add5da53b5f67442a132ab9d50a82cd3b46dee78a669db964aa976342d95ca72a5e418d7ac8930c4a23551c89a345eba8809d3c54b9725a09424c8042a899ea64c990e781c44d930467729278cee52ce49e5a4b4566b4fd59e4e285496699bdc368f7043659ab66da9946a4ba954f7ae561c4bb2581e218b63b55a3366d8d8d0704997cb237479c6b1bc1b2e9751660f1361f125160e863b2347230590f1006e0532c820e345462c167385713df79764489a1b737f4954807d4984d050468cd210c60b3224191d51a59a185c2df747c3162b3068c0e24661c48b1ca7ffaf1625f161ff826191f2e7a4814a9ef35b3388716fee8f8626301a94b857244b9020512fbea8b57a377eadb5d6a326f32869ce537763abd65a8d64548e86c8b5e29672fe112fb840e305748224c31c6199474718a974d29929a52b2f2ea53c90d29c4e9405244228122231a089e2cc99339f9190efc8d1aac988153ea3205c5899f98c94649bfb3332e2628b2d60e852648c4bc7ff0530b8a8dcdf91a2cce388bb4dee2f86158c8c91bd8f51b994b6e052fa25e274e661c44816997e46ba806145260b1768f1d222a605fd8a50f95ee072451543b09882088baf481443b0f88a28916beeafc812122b58c1eb958594af17aae4069355fd8ab63f17c4c01cf667db1bf9469c7eef95e7742d71234ec48938d1bd78846672cbac236d30f3c6ed5a1e585af383184bce2435492167d42cf1ebbaad7bbd8c21da102b66b8d726f7d7c208b277dfc3985f5cbacb26315c973752767777775f317153b9bf1688889167ee8fc8172dc83c28120b4941a95fe90708a83f6212327c1e998d3a314208218410769089875aacc00401853659a1070e9411c50a4c404cb9820227e32382e62352c547c489584c096b63afd71252bec084e04c1127c860c11447486a7a380d99e264c80da72b880c9901f5114182099821456c0cdf1cb2c2494a39a4c2932754b0040c3151a270315ab0a189e10b9bea4a95942ad99d6094d1c62115741508c124155b53be9459d24f7536986eeab5574af5bda554291ce4794edc38e06b56e669bffa03bd684725067af9b881a50b2c3c05bd05d65a6b6db5d6fec96df6a7afdda9d657a5f3344fa713a55e6c761973565447c26b7624bcf24f7ddaa355713bc226be2fb85c5358ebbadf94a45c737f4010f1019104c45234024249f65cd948f60f88a2ec53ce8f9133733d17911244faa884c9fd4d29931990fb9b5244b62f1b2137e6c2af76622fc827982bbfe95e1080f8c00d609e58b27c2a32aade666ffff4f6df03403e65b09c412c27bbb277f3ac3625552a77f7aed27c9a79ab9175f46dd853f6bd59fa277bbaa175debdd6c57ceab40ebe40bb5dcb0583ebddc8fefe5c992b1f45bf5a7b0af25c2355a2d6d367bd59b97da4df4e6d84d15684a1f08db079b21d902bd32869bf3c8b918925ce8aebf5121e788eebd58349d7e096ca54dfbf5aad56abd5bd57bbf75e6c236cf5da6ad5a55ed57940afbcfa5476efea5330954aad520fe14fcd6608c3dd67177b37ba56bf86bdfbdaea765e4ebe9f454deb3ac2b6ce1bcadbfbb6635b69aae789dd59d505c59cd29ec733cd058d727c14f66299ebe2f6630f30acd8bbd7f5d9832bb85128c21b7fd538343477292b92cdffa620e5fa59477c02cc6e82fc0a3bc0417aa0829800adc8f33d667f6f6ec9368672c8f379b41579625b3df8d65ffb8c4637dfa6f38eb544ae7fe3c3bf7e8daf3b5c3fbbfed67cffd30f4b26d74f294ccede77b8debb193fbb54378ed3c7ed87cd7eeba03eeb6dc7fa55f793fdea55cf7537aeef6cf3f2beec6e5c4fe33ba39e27d6785477e323fb1a9f7d0d7ce3c23c8632f7373e68fc7d1a7fff7e6f200c813d45dd0bf0e6d3b7f1d63e8d8e7b9b8efb199db7bdfd56f7b3face70fb5159d8cbde72ddebc7fec5aaceb3dffd6c58c371e351df6239fdd494ed07d17cfa20a71f704c768cf23f75d5e04681a12d19d8af5b05e4d76e3301661e12cbf7548e2a8b294f32fcfe9c750643f9bd839e63e909651efd9927c66e58fff401fd514acc2f03dddd5db624f660f56fd95936d9ee831b619e33681c1184fbc4ed805b1bc990e988d3efc5a453118549fedc5fd21818722cf7e70315790a91529a0c977cacf55a8c0f54f6feb975507ffa74f6366adbbddeca1b1116612d145cf831ebb59811b284deb55a4dd6afe865ae5afdfd3b9fd33047c5f57a27cfa0995b6ff3f37d8070347e6acfe9708fea5c9c1457fbce3fb49f6183ed8da833036b11c67db99d35ac3d8daea306ab4efbdb69afd23ef559b39dd5b0977d76b136b92859b837578882f00a8428d4671095bd77267486511d09b1ec81907f50281484afc51c37c70ab6ea6ee7eab82b6efc93f75a6731a2b20c6f518ec0dddd1dba15ae03808912852b7250c8a069bd0a0e0a87fe428408099a0228a38c32285cca523772bbd6d50c624f52e903dfa23e850c3bcf33fdecadf571c7d766f82773f9f4277bd4f6d0379e08bb8be55b9b5189fa299fc2f7a14cb2373f2866e8b252ea13752644f2fc23e5f6c38bd00866ef9d9e52ec41239ae1a0982b0e8ade0953eaf9b0123ef51b1f580437904fb1b7faf9a9ad03ead4ca15be964a6debc08399f559ca59d67596524ac71216655a7f72bfcd5775d40706450b2d0aff54dcca2fc00dc478411166f8473e7df870c64cded4df7e3e7c016e607fa2366c83e9067986ef0579ce7efee9b98e6616fa48232973a5380538948ab7083459cbf067931fb2640d727f3f10e52fca972f8a942f4a1639cb5a137cb58e55ac5c8b83771c994275f1e3fbdcd8705dcf32ed743a9d7e506d4f274daba13d0aba97599c612f66ed79a243afc764eeee1bf680724e1e500e508ebfe79ae7d893990e09a530a187c2946bb2473f28fed87c0ad93bcfb3e7d36c89267b1ecc27fce3ffe3f4adfaf4332f28be4db669ca144a31e64ef1c48c12627607629a6dea7b403915fed2db3c4f84152e798ebf99eadb736c8faa814f18b573833d1a36b077371ad806f798efb20cdcc01fe293db60f26c34e5fa36afda7e6879feac35b00a6fb8c6d370612387efc2aaf9a9ad03f83f27bcfd06e7fc0cd7c0d3df4503ab20f6366ddb519be44c9b547377b7794f9699befa56577fa61ea2fe761e8da63b46f03d1a59ca57ebc87ec7739400778ca0914be8c5b2c8a7f9f014ad63470638436b711493c18a188e9c032d535690440f4110b12099f848004613231d8a66acb999a1e6c83d3ef411790c65c923c6f8fe73f39101dca3cb3ff2e39c3dde6560956195915d8cdddd79da74970b76ad8b95820b83cc00b7655680eb8a10464c800b1d90bd6e4b2a298b8a3b803b3fc0b2addc2e4dc603e6bf02b82d030080ecc625528299ca4b1255728c33cb1b11a60d71bd9be9a414c23259bf721075d4c0e18473ce39ad7cf8ac2de8a413021591ddd8b8fd4dddddddff068c75e5c6bf60352e5493b9680861f39a115dae16908c7573727f5bd4e40640d66d571d88a91261bd054d8699e504abcbf55e8b451df81c441da9434e8645a27bcc713deb56461dc73765726719871c8e0021acf5371f2290b0635c92c147e24bee6fe94bcec9fd2ddd907beb4131779b275bdd6f4b97dcdf1964577553774e9ff7fd1d4389d92d4e5d22a5faa7b7a7fab075e4572225182bc5371e91c8b64ba424e7e3ac2304a44a62ed7a0a104a20eb97b41166352a6e76eb13294dfa9e45f56bde8830d6951b1f4ed8058152bacb78bab1c842c603667bd36911561f621bc4f56c9e1ebb2030cf9f58ca3cbd5e22a5d3b797d6a17fbaa88e48c967fe78828c5e22a548a4d44fe45dd9bc2da5b57e89945c51036f55b93109870a48e249ee2f09a404645884f9b3ccdcd91143f992c09263d71f12594089b7878c07ccf076cd78c0dcd77f86b3848041ea3249ca1e88c9f14750eacf86a51c3f272a6914bbec2bc9f5097f7ee2dbd09d4e133c845bdcf6e08b20c32c9bcef97537713dfb232b9dd2e3b7254b96475a584068d14205c5dd529453b93f2d6932fc8b638c2ebf2d4abe2d49bd45d6316b5712160cd165c81114302748a2a585d409f2a90a25b47c56b450e9268e60e08485121ce9e1090d478a6eee4f4b122d50583a34118bd5606decf55a22e54b22e111030e77f0da9425181009243740118394263c44c182448b90164e2d50e2083259d4b09e201d9186a5244b982c4e2489257925c9f2c4882b2c24324b9521ac19b21891e50a13d2d151dfd022c410c1855106546022c69721964441869ca188324762f88c3032e28531b1d8116b63468cc45eaf16a47cc5622c2231160c4454898188248a8860c20516d196fb2362055995fb23028a21d00c51c42ad22cb04244c46201cb523ee5feb094a93283dfa8ac551f3b2125205a96c5cffe8481a4deb110fcb791c4a5f73a4e7df928ec9f451a6f33e369fc8c175202d282f0e503812f3110970b8380859480d83cc44231c7a96ff334b04d7d88637d54976d9d8685944e2fa43dea4f1888ea535848f5f021d6b050098ef3424a110b41218e533fc346f121168a580862210d384e7ded85fec6562c4e08ebbba772df3db03e8fabbaeeb11dab135202923d8785604ff6aa5f75b7434109888651d0de46121852719c5adfc677310a424a2174cf7cfadd83c228ccef1e0f52c95a7c68254dae91fbbb62946f40a01f42f7d01701f6744fbf2afe81aa218f35ca8b3524c61af292afaf0a99ecc9afca98dc5f9530d915615f9534d248d6315371617bba474a4359ca0207d9dc208375d27bd596eba3853f3be951f2c428a5f4f8509a10811861d73534954d7936e9a7cda5b9b249862ccb7a831d3b9f0883f2c37cece677076fe243a30c97324fccda876e3b409027359a734a23298da6d194b20c29647ee8e20579403965729466be2a4b7c4264914db2e95bad0883306b272e8a7b7a4fcb3638155c0981a2ef8910880f8d3298b5ed4388bfe1a1ce83a79ff5ed5046751d263b6d7de4a23bc2e84395fbdddb3f3e14b5ea40f99dc4ef82348a91157b5ab61038fdcfd3a9b38ec3b9e07a9f1f4258bd72545c1efb1378797aff0ca24b8a0bbfe73bb60eb1065eaa102f4d0e85b23f97820b73075aa65d2bc22614f2b984a098e346e9dd0d17b7c5f53e4cd4e1711ccd2d0ac2f71e429e30b784088baffd4ed676c0f6e272b9bcf0407b4fd873b9fe274e1303c10ef7a404473b318784488d233e87c56d7d61adcb45a5a84fe9b40f696fb452987f24b65a0b4248c9f255b17e8fd60133fc0a27c0d33a60eb805efda93a9207fe7cfa19abb31b7723ead02679fe8d0ffbf45b3fb9a79d67dfa39faab69333deb34f8358caf36b105472f6967bdbddbf1175288638acc5de90f65ad98d7b966dfd8ccea3ef2d7cc3fd8d0fd6f69b7d7f9b6775abe73a1e4379856ff7a3c29d4f58c394bed63a4e8079be46bf5afb755a5b6d09d956ab816c6d954f3f3b6d1ef0bcd638e68e1e8d037e0a70a815ed9053a675f0ab943248f6928c40062353fc785f55b70ce5eed8ab3f5ff5aefafb1d9ccca864ee3575b1648a6804002080025315000018100a07040281582496e7f2607b14000b8192446e4c984b23518ec328888118864188010411638c310620a214446523001eb7b4fdf10f17f478cccd66d1d77385536c88af37c2501c714f2b79a5707a39275acdd837d656f15c4d258dfb8ed2215ecfe7e237cecc421f8a4cba2d897a9b2db36d29530c9c3e96f4c6c6759ff9676f7ee5ca9c77aefc8f85f29087dd4be576d52b062bc9d6c608f4b65341d88f80db18fc277daa0d6f5bfd148b6c04a222265b2a08a32563365034909a7f03ace71063e5170229b0c4337f100a20b0192a35b4bdde92bf251c3d4dd345dd854d290f5e80a7554ccd8cc96cf6e025989cb86aedf5844037b8df3ee5b15343f8157a5698afd32b158d1e149fcb8c4e510fc4036d82e8799ba0b23957b62caeb1e7a47575c208b76a84644f54c292a479a736b618d173d599a96e08956b9e065dc24e3c610600bf69dc01b6cb53fd1a008ee649fcf292833da048795af2e441a852e0cc37e11b79135535bf4446fa5ec54a8ecaaa237944af28c25e2d1b0ff3345674b4c60df55a3b9f23aa021a3a643b5f6fa971b10f001e3b975b50b5cf69e470af54a13f9655075fc510a5918a3f9a3defdd49783e01d0ea37cac8aef28e8fd9ea79a1d96362737e5b861186fe0f93f4b1e89f756755d900a4f4e38502c1b26d47b34efb26bbb7011eded0c41a0bc802a81f0880ea65c2a5c02b5a96b1c4259ee760f3a26f9a8b0372cc70c9ad77ff445971b588bd6588cbc01af06d08a0f60b7368a7a9190e36c19353cde6b33263ca11f81ae380e91b3f1122556a7a463207a494e8512fd0572dcd8ee0fb695c2f8e26302ab27055a36fa3a84846e3c9e2d6bad9565693a6552753400c628d2a05fa18fa86c7f38e2ab26b7ea8f883a8515136c28593931a440be56730e2a32f5f4d16944fa7617d6a32b5e139c617d013c6d11f22cb50fd202e818093bc621d95f7e3c57e7d34751f592ed44c1d2213399120eed5e872c165be09b223e63737d83fe9b97c7d54467d6979b0d34105ec040ac5118bc9bf97fd8fee5d25b2f433b4a1877ad34f3e502094e27db5e16a003534d1edbe0be84bfe660c2b65640eb468c73a5e48069d602e867e13593045258401a5aa9d63e563a9b6aac38bf6282539961362d222a78390ff60325a3712232f82f3018a883a01fa6a9553eedfbd3f4a166589724bc7b4486ecda478258543a45500efc6d2c73b21fa6c7cac925da1b2f83754d6604454d62eabf73bc4a1d752c4e2d30b02ff6fb57da51e9c3b8e839e98b0fa5630e0525e5b793def8d8ba3469dd32c9e364a805a3ad29ccd426bfbff3e3c6ef711472fb1e342d9431a0df7fee6617ae041f86f1b1322267fad2631d3e983757022c3e042710ba99a6b12b6e939a9e85580e171eac5002f185faf71b7d40a77582d2e7c6de181e330659349b96fe0e5d01c47641ac50177a5bb9e1c8ab767853291e22d9916bf535da50be44ac862b5a8e8a99323ea770fd431d6a05ef0d69ffda15c8be9a5021a1186f535dd2e3408dcce4750734919682b9aaaedb52cb1b0649885d1b6691c883b1c7dfb7da59ff731721f06bee9a21e90bd2f6e0c021f87fcb97d623232652e83e74ed87f4d7e6d99ef1d2da2f51331064b4438a3d4246a01d34f28d4fe4a50e2c932d3a92c9574327fd0e2f6566f3c3a42000d179d8e9c3ac091c9362440de12d4d1f12579c091e9d993efcbe205f4d7f434fc33b5a88966d330ed5c999e80bc6c4983caa08e83aaee7b768345712aabb39b04d211b74345790a2b1d369c59cf12e5117834502630e4e9c1cf5dbd5b8bebe1bd7027777cd1011d3e4e07b2cfddaee4e71406de19ab6e3c9894702c4dcacf020b361d85c125215df490e11584f25aa570d374cdbfc7596322e4c0adb73798ce352bf7b0eb4c47a9a80618dee70bbeeaf87d16c5687c1e80eee4f0c24f8be334f36ea8c0477da89f75fac14bdfe640cf7fb4ff3411e1a76aac885fa72060c485e2a37280a336bccbb02e37d9717a5aba8dc4d6d757fe299ccc4ffced1fae26426d4b97e554cd33222c113606f54ed47f059ae6ea2c5ff536940edce31a462f33bf00423acbfae1d0439d2da97ccaecfb7623ad914a5fc2e48af7fa913a79a9881b1c9f2869d0bbc1b52161a7da7ace6928f6f0baa9a7b882703e863776b71b4af33328593450b668b730cdda1c52772baf000fa2e433002ab0f1252ac730122352e30cbd62a04628c91506b13ca2725141eddd1825ebd31af5d78438bfb75b8554335613d661ecb548fff197b3dc3f47f608575356ec524c0172f3e1e7390aac0509de8b0ce35292b5ae67c396a2ffa47051198723f3d48c89e7212604e93419f43de798183b003b2a7c3647d3b392c0ec108f6028ffb3e56cb4d881ccf4ccaedf264e2a84636f819f9a18ae1c7e54ff3474c7092a9375369fa0b5e9ffde8fb04cd77269adb5cb21cbe80c670c5a268075165c6c3140fde65dc9b80de1776d959f44eb89618387f9689d5b1a4cdab631e7cf46b665abdf0a6c300a9ef535d6ee6ede5569370e27d9f289ad376d4f665479e598594e4720c130c9530ba6b48467258d626027006322d207340c07931d51d4bc0b6bb18e55ac1858990b30e4ebab75ffce2e9680fa4bf1a92de2e1801449c3b9e6fc1b7f44f5bcaa7b73bd45a688cafce864a2063a5f34ca5e092a343694f1f7cbdda6fcee90f630de251091b9f361716ee51e7f03d5153322927115088a27f5647a0f5a39cde58983b2ed889eb82f57ab96fe496a353c2f32113466dd16704d6852826eb9141eb7c57a8ab7c854493e92dbf504c3a612ca7a8cbb5dec3297bec7c4b62a7c82454a1610b40442c4a95cc5996361bdad4326d25dc5c01dc2b49dbaa13938823330f3ac189986dbabf42734b7ad713afe720533f506ed51672c59d425737ba1b5c8843ac2085848057373f7a8525eb0dbc06051ef468fc82468cf8793fc724991a17716094b0dee47eb6fb08711441f7454101a1522652e6d0393233eff8ff7ddc8af43fc336e5c6e8e92636a00088c15d8d07afa8d6b15c39c439afa7f7c5dcb660ffea279d1da1fe0fc214988d9fd3b1677d00f4469af312bc075f9ad261dda59df60ce6fce10c3381982a26bb9ec8968697b084dbd580b0323bf063e30f41977f6c6c938015c481375a641b91ae4eab1e54b6006433c0b661ea2cc4edfd00ed856da5fe3b45efb18014c29082397c3cb833ada80fb5efedb55102b38ca449f0bcc7ccc85500c69673893241a4ca20a8c760fee6017acc22e776c2fc288c8c812ac154fdc23b8b4d5192649ae18d1ff228ae047a965e2ccf6e96ac152fabd67562c3ccbcc2a98433fe7a620e02ec5265a97174fe72890576e6ad12be4b7f85763f909c3c678882082e0ccdde6424cf865084a4b9205710fae0e79290d11122b9f2451bbab2b63fd645176ea887ba3f830ee1ed93d1f9b23f423846919851809d50f05b1c35fc20ecee2219721f350394d9c47f28e916b29c8bfc8e04d57235da84aeef03f11fc363c241d942d87276f3628c6122b2a601922e24b93f47249b3721b5eed5142d1a8df3cd8081c74997012e90b9fed577089dc6058b2899b542d824bbda0034f04dabfa1c48d0094a6ac7775e8c03bb6fbbace6f09c3b59e6e98f64c4a787839ce0cff82f6f8d2b397396f19bbb5ea857a25fe6371d10f8bd6ff011282fe82b26171dd1d80a6df81b6b01cd7130dc6a96b28829ec0c4c80db60bed90f312efb946d9eeacee0d3569cc25718b0026dcc55ae581a929aeddde62a7a5d90737a0ab69dd5ebeeb1137e3ca808b000e4e5fca055ec9500372d38208c16f559053fe4bab4959f1dbfb7da905114c2cecc59aca8d51852b1f51975972d1c48f2673308617300adfc29105440f471744958e5007f45f5f0c38ff062a6c7815269bd887c883d921762959feec521827c04b53715069b104b49375f8fb927cf49139dc977a82547f4036d8a6938df3ef0084cb9c92bc1b0d95c0e6332f998b59966cdad2a5605069ea6588ea521da2aeb0ec194a6453b9de710ce6514f6f1fee8453b5b5d2c4c852881beee816afcf23c07edbf2691dc5127145cb8ce0ee8e3a31f697a1315d0e8b0c1dbbcb54d556d1426cfb09a46befc4bb26aa76baef0346e009797bc8f3354fdeb2769523f795f8c604ce6f4c447a7bd964ae83561e0c70bd3d9619a3e2f82cd6055c784325b1b1046faf68248d7f9b1be5dd4d78a519c1b8378960966e118c42a932799b2737b5c9294f30132319891602353aee839a85096b3902ab9ea908d0a01a571295053ff4321e2be415dc8b8bcfc476a9153560adbe1de8fc7fd0212d7a19a77534ac415e588f949186b7b19eda915cfd33af144972069560005ee318983119246b9be893a0bfff711a9b22c1c458ee0a99ed9fa594de56bcc1592e422a7ad39f111d302b1b1b3c7e4fca715f17ffe00fda73b9e42ef0c7d31c2e648a9f28c1928b7a926a6bd47087057e09aaa1a398083058efe2c929f822a1f53c2818f658c4399f2400b9dc348e143992309acfc484fd9bd733a828a3227392cc176d81b9adeddb82a13fe4973fb4a5037c9c2a1e0008042bb69a3ca6fea1544ee92e41e6e5bc305e3526a438b77c8345e61bac5ad9064c2fbf23cc71dc7c7c121906296cfb7c101c67ecbc010fd824f4c2182f3c8a2dc3155531a886d7018f926e5bd2d1faf30cb6e06d6fcb589e4ad379f7229ea996ed6fb08e7aa31bf6e6ce35559ca0a1cb11c73917d6e4d8f195633c1c9b3cf68fc55432f58273941fcd23ae34f6236c23896402b464b4cc6c79d61157404b487a83e2947c5eb70b031b20db0cd1be5d9c3ec074e4cec262901bb5b7ba84482c3c16776efaca3d0bc4d53e6cd28be0eb66215a2bf6e47d020fefea1b1c42ba59e505704f3d2c9e77258c86ca30d66d14c1ceddf5d77a3f562fb94db0cb8e216345f7e7811d12232ef2a44bb3603fbacb3251c7d6546d1820382922ddca2e9cc030a6eff13041f88d4fe81a814fd50b637f01000ac97deeb5f2164ea9480d29f2b082c37ef8c206543c8dbe66af1133285d0b937902d8027a041703aad19b025518271cb6bbf3161fe5aa7693be142c21adc3c3bf47e731b2116f34b9d7752e2e883bddb7db0ce6418bcd771cb4a092b304ac2b356791f9d2343d9b36c7013ac3d9151b041effac6833ec9c28a3bc7a70905310399c2d5ac4304657ffcd8048ba88e45d1be20d42936632d9e56de3d7c6d9c9e2bffd0dc4454d1c89633f3035399b3432822811de43eeb062fce263f6203f949d7c223edbab60b330e17e590288470abbb888ddef908e14c2c6e80cd40b71869ac5e0d1ad79c96eba4d98f69e62c856cb3a110270f61100ea8d2353c027acae44c10917b5427b622ec7e59f85c42947a22345339e93981122db7cac0b71048e124cca3dd4132dcae4230b735b9723d9fd87838d5c60814e83387882bcad496e4d1cdf28a364e5cdf607e256868c8fc9444d78b30d0f70062a749b0b3823605560d3adfa3d36c5af29693be2f8a2baf8c64648fbe7ac6b105dcf71599cfa10d22883b7b3859e19011016990d294e69247561d506c12a800bb5c929c223922cd423ae27db4832114e49dda0c3865b701c2329bef343d348aa1cc601389b50014af20838de9afe2895dc43c3c3ca21df4488d1a65c90d4048f6358f3eff6840df7dabc8f19e47f77e68f24fe11be4828b59906514efddf3badbaf57fa1f915c145fadef1f57a0b2ee72e31bc0956210418b15bb80b020de82cf504470f21171a264ca5708b39f4468c699efbff25f8aa4ba2a186112b701bc35bd989b6327c93c7b34c69a3810a59e29b5748682b4998a7d9f24be4e6205221a1cffd4a92c2be4e85423f186ec7626850a42d7961ac5c6b5425360ab765a0fff7dce98f19f5e29871e8137e245db07402f73591482dd2b568ae3c1812cac635631bb34d6c7e2d11219567277f815e0733d944749b08d58dc768d1f69a21b2cc16aff35a5f5ae011511d1c806afa805a6dc80356d48292626d119e7ad19e37089b7fbd87b16ce51023c66a9116a8a2252903b6686e00856a4a0f1da9acca5a2eefe4526e0770ff37d2d6eb120ad46179644aa9be339bd57e1c2748d56374d95f7abb3b3d9b5eb13fca4e53b33462990b7abacda716ff1a153c80bc67798a12ce244345b26908e93c15327eb414c955fc35bf6d2285bfd3dce578b4c08cf3190b7778a6b4a75562bd9b6529452c320b62f2590d5b08d46d515540aa5c4eca01eb1f96cba4f1274391c96c3ee958b4fba579e8ef1eddeb367b14bbe7997d8e763f6612887a8c0572a88e4327d2c42a2c04ec1c52466093455b22593a5f5ee23ec1a0bcde7510189e298110598dffcbb811a53e7528cbae093b9730df0536099e2d09f3ec4ba130c995fd7bec8c451db2d0ee4eb0f7bbd0ecc4bebca48de138bf38eee38d705a867a0468f5704b2a3afe5a46bbcec832147c8e7b298abacb757635d1478aa8cace81d55f08a312a2620b3d5303ef942193535380bb86a2cd2e007cd9c4ae024aa32c0b4ccd6e36c089535289c7650bf1e5ac6dcb079f0edd9e618e4e56c388631a80819e5d6fae619ca0c0ca430d99f4d49e02fa6ed071c121edfaf21167addc9c92ae6305260a1defbe839920b6071d1e819db7d376d620296aa1be6b58c980bec1587455c26f4f61e0ae60e52ac187bda3c511066366a351bc0f7ca3561e00198f5b5c820977b574552a527798142cf35ce9eb3e9cfc20f197a64a77d0ed7d2d5ca74998cb683d16d5ac0dbaef5363016fc9eda3aeb78aa9e99aa1a168a9b51a8cc3790276ffb091b428ea746faffdec6c04512125d5594f3964477108cbcba2291630180b5cffc8ad7192b42e1ef07fc4c5220e733110b8de5553c2a6dd41a18cc9de133218d1f935f3da8e4a4a310b9d9aa4e031680c189a14aab5b49efcc9635df73908e96cf622f49fcc8c5599546b8b5bb60a63396cd812b90aeb7691a80c1481f8c803cf4504f66491d2668d71a8f53e48a4ba66006931adb4e15c4e487c28acbaffdc428a7904b0b08e32aa2ba7e884a13391070506800ff22df0805bd357d1033db4cbff052f0bfc0481c3a1023ca810ad12618213432894a78479af027441be164db6680fb30637ca16e34cd98f71490e1935ed77605ce58f925027b9fa80d384ef190960b4940e3a4a423fd1b4892e9ce1284f208c855283567f7458929d505e0688ac9b87c408fed0b14e516d1fab0a00b686fa55d14b6f863489b2de3ef9daf90dd1d192a1e04e9cced34a7a4488c934873e608f097dffe8880070520748a217fca337699709f4d21deabd304bd20165adaed44da961709f8d44604369d86211a51dcd29a01ced7ef697c50e89464e342db8ceae111881b467cd4c9781e563df10c1dc432001f137f7a2fd3797adc1d0b655e20ce52cf122d394df623cc24b0c896247edf4af3cac6d7c9aa301c5a0c5422d94e23416d92587c57c67bf654364f4e06a89f518a4d14c8c37ec712be2e47dcf258c2e6600e2d0392c8671cfacec1f3be1e2b2c190c7a7248fc2a65a99b565a44095fa01a820c16237cac4a0b2341f1db3b8258149616a93846a5ca8adc442c99db58fe714734f8dc94df8c9ae89191847142507ddcacb0959fb16dc9c20f9859970d868d0dac5df48df230361f27726b515a07bac04f32c73994261040aa2e617cb55eb1e0a3257cbfad8004022b4656d056f6882d0ab98a030b115c4453ebbaa841d591db6a34fc267c75d2bacd1beec28a1028e49e6108b5aa8a376b42951eeb584cd8b4195bb6d88b23b6fca19745aca1c3a4725cbf9462adc93f30720b939845ab822a4dfe117a44c879c523eb7cc6ba2938c76cb52d8c6f29a7b2ed2ff61aaee040e088f96fad9614409cbb5e115f19356bb89a8785e3716b6e858dff00c15e4d250bbed912151363028f3a207c7d8beb2a30ee5a949546b1770bc4321ef81466791c753fa439d841e52c5ab0aaa2ff7f7b89a363b472a7f092c81b590d75e42e744a9242d474540eaa259082177829cae2b7622476a9cbb08222d730340a01527beaf4c32d84fb02f040500ffc07dd0360a442187d28cd4bb81b9707bc94ad9e934851d6fa143dbc6d07ce3f68851b807074992637d5aff3db1690372b8daab42e1b69202e4323551a4b94ca7af828eceb93cb457694fdd1a5d71ce5ebba1434c094d54eae815b54c7cff8c06701690f8cf35ff9440607a11f1a5edf23511b39b77a168356310e54278c8cf0b87b4a4bce59ea3355682518ee90c7428a3b2d240b588885980dc050e0c9e8017de26e76c5d4a696ce7d08c6edceb1c91f270316494a0e70dd4495049c8e89a1470c44c92115e8b566aafe00535c4ed1640469d55e9c110665e0583880ecb99644829b474059dd5bf243a0083be9b065394d831269bc2deb701af865c4b34ec69b540717223183bc78653cd479afc612ee9464f2aeb84bcfece4914e553ae556358c05de6cc0837f4740ec1d5ba6133dabb9973366a68a1d80daa19f6b9b382b24892aa326a8fa4176a00d37489a6b9019670eb200ce735d60ad902f225b6bc05ff8d5045e142c165c63b793f02023647028a59d263e7e8c9058911e400e51684912d02fd8e20f7d356086e5a0fa641b8b1d72b738ef7b24c48aebd9be865fb050ae37b6f6ed68b47a1905d7c87f4f62fefaf2c1daf9d2ac3215e6bc762b33cc1801a9428a3a0741ea45a368d3e5782c641723e1be7f2d5da02e966080b4d52c2abc42db5a50d75746a9b7e55839d859404be0c0bc4234fa3daa69834c6308c8368ebe7d992f82834aef36ea0262f56c11f010c103844e55f79f7ed8cdd49ba411a8b801c1bfc46c4c1d3d541c62c946468367b7c35d625a04df8e75bd263905c29310db08f2d443d6e7ca6113ab381367880871c603e02001a36db03c9eec3b8884626e3aa8f0ca455800dcf0b16ec0ff850bb3d88f735c89d3c5fe7dce2bac7aebb9c451cc7bc2babf15c0ad5a50d33a982f5e84b7392e6e920d883e6c6b401bf468982f5765f168f8196bbb8256bd5b44948011128ca91a5495025f031131b46c59c91c5ed12b098efbc5300d57de7e3e89b36ed07e478cc744ab30bfa2367bab7a1e2a24d6a360598f0fc4e25d4d5c8c9590c8d0885f113257f08cb3c66b434d383c8090a059ea4e59dbcfffa3036ffa8beedf7ea6cbaa4c9b65504a4de2d1fea10cfc206d1a843fe258949ff2210bb89e789a648f4cfe6f7206433047448cc135f9fe567ab54f459c8475a7c4ae2872a28ae8f0e34e1424cf3890bad75000565f91ee3387a4369c472253dba4a7fb3b69533ffcd89c2fdd938bbc0f18dfc5b2749fafd1d1e76cf2d91128dbaa9acbef69e01096fc8f8193cd9e095b1082c00ae66b9453a3b60d159b7ddb00f380fea9190eeddb4abd62cb565537147720dd7ea613069f787f02945de554c05825066f16968631858b0520e1b4e4698081e200200bd63992611f01aaf43ab115b1a377c089ec6a2f980f01ef838ae104845f16c180f9fc5037b9e31efa06e04ee822780d5b150798c4d0c6d15bd5141fb33ed00030d63195d2bc84f53f9c010a3c5fdcb2820c04b1077f09538089ede109727b2c731b9470559ef473f951b6caca0a9d1f1113c981985cf26c03df03bdc8c8aee835d658c4e056e7ccd64f0d39e94c7124f6c0f6b3822396c4c32ecf1a0d39733ffeb0b9a266d4cae33337825b30e8a7ceb317ff197baaafb68a51d5a13f50538a180a33979d55d47ce54509a1c510bf29d85e55206149b98298f449dcaf6a7365b61bcf57bf7a2bf7696ce75af165f3195ef1e6544b15ee27c0144f5fb8824febcd3b6abd3adbdc04587973c2e49e102a88d4ca4217fe1ced35d79c2a4a9d3ed207057f8328fa819c67e9f71804795062e18a217c472e8aec54fd9ca90adebd141a976c09e2a6327b906325b6c52dccafd47116cac022521888c3c2ac4121c2ebe53bceb7b15aae00823e782cd0d25b22298afba887bbff9c1de1482690b3b48af2b81dfe246a634253cd3bab738a6e8e0773e31ca1ee62db750191deff453bb4edece9f03a0b410a4df4329a4f06ffff6a4f973146be103fd41b09cb9ef2a0a60be72975e11181b2e8a1b4948975d4e65c1f443589aea17d43f2df92761e17d09b46db8c0d9ef6a00a0a464f64abfa2c526f6f0b90f920bf000e215ccf3a408e84264aef6944ace26a2798c9251a4997d5429df41bf51cf7b4c540c02992ac73ce1e3ebe8253e1fc491caf6176241c6dbba75bbcf0e884dc1ea35e2446912e2325a7a1fd28a88bfa5784bceabced2d0933a48196280adff07710d03a0bd66d2fb6bfbe6c3042365fd088937874f9bb52ff3fb47f7d86c5541a728d92337442464dbc51a87fe312a85ea8b7bf9c75fd52b87084e7f344e5f0e40bdd4b4d19d1f6dfa89add84f3601243c2797ea3ba60caa86da05bcfacf9e4e3e841b7bdf8992eae7666b88af89fc9fea357ed94d2d5cb75714430b79cbbb26b25b45f33ceeb712110456faa3f1bf65d0c98a37821c9c59f9936f3d85cfa8df2d57726efe929941033f9c9c9abadb693c3bd8f28c8eced178d750543fb8e47979cf5fb2a7b45a701b48ee7ab7d701488ab0e57ffd9018badc42e41632dffeba598c3aac501166390c1bd6f44f0e72e309625b01eec2601944ecddb6336cabfc8b6d6bbe49221088340535811ac9e4d97edec5f1035f05ebd989ca34efa7776be714c109d500a6211499e345b897142a5f32990b1d2d6f0cb6f751011123e3d1c310f20582d19c3054f325073f3374649c05a3125670e01646c996124192e1ab7bcb55d2522e182aa4046d90fe7d5e771dd9111e554982a2466a8013aa4e17529690a84618d67ba5e140ac2dea0a8112122c1da728a9686394a9c4d0909acbaae4bb6c64f9e729901c93a8beb27923b19483e38ce5cad7a5e90f530024e89b54a83459d80d019968b3d6f08cbf1480cd9a0148622daa1bb82b2e4e8717a424d33fa9f86eaec98d09df4f3b21c184261e59a71ae0022b1907e438f1261248cfd90ec18e5950f0855dc6236b5c2d948e0cb56cfbd0a7b3462a262d6650104c1af3402b95a9c657096e5c9a89fb32ca555ff079f8ac2f39c1f8ef12451af36defbaa43ed25d5a02cd9ad16b4b80a1d66b3623a4483eda09e06e71ef38be76f98f1b1c944b0457d120474136d0f89be972a9f290b915849cf20433b5ee89a65cd38c386753c570f17f8578dcad4629d20bda3c65392e98b34db8320bed93451ade9fca016088fedec33406dcdcb1ed1843266f3382ef322092c16a5f4077ee20afc07a57921661db866fcc73ddc3089f74f57284cde257998ffffab8e6e2decd8114bc8cf7c2fe5cb2af2dbb766fa55e09e90bfc9c2a5de75c3b83e99543c6fa5f14f4f97235feab494196005b1a7215279470206af03992793e5030031609e4351baf936820cfd6d952d0c023ceb3a1b857ee19b5256f34267058d26e13f03d0a8876dfcf5d5122eef2e8aa12a52923dadb0f6244c100d8222c503cc02bd007f0c4529ac681aeb128bcd38aeab2b0c4065e2372fde7661aab56ef4bbb7cf57a42ab5aedaff855e3b00385b1e8dfd740039491918aa4977c3e0cbe7fae532db6371b0f95544aac09cb8709f40bbfe9fd357ede0c3d26bfae4d4439acfb38ab5183803deb3874720f33677f97168bbc80b69b6891e12fb6014e9daf7cb3a65b916acf00272d205deef1433cd8d20f1ff25ab0e0d67d1666b269c433cf0e363103e8e7af2e57a23507d06990d8e1d668c50be6c11f892487a7143cd0bc20d400e386961063c17db6dca202f68ec54930cac181920f33c4883353817d4c4bfce2d006b941002cdcb56a1c0e3f5697813ea6b40db1686336ddb9daee3b1708af78c3196708b9a3d5c0ce270f0f6fd45c538907a9016660b79eeb02713092909fe8f29df977ea1f6e4014201616489eae8d3eac174317740b05228b3f5c854ac3cc17f046568b890b285423d17e70391cccc1c24da85562cf8b31122918edb3e34281e764facdf607c539f58411d42fc0fb2c4a8f2b953f0987d0ef0be9a7b06d672782a16122ed810c8512b2817a603e7c708333827426b341cdb11571fac88c80a08e17579449040f1dffcba483c2189096260fd27e42608f74505773ca99dff4b9a08701ae02f64587e3bed68360ca6e504fe71f4bc352728437e97b25b719ff066745bd792b814f0ad87586f1c0fac7a81dabb27455770717cee978dbd8ed8dd4b520bc0d30844ece819c7aed23c0d56ae1aa3f27729811c8415369aee4386a86e657c5858baf69d286a8a704386208588ff20d054e5a3568350f76cc844bcc6482ec218231b6e0fd232a0e6a970943fb0719ab62bccdfa8dbe25e335c8b94d429a1b697cedd8c2a623c79eaaacafa61d0fd3eec1b53838715dc0483831be8e8760d8404c447b25ad6c04a57104920eb3b5081547c7e6d593bccc241756595914a3384653cb5c87664b8892e842a5d7f9c0de4e7fd521075069c36d9bdd55a2f8fd1c62eb8c23ee10a3045a9387a780d7e3374dfd123f1bddf1c5016dba472664d644db754d18be4e2f006c27dc86a243cd03f8572e27e2c6e99dc7a1b3630d728b89df6da9a6401fcf6271543f9e5f501b3a295553b1d939927be0d0ac4fcece064fd38526bed74c3d70a92dadac006a6e4c3e73f8c872cc868a3f719f9601360a8d09a24c0788565b82eadc9fd5213ebe6c92bfe9a680002112e0a3439bb252ab99ed2f9e57e8f7ab6df05d899e06e3c651e9348e7873c29e951e14c56b98627e906e9103dc3a8d90dffdcdcd4964279e1a65514fbf4f13ae264bd4afdf2b6b7ca298e2c3ee567d53f7c1dc4f3d5624f321a94bdd277547bf81322a30b3a1ec861949985fe13d8441d5496796da0c675d12670c1bce26489bc8cdb96c0c1cd9c28abfcf4cd8aa311a3daa9e084aca46000c29fde05943de9edddd20441db9e3e814fa97ebd1bdf9d73cb1e85dab5e50b3e81786cae9e9fa557b0b6e140a914e76859b2c230dd2b81169db8e1990c917be95c644be82852e567b57ffcc6d2966a3227f4d09e2e877c6b3b9c0a29612b34de89f2757946f9240e185859b37929e0a1508f582c70f848c56063cba09e371b9630cd4390617c30c38c76519e19255a8f668d97ba1b7ea1398c59dcdcb4cb720ea4d9cd53706fe70f17a21840e7fffa4f2cc3d6410d20ef5688c6113c666a56f1823ddb3a0bedfc4182384a399c4b627cae96763b80b53c41583e515736b3209abe76fd5981752a05111df6ce500645a045b04f54f1e305d3f10d8df063c7934564aebed847d203671b736ad4a90fcabe18ee14707e70890366bb9ecf04801b1399fe21449a66209f0a9ada7603d5cec07804532399a86075639d3adc9d7d08897b9fb5e963b99b1b0e00620ddccb4057fc498197037823e5cdfb6182d562a0125803df038e43e53b8b0141ce600a2ea796a7bc6511f77befbb91e779e0bff3a01b6507a4a0bda23788eb16cdde7e72e5770d9501fdb5363c5d31300976460aa23cb90aa968a642b6284506adab426459cb86d04df4ad28b20c344a451cbe79c4b0bbc8a44122dc139d41e81b284d23f35c5da1c1d02c1632d0520f849d39969bbb2bfe85601033e2f261f59a75a0e3e59b5bb83abba915c0b398f529f48d1b3bd81ac1a17f99b8846fa8321a19d0c06645c72d230b9849d148851b6ce38f2a46b23a8af93bf14e8b34d7c1e5051596be381849a6dcea0b34a3d118f1005e4880f14f43c2daa53e872dc483a8f36f633cc6461c054bc434ac65ff232f5c86138898d477ec2d825ee37aa83d4a89273c1b5a015840f2ba25ae5f94409a2ab023537a8a924d54ed34f29a8562a3f679f71eb71c162bd0d3aed4a85b2189222875caa9397b32c2144ed4ffbbaa09b5011490eab38509ea833e661eb89eb6c7852fb6c191874d2a9719166f417c074fda13a569f02d9381ca10df18f003fb8c84c29b6b8be792af9cb912679e3e7fb19ab5d556fa4395126616ebedb367fa4f7b96ebbc0cf777747754836dc35cd4a5d8815f4547a9c7b3854d839f444d988c16a30c590d8786a3b1396f639c0fb52885e88c84448742502429454de3697632f427c08988262007ce6e4aa770797c57f87e606bddd4c99f88e689a58eb8759bc49d32cbc77478f2f7480070bbf56660ce25a07f9de3bccc8eb98d0dbe25adb73fed9f468e316aa10e253ded70911ada6862db57831c4eddaa01b1ed41ccf2d5155c5999a156423955ccd6b618e3af828f9495f6c537d4b2a97ac978ddb8d8f8efc2e7bf4dcb08b069b9eb3cc60eaad94a3776684d5a8c646bdbfc0102fb3d9aa1df0535e65015e18a395b296d9f7bc87d34a9c1164e9786ba2bd66baad2482baec7da2074439ff660f510603bb3b51ff72d8b8880e6f1c1afc385f7693b8b86b6dec407f187a0d27133df27d3406a8142fae7dc79f66dc7b1dec89d86e81d4d38b8b76f877dfbcb9794195890974c68daf52ca96b1038b813d442546131183972cc2f6f0a8ee5e090c2e350edf60618db89e9810e67c1be712e0170510e365e7ee7e05140e6d51d233be91b539f3d8b95b63a0d5778a943b34f75ef9289f97a003e22c37fd00a714be58746ee0f433b19a9ad19eaaf0cfd261fa72b1f49989dd83b4812e08ce4d602912ce75b976f7d0b6033b4da796697b9a83cf709baaf8e4c853ecdc3acda523167ff09c19e7174b8c7c51612c7a02e1b9760a4c35c79c2d822cf90e748070a8d2e0ce714a1f291b7400c9b53ae02e9585c51a4d641a9b149a57529dbd6cf5690148e12538a6c0adef1c2fcadb0502ddcf8e0d7713119b0db5be82c292cbeb591313c50490af70cc163d4c31451fbf732fa5c517ec5c1f360449d24acaaa463b4269c4542e57b396d1d37f1b4044324959cf068994e937b41b126633b46d1ab4820350496f3a09ef82e70a55957149069899c2d39cbe18e12b3bc6871394b4a6b1a6b805d1f301143501d268c7dbcf29dc44184775aa602227305f0e27ccf48a76d7e1f660b071d8c9cd5cc91ac48a6e62acf530400c92302a0b53d3c819fb6f618cde9f9ea65556d3c016076780a415018e9e964489408dd29a6686933dadab06dc2da429a39667d3b193103804c9677cd8d4db71c8ab040a45a9592b224f5c7db1f95f05b62ba92c04e0d06fd44bdc82b20d0c3b660a8da4af4e13decc11620ce435091d236ada6dbada8ca9fd46a014543228b5186a16a7c508f30a69aa8aa74e680fe4e5d5961a75e93c0bf22611e46e77bcdd7b0a9ea7785ceac37b1ea644f89204b6992400e6778a60110bb53ff4e447881c703b1b778dda5a284ad595ab967a8e3f3a0c215d4aecbf4c04a4479e97838d3e00a493fe3406863a45cd2ae52ff0d7e4584392ad1cc34c7179490b52b5ff3a97a81f6096005573ecc737208b24d0967d4e53008d9839e33949f09fe156f9af95f4f10b482d314a1f5960174807a130143d8feaaafad1694b1078cdfa5e2ed19e0afe01b35e275788909d0ac86cda8c630222b0e7c1ab720bd7cfd2ccd404ce8e629a5e632603ea5c18f7af14d6021fa5912e66966b361f1451ac5b169d49cba3719642b0586f6dab5a4281b92d264bd14aed2af9272631ce4d4c7657f91d2a16034bb349029c084596d40e670638152f3fd8ac1caea3c83d03bcb76a9468a9300db01ab4055364ca8d944afc3aca3d5d6fde863b2a723f367a113f96d9066ab8569103631e684c7763c9d86c45664e7e0632a341b22b151fed9f9b9b7f721b9ed03a32c5352f8b7c748e00dee1548bcc7cfb03df3510bea546a98e683639f972c08b2f87da90555a0fd55ad53cc5a6da2e0d36ae94317bce291b6003681b9f2d64ef0507c3413517df68078a1c03f23594c0df86fda4888a66de3b5aa89e49cb667aebbde1c603ca3f5631e00e73b21ca448f74d9d969abe25f8dae06cfe829266f9da7dbe508e71eae556462465af2692cd245cd9fba5b3ab43ad11536acf070a53f72cedbf1f61ef77704a8ea39c2506f498187ae7dbdf24031a7917ce24b4242e1bf573459d4db43cecd679017bf5aa8aba71ef343a3961ca2f490d6cd2018cca5527880d2d9b1ca6106b4edc597cb0b4908fb9b37ccae99b8fbed114c9f7c72ea7809a668861ca94c10ff56d7065ac10818e9fdbede3f903db77fc151c4cb22be0de970abfa4e30854be2145cf37f1e0b3fe8acd6f34d166cf5d54561f690f011efe942526f597632e9ac117ee64671169b30a3539fe01419556cdd27eb7a7785b579d34cbff4b1d235fbcf590ddc76956505f78719af004929c8512c72a416f95a417811b76658b45f67600cc981200cae7df7adc3e92fd65ee20491ac3a338cfed5a5c51ad7ff130309f0951f576edc403acf1196788fb0ad3040e65536ac13ec5b0055f4361833601b4738de5b8eeb067e663e33bbfb1754d88df4a49184a8367fd04ab9624cfbb45fd6341436248129362a340e4788b83c5e4daa17543e048fb1c45a0aeacb78232fa60f87aa18f9c43b1610f90f269ae0c64eeb9989281c89947ef536cce1ee7c97ff86cdbebea0628de870718d6f6f00c6fed9608012a554e3068e1d3db9e39800f8044534df53f88d56a9cb5f81a93dbf81a19e832f32a8c0f656cf095780321241fe794c3869ba9bec81e8b048d4b8833e3044697e65e8d1a6779358f1d184b2837d4ffc8fedbc0337080d8a2ffb2860cea7c8c23a99536b75a2f7b99fed6a40b9b755dda54bcf30b6abded0fe3e3701823772d00eb2e368e53157273f3e5fe4612f5f47c300bcc3c4a3fd8fa76a5b038d5a2a6fd7b5e47f476bbf3ccdbdbdcfdb82bd84339152c78704e77ad78ffa0b7f6ea09eee96f2e1af42f989e47c5612831e47b9382dee5586685bd2057d86983df97a665f9b0a48192991e88b81d80f8af9e83cd771e96a891faf321ec2f7d499055623aec2816c3eeea0c5f2d57fa126aa6fa68f0f20355d74e03eab17fcd62fb33e8d64ace0b607f3001983d1f7780894b7b875a33cfb5542856f902d353f4d29000afbe4c03102316aff62306d82d30671a74827b93fd16275f411f32275c0b1a8759994b736caf7245ecef0e0401180852cef09165cff6b5acf5df69c1b071a731ac2fe2e0950ec3f004725c7ce81efb5cfaa464acb1dd7a7e73230ee0b6326d66dd701358d6b7fda2249738679669ef1cbc6cd67f099960c59c25c7855edd7512096a0486b6bed41e4819fb3f28cd2c9872e293ab7db91609a9c5994e8fd09e8118ff3728cdae4c32c22e1a7d1420bfb71fe730791e8810fa924e73348ae3e5d42b168c3878c87b38fd5d066d9322cebe5fd86aec0220c7f4cdbe5f220e56cc688eba8acffbb1add6a2a20191b87fbd605555e5d7ebf60081788d8be5ae4fdf84f1bdd790ed3e123b94703c4690e37df4b730c1bbb87fb810f3438f7b6e3d82f8d7359e78efa73772cc892b386e0742c715065af308a3fff8c47ca699fc75d91b9d7dfa66fa87801e9df4851d889dbd8e25e822597a47da00ed9de1a86fda2d26fe1f0257c49b74cce5fbd9bc8e8e792964617c5447adfb3ec1b78bd3879af008ac104b786724b97c86c965e617107dc00f13c9950c204ff67882da0cf3403c0a496662b18cacfa0d57d2fa9b3b869fc215b6da336cc1b5c3973986afa808ab2dad036050f9f6ef2cd92e322456191d87d486ee149abb2d9a8cc3286a23d6328708b0e266fdec3ccae277f9a2cc9f565192710809780c707755d5df1335638d9c75fcb201532a45c88381c27a3bc657fb20dc220d68b702b641a7412d447ee983b89841586865b60c9bcf4a745f353dd11dd319d634cc0e7261f1b09c1dafae14909ce3614b7f6f8dd0e330b6ee836b990dab0978c501932b0b3c64e4d8579a839b460990511e392abce9a59d8a75acb7aac9a09b08c4b44c0cd2898e4ddd86a72aea8fc75377b99c9a184863a5cf51867939e12d586deb120f9a7b31fbd317ed8d71f91b8889f8afa84c733693f394e2e522b50d0c46aa8738197e0499642e923b3c3e3117dc278cf9da63a0c0c6d6a3de78c98d4a9d4321cc20efbc9e775775ace77611fdda94210d46cc89715e46e3d66151c32b878105f28c52789717b40476d8d64691b506e5a7bd9f13daeab24236ced6f99428581db3fbbbc121d8d1a378e4814e64d94fdb99461e74862785f4ed01897a85b8260e2065fde76773fe975c7745dd4e1eccaf19cd28e672bb291e563deb3656fbc18e7f0c84b6b4be6224052ee8de132ca4bc30414cd799e8ce41e4f77f765bdb5af1104493fb8538e5cd2cd4ba241ec80fbd059908649392c771460c3ef708743a7a7949e8afaae83cb45b7beb22ca665168588e3ae931e002a84477ae24d0dfd4bf520b7a07473dc3669f4dcb6229631cc610ad2cf1913b1a218034cde4fb888f085099efdf1e620a5db64a0c73e0621957b773100046c2a7a6f5e2e8ad8a9ed171ac251180b496027a9f995596993d196320270e317e1afd5e2bda80a75803d9f7c0e88e238343c8ace8cff5084d7fc338b5f5c0ea53dcc7da4861e7ea75322f0fc8afbbd7cc3114246a9c4bc82b25998a1e340da440c9813d707c7d1d39f6a29b05b9cc29e0256cd6b53633662daeb25b5cf5f0f8f3a4f107bb21b58e0ef6922c601d5e1267c65d1841cabd5108c0c1fa150523c802f1972ad4a3a97a9c130450cc39039b8bea591828aecb9d5db1a9bb39042f62a181d72e29a977d5ab29cfc485986f0bbbf74d24ffa3f50850492483ea5b82552200685b76cc0c37fa1e7e9bba90dcb1994140ce851c6c93d0b64eb9894c82819d773bd21889761aeb001fe0dc11349c89d2e88a722fcfdee45db3226b48da62cc691b69cb30d2a70284247d614592179de4d8d2a28bbab4162c211a2ecd1224519d61ae21186a7804ae002c405fcd7d94cc27db36e100d167a9994394dd691bfa06a33db733e75a4a060aa5d8823bbd355e394bb41877459106ca76ed32e2da2b70fc050b167cab6fd7e86b298fc0e39e3f243321da576496566d3032fda6e3aff998bf26e6179d8b48753dd175475db02bffccfea3a72d48db18236a119476d0825a1c875d67161a933e97b42b983fe68f60a6bd9813b34ca21c2824722e13607f8d048889ff5c43d99c64453c580dcfdc7aa96ab32f9e8a5ddc4687e3dd673c0a55cc5a76504f86e9e45dc0070e4daa5d790f0836e8b64969dfb2bd402a59758cfeca5900529ac764778b72412fdc663b8a56a59385ec136667e5a3e29aae6091884e2db3f99c2cb93c15a9328b824705b1f7376116013300fcfb05387bb201c1291011c6d86f41853d556e7bffacaa2b1ad4fc3550d4257f87901a1435fc82a53ab784a5e6f7db125be4c796d8f8b584f8baffdb5ca5f305046ea64908b176e216c054e1f64808248de0f68d1a7e5f5e9341a7f7c42dcba8a058c8a37c09b58eed50350a018a0b04f9b6139278d6d52f48e60491cb5f07e7d8a1d587f71b42fc8bdf680c1e84ed605f77a111747d372554a7cf6e5e0f113b7b10d22117130b8ad3455f242038749155d0f462dbbd67fcbf229040c7689c094169f53e935e7f4808dab0a24bd206b168f2ccdc945b0c40549e75ddcb75e163788953cb166a1beee73e1e5f4aabace38ae7faafc92f193709045b637cacb1e466e76440053ed5bed4a890ac0784ffa4e0fd3494bec8af112684e489f8ee587ab83352b9952077bb897a35d238556dfb77f0019ff40f3bfe8ce95b72f0098e35d1f5457766aaa4cccf969d3e9442e1c45e79f02e15b3a0c0015b9c3da62803da322eda45856f19b7f2fba20690b1fd5a8ee025b45624087ced6614feb80fcbfbf7e64bedbad0227ada704a4e2ab67b59fad642d3a9f6cc6b830d2ea1f05de1b3e1870294f4de79b01ef1e729d7a130e4174a6d2f01878e936445bafe3a89e53be4d7b36a89a9fea471ff66801b5eb993e2dae2fcd7fba27dd42b055cd358b94ee4df5126e330b74897023fa977c4c309270748eabe0e96ab9271619cb20f2ad3eabe048bfd116245db8d5836dbc8714dabbf793bf1aede20cf2f60218dd39d122e734b682c0773104bee02569bd09819e0d694e6bd073bf46a2a06a875ae8f6262c9b5c1684284675cc0ae534c77c36269b1b0069637c0db4208961489640b2f8908eed155212f46edb0646e1a80ab85249af0170502024199f1cd81307d1f6d7577afd4fc06736eb7f840ef919b593d9561e43710ba56dc74eaf97a7294136c4b5578b036f27e870c41d80e662fb5dc32bae25b142aa2a43575c5442cdb5226f2cb82aa960b4be06520c52bad382e0af7cb1f9eea9ba2c2abb582a6f8e8fc936d728ee9118421d73485084689949d9f27960d079b1218012037ffe6d3e968b853853fd33c1c7d0c7c99ecdda6dc8f871b8d38a223e2fd382edd7b729f9b6fcaf7f362e9fcb1c3e7996e9d3c291739efd6ed71ad8b3c5de4a2e0e7f4db373c2582b08b0ad061836e35f21430a484a7fbe3eaa1a9f5519a4ce22291e0ddfb4d7b1562696ecca5366f9a60c6f8cb73e018ca6fa6d7219d9c8cfa2b62c349b7a0e98a56d436974cb395b31da73bf878ab1d55c8dc1f4cc43f53fd33c99deffd1c6e7c3444eb87fb6999d657aaa7bce67175ec5ff7a34efa7e1fe1b12c9c4601a679717b7a7c6cc5cec583915d1d465224a4014d5a42fd7803f3c2eaf318c788187dbf67403e358d22f48f0095c35adc244502274421dfb0b5c14f8f64769aa40eb8404f88173ba6d11d090af3e2af878cf1be9a556b669b0da037bf06f692666f11f450d42db6bf5fee726b4606bddafd44a5a80ee5b88a3790303d834024577500482f97af1e482b1c18058d20e3873c27ca05c72426f85e49533f9b78b69df2671d69c97797fa953dd10974e8bb85601ed8b57eb72cfdfa28f8186cbd84ded913e7af02df87ec0ee400d1e7cdec2194b5d31b5a07233907b38e8b957d884e38b3dcd2a8e06e2bfbde7a8dac98a868d673e804946be66b27b1e0974c098f113d3eb139455e5c63ea7372f17f71d7873b512cdc9297f7ffbaee403c30e4ca3d2ce2b253f598eb98d72a3a33d4b245b007d5c8551bcf7b13e38ed8e3c193a4f7e9b7ceac0227a9799d160e05dbbda87b9f2c95cb102060ea7b2c51b065e490c01cd15f370a108c40927968d63c1fb9cd4c2924a86e9cc7e7eec05d3aea9b2897dcd7f7ddeedab904131b20a3435c9782a648fe1bc8bdac8a54cba06a880e98aa087040e9099460e9c2c9584b8f9ba95779b61f124889a274e5e1982b481fcd2c17549519d2ee384c573cf5354618a695495e21459f677dd3331b89869c677c40d05efe06f63dd745880b7791d586fdc6249b1c162dd07905c538f6ba8c2900b06aec036221e360e3c6e555326551613a84702521171db49086c6f7d0fa196a8062af6488d03d0727b3f58232a50ff1dda4c412dc8238dac687cfcb795238774d05f74095ee79eab4effea914c8285bdda9feb77309a43ebd51d654bc80fc8dbf11069910a0a68b7196c631cbb5eca6fa667c39070134640e624484345970f956fdbd1a3a97d7f79db667905055ed2448ecec4af507132eb52d8b44e0e96cd987a20ae18488b882147274e03701420d00e2ac90bd7a5161660daa4230a7143eaef71038b32a78c249e72e2fd0ebd1dd6200f4833bfeeb252a67a220daafe6d9df2a97a7b56c0ec1ba33f9db62cce57406d3c879d1efd5030edba00598980cc0cae3f1dbecbbc03ea2caf6061ad4f5a030c2331340d090371beaed5c03ce7cf9091a04770951c1115503f16c7bfca3499262be1b94dd7e834af03845640993627434bc5d7c2d8360c2777e751df7308ea01b123117a8b5d4df378b50fdf80e701000fd8a44ef4044cd16d0309db7669dbbc62c1225fe1ae646932db76d0a0031d6595018ca1c0d8261731e1ab511ae7d5971ed812c1e37aea4eb9751a46df5a5038f73aa3a0adb3806e2ff39c883dcaa3e51dbb695bd4812b0e478fc5e10ceb5a2ab10db2d3e19305be0489175922d268f74bb38c0e4446e14fd73581b5f2d21c3c2c35f453c0a9916f376567f92c8ce9d525cde2faa672330c9da6d8145bf2023fe5e9445206659880509b804f9409a9098ba0aa3d335183daf408bee638b91688f3873238d7e75330f52a964f1b8629caf4ce718be0b16c3b6f81bb02977ec6a2304d6ba725d472be80c8d0be614325f09e13431028463f4d289e1a71b1ae5660b96d9e7cae01448074d7690cc9b3c129759639ad71e02b042da0c71feb30e29ca57a5346b7f80e26b5eb528f5a594748095d74a0c697d0910bd9da2563caba40ed10daaaa97a945ad1e487468db796e312ca9a903e18f3e4e370b84a2421ed9dd6929ce0e19696d1416074bec84a2baf668d0782026c514c088816b9714995250a0950cea181121bd1b34488ea0df886b5166d68b02d21ac256c83cfb9e27f10b56ac36d0ac1921de7730a562f23880cc73533c02e22a433c3ccf75c9ab0c606c8543f878b3dd0e8f43109dbdc522758ea891552facc632578ae7e792860a1d18da6cc7c8ec920e8147561d7870a0f831db345a66c80f13e10cc96c636445a44bda7b8f6c1a983d8302bda659df951591cd8f92283bf084cac8dc8b666774d18c7827544c2e69564427df23318cc22325199328468e1468fb8d0de1a3e0b010b2fd53c0053fa40cb7032300922766ce3efabeeed2fbc354d14ebe27cf8a2a71c42b0d3eedbd50e28f6aef360d015b52e66640703f1080c0062e0de48991822a74679832441860d916ff356c132a159a2727dbeed1d967cbb2c311fb5e0b4c7b289c7ade54554385507778515181938b83672d41b316d3b9b668b3be8e85e383f95f1f1f0bf6e772ce4bca8be15fc464b5f13c5806fa8da348d4f63cab6eb1734e3b44115275e6194bcb65e1a79235c83a98b8a7ce1e9c627185103ad28319c6aec66726e70170f179a92f0a33db99991bfa44b53212f84d09197d4e5c7276bd77a72eb1959706855741746e0253a48db1e4f932aab575dc5b862bbad7d80fb27190edbf8b2d03145482c02412cb4f5b76191e309f834401408f9aa6366e0d24fa49f3d1bfbc92e31d80848f483e437c017301f711a4eb14f737ce1219442388e5998d52f3131c1bf72a08c7f7f455ffc29982f07eb00cb9170e39b49f3ed68947b62ee572381938b2695708a4541b9faeb95ffb1129c4cc73fb8a6589c304accbdf2d7ee4d65a5c8e8863fc90bc13556ab797ef02454c221e4d84e1dc1466e591b9a0e09d615f0a802f96d0fb1938b5d0a1cfc08bf615c6d68473d1c0dc3977480a3424659bfd24e244be6885e3d97a342b396cfbc326959f0be2afa464c40f23ad976afbb4820b882661e01552976c12154fa7d40cb97b07163a1d2338ab383fd9f6d468394b35ad963af90469075cab96810b20e4d46d47fbfa6b846b1f0a199b1e09b3f676a8a0a1d8c2ed7baf0b670c1e30e893632944aa692a0b0a8c5d1ac18e4b1b2b5e8c81767a28fb29ae10fcc1e6219ec57c33a7ddc140b399b86860b494d0fb09644b21645765f656993ea8e361a1a8ff3c76fc6c5bfbb12a87563188052bf741f4b181b47f05709621d6c01474a3511c416c8548215bd5421203313ea52807a8ea63256bbc968b00bf03d923040868562c48e07588718493c4959364ca93412f2c8790b3f072a353bebd1021a66a92b9c9f243387fa51f6b4bb55036dd2af7ad948b1a8cae2add5be3a3c5391f656e3de99014b6e4b25ff811ec968ae458bf03224c9d719fea59b7b34d2d5ea08ce44ccb806148f201b94cb1b2d415b2e40666b7a98d4cb1458f105e5a992b79ee2eff5d6025c72ba8a37948db1e5f30225349f9cd8cfa07c81cf4a78d126f22b03c43778570b99d99217fb9fe0923e697c32a74443d19fd776624d08165b4daa85a297ad8c7d372addb2b285ff3da3862ee3d1bef4642fb126fa6d47ec44a2d64d47694650304c5f852605ad1f4a0cac8049383e6d71a45dabf60fbae8c3cec04b84890809863c622b2b742afe41bce005debaed3bd303ef7f056528beeb975fc1a6dfb92ae71507e8ef57f8bf3c108e0264ac89278e07f66c365ca3359d469cb272bc0f2bef7ad833af334a2af87830a60086cbf3bfe17fb7d06ea8daa89c68fda9e2f109d09c05d19387e886c9201561fec1b003667a0009e932b478ccefeaeb8fdecfc29ba6fb6e65e2de7a18df8a3e5360b2c552cd2fec8d768c6462b35dc63260e9850bc171d6c4a10e85c4441310dc7072cb671b39966248b6ee0f8db3ab37fff702297164d41b5d3c82ab24cb42cd966ebed2581e070abfed136b27993a4c05d291b6d97a26eb5246878a305725a6f67ce4960135a130098fec7ee53172b164cfdb016829d2507c14f5a22d59df26ce7c0ceafd4d5a1a93cf5c9951ae0eef487a6409f7fd7948177a4cce249468eff2ddb7318ab94438f5fb1178b26027f3aa7c6016174cd139e49cf592318e56ecd97d651d78f64d4a65ef8ffbb9339024c434fb5087a9aa44a1d34bf995cfd9d1c66c84193bde076719f2b355e969f2844a803e09f152ee98a8e5ad752559cc2dd9a12bbc48b5a1bcfd3ab546e7fb2d90485e9dc720379f2870a5bb23ff0dcc5712836c4742f48301f986082642f74171bfffcfe54184c923559cb01e9bf5b679c152406a2c8ad7fcf6ebf3074aaa8c49095022219dcaab4925c8c89441b82bdd7b1b8c6cdca0ec24200cae2429d750623acdd9469fc900465737125fb9464e58199b4f1f580f7508697b725adbdc4c7db1ecca0754a4197b9d8020db95f9dffa187842c60c8db31957436589dc88cd61ef06b3aade51aea0c8a8f0785da179a09316c7aa3c7d94133f73b6512433bd038ecca8cb5c2f3325090b7077ddb5d52253826441b164f979412a6b7136d226d2c71dbdacf5569384048eac0f69c50d0c33a2e640cb8e5a24676b9978a0ed35e36f59ee2b420ed4c733fd1d8af0093c004ed1d08802e02158f6c3fa9b5a85ebc133a38e11e50adb1ac0c94bfbb27b51ce0cbff2502167845e6e14a4e7ba12c7461de40d075e852c6f598944c874fd2f0d40578809949f12ef8fa1fc0967a478229a852a511349c0b776d2f520cf84808cb234cf026b9506175ceb009b83a7308b9192381b602e66d707be8282f31c9f130cf0bba79e4f4cd270038158674826026d3a1cb5008bed2570e70cab4b67f42e94c3cbab586574c04b01544ad0992d3fc644cdd702bb39f8a246c439ed47c0928a2cdb66d6a67b5a5d666d49237cf306fa50236b33e7824888a8a55a6fdbe243d18c2c5c209418a652f1271fd8d59270a486c011aa51eaa1ca7c34c3bd687521309bd165c73079635d816ba605f992a8f9890e0271aea9363882118a1544b4fe43e9a7230ba9414867ef0eb48b949c02160b39ce9a26068d68643d11e06102a4d560ba46a582a6cbb7aa345a6131c6331c667d98952145cb1c39d7ca06cfc68c764dc053a61840a430663316c01b3acbb7d8c237d4f184e6a2ed6d4e1a08e1591b14e0a4637e97a3054259dc703891d833475694afab24a02af94c80b2b00ddb05459bb6145370286795b0e0689dc45495fab8d8e01659a2b30b745308687b35ad3161785190730078f9db67b1e479d28daa05c410cb87f82d74c743dd56b4e145ccf01fa3985425f508c69491b5242a366f2695d45820f8e86f39d5fbe3649d8caf9b7fc76cb6fb7fcdfe6df23483db6c75aef28e6140003e895f860010000c021140000ff5660883180204d78b280cf25e42840973489f8c680086947d92d2591c84d24b27b07a1042e04a5031f118cef86273d1e0f4f587858cc2899fac440cdb0d284294b92f742528468fcf1c5d0f1ad80438a8da3199e1218272cf57c5f9658784966bc9ea92228292b4e983e189286204143b4e247121d61707841363ea619636078a3939e4f8a13162c98699199d2014a8895ef05d317425218249e0944b21f2d313a3c291c21d8509ae121c1f87e28f55051626183191aa670407d4d565a60829114433203d1961f1e0e3a3ec0f17d6003cc0c0f0a0c0f84263d203461f12131f3d530d5420365c5ca6783e927a909490c4422fc204147101c326cccf0aec018ea5181e32e674c58ec382383988f872e2cb0783e38fd3cf98e242de9620e0d249e535251177372729270e8f56dad3934c7006890926c484e42d090a2c02c92165815035be2c16b898b165c97b325310c6433e2d2a38dc8f0742b5c70de0e7cf77c44f8078537c5b6f028aa473b1a23b31c6c81e15243027281e4020c89070867ecee72a60448f7b21be68cb8747aba8cc81cada8b556abfdec9e6ddb2edec105713ae79cb9ee28c951113f6aea20c599aea3a8a331abd56ac5796c7b791968ba5ce820c5f136069ee77d160907241e5d939191164646b033d688c946461222adc8c886c6358d084a23925af199c139a0c68986d89460abb5d5f3e15a973325529f4ccb4782922a4a96baaacb9992232e74927646468c8cba249b93285a6648629678b0c44595cea6c6cca8471702ea22fee97266f49a19a9502226773cb35101821f1af04bd3c4e8c709345ea02075819cd20116d1ccc70e1f43663e8ecc88ecb0b65299c0def780ee7ebfeaf7ab5e8292e27013b2e3c80450956bdf5c1037377f41d8cf2ed9412a42dcd1e28efe7eb0a1ce166a985624ca29c0b9e9149c1139336f40283d483769276f26090bc2087b012b0b9ff371c5b999bd86720333221fc82ece0a80157c7ead3c3a497f460488c68c88500b3975de48f9ca80375f196fc738015914e9c402b289c687233339253497c8305358c6a551322133ca26917c5232f2180d2023618c1a2520db6124808c02b28b05b624e49514430c4a4b56f0a430c19c2132264086e607d9c33c4146dd3053904b1f8c288c13d411322fa35c624200a28c2869aa81e5c61024d80ba0224d23d128a2935d19279459e4623c808c49529931328da0ac8a0c36e2c846983c60d99cc9a2f9457221334ea8a451cb180199d13866fc64dc9610c6ad871599546231f28c56a6430628bca074e5842d5fbc1ccdb011c37824cb204d212e78d488725ac10806a0d9e501b299464e1965c030649c35708c0ea040b6c9a49039831329227288149026b33348c898669c1e344026bdc826931032d96536c92f36c628a34b5664e432ca2750462d1b1a6d642f7a186541948c625a5b40c8260b2f60f1a1c98f518771c640804cee70644c9243f0a30890315582f0802929023302c9211b5434397232f3342231d27365dc2b590d3e9e860c635c182d905541fa41693c3386b23063969125bb318a29804c4ad132566000321a70f8a13202311a6799ad0592f1efbdf7ed0e482df2f3ed26e997684836c4cab8c2c80095ccd3c16553d6c278436201325909f40330a49a809490030b47488a82c4806a642b8c8c20e420939e8c0aa84000322733320b983107d408009908495a4c290196f535a148fb7d5628521ae3e1e5febe6833b8219d18a82372aa05b5cb272c854d12767beddadbc4ea6da8571bb7af7118b074b5d1a1de711cc7e110afa74b7b956bfb1295ceefaca63e938486334171e2a943fe8539d582fafb651de185da823af6b9bf21e642ea8373ea88acc51d50b4dcebe830738f016d3bf59924b850cc186c34d627f5992158515e77bee80bebabb5e699afdc4dcce9ae7dc6fa869a87fbad06d19fcb69cddda03b5f9b47f3701ca7613ddf7bafe649c19a00f8e0a7ebce7aaac5494b501632598eb4bc766c08888ad82fefff8de4b4fd9b824a5fb5a6e372ce9c4b07cb2e678e9b593fe5a86ac7fad4348dc39a166a9a96431deef16b5a285a4a358d6ae2a641f377d0355a35fa77c7c8db07ef589fe29c99c6e873c6fa36e7a418533234d4b8cf61acfeb44256584fd0d7366c92d07e8a3bb663e2ecfbf936c17a4d9c9dde5aebd7ef7b2f1471d5e88b36de8b96bece0cc5b9a94d15aa220ec51dd056ba7deebd7ba8771cc77139dc3e1bd627bd938bfddc04d9af3ff687863f79e2a7e1dc7be7df3eda762f9d3b60e726b7b51339dc3e33c41429501512bab7ef57bd4861fd827deed77893e9fb572e4b717628a2b83dbf2a1429acef1771df3e93c4dc3e3bb67d6c6b4e500402274c31149992a327058b8568a95ba2a6175796a49d73ce39e79c737a1a9c9483dbeb4f7d2bbe34e350e2c8abababf62e67578a7ac7e9bc4dd45ebfe3e4a4d5aa6ab84dd904713bf114f55ceab0c454abf6e74b718645aee090516bad28708d05af06b72a7865aec840e1ca8b5e4197b3a7304f5b4cb0c9818003c49ae380d9d3925ebb9c3d19759f19df01e49bda41038e990a9e920ca0a7d8f7c2530b1f3f5011e34589f284ac4041f99e20e530e29d09f219a921068397e5c63765c637325971e1b960458527c3986f4b974fe88a27a48948d257e3480d423c1b3dbc2232b4c2b0d02a53c3838ae175a9d2f3d95065450e65bc16529f162c9f0a293a9a783a24f1be107d41377c5c66e011e41941c14b8184cf0a1511be28543e689931e3158131d2f295e0e41139d1a2240622de0f3800d1f15d79e17391c2989f27a717539c427081468530de0a504caa1c3d0172f49d50c443928397038faf4a8e8f8c0daf04133c16a6c83e0fa6bcbaa4f16ee8e11b810bcf532b0dd3d762c9920e3d86c8d8102386272bcca0e1c100c38b92c2d39292e2811119cf8c97243c7c4ba2bc98783f90f418f2cd7c7c3d42de8d16bc17277c4e237c334481794ba2b0688df1e1837d1921cb97295e15a5d6d40ead33453a7e784368f864b8f0e100d4f25242cb87261fa026103c9e33df0e539f095b6054c42c79478cbc1e664c807c4d762ce1f056a80046060ca61816a616df8d1f92c47839a2be282b9f17282a90b8184913c49baac1f302c387e306d28cd60fe3970214175f0b5054781e8cf19c7469f570e50bc273d313cf491e0d241f0f221f3f58e8100187f7828d1e66045d284e8e0b4514b78a7c06d51135c4b71ee912805a9b46abb56368ad16acb569b45a1bd66ab5768cc2be45610fd6f05064b54074feacc7ac1a0b6e9fedb37d2caec1a5a84f5997b328a1ae022a7f872cbe9ff3fdfc47a783bee7365dfbeefcfb3e0ada31df32b7697affe62c1667b1f87e978e8ad7b058cff98aff6ab3585f82d6a89eb356abbdbd38572bd687e2aca9596dbbfdf397b42614f96585e20852d4d4f0b77cffca727f5fb5434b715c3a83ae73a1b87dae803e0ef5a69101e27cfb70ce7fc338e71bc639df310ae30fae549b83c0abed81db67fb6c9fed739f7451d10dd0e58c0b935c6badf5ed77d0e70e356df57ab5b168fbd43c5cddabd55ead4ad4cdbd4ba7dbaad5eaf7d6fb35b70a39a87df525a8ca2576d07534e87e7f094a010545f87ecdad42ad0a75785fa55a8522ef75c40cb10e75fdcea57966081c8a3704c330767700e9977ee91ffdd2310dd39afe069aafbd75eb376bebd6d674be340fc86b2896aa5dad99d6a7b43ea52f7b095aeb055274fc9d9d9fe7e73c3feb682ffbe472b6f56b9f367fde5edc504b9d015dcea06e4401e5a81854969c517c7e71075c65fa9affaae6ed36a1434371725a15d668d5d65a6b4a29ada9a9a135afaa59a9e8d65d88e2768e823c0301d230fdd2300d031271068ae1f95201c562986b97e62a55d67abeb4d63c9a47f3681e204e371f3a792356212b5df5b769a9c6f8374c878312681dbf146d4741c5597fcb8dde802e675aa4a0626c89ea5ddd784b532f4097b32d3bb4cb5be1fd2a1575c4fcf91c6a4af9d3cbfadbfafc9ed7b3f7f83f5df39e4bd2d0829a7007ec3cb4228adb3117a2b8fd769f4391c2542eb0dfce849842a70bed735c9d38d4997f7f0b33e8ba568538bd457234961b6c6a72afbc544940456cee7f296f00f29a73ced5a583a5ceb9d69b75a85355596992c87ff17baf0a454ab5ab699a168a3b57bb5acdf969d239b9cf4c2689f95c6eba943ef79bf67703da679a97fa76efcbcb71e2bddcfd0de68e3eeaba17f106d5027a7f86e2a5f40b8558a108f639676672f3d2c6b1382a5447d0234947d09a9676dfe6d2fbd4c9e60b8fc41d3db312c771dcab77b5d69a9566082d33e97797a82aee3b7924eabea5d406603da24214bc42dc35f14775aaa465edb3121502416ba994a62336a04e23ae7c924f5a73d7ebdbfecac529cefe0d4271473e3951a76e3f2b65a5bc94956a055756947b1aeba27ef93878ce3975f077d0adbc967b4aa7cb6adb6b34d6ad7d3c279edc4d9754bf7c2cb55cd990c3f6317e6a1fd3abc29852acba3533d325da4dd32f2dc571596a01559220a7311a738ac164c2483061db516692976cd02f8d6a580ddd94524a29a59422acadb4a3a07d92a0f3699f22985dae249d134d3746680c50bf3f1b13ebf7b9312aeee34ed336069cd3c7fa722ff16313770b75f009ee6fc89f0211c4bf691d9c408ac87fabbe2edb410adedc412901fc7a6e0dcc2d1475b819991e1d3ff76482bacabd88e736819fd33aced2764c458880f68ea504a40cb7bfdb73ac13a60ee5ac9c9344a6bdee0ca4b64d708fc30a4ecc4c7b7702d3dee10bccce7da741c7e1b94f4c152a3a1eeadc09fc38b436b888bb0e39209da473baac942116d1d91ce158e6e460f0364a38fd50cad0025b6bad683a49c3f4e8723655d4bb9c4de5e84f292d51e96673c4e94b16200882a01429556a35b489c245dca776518a317fbaa33ba59362e9249d8131d2e50c4c8f19989ed9148d1998335a6bad35a9f52a18e0aac11215e7ec9276639073785fe7d75ce7423945ac7b76dd281c0702200513d56bba9c8159ea94fae054b5a422f2dcf6056c98b6a9fbf6f8020c6a703f7f775ddb634e7e766ddbf69ce26ca14784cf503f7e9a7db93193c2f2ea79292f65265989a8e35ee5c28965cf39e3218e4768fa9c75d19f7be2c75d88b5edda08e1f5efc6699b215e2d19290d64606b4076edf16f5352955629555d2f39665e6e502084e3df4c688fbfbb745255bd5457e96afd9a628a28fa964bd412f48a9a8e16eee86e2b974ed2fbd6447e1ded338a7c678abeb92cd6dd86aeda242f65259c3fe737217bcef9ed6b2e5177ad5f2e45bfae1ddd379a629bb34c273ba9e9dcbaabbe53b94cc8ae7afd7273c0da5785b653a9de84ecaa50f59beab757859fa297a073bbb8143dbb76c08e29a53645376999a11f1a403fdaddb16b6d1deaf92fb6da8ffd1f155db761db6747687303a72fb7cf0d439b0fa13e2db5e1bc1a46716e15aa6f6dd5ae0bdb50c4dd0c612bcf0c6183e80d8a537ffed8f8e0b4a7a82508a5c6d3810f4e7f80b0ade1f44323d47886a12223498e982cd9d4c0ebd0101fe2435cc7fdb97575a92ed5a61e9c7b2088bfc1b199216b3bd683730f04f137383af8ecdc0341fc0dcef6d93186f811f77ea8880f6d1f3ef4d3453a344487ba6e08e440be7d9c7e1cf519a3cf307fd7513df70c3dce69d0df4d3d436dc30383dd6607d7c9af75b3070e73888a28a222b624f3888ae8eed7af46aa919ae476f36dcff34bd46de6089a423348888ac0538886ac6dcf414d93c6c6068e5f7611dcc16717c10ee2b52ece2e6a1e1debdb6781cda04a458833a8cfb27cd0eb83a0384ebdfecc51e50c4b967901cf0c21ea97a68106f680897a06d51ebd6e45029261a8848c19345257b3010a0203170000280c0a0604633910a5209a6eea0114000a6fa43a644020a1cbe2300aa22006621006811806011806011000401806210444ef050076f6bcde1ab1a698bdd6f28294d8a1cd98d860ac9fa2cc794631b4df3e536b1a811f7b93ec8a81df3cbacd87cb18140b77f2fdfcbbd04fe416226186df23d0afea4bea4a196c2fd03a06809a055ef677b7d259c262a714f810229dc0dde4a891391c1d3d6171dd69e1a28118fbd73ea7611095465c751dc06645a66dc5e2835dc6726b14ad7e6bab613ba7ea5d29989e88ad296222ca381fe9ad86fd62d26e0c921e14701e75e76b234b53110ba03d86afbd6680e776cdf7a6b40ce3fbab43ed043bde65324b953fb27506593b82e6110cfca8170410ce2b9373529055fa388e7bcc00f7a86530567de6ab0b6ff30aed9dc2b3356d64bb0c6114917d22122339b8b0ccb4aa25626505f972b015afcd2bf12bd441ec16e6c58d1ca443ba720dd711c711b286644e2b1e05610cf65b082862cd9ebcbceb323c13c03d2e382a1425e4afc32a649916e7eb449851d2a1c3d7e4755021b6bb1e54c51717fb6b7065a5b3b5215d7a7d698e688e835b8009221311fccc01132f966f7f551c8ddb35a8d0cb8bacf7a4b73b5af3750a3aa6bbd4044d596a1eaadb8acf359be3f28c2d81d94aa69301cc95152c053c4c91fba5ded712f0af1bbe6b47797f319ae87d877b020e259022bb7f75cafdcfb71c3957c8a3dbb5e0fd7ad059d55d4801339d02e22993054c972605c50afbdda70053ffa5e909e77809e27e2a66cf601aaa75c70843b6e045e8585de3ee2c5c790574c54e0db22a48310ccd94b49cc4b8f9ab75270302c0cc4aed9f754a41828f88e676fd4c65345d3c6a38cb1b1655174d178214e00faf2a20ac6116c544ca60e018d5574554cce0d6cefe82e418c21b9dbfd4bd54d972dcd6e9e884e0851df1e55d9c0936f20d5b8b13097fa72d2b20a028ec851bfc07d028f1b7ba4d93dbd71a1e8bbd385c6ebb0a925b44051799f8e64aa42dff32b89c641b5ad418aff2c76e54452e4030784128e575ab5d5eb5ab4db4e84db04bf101c3fbaa4926eba16d81d3cb11e92d03cf77fd56b17dfd5143bf32ae2f4397999535f6816dde48dc56e0f6a6ec3014be1fc579c3b2dba7985da80a4380fcecbf6a10cece87cd4f848dfce797482640056ccb208834aa9a4849c281d7fd67f7103e923f30d9b19f2025c281477b12390a7f800eae9f7b0c634723bcd5261cf54383119f7dba5ea61746b94125dba2838850e3b0d37fa727241ad290fb8f4f9e32fe5f027490103f8ca24a3290d9aef53dbf128b4b80ecbaf291e0217b5e0f7410b9107d59624a60590d7b972266b72cfd2b1ae2014978261c32b78e784410049313fb9e4e332dac79f62689fb8b7ebb1ec8a8755f3377a9d91b7ee7a64e04d56a9796230b1162bfc6f28cccd8080e697ea81b4d3c17feca30c9bcdfc74f9f65d71f9639a88b29a5a0e21cd749e395c0ffb351197da6b5d76984fbf214ba4c48627ed8d80c0e81a5a42c5c5451575d8b4d1e876ed3880542ceb869afb71c949e385dc55000fe2e648258709ca41c67fb067f66e5ef136113ae8bae2a12d7aa95471bddfe3229758b939b62cb0ba4a4aa84a70a24d2150e1e3f17a4de89d9b479c85f270ea38c6338d81cbb3d33bbd687cad2afdb5a4b34a9fd61ba53c970af0cc977ffbc8ffe0b8c2dde8eb52d18fbb30aac6e21aaa6f6decb984399059a4b96ce305c382fe14e77c810f5f47226049b874edc7ac4d794e9c65e709af7c7cdf5d4e996acef9ff1497792f98cbf0f9d17aaf172c866c8cd00be14bef492a91ccf09a32868e14421b1ee695149c4db294e69c4521ac14db3d72ed943e1745799768e29752d33ae046a10e872a00ff4712f49552f4d3c10035d1721a1d4b6c066480cffe31a9467ea0f68328f1d77dbefc986815326c15aa2e1bf584e00e7915c0a235d5cf5988f33c77064141e4efc6ffd110d18e2592d8bf562eed1db15a42d02994a369548d19b60d506aefbed16059082f7aa0233f30aa02f5afcea0d0a870e10ccc64f7621fc105b487321dedf8e3a30f97add612ddcfa4b6d32c2af658b929f04059dc283cfd7c40aa0668d340b1fe8b455974a9de48c2090356d78374615605ce5909c2ea472cf5c336013cb58a102cc4463a05085960281daefd633a100a55fbfff4ed76016dc5fab64be227c4642eb4a61280d9e5053ac0b97151141cef7692fc6c4665b19f585e35a1e6383e7f3653df3cf14c0257d0312c849052330682dd3ab2259bb8fd27544ff0142c5b3e1d52600b5205e0710711be267d83b35945bc0e127b0d4d767cba0e94ee7376ef4626d178567e941caee3145c9ecf07558b5d43af2865310ebfad746aa96bf502dbb2467747442eb7bef6828a58f52cc74104ce869ea9abd8c2f3f2eb1820580a2f7f89a3c66ebb4d96e3dac6393f7fdef15e9de3794e10c355630081f2213aa7c14af63c21d7b2954329b546ace0cd438ffdfbc685b4a14682e227af8566aa352a001ed1e7a82f2c20fac9f8cdcce15f7d0008fd1ccafc3ad65dae5e0b0318213a0909a30ccc50b3c9d8935422143c054630f81f16f0dd163ff53a9ae8522ddb679b4349b8cc9d561cc3abcdd3d730cb34a3341cfb99ce100170eb170e02e5ec724f80d445b67e9bfe438527b987cc6f3dd72084e19e4156517f4c400546ba32cd5e59a1ee7dd31f7c3f6ded704cbb2cbb56d0334bc0fabe33223e6fb70f68c4d0b254be2fea51174f891f6d79d850f4450da97182b62a09a376243b830264ab8b1bc06770e3fb5a9641bb4f7c352f3d8c0a9d8fa575f7a7a0f70afb5901cf197eff191b64e1e02c1f5707e8c1d58d78d12afe51a7dff10d052067a11f4fa6e3cb8f402c479f6bdcdcc47b453bcbf1d9d221361b33d89493aad049248562dd97796ce8a40f406c9874f18f96f9ca604ab61f20f77611af9956f0e95a564202732c52f12c6b443e44472b3b5be58f892e7b0249478ddbac84165bf021bbdc1d16623515d0096173091104ae511b3c31f93e4e654fb5750176901a62ae1bc854b88a1d99b47debf4f3c0f8ae2eb8365b08603499cab214731631232d97f35616cb5922e97b5839f0b983cc9c4c1d8afe1c53c728c34186dc1fced42d94d08476443a979b0f71fa20c1ccfa3fb0c265b6919c36f9e83128ba8ba070856c2307a156d56015dff63811adcdb9b538442c99fae15988ff33a252a82ea3d11a9339972b2351208be7b614c3eb216ba36b7fba82c52c12b589cdabbf88eca975364394dca808e4ecfa484ad1897bd600b20d9241554bec72daa81106cdd1db053e3b3f38803c06823fd9dd0789b20b9f1cee8dd69a9af4e13ea218767f10a1d976353b5161f8c17933cd7cc1a2224589b98b510c8599c90c2ce3938184bee62ef48faf8e53a472e589c676f25cbe0f7882b454df2be88c119d07cb8935c69803cf84b3dad80046160c468e67999a07267c1dab9b7616802ae3146150a5ecf5e802980fa472a8319bb591b448e068d530c463ec08723bdbd7846e0d76974e76df6f6116205643d1432061c3901d6c9b879319c7741353ac3d0a3433ecc28eb1ce60108c4f518d6f49a859cf1e68d89133884a3dbec2f1b86bedfd01f34b1092788baa0cb46253457220544f7e0607c4fadcdc31c016632a495d288c86900c229bbf3d4049475d852eed77bef89ea80e4e263573108a03a900bf826c8e94fd102e48a9cb66b427cd8f49ff6aa2742cd708ea0677ba05e00243cd821151c61cc4c987ca406439d7fcd9d8e39dc1a9295eb7863f33d24bc130e4433e53244087367caafa4b6104bb6f98ec24e3c40763a8f1234aafa2a7e5584eb4246fd289e3ebe9e65c832c64c1422ebddf7b0992a548d289067916bdb36242f8cf0f19ea2a46260f5ec6200f7eb097d8de953adda22754e8aed724372d48f86d5e960e89489f07126161892889c3fa990ac0d94778c48d14aedb898b387d792412dc2b68e853832661a43e7264c56e9f7477bc1e7e9b93050ec1c423527885023b0e422dcd8d9f2b276008dfbb980d0999a43041642c04cf6f779bb57d7d7158ca10f417b1119994ee8d133512623a1304015c9a141475b83f273f0b150e8bb0ad6c35d1fecdc160ae0b71bfeb295c36926f6c0e599320fe4c2fab06d79f710e3be118876b88dc15b21f279ed33c71e11b89613cf0387b78da1a25a057fed8526ab09ebc465ecf28ab18c789a6746c004d3ec3c0a3e36cf436f162c92a55c2f98c42ce67ff4ee36c15a63ed16bc91880428f0f3d9860ec064ab80c8836db345a83174c0c44711cce0e34a788de84b7b0d71fbc1dfb7ce13f8d4f0340de9a2ccb4448a359bb9a16f7c08daf5158ff558dfc504da5d47bac81c932f04db8b79393fb5cc371c74591531244c4833af71e64f286d9f2766f0790624e5274a3dd1ef4e780b411905da1a2101d3e915879f75dd227399636996b25205a123ec20b2189552502f236b2f0b5e105ea3ecadc8d66200cfc5b65671cda49800df883f01ae246ed6abfe9927b30bfaf9cd284bdf4b3fc1d2430c4a0e597d198805a198d7b327c1dd73ac994aa2d0c0ae1c2dc548aac29ca0ce6e1b7040527c921b72ff6d9263441e29180e7eac8b592df498ba78c3ccce6c5163f2bbad0b16d400e49c3fda8a5c7415cb7be2a1e9330cf4f462a7dc7ff40f81ddd8b25a200ca39b666d1c3b922b95d67b082a025cb8d2fc646cd3cba86ca41814814fafa5a6538b8edb1089f3e36e5bc20ac0c74b0fb0a4f95b4900948c8ce1a21105fdf8bdbe9cfe7fce13f522a215f685144827d81bdff9e3059bbfd45b58d9155c60e83c1d26ff684f0f5ed4c016256ec682e9e30e4bfcf98de6a9462b6e75cea60b06f4c78914596f11af00a850244804b9d19bbc57ea49781ac6b06bb90d7ddd6b5e862f18df1da43de390d41fb79978095be1e376aacaec808470b678065f17b64d84c59165d82674b57004197e27b89bd85c48b43b400f81bc0e7b8f303aba7fb8d391af8b6f3522638d6025fc12856052c8fe3ac7642203683cd96a2fe1fd108bd7c52f413f972f8d98a579b2912e79e686eab222a40dfa75d920dab3dd593e8b245029080d057d7d8d52443c307b1aa26855d2d7237b8344bec6667b074d51c6567207b2f88589354be540cae607f897b653213cbfcbe8a4f7176a2373b492cd20dc4d717da111a437ecb9db6bff57c543db334456f6171faac7d09a8d4577330003ba6c3c6cf2ae587e386c238af3f2ff05abb23cde317858a68123f7e662089780b8248042ff558ef9fb6e8b7cf42d5835c68fd13da52b73392a6d967ecf0d5e34ef165e21e4e5bddcd4e7d6db35f2a82555b3438a43a6be6283f3c8411afec2e3851c94bbd30e441944e9c2fb4eb30175ff2976f21214bb5680cc1db9d76befa8ae1879df0a30df2123d8b5a2851dd1ddaa53b5d80a92b91ce01ede192b3e8bf0f0178459059f286156143138e19ed1049490ddf20cc70b78eb3b4b776118a85455f31d9be7f9698abd469e7416ab8a790638bbf0e7733a5dba6cf571b6519ba62cb59eee56486b181af093fbf4b63562c0616345fee7068139410802f35bda24f6085e03d828a33c173acd644e51457744d2527f22f462614b3d9e1f71e31ab94a44880445b6de925a2ae4eaf04da5cf23ebe85264854248e3af040a453f00dfcd56cc2f25a3fff4f8f064d2ba4c3c0a861c2345d16454138b4d0c9a246d52e91b6dd21dad2418a228f693b61054a497308e986ad4a8bd2142422a4647c4252e7a6289d2c3ca789f5bc7d020998d09d265fe13b758cf493765b3f5dcee6a0673152edd6c85a894500a23b87b406763b51226a31870525b20f4f93ef03eb7b011d8db27c0517f94f2c1f5bed695f8cc58e4ec0c8bd9c2c5063bdaf6ccb32eaea8cd961d5b917f0313fd85557cc0d81a56aebd14c9081e2bbdde13ee80949f420ee34b24b81ac5bbe519982e88d2e9b99babae503d0901e1cf3e7a8ab890b0bc8965fdde6e6e9e61f243f06db23703e8976220d4736df92300ad4b6b32c16a26fb3090d4e5efc3d2cb2b06466312ea3018c8337a6ee4a3df7d0c753521fa7f475694df7a0d833795a45b94b942945b339168bc8859a2af27f482ee2480bd046f9e9d4a98620224dc50b14b081596ea23d5fcecae74f29bf70df259e848046d3cfcde99634870053d4542a7b7c245b4a80727a2b29d8025b074eb59842e4ba82db3ae72723590b306407a1b84249686d1b9e51236daa413429718c4a6457b5044fccb0e8a037e7a079c1adc8cf1f3ecdf310c9f7729936b2e9324c745159ff56d547f08a77dcd80c77f7b110b6fe99b3394b9373ae622a692f919beef581163292842528ee03fe6e4d8b137fc264792f7903a9624cb2fc8ac45f4d52a28a07322581451229149acd1c580ee592f6cca5945dc889c98609e3c23b0ae1101a73ee2a5b003995ae607b0442876fc4b43914934c61540778032006923e4696c616cf87f8b3bc15186b2c5f37137305d91e396d4dcb602d0cff05f86b0402a02c1bd92029c1d884e13069d42e44bde512535dc46bd218f76431b21e3e3c20f6db90a1206f9d2686c3a1cb0e1e024f68224d2f92164c33975440d66c7c721b7b89fb9d587a203d83b15a43ffe125e6575419369a635c68a6ca17635262473ed002939a63c07e2dd0c944afa082d0982f97c756e4dfb9c43841b2fea04a5699d38eeb7d463863a401d8c25e44ffeef74853de8a6ce8da5f03fb85832ca8f412637ce8894069eed36d21aa699501507735bda3538f55d81b447b1b4f20eef00b40c892b9cca7dfb01ff3789fbdaed916bde36e73d558b9d2b1b042900b6b57e07395d97008c0961c243aff0c305d81ee91dba4a738c87cb44443a2908029be1e1d4850c90b89f74b2d905c866f672df498084884af07d16e18b10f7c5fa8f7d4daec1a1acdb550708b790e7188456eb5bc063ca721f2cb38fcf24e6e723c802a9c494f24c2b9a1d120b827773dc3b1954f7ebfa1c77fda26135ed997d6b0e301c3fe40b4244207ae792079a5c85e4276e12453538f056a4e46f1f676d3841239c5b742c0b3b053fbe7d9ff238739c86d735aa69a412f318146d0c686d3ffb0971dbbe0da44238c40a39d70ad2dd20a47c2a8efe43be2eb87f4c296d138579841ced4bd9294e0bfe47bf0bc86b3a690442698b8ee1f8d0a1e72941d17ade2a193e710a1af7583f8a772d12c8440efffcc3065a4681003e8adddca26d4186e91fb429edb968dc231224eaf355501e6eaa783d7dd4d01429c5b295a249acbc8543f1bf5d27731d0713d9a9029471036acd92d971fedbae7fa8b9c995b207578f7f665062a576c17d3111e4e9ec759c6aa1a9be52b217e1b3e92c6cc8ef6b2ef4b6e235e58544a3c92a55ab2a3a9f244ef926c7394453cfd9077399f885c7f5f9b132d147786e032a878598bddbf3ceacadb0455d016089063da30dbf8fc00b76c12bf943013279954cd705691067dab2bad94c20544cf7ac3b10947330e8101d9fdb3f98df6afde8104d60e2d9db0e331524c4fa40849fb87a43c9b9059c4d7d4fe03e0f51a6401843b4b8a99b3b1859e56826eef759085074836024d3fece4fe3e4302dd9b84889f42bf182f4ba77d9b8e808d13c33a5ecc8ab6904520bb6733ae848bd2284af1f157ed5a351a7218d7d9ef71c76411ae551861489bd06ed60e8ac9469dda50a686253fd4054910b191097fd80c27858b01ead1bced12dcd816cee1cfd975b19f6625902a52c9968621178dff1f44f64bf33df8832ab2088d3d910684eeb180e6ebe822d79d097b563a5003554ddfdfd868075171956b325d802de2ac3a2412a6ba82b266f71044f5c40ad6f0a818903fce81b1a0e507cd75af19e09f904884a8677a80f358ee7bd33bda29baa12ba8b2610516ef633c44636a4a0ca0bf867d5be90c062fc841a7c32900af838c23c0e3d8e331d5a5150449d3541ee862a874fbf5ab6b786bcfa4307e2ec29ad7f366081ab70b3b09389e32748c23c9a312742b871d7b0b1bab8fa1b3a012b45f94b4b924322095879c82ff937bdaf2941c37357074ced6aea44799fdf7863fe2f5dfdc9c2f28a9f2c05de6e1b7c7b063074aa82a0e2dbff4b29d9c37b6b595e7157c44069173c30481f36e4f552e2b8a492afb7bd58712bf4efdbe73021a33f5901ab18a4500d2c806bb2a040efae58449aa71c497f24aeff88627ea86978026aa198a7b191a06992c8b05fec19e256bf59000ad5ab8cc3516a4716495941a24fe7ddf11365b2eed62a5922178e63b3ac250d7c5b975251cf702e6e4c075846b4eb85fb972254b3c45771236512ab4ffd7171beee13e97091d8c27659c97e178ca3e3b92c37e10dff37de782b067b0ebea21ff84b7e6eb7dcd2f2744fc8d700e1d09b0c79d82de6ce5aad6c3c0a6970004af40c90600119a38d1355e9a04d21081c916ca572d0726ae8e2d87e56608835969d8405642a5f258622c9a90a3b70a7f1a1f39f670d1a0bde7aa90216a30c7903d2a0f25d03edec1651628dfc9ee07bc1ba116b0e251af8296cb42cc4c6b25a640bb89183527c6ca973ce8a6f4a71f7fdab4fade4a9a402c1f5aab869a32b10a706d394c2170fc8e62262faf50742247667b0f334a5cf6daaa914d95fc50648e12bddc81244bc1eef85be6b4eb2dc372fd27d057d6990a99e8065660af151bd1a5b450bd66f60001a586eda04962b4a004c98183a2cc79b870d8c65f81ab3493b49f4e6a2e2242f50d820b4f5d0ef842483c0b92533917257b5e66efaeec05e28ec4174b3522c97db9e8933fcda211e1ccbefef5daeda86f1517c5137c7012c0673f54f6425f6ebf40a7f7f57f0c19b2df3b678d40abde6348eb4377521592f19b61a6ae4bf731611180608eb3f13c4d17dc689a538dd373b0a3f3c93c7343a8a35f170e73e350e33ba9d4d1e4b9cc38a0174cc2ecb07c5ee397b1e7724d994b1f72af460f1e7e90893ffa7feaf63b3aa2c263917144fe03ac6601dcf7158a1ba9066ad08acdc5f02588e865fc95e79a84326a05029cd40cf22f6987daa8bcb3bbd32ce0ed65cc6cca8c3fd4ab509ad8f1839860e462e297b850324917bc14b25a9c6c6ae1a4bf1a4cd2c6e662bc419f29accde6d0b4ef61a74238aa4f0777fe51eede0a8001c60eb7cdca21cd2e07ceeb0e69d8f4c78db5f28cf2540f49116be40bbcc7acf4d27e33c8a40e1eefd6252c10efb84f85bb0c3e843470c3f2672d6dc921b24883c6ab4a7d155d4f85ae849833e1da9addf2669b5a663d09b5611e7ea508809f08e69197b2e200a820e31a5ec9fb7dacd37001780f046e10e583992d00e2479c5239a0cec7ff04d8e6814183d3e44e82c44059899d33b0b0a79877d8b1c3b4d65a0236d9443a6a54a2e178c33c40f5ba42af020250dff35b0fbde46f370d6dc12d5b3d4238c156cc7a47f7870157888d587281fb8ae7463da61df22cc4941ad05f6f0020f33294934e03a5e0a08c5e1384bff0ed9456c01573d5b37ad089b591dd2717c82857555c588b5c290756a415ab59635bc31e75125bca54cbbffef48c82753a56cd02e5eceb8b82b18f9d17304f790c2f19bad57aa61d28823aa2f4bb79471a8341b813d68ed7f2f66ee4da283bf1cbe2195a74404b15db83f1a34b7fdf31527c214a682a03ce2d22388d9c7cf5cf8c38babd81b3403f398a7a5789ef2983baa0f257464f47f4b55b35d44f5813c6cbe83422ebfec8139c033e57eda4186b28e59450b7429118cfae03422df8b408099c200f5cbd857caa2dcc8f122253f8d345119cf3164ad30a518ea77b30d628519f74dc2b1bd9b65411583b065b5a5cfa3d590493cecc85aca413d5352fb587b741802c0da73caf0f088b5816155ad0b644267f6e222c124b7dc3fc48fa7434885661f14bab507d8fb2eea4ffd7ff600bba62dbb20d8d13a2b3fbd883a6d57538205d87b9254a23089cf091ca822ea9d9d1cbccd7b8c017a0958b07eb7fbf771f472e1084fea01ff5cf4c6a541aa99fe82e5eeed94a78ecfc3ada368bd134ab2c55ba845cb02d15c666c65c075633d95b3cd44b01f05bf39818e150a9afc294e606b82d0b91844ce8b752d3c85287669e50e4430a79f5aefc9f2333ca0d036e334cb7765c03091a50042f5c6bb8df479cd52201048895233837d6e9a3ba8df650d199ea64eb8372889e938db2109225144f64388e7ad03db63cffe91204e5a077f314178d25420503407412422415d19e9268a4298570db6c2180f5b20ceec312e021f7ab0f920cf1b70b7e732b4be730018845088c7d333da45b2243119e56b2dcad369bff713a1ee9e2e24dcf1bf9bd061b75c47be430136a323421cf0fb757de81b5b2033aa1ddcc655502c0f3e8a63aa15ef50ccb9c66d80901e582bd22262a29715b76a195c6c31606c9f412f2d2db93bb759d63cb09c01b9e8c5f1c385dccbe558365bd648f13424f86508a2676d78155964bea1ab7a4799a46c66aabc2517579c4c86382fcaced225a15d0eb34611cc79a7db55b8c71cdbbe8d33833c886091ee3d77ba3fdff05c65a0ac3670e8ad556c2fdcf97dccf5866198c52f8dea88daeb4157ed6677e16c87628c4351301360d90f4b688b96da891c18b0bb8b0db0fb3ad819cf3ab6ff57078c0d6600267525831bc633fe345aa8b3b9413a25c927e0300aa4e64a64f66298898f627f364ab4efcc6853936e44fb12d401e2427a73e3681c04da51b97337687230680f63c7294c78a09b9144bde246cfcce1c5bbb80acf097de3567049f0c72470e9ee2c3463c864d30fd6b69128b6e4b4dd1fae3021e11dadcae35f4142138b748975444f1d565bec4c1a9e5a16ee40f92321875988801ffaf4fee7eb8da605a711076f4e53ed9cab6fd01c69dcbd95ed0071c0fb0a37e79c01c934ab76f61c127264cca3f9dd64f1415274b1516e7ece2f42c09a861011638f6ccc8ab253202c03123aaa7dfaf6a68dca6ad35ae9beac41a3666a55d1227137921f739b1ff451c4b271e44bce637ac39251e66628df8e1ab8607bbc6efdc561f7dd4214186bc30d7f8764d716d6dd669e4fe816f30f401f9d742a315e28192f660febf689460ddfd05cf17052112dc5c412b4a7a4a7461773d29af74adc8810bb395b5f1b73c62ed49f0cd0495687cd6abc618955a5906935fd85fe18576574766dcc930833ba86a7d3fb897903392d9d1589fc2adcd3d8d6ecace5b8fe39d84b44c3729bfd4fb1838fec26665dfe6dc202d53781cc2bf4bf515a59a981843ff9caa19e935c357b1ec36fa31892343f4d24d69baf5eda8fd4958d687b602e774b896c9a747c9d581068f0f7991976f4351a2901ce579c5703e06afa4245abb446535d1abe62969c1dbabf5931cc682d9cf5eaff84563238db6496d1b36b315eaaf17dd91a18f3163aac87b589fbec689142b6ba7586df0736048cbcd99931de177e020c02a75b86b385a72450b6cd5f6e7f05beb97a90ab27898b107fb296df4a3fb4b7f06be88ae9b999b9abb37c690061b598ac7b741318070e79afef81d3152a6aecd664fc342195a520779caa39e87a94db72db2a9c38d475810bb18932791010bf8ee4a0bd75ea3a516fd5f5e7fabdeb9e49db5ddc4f2118b6f20a52a3a87180f5295c517128756b78393521f49b555476b4b7e38fbf5d71e83a2e9618d55114f6662a6ca8106655b43e0cf692326c485490662db1a3927c25eab0e6a77d768d41d088a7d6661fb618978261c78e83667018d711bee1625c8a86adef0ab9088890495387ea220c30d6bec32c5c0e28377f4637629d07343ab00338071a99265e57c30690033fbead8c541970306fe5c8b1f198af0da656dc17e806ba03031207b2ae3e76310a834cac6ed1c82e87b8cdc232ee716b865cbf7f2a1e2345ab8efd2712411a62200dea92275d391a473f9d453856d861035d90460735a5705922f641dc3075c9fc79da412e8d9686396a4f0bc8cb032328ea82e473827a19b87bc075ba940c9fb265c783b48d69095a0a8bb2be8aec8e06d19e62f8c2d94e0a54a0214f3a4118f4f46db3919d3c47de22dd4665667a5772308d2db3ddae232e0d72c6a3bced4838f26623feeaaca57b35f25591f2afade68fa3ba01fcb69ec52a615da93b8cb83d0b0e3f1810d7257d394a65378a37e2610815b2e69c5da93efa5dfbaee796efb310b32c1aad4666fb0a984e8a5671abb45d39bd970464b25343fe8a8bb44f0d92df151d94f8f315e7b7a3c4492da36bd6fe9e23b0c4525a8ceeaf5aaa02c4a610c5dd3edc331588a56af9098e7e40217ae51d2ea46144fca6df98184df6db0da418348284ce282e8628a689124b9d867c025c9a08549153982cda3a4a30d15725351d4c3c1da0e0ee1a27e105662d3005942fe79fcc7e356829137ec9457ea41d92b76347f70d73631600e37003570f75bb4b08375c482e85ad31755884586afca571e9cb6fb1c1165b65744184af20c1e3a20fb7d78dfd60f5c0efc96015d931aa90cdc3fd9b7d6836277db8b2b9f38d0e14e4cca4b2991f43591213f665a99dd0982843be73f8a8451a051194c3209991be0d85d71c507b9b2867d47df4d42bc69ba618404f41f5ea5572fa82455d0d28acf5784216acbe510e9f9deaf5eeadb5b2a73afa02497d9c6d026d85ad0152a98db1b47882086303d5237d75814d9f606e782bc79c5045cf121f1cb2c7fde513c633babe3b764c22bd1a13186034fb2d5bce2304b7100394eb02f40fa74325df9185acd66dac0ba441a21629037870b00547b5e6e63938e3e519c771293d2dd07688f545ffa008568c03538f628b4440bf1c773c64ee936c69fa68188cd44a16660046e9be5f87da45252f1beb694797984be54f049ecea6acd0e27d752a72b4b407beed62776ad06e09da22d8151138c02a628a74e1f6969ac36a13c0ca61ad1abfdc87b60e88842ff9f8690987dc07833e87fc7d45eb7ec303b5d0441f173e4e8cfbfc553f0fc8a30faea80ac08b911537f963250d3964244f2285f3901a5f5fde34774593998a69219ed4a84e8ae20e96d4fd1b83ec78d8679e96342407afcaa682cb7fbb19bdc74b15ba5b583a4ecb0abcea9f19ea7da650d4f39d7802e828278acc756380b31880d6a461e050911f9240ce830881210339bc56db7fffc34b7c8d047ab5725361236c4495bd564cce051aaf9364e7950e12517ed93c9f9d41f1feb6482980c72b7b0aae984d9934999847cfe3540d31de804dccfc9b29ed5bdd1f23e3c5ed11390ae8a4a43c78afea9e1ced2bb4f6cf3f6aa2b4e3baa09eea59ae685c0053d6b5b647f8e21364700fed39b59dff7a072bdf1706d7c06175bb2b6be9e16cb340f7dc9cc3875ac3e8838a631e27ad0bd102a18040fd900001e5c3db876e08d8415c487944e5a4107b826cf987f0e9efa16ae7ce9d077343ff4070212e2c9ec09c8ac13ce268165d4faabb8bbd87b24e058a47edcd221dc783623c3ce4c0907ac8bb59b878b6df9a3678b62de24fb7f0a9f519dc8a35bd6153cb843817420a5d4f3b350b8267d04142fc7dd0ea61c1031aa2f803b40fe80e7191eb41d24161ed496eb587ab7bb080f20cdf5d6bb3675bc343881e62f8d07d29787c0f13d9bc85aa5b03888b040f3eaee72b4fafc9c68305972748a7a78ba754a3ff20b41052407988d72c983c1b27f783ee202e523c4971518c3c0ad62cfe3c0e27b920ece02c0fb3ce278a87da9a85c153e5443fbcd883597f8f8ab6f7c1f207d40f57047101e5e9db220302141c1e219d8a178f90358bba2705ee22a2873a1d99b81ea9b414f71e6c4b81381c84ca170f5cc36028e1f473dd9fb553f710969a05cf992605880ba30d15d2026fdc180c0f69360b801f76cf2ea876397c78604514721e05c07dda37a2ae84e06a3785d14375621e8885f03db4c2a5a854441554d312a04418d49b0d0f3e153cdedaab0f2f105c081d844a85b82078be377f85b8f3dda369f887d4f95874b3431c55a2e7049acf48cfd3d6fd611b6211020571c267850f9b0bc45f1f0b6f3be41edcef3d674d16a0dec7b41ba7102ba07aa8e77c323c5adbe23fa8d879ceb6287c1a9f026ee95b233d8e5b701ea460f7606be81ee07c100bc4c5ac270f4e858e0755cd62d793587791f2d0bd93e2e0a1d2d6180214e23df268165ccfa8389f3b4f649b059ae7eee20871a1c0238f63dcc593c76513a27b5c4fb2bb3eb84060d6830a9f879aa687588640411420101ac48a9767b4ce67be2759f3f54145ab2746030621be011a3ba0c2ade12147b17cee534f871a8de9a3523b8628404041b841e842e8208e0a3185a2e7eb5c40b821221782367a1e73fbc28345adc7ebbc40bc3c7020f41029104884302bda533dcd42c3a37539103b084b435c1078f6e354bc7a86a759303cbb7517713c48381557cf96348b340f864e0a089e0e97ee830a160f0ccd68883cf19e642d6b0f1635cfa77b8570412407c44f9de7ec1440943eb66469b1a9bdf9c36313609bd7f8100ccf21a98bfb45778d4c13306e9b577a582f5a2a99a40e481ba90597f49159128f368fbf2e7c50d56f4845952a913075c4d65fc6ec26f1acb2fac44956333ab1883121955b6a09878657bf9b47de9baa8aac0b644a9e3c8702ebb6957cde170af6ddfb6eb7a08e4b823d727077ea78560d7b0f292e3da6560871fa830ad11e1eed992020ccf14434cb87b03e58e8dcff92882fa67be1d63f8fb3eb3eb04e73dd67f1391dff14bcd92c323d5af71c889f7b0fb32b82a8f710501017fff66c34fc83e81f2cd03c55670421d603fe21566c7930eed3204281f774a959d07a864e0484cf47ed743fc4a2c1273d92c80194d202cad8a1615f400ec29a0ebadce5abc1c2162cf391c8ceef966dc54cfe9a87a6e7f894fc7700cabf9a7fa97f2651d245a1ed5fe7af98f0b1f9f192828b7fc2e284dd8b194637a37bc050809657214078939ad84bdc18741466bfad6db9f796524a29a594019505c5053f06385bec378e7db6e6bafca20b4ea316986f5625d2ce2a93ca6cd2fba3b19c4396755c3ddfbfb6be46f0c538b8c1e94006962f7d7ade407ad079c55456c7a2ccf2f7af12176ca5a03a755debbdf7deda719bd69bde4974b535c4474663cca236ceb9e71ec518fbaad6eae5bc71a95ddd365de9c4195b1c167412d642c1771d3bce5733d822f3cd8ff5bafb63d988fed6c6eeed9ee76570db7256b9f4b64db53defbbbb0dd66d9e70bd4fd4d61177049452caf33226696c3ec6f2b1bdd6d26aadad96521abeefe5e8c3f4d565ec8904123f532d147cde3ae293b55ee7e0258e0cdd2f0d72efbd97d24d2935e1f3fd6d974f37dd74fbdc74ef4df7bd346ce7fc7a520655a954aaec2a95675fb9def9ed1cb75279db03797e771c28c61ecfa24cb1486991bad2022d2faf4c75793b85e5250c5fa94dc82eab8b393f1a9bd3032d6f58535d8e706fd59286affafc48d049fa0d51a60b76fab14010680cc704469873ceecdde69536e06e5a6f3ad42d1dbe4b63c3b785a2ff65bd5a3a707023a306855143af4f9fc264c2acacebd092fababc790d10280c8c3d6f34e473de6d39875b7b076e9e33083c8ff3b6ddbbddbb75f8c44fc370ecb01a2cadacbb2e6126a801c2a6f596630347d0d2250b965d85e6d4d4252d1915e5a0d94fcf4e093946c03181127ca2c472aff6768eeb77a3415febb5d6ce79e7b45145b3e929161c5ba22808391bb73537a7d699e1081b54f2bc82d57368afd6593b1cd505d55ad7aa6bf8511773e7e0e6d460adb376f9268eba410d9a333d476b9dbd82e24efe1c34467d041c3446a5d7985715d250fc48b02009f6716c899a29d3dd32587e6e79798589da77b4e5438e17083568cc897a65fa8c8ee66ce687c6a8cc8412748e0b4c00078dd1eadc03c4ea98d21caf5f000f9f8863039f7019d4d66a55aaeb5665c2abb655a97cefbd555446cdd0250ed480c6a8eaaa6a10d586e2086f954e7805ed0eaa9eb5ab5a6fbdf57a8e979773eb475dd4fd52a94251bf0ab4dbbb71256d71f9aacba8210939d573ae771564bd684c6fd7cbe96a68c89f61cdca75acfbcaf3ceecf9bdf25c7ad7dbc4dd814a27dc82d5cbd97034a01b9c0817405d502d83049fa86bada9a195de8d0674167c8122d4131ed8562d203e29a794d2efdcb6b96996d6534abd4d97d8cb9933b457662d379f33eba9a79c726acff17a49a9d6a1a654674da9de24d8eaf289faa5beb9939f94ad315f07342683c6ae069b5e31b6b9e8393548b0df9ae1db240e0eeb69b2678e031c0d7c6edf7969497dd6bdd32006e6b7b87cd7c59d17b3cb8957aef32a67a7d73db0b5c477bd9356cbfdf75e7f713cdd6ab5721af25761cde73a2bcfbe0ab37fbe39cfefa8fc03579e0ae4796fdbe738ec5aebbba7458209a395c62d203e2cc51dcff17a4c252861ecab3f4031783f7b21e0c7184f3cf174ec132433bd1962eff20eb1df592b8a52ea432beab575794e86a7d4f88993e8abb7bc7c380c59c02f3aa3b37c4250d04f6fea9c75ce39671c35259539735a29a594d9aff4acf30efa5de5a567e9d5cb718983c66ad40e34c089d9bc686cc67cea955ebd7939257c9e39e72977de4119cbea760be28b17a62b2888ba02c6e8ca973063a05a3d601e8e649e077e32ed79e10ed22ba34e26c327aeea6b95f7b66d9ee7390df99ee7d7f3ebde7595e39def54deee78be03a90e8f2c11da832faf086144e5d44a9d6350e61e74f4290f177ab39c0be48beaee044e26eaa2fa96446346b3a8ca275eb0e9057a862fa4d5209a56139fa89f54a794f582c56ec4edb9e91e28bee6af7c821f4843fee7d4ab51ab7f61f54f855d85dd797e0576be55afef369fa08cca6d61c61f0ba7f2f0d1b498f8c49818fbcbb29d5b4ac3ce419577d7afca5720d65aefbd7758e3b9cef6ecdef6ec3b9434b6aff33c05c5fd74c7033b2ec7a6a08caab2d405758e56249a56998f7eacd7cc51da3ec1f9d6721ce734baebdd75aeeebce672e5790de6d89f032f5fdea024ece8c8d577e8c8bfaf77e37a9d557b2158a7ddb52e5f4caf56b2e3d574eb7af255d7b9ee92f24d196373db6190f30dd4b17aecd373a8ed1473e4e5abd72c557e3a76a697cf23f52c5e8e469e7e677ef5e9da3b3df1e4bc9c396706b76b2975dedcbae73bf637c69d97833196f285e719e430ecb3d69e6b6fc6f4ca6dd6c33ba77611dfc08eb1581d679d29ceebd9981857e7c9996e67dcdcb89e7c3a563fe50bd72b90f9ce459edfc2bcfc2e8520222f595e3e5195e77c4bc1e8bb1b0a435479f76d960aec3870bbd7795bc25e056e5eceb68978f53bec6fdfb17f5fdbe675ef6a87e2e69e6f2af740adbd1b9c7721377fa56790a0e3028f3b57cd895d85e70daf73afa39dabba8e7652bed8de71607615a85de579a1e4dc7a3736efbce340dd8572c3d786373426b92022615e3ecfcb1798babc73d5ddf0fc0ce9bca15287facc5647c400cfbbce74ea34bc21a29331bc7cf8722442e577d8d7b17aebd6b77927d6be4dc7a0f64d8712f6371406e6e9ec9cb3f620b2f4315e8e43c2bc112723477f73138384e9327bc652c6d8b13f5d746de09b2fab63bba59437f285a43a0811e2af4b1ad9ed046799c7a038c519b30cb5217d3a0d19d6ecb09ccfb0f2bcf542b8d86bb8a3ce1a1ddac83a58a75214300ed2e5adcb8d52ebd5a8384e45abf701f61d7ab322d155afe08c9df9d95d4b3eea798897cfce09c1f2d6edf60137ed8c1acf7758edae63f532d4316f70e18e49bd10accb70470d674cade907b07d43633b1346c1747225c3129d5f650cf992ca18778af52a44f6d6ab8e9631aed7d5d31bd56da516dc71e78cd255211e7b96a1cb5f9f58bebaf581ca53df8aba95761a1be7353ae64bdf617fba8e15f642c09eab0cc55a57e275126c7c8f01ea9be7cda97c215fd0cfd777e6e635d4b13a9b065e82e2e67273eadd068a539caf3d1dabc780942fc4ea8550436b77cc1df36b72a88343ab437d67fed5315f73d33ae9ace72062aceb71267bedd8ee5aabc4c1f91ee75bfc0c35a071d1f0e1dc74a9f7da201ee0abdb9baff3abbd32049a6ba96783863be60c75b06397d7b391430cee98154f8c4327290c1dd3e5f489d6f51864c7fc1aea086cd1c10ef1f0ab97e39014122d8c434ca3100d2e2423e773bfcb82a12a7a1c7af2711d49f172145ae1f1cb5188688ccbc8a8c80a882880021123584196440bc0ac20a887fa720cea3202a132fec8e22a22c5a30105eb0ef31bd4020a1f155e0092c3931f3d7e10c2837b04111b6404280868890d66468c0984b06c23101d845c44eeb031088757bd1c83682f3a4e8783ee664d0508e410a4e664fc410535a8200522f6a9db6a02222e21174b6078e243440bb63831820a37ca3c20640452f2fbe508a4c2285b1a816478b9846c112ea0ea7a042afad708346b0263ac4377bd3e847cd2ad4bd7d0675dfa66e94dc6d06edd9331b2678c5d015f935dbe0e768acbbcf45870f91879681979d446a09eb147cdf583560784c1e9f13ae4e0ea212ba56e3da449e826a40bf9e2ea69fca840ba908f5d3f9feba5057ebab4daf5d389cbc775c2277e7407dcfaf26587c5e8a5db977376adf5361f9691b49a58b1f98342f140290dc2160beb4587e8100da24374964198c3e69cb018944f94b4e9326cf89a3ee9a4202cea1aa19b962a330eaff701f753faa665da8dcbd685c2985e41134aa0314aed52387ba27ce25ca24b53266d97afe0ab09dd62e213bd0490e6064aa5a4f2023b32c6f41b114058ebe91327d4f4523bf992e1a6b128235a4fc61fa817c0cbd1c7cad3d8cd7e654f907d8c85b02f6fc8ad37e4cde49c472fea26a64f9c5193ca9c3eb1482c93caace234263565d1a0990d8d49ef817a57cfcbd1a7cacb2fdf75f9a26f206bd7593028ad2263f269f8d42063a0914fd0cb1105326fc3cb11052a746a56994d62648c29e6e5675f36dc22c8185304f9a2ee5a6db5b5561912c91893e8659d75d49738909f8c6aab7c51d2883881d6ad689d5e4b88a497de3ac137bd935131b34663738ac6669e455ec64f7bcbcb37dbe11382f64889540c0d436b13cc3767512c2d978b42d12e348ace17757aea2a9a68ec7a34e6df249b6b6353e9b4d1aa1a1b2f573fe79c3ae3bbe98ced105b7354ab7d5fabe1ae569baad56ab5dac57aaf58b12b38f35a6bad354d7f95c39baed5a66ab55aad46a33dd168341a4d6fddbea082277edbb66ddbbc68a9a7b3eced5a9baad56a5cadb6d1684f341a8d76b7b79a4101a2f81a8de3388ee370e84f7c6dbd6b6daab66bb556abd19e689b5669341ad84545494545454545cd9cd8ad170d06f708078af5619e6eba56abd56ab4271a8d46c3333b9bcdec2c2a4a2a2a2a2a2aaaa9c9a9a9a9a9a9c9b55f43be178d0d0b0f5b6c1c1c1c1c9c188ea85ad46c369bcd68331a8d46a3d528a5b336c39ad6dff77a6d7a646331f7d78bd29557db749366eed1778f56f748758f3c2e6a9baad56ab5bbd519cd3ead2c4d65699ea5554bbbb9d194666796c8ce6c602edee4598ba230b0941755a3b8a82d4a53bc9be651e7c4b9b8b7a6a626176fbaf04291606b4ffda1a1b837cb06d673f3e285f266787fc30b4563d4c74fc43d5098c5c599c5a6f21e8a0241488848c2a90ef391439804f198c35c080f20c7b14a38fd58dfeb637d9f9529eba124044d80080144982c97081166c2e8084942a9a0061584d060e4089621419ac08024881844f081a23142806a92234349a03819c6392779fa9c7d3eaf5a8aa030937c88f989e242a40927772684e43aa2870b78081912907944856cb3880f2b0208808ae8000a98442972837891612022408801420a0e3e2d0c0dfd20b1f0011f40f840035107522094a404410c21a5862b4066089225c13d92943065c9d21312fc60e508c89ccdd0848712b324c6250ff08f21ba4711631329212e438c5c1f1eb057643c286c39fa213b81c90e526414a94a8f8b6573cc9c65e9f9e125c90f30290021b132040490a41f84cc232af331a58ee60a53407ae041c49324c6dc1e48822a122641603530d154a0d24344131e4a50243c80b0bd3f4994b0474bc872121660a422286cc918fbc7c3636739f141aa39470cf5341103f5a5caf50152876442b6540984921382b8502d4f0b2fa8208821424680822e178526425480249939671eb987181f0a8404eb71248948821252f493744fc0014802445b587074a586a916dc9e9c0408215ca62d8354f4336bb6b4e0042d6431e2c70eb60924314247b5077a9338308484840a9029c184200426f82202a220424c20191dd9243f62929c50bff8d025a1168e404529e269884c121f44485428091eb24f66658694188250c24a96142c91b4822047488ee8a173ce328f39ccb920ec12524047588644c720f9f87caf8ff57d3e3f1831348352830f30789095f8ecdf109f8f6a3ebeeff3ba03121142492616f3180999c7475f7c5260998f0b5843b979661de65ba0dcf0c4e485224045d824ae12158911690b90e7f0669c73ce39e79c5f477c396fd761ee32eb300f1de33cf479443284ec55b3f66e3774b6b34e2e10fdbcf4ec82969f2e5dc85beed091df46be905bc8727560be5318d46154b401f39d8e2b2866c7fb467639e504eb8ef5fbd66f87bd1ba195129cdff50962d8dff7bc10aab3280ce995e2278ef38de37c9b9aa265995a5e3acda6f3dd3ea836b6d0d66cbe67d07fea7d604367fd83f64cc3397f0e696ef864f6796d769d431bd6e49c4cfffe705d9fe0bad672448bd409aae79fcfaeb3ebeaf73a468137bcb1506c284ed86f66a130ea4b6f793326edb3b6dae98919ada3fdfacce7d9d0ba86e3c219f4b377f465d42c7efb05c3e9a08608387294f033335a9a4eaeebed23527bd3af2da9eb68cf2eb230de338bf7c11c5b20e2f4a7b30d1c5a3b65bd2adaaa288c919797a3510f0b5afe823a4cc865ca94997a4a372069d25317797e3a0b4f4f7db2e0f4d43be9d10fa44fd7919ffa8e8efc92c6acdf985eafffbc819dd2cbc343a9f439c724bdfc159c3a8d3747e50bed17dc3406fb0a727ec14d06756bb75ce7cb17d5afcf0b8adbcbab6b68ab584570740305a33614a7b3e056bb39b157306b9f200eecb1eee025a684ba010e5ce50beaa26b4af50e9e8a381787c668ec463e8e098c40fd023246751943feb5d7ce68e824c5775a3d1a99bd1c8b2c8d2990794d611411bdbf1c8d4c7d6777f5eebe5d6680fc0b8276f1c6c0fb4eea565f877d8d0dfad4775440e479193404ec3414b70e76eb2d602f61d50e75d6b1b41bec2f282d9873285e71cf10ed0c6a1d7bb61a7b96b0182c952215646ffdaab01453352c4f5aa09e9e68b368261d4da24934675288a9af6e6b564a0a733003d7ebd198d8e7e3506a70e3b88edb9beb3c956aa5da1fb79a397102c589cde250a468b55cadfd52c1a95051e954e15241435343b36d56702b56543a57d4ac60c1e20216db410e042b9da086b568914106db820088d958acd2190bb77b332c88c187c1b620acc360b7f068cccfa0cb20834a6706daba09d65b68558d8dc7a18881c74ea1de86e274e933476d22c0934ed2a0110a19f972844286ae20a3183d8942abb55a1bc5cb8e12c68b524668b58d7c5b92198ee904860185aa0aab03c1d8b405c5cbb1c9d544e625535184c562b152a490c254b3abd8a8b0acd81394c2658252be5c2065cab91e167bc58a152b58b0d87e84ad240c52c400dbf3851c5abcf0438b0d83c1601e0db0450b2fa7d2bc40f4420d001e8fd86a888b0d2900295e8e539a08604f704a0d2a5e8e5342f07a394e919a4266003346ba172d8a91100044794224832834a016268812250c110ca294190a857e8046823c898f0b987eb080a1c78a2a4336200052b38588a66908222a9ac804bda4c8865c456cebadb5d63e7df6e528654995201616145c6627a47c199a913215f4f5fc58fdf0a14a2ae2c590c2ce6148f7c20f41b8176a296c5378084d1912c45a6b6d0da720f9c0539aa470a7d41064a78440853a45aa884e2123349d7cc8be8fe554e4efcbd149c88b9f03601ca1848122f57284a2050a969723142a23142950949676b27c5088f8e85e8e508c9e90811234a110594a12438f7befbd639238d149a6dc1b846ada614f988e6cf982f8ba271f1fd4d7f33d39fa49c2a2999c9892f69c93522628a6276bedbd4e987254ce596b26314c60388eebbaf1c9f8e4c9d1f645ee70140565054d50606cf0c0dea3b7492c04f95820f8c27c4e6a4047d824828aba000ce027856173bedee1eb1d9694d296aa4e70c77e7a34687edb69e7a6305cbca4c0d7b0d2aad4492a65cf17a11b9cf830e7a4d4491527445827357ba4a321ebc8443432f140820417b058615343a3e2e56aa5c847a48fe0c34dc84cd71dbcfc2926b380b0a9d758808c0ea4b3aabc68630373c2f4a20694078a1333df4ae5ed8edbf4f81434e488223e57884f52904fd2099d75bb44122680eef5a9e9d10997e75e8e4eb2bce838db50b5d5d5c427e66342e423a7e0e38e28f1f4eaf181f978f8ca7c51df6d92836de2d2e193fab87ca2dff02d6d80873b4cbf1c976278d171aa93add62e5942b6f90c692140b948868f805c273e6c75b2d65a6b5d427cae1e3ea5304758a51a10522b8102b259253d00d1ae213e590f3c7489802ceb63a147f5af8e4b9064f425fb92f8eccccb71490afe871edd2649d8d16f9dbee84440d7d92d658c6a4125efe581074a6900ed1ddede4c07e2cc0150578172ba1013f014c67441bd003336634a1c9e3a0d0d4d964f47bbbb8883c1d7210766dfecf6c01e2f0f9e546f86fd5b55d733e041a7953cdf4015b7efea3568e50b95ea75cef58e4a39a9555dee37c8a22e6c7ef372bc7ba56755a18afb0a7abf415d5d6ca07c95acb5a3d5aab04fdf15ecde823bf4dfd0ae74f6f9f9c44b18e5a86eea249d7309251f214a454a474e949c72ce5a2bcdc0711cd76d252f4a5abc3dc151298c50f73a322a2131676654d62a81bc4c23d56aa56989c9bfc6a50de42fdd8b850e4a490f4628f972b10c0ffd6bcf4cc4c2b80489abd24b2197c8f04ba28c4b98680a63dbb68deb9674c920e85e2a4ca7d62e6959f24066f2d3f34bb517f592d46642f4af9109ed5756b0d2c8e488b4d6de0bf59473ce5ad791491393a8dda4a8128d4c8cf0948879713781616cb2b4f54f1d52be602dc1f2e2fe71a988b1c90f9331ffb1523491e15f34363dcff354aa51e9696c7285ce58e95e46544479fd4c7161d980150ebc803ae0b24106d797195efc3c480d2ffa0b858fbe1c95d860e5c76e2f4725e3cf11940b522aa0c8314e1cd8725444541198f90349178d24cac7bd16890e7fefaba6e4c87b2f4725330ca5856e20a5c24c9179e9148ac248d24cd4a9ca134e96974e8fa6e80638c8d01f1a4489a8518dc2d89ee8067336cb32d332f332939a499fb44933a2cd24da64a239d1aabcd461be29324138280cec5e5ccb2b4b072f6f1c6643e911ce0614aaba98b4ceeca5e2f444a3e294b3de681c15271a935e4eb7f7dedbab53b5d5376367662a9d33444947a22d22fabe9913288a2cd1265a2c4faf212850b09eac16a896eb4e4db5bdf6de4ae7ed52ec145d4bbc3f4fddd5f3da54b4629eba0a3b456369682a9d34ad9c13a854ae1745ad64342400001316000020100a090442c15016874128ac0714000b6f86466848301b8623812488711004611c85180308400618038831ca40a4361e528cfd6aa99fd217454345f7a61077befa60686f34bc82dc35d6fae1d9ec30b1f14b31487f5631acc598eca70b5cbc10c780823572d193626c28c7c3e0fcf342e09daee2e725d75ad7cdae55c244e82c445de77d63d380f3e7c2a26f28970441db7a13cd120431250422705bf05a0715649903100aef42718e24eda45d9fe8c7457e49bf59068ad9238968a65dae2d0d09fc8be83691fe800ba8cd5b039f27dffe0ba24abeba8392675c33a1c65b16a667b33d0d69fd501dec0bb5466fa89cdf7fc850f607de5686c035008fde30211cb9727fc151407cf3ab4db14f47f127bd503834f6308e56c58a6cca83752d7e094a4ae4bc49e263bc58f01283149b77b0f351e4ee3d2106fbadf55ce75cda0226e711bc654b1ebad70d5342d27276350c2ad03d7ddc82913dcd6843c55f88263e5e3667517fedb651f58e407179e9bc3b875e01e9cb610c9ea2b1666223d4890424408da0a30af10f2a2f1308a50bcc0039b1280424b9b171d027d9144f245832cc8f5986f72d9e6ea09967ffb0c54bec737dbf6abc60adde06f11cdfaca3e714293c7a0e9363a21f8aab379a1ca9d4a7beef726529be6cfc25b35560416c783dcf993f8b07514a258989f9d5a6769baba160acd7bb8cd178f7f6d7aac69d54413b09d4eea92460d6319b4a3c0ecb81ccb507a22521739c7ed5ea7293c9300e73b69eaa7918df6ee7989e0ece346483013ade2e630a32ed15e29cefd88522019044301a1793a71ed8e6462258d22ab668fe75a3a909e8acd9c441b5f0c4cf8b1e784fc3384186b3aeb21f0d0ad2b368aac702008d51c41088b20a3bc65f6c8876a76ff20e5c6024e2fb83715f2d3c48a7c8346d2a83266b6df812ae9ec3e6bcc36289d63e95b6c1e60091085655368efb9848909af06c4abf8f11f1eddd98b0ed4a666dca762a0fec362b056153b33ee3e9f46e4871f724b336dd66680ed06d8f6879a2d60e0788a9afa83679eac94c226d4f9406fad59f714295d5400f3a8782d19cc839c4df1edb48a30490558e6d8c9403bc2907b02bd9dd18f1cb9381c9db97c05ab41b533ee886530fc2a8347431ca3e3db3e102061ee3e593c1952e175151fea04e15edefc85863e1713149ec1e758b2217f8469b320853c9de258680b17ca4844a0ee9cc66cac924f92a5b8ce6f1169aefb953bbd59c3759c6e60227477acbe4647134346f4c78142a3e15da2efa91b20aa8c0e913baa47d38d0fa0c98a864969e66996eb9841bb3595621b0ac8c4a472af43c14dec4db320810bdaf947cfe5cc4fd491b9c45b89b8192c1d887299e919c89b4f2509861d806b9f804a5543436af5567eda826b1b11035012018a8827b6fb8c15ef3250d31711dacb5805b054e63a3e68e603b5bc5f7cb97783f31c6768e2371953a165790f1ff25f80c7c6f589544b6f23f1d2887ef73dc5a8656caf88a6200ddaee42d6ac640e4147a5dd9eccc8ecf2105c23f948477c04d4677c97d6ac40237ac6da1e3defc2b9a64c1d19a988bb5d88ac2bdb07c82a4313912d0b4f6c83b407d619566b4812cd34f814f837fb3229c2afc66140f1da48251a6eb51c55bac53f6d94b45cd7e4d6492da6708ddb084591e2fc670d8c7839e8d487d98bf4f39fcb45804d44f15f5a125891f8e02a2e021443c49c56e988a2c54f151d4a9bfae5ab105905a54a86cc182a008a3b18b4b19e80e52b46cc7606ead51862b2abe9e54afffa90d4101b4e4f859004f1cdd810844d58b9c7429e6ff35850251b0b0708f93cd3d7d83ff8b02765cd8c001f1aad94f13707d67c145f8026143ba82f82f533af7054d78a273e970e4fb2772b547b1e94a77978f26cc11b4b594549d611fa5c27791af59f39c9a12d934c5d903df800cfda854568058fdc62765c90b3d500a7039d8672342acd5d86affb1861243f118fda941a84a960fe82fb32e29badb0f64cbbb5e76b85d2f17e2424a0787cb28fc3ae9bdf7dbecb697c935fb96f1636dad9039a1de4ae8e3a7653b7b6adb8cfbd708f777f6e756a8af879d7ae293a88f531d0126c22279cb8ba23de1349eaa79958ecab16d929aa9700cf78be22785e8a2613a6da0e862b10ff20979996033a63e38a0284637b34528db29f6be407159446b1a3b3a084ad09e185452e3157dbc66cc13ad96c8289384aa0f578cf58c4ad9c139c11c351b4d12606c3fdc17363c3dc655433188f8e58cc4edce22d567de5ecd22e8d1e0a4e7264444d4406b5484a82424f5d138db9463dd01b5195d5c441709a791a2476b159f5de40b35d2103434217df48e794a4109862060c0679921de266e3f9af8d1a5b5929bedf0cc971db7ef117390564b349259c2159219672a61cd6dd816e3af5ff44a2468dd4e18d7d3351dc1731e2050a75d1c7493a89625d1c3fe1af7d3f9147bdd144c5739c6ec5b861c9199ff7ae82ae53a932945fa5364c40ebd4489378fddbc104729a3df581ca1700b2fd913d2bbd64088172c29399101777302434cfe4c314b5ae00461a4488da8c2027e3b4d71161f10b07c36d5e1c8f7a0f4a27acf1b6ebd29bf7682883eb6092a117193111554cbacde73b0d81d19ab433f5dd17ce5332f7b2316444b4bf8b3bfa75476588d8fda373c0bbf5e68bf047b3d43040ff7f5842c3ce4a7d281c4cd7f45845d00b2976d6ca5fcf3b9d9f541f64a4365310c6f8a2f580c3977b31e7d8659872227644f488ca212331bf9b1d5686fc83e4221d7b8c7a7591086a72cef04e74cd515580dc87532bc9fcc0266244a90ae73a3528fdb674e15843598fa0c322d25a9d3361960895b3a93a5d177c684cae51e956f3293e5281aba63b9da126d86d45163c6b4f365d14f6e876a22cc1c24291ea628e7e32d8d0c4a1c147426fac0b58642666821031c5964f93836ce75f3f8b56d0095186d60361a24aecf301bdd8589d1c2e739e81451bbc3524d2b6e0fc4e7dff0085a4b0b6ef533e6876d8dc62e310670ae02b598d7b703cb27851dc9802109fe3838c1b84f709374e76851957b458c12c318abfc1e53451a21c225eb875d9468b8745f919358260b55e9c3e161a4da3a54359f97afedbc07a1304f8bf16c1e0168bafa08d377c66489cff478b6d790115931ef806efb0522273b10f69a02941a30098c519385a83501005c0448a35b44f4607d9256780c53e7b5adf1e0fd5b54fea9560f560ad7d57da45581ceeac7fbb65238436a343e32fcb4a186fee51d47536e5d1380873f73f24db7b08689fa3207902b6e0b916375850b5a1b080832d5502361232ec4f8b33571ae38055e037a570896f7c3a5d6abfc81d3bb0ec83501074500c36b16893f5773c0d82834c1a8adc20848717c8ba6848cdf197ed3636a93998c9c143ead009ed26601e025607731ddfb5d085fd242d899838bfa933321606441a9007e169d3bf58fa8bef533329b5679ca7fb6bfbd9faf87dd1ea471a2d062b60256dc027b099c45d0289cc1d64fa3850cd7355e1570c45ff873ff4f3dad21131918b61671325db0fef012a41e6162acf9281e624424f176dc93376e0c81d64e788aaa3e0c86739d8c187109f43a1b285e54cf091359c28d00fb8d5e9a81134037a34fbaa153a4d51164f3746e57be5607f25ed535537912ded33dca38409e8f91364148bf604b7b503faf108ec2056f3918e8d877ffe35897cf23a0c556669ab8a78b1ab2852bfa9f458ba9a0fc9cff4b0dc952cf394b22391e4b9f4c857c9bafe93c50c17fb78d1f188e5df0609cdf4e20d361a8462a766e25879fe61e100ef38a21bcdbf63dc83a5225abc20256f61b6eb7d2cbad34349447548387d8d563676e579b02049394f586f4f108ef3b7eba042b849e894c8a0405d6e017f74963aaf05239986a9f307a30c1b0946c5a12b60014bbd1fcf28e6919454095cb09fcf17adadc0c649af2dbcac6eff8b4a6df734ee4687d63fc7e2f0cf0b99d3537dbe31d72b7071c00c42fad710dd84a7d8c69855e33f27b4803c547db3f66db22eef6e284e999bbd4c932769de9fa964f007ca023cebd02883be5a1540b64df4eb07ae38b548916a966065aac5b0f7637fbc6dba2f623a2ba8a7629c170d7f2fc1196b64f4a35136b368aef403433970ab8a08000f0dbeb097cf94a1ca389a8b4615bd80489932adadf4210322c92278b517980acf471192089713a75b3591d16bc921dde14a7cc9d554b3ae727ae8b913d9f63ab349198ef7fb071be83686ad5523b5ca710c97579713a8fd5b0362b451bb74610b99df05140b89cded80bd3d4799acd535b55f6f35084d9130bc7b9ba4917a64941f448bacc635b4e837b7de109349cff37bd8dfa6691e91f45f7552a5dba81795f7e53b0311295e80cbc7419a5f3a175b2fd3a3191625e5755ef566f9600c97b3e54eb0823bd995849c83c2213a4dcae57152fb516177bd4c9a5caa5e06575a99847b567b5c6a2604c1f0ba4e8a5c9ad844929830a2a24995664761690487c0d9956fc1c694496b776a616520cad36f001644a58ec93a00ba849aed2cc5ac56377811f5e09a06ea3c8518030c3bf9abfb023158dc7f895ddfe8cbbb5ce258eea886bcfcc0689276435f72780b346e2ff441e3b7f3743cf1e4acd224c40942d95629430c6a952ca67753830c7ab7c5a15884e8527abb815e17680919fb4295ec8579cce9df8dc9e41b8be371e4edd4256d258df6d80f2f14b003f434aee60053e4f06dbc3eaaec9089e4726f1005bff4a87e0e4efd4a322379d052bce25ddcaf90750015fe143acd8cf94f721f4c685d3c20b50e5a0ccea373e236204c841a4af0536a9c3b10368a28125dc518d5226602b8f05ce437ff4680e823c5fe03c7c3daf77addda9a4dedc701c58fc2eca1ec77e186fdef9de97d50f6cb349c68f9f87665eae01485309902a1967f2089acaa89283dfecf26f9432a9e8f1e3bbb022221834d57f5714fb956eb03a47f58cfd31f3c4820e7cde63e692ae8f419f059742f74165fbdf800afa395a75379257353ff41bb630d70d6a3576053351948bef81f64235f38e1b7edc96d7ba91c938775720de14664a1754460f3bcc8fb0e5e140e950c1ba078f7f8e72be966c57d0b070c605cf9218dc90c79e39ed8dc16f3a7a7c69c9a2c3163bd3ef2f7d048e35276038fb0afce75073c453caa5fc3794833efbe7de924f2116eb8c207bb7752003e947238fda57367444916879a6edef33afc13262550a43fb9a51a6f1707f43ff60228144433e1d4bfdf5d8444b8c4aa307828a2ff033d55897b3e47ffaef0f65c2157742c56075e29c6e15c5859fb2d1b5cebc2bd060884d42a6e4da102829bea98ed27e56d2614b3b9dce02ccd2c8893fe47681e7f92f09f028b49807b26c158cb610a339dff3798333b93b2b7bb53ff90d61db4b4bf03f50bb1df8d660b0aa90d46d9a043224c072accc1375c174506dcacf5fc03857923372c951f83bbf1509d792fad96d2d184525021826ca0acadafc5879fcf7679c995cda1d3a3154453812a0861d5b2c070be138990940f4993bc8fab968bf136a3031a5b1f5a35dd553f90dd5d9f9a4f2c507a7abeba3ab42441f7946147779522b6e3bf47c2c94f1245078deefb207a6264486f9bc6906b21dc476bce7c5bbf37e91babdc380f9a093a5bbb2848de50fd820a391f5a6152ca9b8c7c919fc624c6b5f2c23460086a323630c1f72893f65f008a844b01129a2e45e7bbd99c4d62b6786a62fa0d1585a626129902e41b3ef8557de8e07b2d4dbbc640a5f0efb94af51e658fdbfd645694ed8d03a830b5a7c88138edcb41957bc5ee10380139742403733b8c6f8be5965abcdf806bdb53a9927bf6659857b7016587e4f3412505cdbc5aaf2b60348c4f0a545d2c02678ce58b0a20bf34e74df0a2afaa5c57616289f88bdbb75c1eaebdb5267ee4eaec414ea06170b1c21762c6b83cc7fce1ce580afe437ed525db2a1593ed404c5b981a526942ca0b4ee4557c4f9a66c2bbf7a9c30fa31123012731468c03f3f1cda5e23d0712951221dbbbc01fd20a3c5653480211c224d062951917088db08b5a453beb331ff08f583777fae24f1fc6ce58c1c840bcbd4e66a56bcd9672780a331be404d8abb6d83b4e745efde92677ea803b7fa8ddbf6c68dfede19b63896d47dd6184ba1f56cb0d44f4813f5877b862d870039a06019d80baa1ee00f0eb2e942e501be47f42a9914f0c169787aa4c0d44d55597f73fe0d7ae14bb121620909c72345213094169ae38fa11e940db1b3ba8c2ce3cb851536586161a6c96111a362e9a2154dd5a1714bc3ee3fcdd782fd879f60276f0906bf5b4e4744141191d3ac5d3ebe1b8484e5b00df14e8f0f995fa48bf027be83d4c35e3e78ee6d555763b71fe4ae88f8864b131acd1e3883e9807232e4a26a55c72e7f5ed20cc815dab9e63031c3438379d3d28a9684f0736d5aa2c8726e63ded177a1eb0cfbb9837db76d50c81b77f1fa9293955074d77e17ec5ca2b7df2b6c995fa0ea5e2b4f5bd34a43fb1739cc8c11cfbb33b002a4fdf3a25d1bdaafd000000790194ae75e466203a672e841482569d78d2df3eb72e24aa2404c01f12e2c8279de0b38c01cc1dd2d1d69d972e7d27cdd77a7326586b67e46903a0159ead99f16274f76a03ed10641149068e121c17e1d474f3d97de88bbaf236eb7f14026fdf7b4e0d76db10e7f9b83c1d201308c3c902aae0c456c672870eba6cbafc9be69aecb3d6e9b85d13ff12c3cdb1cd6544abf6da4d149b394c6a0a19194a5e7a4a8e7f24b4a163d1c7d876eef754dc00b728d104ebebdcfdd76e8e62927213b21298e920caf3d9f3e4da8802bddfe8873e005d35bb2929ee5c931e8ad1ab7073878687704d8a3f08bfb0dd5df3e38f5c34f2a47d7350d3b3f6610add3806749f0ec042304849dded8c306a0ab3b4fe2e7b3f8d3b94e7d730c5dd03ef658b311d20346e0f5372bdbdcf50366fcc0477a1135d586013a3d2842eb511ef5347747b53eb62231076508135b67544a9feaf719d2b9e2e0b249b378068bf61f74b6c884a108e61d8e07ad147a87f853d65201a2c63850748061b1ef62421d222c4e0293b66479032710de3ad1fb3a2e11a49540e1a6aa4ea299471dc13e614999c173c472c22ae0c94893b7cdd1678cd0a29696c707b2d7d3ae73c40cee4edf1921b08702b7106003e0c64ce8cbd960f09f5128b5ce62e3b534f8d8a9453942df0565aa5abccb91d5a96c829215a2b826575d27c47b78ab693e5694f0a1a270d03151a05ad018b9ddd7dc9da55515a35b43781bf91da97335d10b6138dae0a82414ea8f743daac762e86860194d2c5c3786847edc4d43af33f13add627f590d1353d1a2c1ec101c1eafaed9c7af5552d25a65009f28d08fca2ba103837bc320a95f69f4a1a06998467d334630165e0c2643ebefa6c4df12d333f48542816a9ac15fdf3eb6379808ce444a5a7bc69755a533341080e05ca91d98fdd31eca5c0e36b76630aa08045f51d77e160dae66372780d3750760e51aae3323f58bfedd190158deb458fa01c6b72e6456940c6a54acaf93f37b3871565dff2d1f1f62e5fccec1b04e8267da34a49c93acb13cbc63ac69f72e29a7f477cf2a24130c842c9febb3b65d5cf6bb36094a11a558bb927414e08108095bfc38a621c484d78d16d76b1106cc3ba865c1d10b3fdb35df729a4603bfd6c40aaf8c59f902f7ec4d8c07b21aab67513349bf671d318352b05d1cd449a09c78c72e35cd47338f1ad4e6f56e4418c523f09a171bcee26b6c85167e5d46f5e643b970308872ac3639df9de69e7810e57c733420731007b0527f27e514f7a3106e89e51bfdd8b725a59a4e359de40822f91f61f67eee372d75ab6d07949135dc29c5e3f7b9f242a3d1a97d29b7e4f009bc6b9529bc7037b6ac03a521a9ae4ed46a8b52f68f6dfe194f3ba92ba7b66faea43c762c2742c766ce44b9fc31c945c730dc03ceb02dd68fb1eb0d88db2e7d5ef6fe5941b5127713113d2a040feb5a2b32a8e0c6bce93bb9a1ea1faad901ddd2a2ac6d3f66ec930ef182ab712ad608e29b15b34c95e91b13e1e8ed19f5406b7a8fd87e7c3e6b6f48d8626951d9d8cc665cb806e2e39358191325d81bed88bcd84dd92e7fe26ad56861c7dcfa30db67c4985cf191bcbc016293252eb89407411d95c7dc7def42fb49a73198dc604c455dec21c0ef526030514bed1803e6e80afa091cfeb64e8be990d82f4524251a70a66ddf28ad1fef55b7e68ce01d3efcbca6e98798cc8ec49a6f0de06f11fd5c25d0a5ffd34af3d1f50df7ead54b97fde83a7c0e34627eb0877237214083eec694d49a3b625c00f498067d333630faef93ac2eb0a44d2e34070bda35a541890f1b2c8ee25fb856fca6997bdc8982539ab96f8b199581f3ba7352b9963930a1f1f6c37ad9582bf583fb6d2925b6a70ee5b7fa041ab6db75541fb8d863f0e06287804cb0120088de8d53af1d098ee84a96b291324af0b7733214c1a11839876bc625c703080a7de3bec592c297f1b3c988a2a63ed05ab2d2efc74508114e1143423f6ec146864e8f9d0e5afba68725e37c5b106ba7f7dd6245ff540ece8f5a8775af9373a1ce11411d956330f5fa5a4724169e1b66426bcea851e1d23018f4cbb0c908fa331d4b73d557749301f76f0d11076b17f71971c9449dbb5b6044046e5a749cb61d15350cae0b626e29c3e9ffc5d083045a87022daee95bfe538390f51d67c3c4a7150a0563605e58fdc798240fa7c280d6c400e6df0e93208bf79266c031deb71d87816691d76f1996d4b56dc5207cbddb361411abde05f125db8c2b56bc71038e286226b5e68c1a2b5c1a06a37e999b4cafbfc5003639d13cf72bebb876ce71ec92fccd36207610647a080e807ab730bc2036ea5204019341dfcf066995f0f4d0127bd11a19da4b0c810babc81784404ba9338fce1e9c9e5fca4d5bf5eb6e938b8bae8c938124a6b4246d29285eee02dbd5fee7b4fc1399a300c638a2174795d9f7ea8d987287b17020c68d599d13749b5321d0e618012d0dc6b1e1d56a03c345ccb48c384941b62288233e541fc70360b5c5bff33d3244eb747493b5a00867c098292ae5c1a86e0a55b4da41418ee43c41eca67cc1831af82dc858748c49148706b6de0899dc78dc6cfb4b88e3f588b356bb94a851508b0cabaaf8ed11e09c7cc193a15d46add879b945272e964cb17287c81d8068080c627dc16c91935790ce9391d5d78e16ea10adacfa4b8214fd23c2f4a0e91b8b5535b2ac83fa3ed6422e1a286d5b8cae20ae6745b27a7e5c9e3a46204dc863cd0a533d62ce2d6bd278308e844aebdc1a6215f90937ece0390827c886c68e0396a73d13ffab755337b393b9f60cee868bef37f650b796a6ab3167c42698ad0e5fc83e078e98fcf44081a64a425df752fec698c16f48da9f088828c2bfd6da7ce73301cff10b8b1d49ac79a9fca4fef59359af8327bf49fb188a199519ab842abebcf4699063eb428ba74771682735da1cbceaed76c6969fc8e8c7502d72fa8332fd903205b56c160b6a65a1dd1d120663d21512a627940a5bc75b492c65b1ac9c07900255fcd295f1321eeb40b3d8d2c337d79652bf8a9ac6eaaac7d1ca5c0c15d0900f87b8d317b854f94f228b6fdc1d1534cd1f5939bad4773dde95b1a41278687924224a6195d334909ef39e5e86a7d875740457074885e77b94e547e18ffefc9c71a3b1d9c08a1b8e74590c095b1ad9ca3a46b412079be044141085b86ec8030d8e7e317263d892d78e9d36e0f5a34c44bf30ad2895e426ba01c0b189ef0f933bdc2335f44e687cd47c3cfa3bec36e30dc44234796003a7619621ebcc6c07c318b75b5054558f80d123ac2c2a249b9daed5488db6337079e0fba030eff6ede67bd7db8174f57b6bd798ef38845f8e05601573e72499200515c251099477851bf33685afbac87d4718fb59f7e1d9fc88f8e8016b6afe846ee1bf39054fd27838a3a926e168b3879c6843012f4f678f97f14ac96b5a582ee9670f041975e39b96584a43710a4f3f44585e8a894fee9dcb116ed7af9690315742d7c85ac30454dbba90459646546b0935f5553eba66bc6ebbb49e1c924c524d1d378888aefec7024fc6ab170908e756099b861067ec3ade20fd2f8e7ecbc688028979b51f20312d51984d07b5014643d4db532c4ca850938466c144ac60e44ec6591a7f5d51220a29cba9e8966ac4fc7e23949516a78681b546a3adb91ce5e227539304c4016c992ca867d22dc22181c6a65df9019fd25f6b08751a0899c0de3f82d1a2172f71731476f716ae1dbd1b9b4c3cba18ce8698488fc2e8d640416b401ba6dd5c26dd75fba2dc767674d97848e24fe02464ab9b507caa37924741d369c00cbd4a1457e71c95da7a5b4f559871552242fbc8f895e84d5be0cc0aa2933e9e56b4047d2b4edb3f762ec10a0194632c6c1280fdc29cb1331cb663cabf871f647a055d4df32010f18a000b8aecab570592c2225a283ddd19ad1efd151b0ba8574bd711e2eaf436e04999f71068234ed344e3179a38e1b1af0c7633bab09169cd061691340304ee9e2880fb46f30e490c9896bec8a3ddee1938bcdd43eceb16d3bfeb87d86948deaba0fedd15de2f8c8ecebb2447214000e1e0040714b4b9b198642e6163cdb763dea2e31d02b74825b6c2770d1c433efa528a06d787c7f780f0510943a890de60f6124e82db8997c0f1349e3cb521db580cd13454dfb792eda4572bdea0829bedab107494198f410cb283393d50264f5947a5aecd79dbcc0f677994e71392815fc9071ace95b85473b14894583eddc0e492e19b47736793352652d6d8cc27fe49dba966d4a1baeeb93d11ab6e1f1e512b180768ec4259230bd857eff1da0dd983a495011fc4052a45a882a5f1029533def3354e144fb29a57a7159238d250ccf6e3d96c81641007013195a835f221724660ef80c80769eb6a73549a78032b67e5771f497c694c64b7ebe45ea19a155f54fdf1b3a6866982b3f2fd2c31e18428c2a6baef708d1bdc3107edad3b48195ba50f7697f351a71c15cd0eb3f0c5668a1fa2d464a4f9ff4e35f19cb69cd20f795945403085868dcc23651d1d600d08d1a403554059c9e179d3420e3b2c8a5351619d88de0ddeb345e833f4897d5ce352bf2c0d46a7bb203396448fe48e8830f976290605846a0fc43f60ef2857d7b325e9cd4357d97a11f6fe23a692b9e581bf1a1df6919bb556cb45101dbc0af03043a11a4fc4a545dd47702369a0e390b49b5a75865b9cbf342b24243bf61d26c211b30334edcb5fb9d0dac4a530bcf21a178f75e9ac8e6c45aa4ff78a095c1548211d9d0265ee1322000230c6918913884588edc05025c823b26cc5c0456a1ba89ab9cd7d0975b916949ec1f326e4d7b8a2aef59ccff6030a33b7f5fcb5653498ed18d30439fd07d9f7bf577c9f867ddf83865e709f42dd2d2814b4c41983a6ff3fabee0c375fe55bbb9b556fb62abb30e589a99756332e8075846afc00ba72a8ffe1e8321eed5589d7b8019e4facfeded3c24568a054b869ec6be0596e9639ac69c029584a39291f301e2a50e4840d0dcb2c5721bc0bfece89c318ca28c0129845c2261f7387f141364fb9520414012fd8822f5f865fc80db6bc623c6012abe49ecdb0bdba6f83bd463c54d03264035c9fb1474fd52688444947d536c3f5a697f3058116c33096fe5755ea6d6b2da7d9bcaf8ae59e954a989bcbfd433a846726df6aa1d2cfafc03d644dc37b6f6cd330ba532923c4e1d421c45bc7a6e2fa6a3e38ce87a8aaade1767c1869ecce9d669eae309598acaa146ec6c2b838fb994c2070797c6633d228589a7f5ae9a79eca5e96ffc46fb3a48f9e8ff875c85c81e23420f64328ae5f81e526b9ebc70b5c6bf2b843085616bfe52574cef2a92766d04fa87a1733d8f457130a654cb7d0a815c0a31af4d7f50fcbaa393d41aa48891f7deb4cfca9c0934fe487c13dab9ad65309dec604ef4c2a1511223903566826a7c4bb3019fbbbe712024fe68114c5c4dd1fa4683690ba9875554249c2232c615050fde4333e87a46bee1f585640f09e1a98f93c1fa081d13c7e472e302a4cd6284858f2267bece7c6241fd02cb762c3bd1916138901a8e1ab9f9f43aeeba70a98abcf3d970e02d545a72d75ba222f9523591d98d8876fcb07478849ec0f224b87bc400ec94a93e8c69e5d2a2ee1480addb19472d9ed064b91c0bc0935faccd47586ffc047a4a4328e1663f05755934c2f38795cc25618e43ca8bb8696b48d74e3d13732eb1d8f0e8d9c49014375cba1c2da94aaf0d8d9a7e073e567a524703d87a0f44f7145081879d4501e6c53820beb732f9a2e989f7033c4b67b0d141f7be4d5865cc8354fa4eb4c6faa0b52b0b77c062849be28ddc45113e74ba655bc50d95fdd53afb8e9288759a2ce77632f53f1cdaa0693d84e605b79b442cf482666b7d02aaa8620e5b19651f4a201e8cdb41c0274e9d4ab1991e7c704e8e406022114a80073444f9a1b5c60b51960b17a89f999db57b91652055c47eac7c3879ad8c08624b48ab52d6447f6036eb0bad12bcc641112b2183b74dea3aee4d151bd33ae578fa1c6a3b8216a76d4da1c46312362a29b884fe28f7c36ed9fefe8d396e4d0a6f9b6773191a278b67c8603244dbc4f4fb083a6940b56a9e341b4f830eb9554511f6f6cc9d9c8f8da1c9fcff85db0ea16a329ad329d2958b03808b0b76e92f367db0dd9590dd08e2420c4505264946a2e1ab0dd4031c1e8bc18c343085532927381a78ccec04a144e2ed74dafa8365a7d6d9dcc2a23fc23a42ae4b47372ded1521580784dfccbd61ac29b1ef59733fc4791f2c79d165308d58a9e7c639b1b462990f40184f6ce620e71235294d5f050ae248f43ba58beab5415845415d365f2a09fa78119d9c8a6a669c472d187a905962d6e7863121f3d17a63b9316e71708cdb2f847e2b49ace25bdf8fd7910cacfc6ab43fe85af63aa47d6949e10dd4b9cd04a62797a79b84d3fc86705f6c74765f0fb4772223e433adbdc3df68fdd5cc1683aa5049ce9362d8469787627db5cd43259609bed0bfaa386614578cf80e841c42d3a87484847c50bc1e3c08681fa2a9a37bd6b78e5b8c779550e48b77997ceb379911bc26494781e213d6a04ec451c7e5c5606f2c38ee595f61c447f5b713a5b4afe0c915ed71f394cade69e202e987568f86f54c293569749c95dc07f80be55c09689c1dbdbb61f59597b83dc46d43f72e42b1bda86a5041966b67329f64648bc9567947cf26e6004a13ad7025b76990ccc769162a6e1a4e007a145921c0bb5b91e9bb9063cefa60eee689f567d5f38d56cd29e0d82cfbf2eeecdee866c1eb53277c12204617cf985234ba5240f1450bb5b6c2819436166bbc1c2b870b95011babe15d1ff3796a38ff52f6f084f1352b3758194462379ef2ed0ca39546e5f1aabefe2a558300ec7cda776adc588b26915376a2234dabc37dd3b2da4852ccfc968cd173531094b19c0c2ad44d17fe3d5c99cb9fe7ca9115190a7a552a46e86f5d8a7c4f855cc2e59baa506276e733ae998932040993131a8b8420f7475d636c8885ca8fac1dccf72180cd44851ed63b4d73512210abbdf36086faab160a7f63bfcb29910f52d28a4e702679ae4ec44d786975f42f21ba5516402a23e890ee3a6e9a156b8590acf4ee7d2d43a4fc6ae2a1ee5e8ba41807af6e396cc9386a7464e37cd40598285a9abad57bf2a0093354ef95de095e125b5ffbc9904574867dbf2aa6b537352bdde4784b23f93515acd4c6b9a20e809e098df95f799d94a706a1d7744e2d9871402d6b72ceecf04393a8df578a1d64fac2d9488ff0ca281e4d2bdcf82fa14fd5cd371e84d8810185101e2acbf1949f2f2b68b0747786675e59d4fccbd2c1d8c5b234c71ded3d346370c73bce3892884b2b71e305be386f0a1e124ffe8d99f8cd5a2b0678c230a4f0f3e316e167fa20c2cc23bbc6f0542a889d5b6d9547e55e712cc6f188af4f81c140955608aca8203f9842ffac84b55813f183bbacfe1f71f14053b9ad0b9ea3c9df349af64e2b6599baf05962e0091938da776a831f16a9640d71ed17ef26806cf1254581650b9126b636c949a1744e13a24ca26ff303e59b235b1c235df1a4a4e69c1705839d32e30b4217e9892754b5f1ac90cefb86239fe4a84db63aec8710819234920eaeab89835166602f28f937a4aa7c17804d081478381cd81d188f4517b4981914e8d184267405f254e70a68f3ff79295121f8db614a9e77dfd28b16c172176f19242a465f021d39fda0d95e941b45f9227f33f142808271e5e1709a5923416d12c906f20ca4e3ad660e91a965ccaa9febc3cdf2cb0ed4d4aa898e176c9de1f9f45304c62d04be7729aef71bc4f12a986a8db3e271b8256628757124e0fce717e19b3a057802eea680436e1343ad05294215fcd249424cec0a923ceed9b815ef4fade225c6bbd06ea815876512da4a902ba283977ed7db771dca03a550b5a84ea5d4da8d4f5721f8da5f091995dc1a920ef3a396d1e7dc054d11d5a1a1281c38f9c88ee9c83f08a43aab37e0e20fb374e7c66cbea3bf4fe1384643adaa17678105526548e740db78a508f04a20abf215195ff94f42f52d3fafee855a5a4dafa8d7aa5a8a4b3a1d7a7aae7f822b600b13681387f3695cd5fbbae117ee91b65fc8fc23368eb909b4008fc104abec76b6a9b30497346b5d46b9fec5defb40fac10c61cfa0c1408f97aa03f0c627f49b040d2165d72465c3e93696b376f5d6c6e7f6d2ec6f886e156bb202a9c65915ae90739dfc9403d5887fdcb4c3d0a551ed8396322077598842f96b7710b3e233cd6e3377e59b8a9a703a899c69852277e4a644b18373acde63c8febe3ad1a942bc64dacf2680f428a15a868851dd50930d5ca51be6badea2a19273756a4350f122fc79d2eaec5e86ae55c71ba85d628cfcf1598709ce033c8f263b0f06b31e6d8adfa2ec05fe8087021f0a20bf5e489a1636d633484711722a4c5f5e8826c80392cac2d7e9f816e83d5cdd9dc3aa608993e26700f2ed2e59089a217fe185857b9e7788e3595faaa0d23f5a3519afe3810cab25449397c75ea3b675eccd49205266e65c604250e68bee353db9a61ee446248c20b9a4877df8429555fade7922e9e4ab9b6ca3bf14c44f865e614d27ae5d5c8f2c14cc0ea09e18348316eb15efeeb2802d865fad19005cd1bbfe92667a76a47bbeccdee9c4e2281f3e0eec2ee890c6a7769f5be5adf953af78de19cfdfdd96c4c6ce2fc3c1b83189385c10dc18204728e418f578f76995235d0449a0df543e637741949efe754bfca8c4f60260a0beed9b4241ff2c241ef2439997c058afb4efbea0c0b9c71ec399d12a167beb443be29e963c3f0b29a92bb20a01b8018ab62070d3daefc32d27e2b0cee9c1a6447fa60c849a4ae9932ec3e8ee183bd9e7c7db452e294428e318aee9b62be154eeeb1ef592d379c28c5d11ac47f9d4a3a06623ee3d154330eae94d8db51bfd6c4c5a747e4da6eb58d651b25302c0c25c0cc622cc37f2d95613a26c162c6911e24895a865a80c1ae69e41d9922d5a5d3c6b4eba04cc467c994fb248b1e01b126b306d1b1e12fe1b1a434d63416c7bced28aafcb8d08b9ee49875dc380381746798c13e9988f8c6be8177954ab71c5eb981794d129af369d08a5a956e2837e594a990510e8afaf1a582ea6771aacca963a4b764cdd0455afd60d347805ed41bf33a80f84996b1462a830267975f060bf51bca236884b27b48b86151d2ab5981db2b1648d4c399aee66d9f7a13a587928521daf6cb897c4a030494fc0d5343e287fcc22d8ebd0a414693f4edd48f86d22e255e890fa4c27e72426895362b4873c1cb83319f294248676bc91c6227c7d8b5d09f5ffd10255d773854da815d3f9e0a86f22bb7467609536d02739217f1be00dbb517d37a34929e9496f43ce72ac9d47500d5f3efa00e18f3270286832de79b1e2ef45ffd20ddd590f139e336626e4b284832652790527848c953a448131de4ce4f821e2ed861a3710bed093632dae491b09ad9a009b6b17d0ec3e5cf6bb7c1598fb806f50e2be494eea513c39984e026c8fe077085c347c73eb24efd151a3828b9f4d627f7f005200efe2d10409733a03a3590e9e07841d15e9c68f55489ba6d7d843e49c4f6b6bc937f1a6ab31b2bfa789349d46ef63dd047289ae63a388df8097b1bfe9cc93b3234190c4a4e5e8167ae9019fb602fcc440444c31c11c1d97cbb69ee224a694d6bacde90b2766a84ee88919b6b210c33ab8169c47a3e2ade7890a82b6716468d007fc274645e13bbad028ef16fa31d287435a995460b82734005e9cbed62896f5f9831db7d7fc40ab4ae373190ab60d301daa5670041cae64f73a30e66e3685bf57b44308fe2dd60518f88b5949ae5bd380ec364db9c6386b6be9a65d7008b793a5f0ac7cbb128f130a7383a617f2896f8041b13ee2ac8d71034f94231e5dfa820311a00efe33ed7a3e8456c6c5b29763b0d2d949aa1a4187e811628fbd36f64a50b087d1693f2e4d0f31c6b85a27868847aed522fc15d4b3d6ff1f82029d2aac78066d67025a6ab225da0fdc547a77810e0ae6f0eb3e67c71685242612cdbd4cbcaee91144a4201f1d1786487c89511b9f1950235ba392f0c81ab13e6bf51c9851466a4dc7bcd25884d5fd8850329b84e856634e4042bd6296754ac99259959ad0907fee597778b44eb3ffea596df3865dbb68dd8349ca59452588161c2a73f806b1317e8acc3d141b1db5c9c54aa634b3838eae0be69a184ad0e1f9f996e35bf6128e1e2f8eabdc6dece2fc584e0d8a53c527f608650fcb285d775621280439c5081bdbe5c0922012e86e139f99040a2b85466ddfb3f3c107425c82350f007c80f6e814f3d57993828065a4308ac153ea98a2d024de2f7cb895446fef3a3ea0983fbfbd037e907d53ea975a150a219bd39d271cd040c9b391de9b375921b37dd249a8dfbe85fe0ed25c19cd2ac4956ffc3f00a525628d605f9f17e42d4800623896752c207147ba505f9b68e151363ab4571b8d41a316ddffc8d58fc7dafe4c5c04444adec440ca1be3d773e84c584d28fd5a43f7f889aab35d26e609bc1faacb37006ab6d9c573a36bfa1a4a3b39ad05c0f6615ca069751b0f2121330a5611ba71d04241c56151abacc89089bdd6cfbd11d440405dffbede4efc835847e26239b7f768c01772774bc8806693a81d8ac84e397146f6b837c551b9029cc77516e4b817922f6887eccf349416019df3e56498e4189d8c637e6dfa9bf78b63e1cc21aef3d3af94d62a679046ed5a60df7f53f2bd576a874fa255316997060e92315d51c108d651a06cf6fd1e188624d6fad6b46d6c89e9270c2158054ef4a75e646999d2c9b4fbf845074f381daf5d3978927b2db9f08a409d88b92320133cd9a15bb711a03ea4678bdb9397871034892d9867cfdb59ca5ec54156c0b5f0454658a7f00ecf75b19b41432606cfc2576877be59906c1a2f58b86ddca9b40c52b7031620ee07325890774bc11aa3353c46b25c33ac7cf6923e4718c6b03abb1fda59279b64ff67d1479cd788c60dd9dad32f4ca29ed8a21623f4988f96262e911a05a89383cbacf39c135d30192eca1b7a61ecb39015cfbc93403fed87d87ff90e4d5a5660fe73d0429ad2a36c75a948f7b23c5f7d3300bc686d8cf01d4136f8efc47693fd7b3f01673689353ccea8118d8df55386a4b3f46f51e8e25df6553a97c37f3aa1c3209cf8615df7916fc713b5da6a16f9a1ab7997385c34406c80a8145b9e68cfef20e1c1b85ab9bba5bdc3c8b60efaeb363a542520ac35a769884f26bc1e37341eeb4bd10e05f610e69985824684ba2b4f1383eaba9f9d06f425ed56127dc6f9a377dd1b1a4996a72c4a6793faddc84102a2e9efb47ab35e21037c3d7f123b10001f65f35d01e93086be6cd006928a363dfeca6f8984ff2da448f1ed971b38ebeaf65582195c28584381ce0a0cdb089b42d7ef1a66f6c86bb93d2451487b543512f9872aa14d28823fcfec04d83218909baeaebdbe68c7fc0031ef5510c6af13ac26c9cd1a611a9964e0ca700e483fd34b1ff5d3ef724cf4cf2da1da90939314e12a074777ca5d5dea7d7f2ca95705bb46eb295268433c0e7b2cf1d67a9bbc41471502925e01ff9d6882db9af31b4f513b0caa56c9e384a97aef25491b110c2ef2893c73c698634a9c4eb7a6f629110201ff70c75a642a70eb5d6bb734ee2367fb5971a5c453680df312ca8c4c600fc6c87aa26a3b4a6c694b0205d4fa5490ab1416dd0dfed45b98f3864fe9d1ea8c109bfb64ac476dd6cf15dd6fab1207b2349c94cf876849fb8f1e10924dd629bcd594d7568ed86e00fcc57cfe203cd86c2c8acb7a2ea2cc538c80157866aa64d08fd60dcf435d04d3a5d5b421d7115721a517bd9b7ee8641ddbc16bb9f83d0853cf0ade687f3193b961eccf950903dc41561df7160bd2eff2b7fd5f62fef07d736a0a8258c671d10f3c1d22226babdc74df79161d13c37cd03f5489eed0d18ffd55aa6e90c363743d2475330e1571662d88baeb6c412640bb662942f864a0f3c9ce1bd004f2ca6ce309a92fe330fba591bf54ae189d7551a17a6c888c2a9d548c8fbba86de3e0bb35ff451c5e0d8b1a06f546e8817939dd16beae7acbf03cbf2c93680a911f731fffe7ba1be431278a2159b9d8357208d8c9d00849768dfdc337503ba297d925715c9c90646e9e2c2c357fbf41c418edf35e75e320c376d6ece636854dad5c13c6918eca1e09c72d6aea20dbd0a5703c0ea0c1bcf9f525e5ff42f74aa9c02b2b707741db6a15682da894e03e72c72bc11ae525b914fcce2a03718197ef758461fa89f54fa677a5561bcaf7c1613f47e22f4d9445fe3d4e02b09fe429fa61da68d10d4dfc0524991597620cb62fc01d7abf78c187b3b0ab0f65f7d54735e31907588b9702de88615e82885e4725ff5222a093456b77110e58655100b7a9dcd8cc35d0f719cefb34392d9e874683974c3825fe414d731c85c5b64633dbd43c0c2d1055dff43431ed75e1efa873f0bfc1472175c45edb36725d6901d93253e7cae05bf80b73e638d8acd4f296d3f6de458377522d7e774d2e8705f9e9caf5a861865012edee8d945cbacfadd24a08267f669d62b7bb5ea816a0482d9725c184f4811ed412afa002b853e3cab0b37c968df28cee391d6ae1b6355653fac0b37845a3bd089c0483ed9cf284b16aa3b51cb012cd21a10e701479030037de790d5e05f942a7992a76add67653478a9914c02b4421d8ac68492a819b930cc25120779639825bc707061fc7fa83ce726879f71cc80e4b7d394d87adc3b594accc298ccb3894c9cc6aa9a42bd9bc38a7b549b936f126f0923b37970c5c6965b10706f74459de19eea035a52e5d0d6c41db6fdedefe78dc3994aa390b2a790fa26513e4686257e2650be75a54b03c61b25a17c1fef834f8f25d94e76cf8a15cfe99791dba86b02730730a6ce58467ecd0810fab78841a3944a35cc1defb2a59cf0368d96c2c4a0ddc64cf74dc0804b6f11257fe4cbc47c3527a01dc82d6216af9222a1a903543692ef554b22be5709cc74dff32dd117c720d03bbc1f8109728959e4d9708c3423abdd0cf010a0805c11ddcd27d6ff3051161a6306da0c5ed660d0688a51a716e90f4a365f6a6945670165e2d998459ac1e0a628bdbd45d1867330246a2c423d42998d1c88dc64abf1732ffbfd807f3a7b48a105669ff8913b6356177f70dd761eac826a9365c4eb969eb5dc4c8ac6cb0d9b02911c02ba049399d45ef55c36da0e4c1f0e75456296ad27aa1eca053f033c0386a8d197d830656fe15267db3b6f5a56cb17d247b1b7f097794903bb601393ec047cb4db05cb12e37ca58bc18f010139d4d422dbe17c7ffe647f053f461982882099e61bb474d01dd4140830a53019e31393414892901b33382d8fe9cf5ebb0894d4b0d54fe14b5275e1ab6f62295e0aa81330351aa4f00d331c9084165b4f24d8e2240607333d10734381227f2419200d723b569218abc96d0edb5dc176f1c83f5c510b671c7823eda68291525741fbf5d216231273a29dbacb63a13ac78aa9c151019fd2bbc94066a1e19298e46a95d50a82ef365277c55b2f0757e10eb5fe7f39f1b88ecaab94dee666aaabfa954fcf11e6db1b02ba4fd900f81eafaf8388b4b54ffe54318c2794454e1d4cbcb97230fbdfde05a34c6cbe6c8658240eb272f523dbf92094141c0b6a12647dc2b203424cab59e47608304a6119a16777b6f8789045b032c4c61e5df4cf81b0cc22593c47f5facf27143491223cee5db0f18a09660e199d824ae1f524df54b5fcb777aec926606d68b4c6a7c20ba004337a201a2cf7c7e24c43d8b7c0c8961c348dab913f782a16854872066388cf45df4b700b0e6c8f620cc980761b349b66def0f332f39b4d128c2712f48b4dc246f7df4bf19b462f2c24bf91ce78ed1e22766899d2231c180e958702e680f40bf1242d0e6f38cf058c6f260cacdf0574219a2496f37b93ad165eb0d348bd9b27e0a11746292acdd2cd94351eb403fd819308ed0fbdc2c2c3589d0a2b824c31b138cf94591234d34a7dd285ffe62567cd437b59403506990e1a51119ca37ce63fdb6b490eca6b3acc47843887e09f496ad069a605b3849c19b1c2c51604c1cdbe14349030b476606d0d84561a09b0b6c57d43243c0f81a0b50bb6a3c3854defe0365e53ecea2ff44d16e29053facccfda0b9db61b255ca304b279ff325e8b1407c443eabb8dbc40b61ba168a80f4466cf5e2312039c6e1d68670289cb027db37f25a9128f2dbd890087235867bcfd65f5c0b45f09279217ce4100d04ecd5c944034340a11c27b42f7c316b775009dc445629b086447565ac89f546a7df403cdbd3e9c3acff1954f867ca39dc01a115a99f7c9a37066de5a9649a9bec9a20bfa081977facb8e70f45a06336bbbdddf7dce18ce0863b7d726e8304ec6c223739a2f875bcad98463d94dce7f6d8217f095eabc4e56a1326c69a72538f8fb84b127302725b87643485a2811727c8315ad4ce5cbf8aa9961697a11f4e6b8cbf1c7bb8d02d289d9e00d1072ee0a9d86147fe91f29ac65881e213bd763a73a12c52e0123a1b4524482148c3415857df4d68dd0c44486d0b676f5f057282339e2dd2fb5db998cda810b9953722304bc55a23dbb0ce5186a1f761ccdac95ec1bf1bc7979f350a2bf6d8b0569e947b55439eb9c08e683a125df633dcf7a13e4fc60fc1d7265928531214d33995f3f534ba3cdae407dc4fc62fc0c47d5bfcc00a7ac014c85277bacb55eae30a3b59640c29b5e62fc5c7d223b38106415f015cef2a05fdfe294563b1412a3df7261bc1a915538113da584da571e1bf0d25500d9e541fa27c6c01d81374eb78b476a4d61ed850db12ed4ed0f7b052fac911f12cc9b3ef5767c2790f589d3e69a1cc49fb4710283d2f8b3e3b5f5781a8db0b5e77e8848bf5bbf0bff77d96473158a41023726ac12ac29a288608039dd8d4f2a3904dbbbc83eb0be779d988dd3a26a8cba4d26d3dd26445d379d7058b8e01612e8d45dab0abf6b2b606032f3ceabb049ca0044742509ba8a5eee2160e79fbe3848dc562302d4e855741ed715b1c478bbf7e1a7c4218909585db324856ac1d9b46d8a3b7bd0364d3c92cd0b47501e37d61362f9817961520e491dbf14f10cb7175b0d4106c5b5d4a76fb5def20b4edf63cbbb83718b02077a140eede0ece7af8d25e836aa22a3ffabc5d93126882d251e599d82dc944b6a74a6548ae71c9146d8d35e96c2a0f712a4fec878ed25ba75b9d686e40478ffc8f4d849e90201c88748bd0a2af040d3f989033f9628fe51db025b76f9c705cc12630557e92383df030ba6df27a3fb8dfb02bdeecb0f7fde9cd9db9e8bd4533c88653d96af97046f04700f2826c8280437bc628f8ba38febb117340ecc0e849940a98fa17ff433fbf8d9eac681ea7bf0bb5d93f562edf4af2a32f8bb9b4f71ccbe4a98c3aa6b6b9408d2eb8132b9403fb8e257c75921ea7209e1c0c3050ada755459a4a37a5febfa8905bf2ff909819e604d5a4d4fdc07dc78aaccc6de8f183f55710b113196a40a69a3a50860b81d32271cc2bd593556531e57981737277617b0a13a2546eb5cfe2ff81bb82210084d74f2cf9a6b278d525eff999128283b168ca2ac4d48bf207e1f51e59bf74e71c3a85a5abbbb9ddc2606771c57e1b8da1096ba38b59d455ea6face08f70bfedb9bc8f6bfabdd0548fb2325cb5245c228773372505708ffab3102742168ab39839a33717a6a45b8abedbbc8212956e8e265104df45f1ac6f1f9936b6e6b9e76677e9dddce692ec841bb6cbd30b380e5f81bb267a99d501ea6c984b0d589dc4cb8acebf9ba6fe13462292b66825dedf0bc3e87da7a182780986bfdacd330bd9b20f6ca27355e0f4fd1d92bb024f58102dc966a2678c434d694ea087d35d9048ee7c6f08a0277a503e70153a4173b6612b9f3a453412569ba6ead284c0b41195c2cb83a082b836ce4cc85ada1d870c703da09e743aba41716860eee64c997218095a8d2b830723828d1ffed69dff08a09f8a90a1a5fe009ff79d9b8848d20c13dd56d8bfd44df2b6913c3f2d1ccc84c5f135d3501fefc5f1e6f62cd18253e5efdca8243b12864df5945b77a4ff27d41d8dc3d6e84aef205a93aa14d23784c285ad2d262f98629c8545754693cd9a9769e79c28dc5ebef13ad0fdfbc33783acfa76430abf40ec3aabb1d453f2fbafa90f56efb050b53bf7a2286fbac4ba526e5969a121d2f572f721f07824131a18b8fb0a2868ed6367f5b140783706f35453e014225d8e0d28f511ee1ae8a907f3d4c7145b2cf26f97e38af39ce71be9879db67b374849a1e7812aa8a52d2f0963dc44808741e759849d9a68b5a25f0fb2b466f74451f15359de8b61ea623b2577ccf91196cfd2d1d9252e1ab79a95ded3ba13ab3db60f57b4439dea410bacf5ba35972335b7385fcdd6ec557a2d567ee07b7b2db31a2f4d660a132d6294c9a057deb65c1cf1028cc0f6bf5908f90159f54c6d7b914140b48ca895893319fa14bd174b01ea2d41092407d46edaa5e2e45ae342f0c0ae8eab592ad89871244afabe53ae2752b1dfdfac57ed3d16c2cfbb9691332e4c9c2435686a06d6c80b875c4559037e1c69cce6867c10c767e827648306e9b5d6eaf56c576594319ac3944fd18cfb29ae9887b2763b648f99f6a662731eb36ea43221e6a603620baf58c2a273b30afd084d85ff1b043fd65a69ab24d7ef3483b9e458ab3c25374c95a15465ab01ac7da12d6b8126b574629827708f01208c8bfa2e24520462240c22302f31d30d49d4e7f3884686068baa5167633904696e421d56724052fdfe70eb3a70319f2134b30909647605bc92718480e932e27f3ead0e07f6d8f3b0635073559ce69085d240d8936559b547403a12cc4b1e3ff1f2cebf5dc5806b08334e2f36f0858308110f210307d208dc8d4d95b6d9f24c26435c1f86a4c91c51283714db627f28c24d58f31a9172014652c23f567b89c3e149cf2e33d7f886329a595e386d84f5f2327e1f052ae213f92764d280cce4b525a7ca6c789ab04cd878d0e2d1138ce6bab76c0696d89b3519695da23c868e8c5c6126bca8afc215f39dd9708891d9d520e0854451173057cae02faccad5b5d5098d9a40d0da5d0b14827b57edeed9eda9a20a83b1be1a1a0664680c01b22ba61f8641b9972e5b652f1d7cad11f4cab288f131122fc2d9f00b9f1fa35f43b40ccb1a13f57f41dbe35e8269ad5fe6e6bbbcdfe2684882412d9bdb97207ec057205a00599c3d729467cc2277cc2a7683bbf37db6eda4e7eb64b390cd9e19c88783b29cf61c4d494928dc99337d1dba9a6af896a425513141585833aa188a0a0484d299d4a31ae977742a5587271a932d0c64a2028551c64253578e1391d6183d00f214ce42739896ce4888e91248c7849c06420c15de193e0a63a9484ec0e4934c624f0eb624a7a26ce513135407b9eb879925166dc0754a8747ac6d1d0025bd59d1907825fc95a86d18c0bc156334e04da665c0e0068ec22be8e18e70e14f9b3beed38e6d3a72125e4faa124e4f938c258cd70eb5b1163248c8b6688fb94b657114ccc0a162a640b5f58a655f787edafc2e62815b6f92cb64f9e62c566b1cd5fb181567262f68a6d7ecce6c2d203cc667962fbcf7f61794294fd25da420fd332c4deda8b70f742bf7bb3981a9fcb0ebdb8803e14b4f21cdd617d70c6599e8b5609ce84a0c81cee5a2cee5a585636ce5a62fbe74dcba2e0e412e7a1e226a41feeb40fcab8b8c3dd6745c439a025f8f3e4a80e959a9bcb760a2bd435a0e944d8f1e5b662ffae97dc60b6dc443bb45f360c7d2cb52c552d52252823a6c6a6d847fd986481b970f9477fc73ec1192f7d24d0d64aa12364eef3f9a00cecfd31b65118ca029382e9e08c83ba1d257330a06e7b8b2eb5fd3f2528833e685f1bdc58b36052302de040dcdce7dbfe96b34adc1c02444b2d52a6151e63502e61dc453e4329a7ae5d36d4f004da709e3e0c25868f21841002f122c60c161c0001273c50e6e993af3b638c52d660be883183050738e1417d7237270626a516b8c00ef462bcb85a4e864c6c4065736f010c50e002a7fb22c60c165c10c0009f6344056efae4eb563e087d6c20bd15a18fd5839090d48a10e6595144ec56683cc850c7880a886c8c65f0e5026e23232ad82e64a08c1f41193a468a50001a39523d4cb1f480434f886ad0a16ef821546c6eb4637486f0e81441059431c6b86520d283109223031c1f421f126407a86780e5e3d01a6e1d31aef032858776b84888971e9d213bf888624e9ac3901c7486f0f0863c81480e38cc3943a11a88f040e4053d1029824811224d88f0108942c40944a660848d113c181103238e18f1c4882018e10423aa14d1a1880f292832040f458e28028422521829192181111b5113548818009d279850418504456062841c7c9e90302c74510e53cab816f1203bac353a84b54208bf0d219c3f44fac204228c6c2e0781088f128164bb6ca853048badb6cb1ae0c89ff31d904696e4c83f9ea8e0f4b8b47119fff4dc586cda033551144a5ea05d9ff64051144551d4463aa4a1268a9235401aebc3dac891bf35b98cffbd39dbb8c4369286ee80d407a4f11d70647269dd9a386be2acdd68b604bb4161a60be50303b26d240dc6031cf5bc9450946c5993e53af398905756344dd334cd344f97a21cc64a1429e30fe546c95242fe54469ba3a8ed9af5b6bf5c09f59039cdb47d8821320fcab0ef8fb339b7d99cc5c31545622628c3e7731890ed54be2724454ace921f2dd58d87f31da19d1cbfaa2063f48cc59473083d093d093d093d093d093d093d093d093d093d093d994ad03099a8e785940829914a795e48897b578043498492c85afcc9134935578ea45401968fe55683b50cb324cffafe827f3e2b56e4fcd913ce296383362b46ba4238c8dc079b11ab89329bf056197dacc6759412e2b94ae071c3af10c4fd20aae7c0089b9bb531bac590a3b4af8d6d3ca01744f538da20e6d5f9a3009bbbc255551b7b84ee19bc3a06979e5226fe0ce93aa6c6efea7f575026be75593898aadad876ab2d0697867e7745ad0a61d41e438eaacd37ae70056f957139f6ad1bdb62b84cf48d31bc64c6e5d815d67f11c3e1cdf0feca04a5a21b78b42221990bd92dff881442926c213a211f423e213f1072042908e9d121a2b404227420020544cc8008179c80ea201341080ca8c842d80d75840c0102fb69c797b5cea96d30948ee2d9fe93674f892383c8ce5a6badb5d65ac793d66aed35b75bebc548556559d7b46e48d7c4fc336d6a9acba85d99a65dd33fe79dedbfa2e1bc829158664bcb353f2c38db1f7f827c846c7fd0694f1964fbe397d035b11a19442445a2e95134a5a747f2e8b90290060070243f3f84343ffab6f4cfc6816eb6fc968d6bb1ebb36c5c68d75fd9403d7c6b9ad39ce034cefab414a8dbf2ad8da3e1db30d0d3b6dec1b72f1f0050daaff4889aa08c7d177ab3edbba6365306d9dffd210cf4b43dc99224a0d34762249eda4019f331cb57b6a4381b3eed20fd01692cda032220bee6c00c99fad8f03593c3c83445b98cd44cf4319ed785b7c3f8e10ad5fdeb821b6ab731f9cd8e05e0bc07e56105156374bbb1d814cac8bfd732cdff3d79d832f334d34a140943f2aca0a8441965d44c26209aaee4d560f4e0cc7c11931cab6c07caf09f5912f326663b70667ec8085972d68dd60d21be7821dde768246f54d79d24aded5635abca6ff89450de6cbe94f7c219f89f2d3241e6aeb8756c88d19035a8d6f2a59e70a62586c4c90d49f4e7cb1a744e8cb452fda558cc0bd5dfbf712d7d2946ca3aea08672a46d26e2531162c8cc91bb66636aa1b958ee1312a6c424c7ec41a00f7acf08b1712b351fd9540a5a15b38e79c1323cd7761ca40b2f67c9215ab48b95d388369a41a514f5d59b65a175a197df954db0e54d91fa68fe906e7cd50d31e3d30cd381d8fd59836e00a3c6cc0fe7a1bb09817b0bffe06a66f60d3864faa7b3e49d6bab1186215527c18a5dcd7ddf79d73dea794d27dbfd65aabc54875d3cd5a6badb5fbfe3ccd130a954a69110e15d6c2fd19b2566dff6aacc57d6b549a96b40c352cb6fd1a169b6a16556efeb4a6ee1862953da90d9cd9980a953a6e29298bed0087414bb4f4392dbdfb73d4f58dd5c92a512f593be0bbe18434d74240e4400cb10a8cf329b6b9aade6e31e428d96a3daeb5da2c060b0b102be7815980db9f04b76b9825ae47a38891626edcb76f43c79618c9ee499a8fd558560cfdfa31fe9a646d92b565ac62d61ba3cf28403042c5480f901f47803812c4b22c8c8f1c39c25335018b4a486c8e547124e76643140645311a895224c628251227488e902e040c934827fbda5027c969c7cf31465194f2134ac293240a8410421821fcc4239bbbb89b8409548a4973c02129e824e1b1b9a993a48424b52592258460950a10a1891f80d081411150ac40856cea3bf8f01cca9f9c29a51487d46dd950e748129014c15da0424d7017c2944170116a828b920d0f20a6920d0f5a8a4484d01cead113254285d093c4d87403244867ba0162dac9a95e4d514a2bad1b74c804b47ed86e82322e7ce9c99c180594511f7a0f2dd8f063e74f2cb1e13b00cac02fab4951d5d2d4a550d02872446b4c37406a90da5553bda940aa094e5c531d4e1021a70e2748775dd7755dd7757d57f56e4ee5d9f2abfad59d9a2347b27ad6f2b0a59aaa536a4f4d5d2caf0e278890538713a4bb30c61863ca59fc71637a3b2b88902d1f9f3a9c2072545dd7755dd7755d18da2f6270ce8927d6d7b2ec77d9285b3e6651996dc2f2c891eda4907bea70827417e65182535f7c53188f2d3f2b6977caedb9291268578fa1ac78aacaab76aa1c3992159c4f447bb9e06a3f406e10ab9323cb0439ebc602627d2c53b45016ca4259280b65a12c94c932d1cacbd93259a6699962756fcea1d0bfe59b48e6846a2a958ab4f22acf61dcee565ee5551e8ea69b5497c2499d524452dff77d5fdc62cbe51bcc26b2b7ab3775530ec3de9c43a1ff4aaf4bb1e536faed6e17635211b4affdacb5a6bddded1cc6f57df96a2e87e6ede2edac6abbcec65b694db94c76cde590d55c2856de8d31fab4dff77d5fcaaed8d06e718310b42debfbac3dd9cf7ef3fbbe2fa6dcfab4aacf7a55dede965ad767bd29ea954e7cadbfed6c674261d0854f9009d40f5b5aa629b6f4523d6c79bb27b6fc86f0982be20de22d6e7d3112687b8679acd6f55ddff565d7875ddf757d9a93ddf56df9f4de7b31bfaeb634cb34adbc1976596d55b5deabfeadda6237b525add7d51cecb6fc88bdea8b2bd6f4b2df9695be58109414ab60583f66fd02aed7de2d8d3db6790b2b3f3f6f1c0d1f03b0771da3bdbff5738bd11eff8cd1748df5f8f15b9f1f5b333c6f1cfeca425cd196c671bda671b83c0c74e3a6d6d3a585f82e1a82f40cbe59fea3678b9ec177e642dcb81cdbf14fe99605b6f615ab3119c0618f9f9bc177a63911ec1abeb1c6f4fc19dc92db67f0edee84ecee79db05abfae93038e79afc11abc1f4e74dd35ed3dacff0bcf2da361fdbae1972253f86619f315d31206eac71546fd5a8b415ab8d3dbe75c4695befd79c5cdeb09f3f3d907dc51a87b710dfb29e866faffc8ade346ce29f1bf679d3b44d6e6ce3326d2dce7a1974ecf978e3227edf381a3ed10dd99fa3a7ed58c5c1404fd8c6e5a8c19acbb1ad877fbdf53364a5818deb40e75356318229ece81e883b5631822a7604edf8de8600d0018a9a0fa258a2c4922596fc60890b4224c89a0c78902b91243c8ef08ae04db1e486253a2c31c192147825f052e0e178427843bc233c1c783c9e135e10944871832b81828ddc81b7c3bba106afc7e6f2f7408957832b41422a71628a4aa0dc10c5542245c9134bb07b15124a9c28816243cc7bce871042b8c130f22dd3b860b4d6332ec7a603d82dee14a45065cf303fee2c6540b57a9d19fd8ad50c60abb0eb06eb5fac6600bb05cc1eede9779b52467af55afdc66c1fa2909b90f3863a4a4e4a6c94f088314aa9a4537203e10c10aa29439173c849a4a8a126a1a29b744eda52830e983041921e382c810817a4a072f99b4481ea909b1c61a154e103c98d4d14337fb40d7590d06073f99d096d2243c9144977e3845c45f672fdf13284ec449e4778e6bf8b2341d0e2d4e4bd733e494e7f69c2f3b106e7c45a8c52926a447df5ddf26510292729a6c69c9e034faccd49636e540ae311d54eea964b1e5aadc3f837ba9d9756d5c213639711d3aa5a16dfcbe27b55989555989565ac5d195bc958ae95f82c41608cb2674acf949e54ce4e0ecf97b393e34520f1264a8751282047069071d2e8fa058cd2a54f4a27adf55ef656d8c2d785d5c49d65179669352b2b2e18a9e52584914097c885e55ac16ae0d68291e2ce2d584ddca089a10bc8c5c56574a1217f6e5e4aa3671c8eed5a7edb84d0f19c4eddb19a976d311ad7aaacb5d6b2765a6badadae9d5756cac1e02e4c37d1f8c02505b78423e999dadf412b28d01d1ff48dc5b6761c4636c565e46b365bfe0e97a5b2544b0ba0b0e5dd59ca65644b97daf25d72a48b2745ba44912e50a40bcf963c3b3ee7e2844a4ad2d01e4933a7481aafd4ce5d6d96132923ad9d1d39b29cd02f4bed6cf95a49d2a47aa664543e2803ee975d5d52483074c1b96c398bd81cfc81a396c8b8b1d896c961645ee699b2ec3e9779b53e9779358a2d3ff358522d5e06c4c52469bcc56bf15abc16afc56bf1b6fc96969c961d49537d23b96cd72e5e0f3cdf69880fa37bb5efd5216a27ba294b6253ad933b4c12be51fd7d1b118b1143665acc0bf6eb5badafcb64299fe43a468a91564427a84032375b7ac89f8b69510dd975156505af9539497660ee00634d6a8e9e36ada99bc8e6a84d957d43ae2fe1aec13e6252629bbb6373ce893da6d7b5514a29c56aadb5564ca443b6de5626d4f5dc94b25dea8b1d57eda5453ae4fa12635f3d09bbfeee0b7fa5636aec4ac7ae717df5a4eb04e18c8e7de998ebb18fa95ec7c6b40c97ae61b1b18670a6d2352c66ace6e869c22baf581d21f221c777910f221fdcbbae9a4c221f443e887c902e754d4d0d8b2db5150243171cc8c60803464d4d0ee3e523ed0169fec78e4fbb1863c4347cdbfa93cb484f8e2445a2da19d11384a35a773818e8694b91e7bfb86c385ed49334ff14891e70245fb301ea0165e46b4e4099fada6b180d07f0b0c1e56d00991ed3287d4210e8e1cb16e31f7a1d2bb86c31ae635e70f997bfe1f22fefffa2431084eb1b2f1fd22110fdcb8720f42eaf6305d10632b98cfcd016311aa21f993e48c710ab806c5ae2b3acc40d9b2f5f43398c9797d0af87013409954a131d76931234414193aec90f4d806832c4bf8b2645a0c41863b48132a65b512c29568f4505f3c03f806c292d94936bdaf21d6ff13af499c14e08ec3e6d585a5f97919f4fced43dd2c71a69eaa9835a5fbd453f6a9825fe533b7d2722a9562755ea4e5f3e89be7c1db5ce27b9ae70c0b4feb516636badb59aabf5afe8cbdcdd2e4f728cf638b2c7af69982539d318ca51f638dbb4e8526aeeaefd9c736a4f29a554abb5d65ab5c7f6ca36510ff2f5d5273bdaa552de34a1ecdb4c8b7a90ef5becb1855f7bfc242dfbbb33cdc9b0b1c75a866dbd8e5d237bfca44c4338c3d5137e88653a267bed63f0ebd89a9621d335a08dd5d2b68f750d68cbef347f86572e04df86c14df8041ae6f0e2846192dd66cf09abff78ce6f248c6a7299d9c9d194302a21a0cc347592a6e2d417409a4a03389af331ed60d000ceaf38f3135071e6e3481ab711a2e2ec49df07d49cdbe8f9be03bccf69527e148a94990f054a942852a4f4f4ec39e7744d9b1039c95cc5b1d9128b9870538cffb9080799bb187da73129a59e474da65a6bf53c6badb5976f34eebdf7fa265a027257b404e4ee4ea53c2f9aa2898328eec55e22c31a773ac94b36980c3520d984a499ff4189dcbdf7deebb2a7969f45054b1b587e3eb1eefa317e3e3eabc3193873777d1b625ec06ffd0d6c55fa56a2267e40c23e49d7ae8fb59c433fb8335e68ada63b7077777777778f718f0fa3bbbbb5d65a1cf5e55b29dde79c94525a6badd55a6badfd3ed9c92e95f23c1d5c5e030291ac757bf1806b88262447f25d80325226060b2dc0510cca824b16a40b108600a08c843b356a9b7b5b2b4435493901b6fcfb73036d181826786234aac6e19aa331df692a0a2748d13305154f9802852848814a1553a0554a3b4650030f1b6ec0c1a6470e3e7e9000ce481a51571de08c7c1ab1ee0067e4539a82344573a48c7c27972714458a24404af6c8d1144dbd1e722aa6804027a57302478098c2880d4a180204cdf9e13bf8a033da90ba4d7474769882a10bee96b67c0c034f3a6042761677c21ce85b96239b1e73ce39994cd94bc030c9b4148222e3eb253c4d0cd38ad918b98cbc2c6623cb2846c23ec326f6246b67315c663eaed6de4a6196e40f762366436a8fbd86fd0c59357de10cbdecb55785cdb75f61a47b5916267de408fe8591a2b4e62547f3317d61a4f9148ee0438c845918694e38832b0c9b36e65b2fe40b5ed7755d51de0cfb0b67e663168c9695699f358433f3351d37a6b90eec4c637f3776e95012320e2c5fc0a731c42a9a96accf0222b55d87c9910d757254a09303c4eeb6f5694b58eb087907a893ffc958da4dfbe08c530aea224c951da5865bbb73d3ac2899cbd6e7833266aef2b594c78e537374c786b2b4b9fa312d581cf76d0b777376db875b8352750a184ae80e9940c104b535242413279838d9215adaf8e5856a041b3f3f374720c618638c31c618638c31c618638c31c618638c31c618638cef51661c8e2db50e190b60840e12504443444344434443444344434443444344435c702fa52d6908899c013f6d1cf1ab1199a31ec8dbf5af49d2b86cf99956e5caaa705555d96353e4b8339c354b573a6ee7280ec491a33c5c0ce4ed197286bc97ae6eb6bc296fb1e3732db2ee86be6ec111f5c85ccbd76df92ddf35c991f4d36e91c14ba99242f3aae99cb5cf9e90e3d6b42d6ec973af2a7e9579ceec24467ad911cabe2fbb1d453bc89cd569385046a48fd1bfe8638b7e15758b90a5394d06558e166d9039e9b613a98c741075909002830b17212ae67411ea61014e1224f044c1c41072a04a1e90001a2801a409131d9e20024e21270c72f003063840184191b863dbb01e63a7301c0ddf76cd4d8cc3d2e67cd77a831bdbdedae23bc5f00019ea2051dafe2c29dc42dcbf813d836f1cd9831e3280e55ddeafffbc6bae45dfc761618fad8d0e21bef5a86dbdcb11dff667a991df3507837f9a9fa8f42ed426b57468660000822001a31500002818100a8442912007234551cb07148009738840625a389709845992e4308c7206194308308400180230325252040263446b7bc2ed81ef52aab368456ac8a3a46a91b9f3b8a1385244ea4fa2601c7a3c8624a4e0e627a250404c392500f6e6c015463cb3afc64ff2f36d6488e3d984e692793c348e8e89bf60c78babfe9b95d62dae8104f93ca418e11a8a2af859f6f0581417ef5bd863b20c2d70c3bdf61389965f0dd6fb93f4f6e43756e5db4e130bbd7ad36ba8ddabb4597ed0d5bc28289fbed7ada8c78ce78f6e119f9b77a35398dd8e120f219d6bf62350855914a43674d8d6432f40864b3c4555b27eeda820661ee531a413727d7abca02a86788b09d42794b188540c56a860fcbf1fd7185b61c05e489642edd686b300c43e1e54980b80a8a381260b5897fef0d419ca5ef8e03d0c73af6f62acf6fe6344107c143ceaab163c9c5ee92bf9a7686b13847f963802f93afadf72118152fd246016e00d48202911e74d94869bdd873db2a860fd45333d1741d5110d1ea8b21fce54b708a23202c1bccbcf22ba14ef5f33f3994393dc8a1b7e4a6a5feb3197ebc0ca4286f2d9ca8773cc22dd7fa2f48b539983f62ac550fb0e6c29d92b52cd61a8eeb9eba3f1f23a18e1673a88f91e81412a605fa2bac6b8ad0443c50d244d002499a66faebc051cbb2581cb44a361a5de1e65a50bce17114f44b9022d435a07fb1d1d6bcbb418864277b936379948b43ba01b5460c09a9db53346db0d20e7362e07349b1a9020c92d44a0784d22323afeb12ae3d65a3c71b1e592d136a0aa00b67b59846f43c4a38c8ed4a6ca74bf9d5b40f4ec9fdb65b425c5ec88878bc8e2823afcbc2b229119fd7667b293c88a88d4ad5b2773a3f3e8b1ba3f3d0dd1c8ddcf0848091537edb97b2341726181d86f03b385c9fe894448a669e1225e335cb8a9216e7788fd132ba99ca781efd0daa103aec97bbb3b552a00dd8cac8f0330a205c108e36a348d45c9bd1483c2d80f2f951b8df3a3fd1b384c760a41982b8c9df92647ba6b1fc5c0a3070c924605f8ec607fa8d9a216170136250ad9c8695b2ab394c3db70d755108b9636d0a4dda76eb00f5736998db816d7b603b453be23d48a157a0d8549af2364c14c8a59427d5ee952c04d97fcf7f131d28fdef04e0531c28e9dd50b09d5653078f42299fa2095d37c18d4ad43395821db515a240a3dcbd8c162eb019fde0caedd659ed2e71b84738dd6faaeb9521b60dd9b1c0ac4123e26a25ce848a9b4f8ba8b55f52d203835d2f072a75c905a7f11173572bbd25ecd37f96f82b798eefa886685c895b7d0820d86df6c69652dd2d5e0774fef4b2e7296332fd724df2ee9265a7aee10ec657645329e3d8eb6a95efe6e2af749763dfb20d48c45d6a73b64db73b2fcf782458608ef0c87700113c0aae2f6bb4688e373aad4f3a319ec18b5bd457dbc17d48aca48cd77161a37b7fe6567d7f28eb32573bbd91e7461447ec144bb5e23ce3c79811aa768c6f8d059950226c9ba001c1299551ac57ce158122ebb15f68b3a374466c808e9a8dbb36783cab710d9ab8698a6479925733248ba42c3e00cfbcc655c04c834010e3142ab49c60e1595c9ecbf33fff23098d92355c6c223ec990d09069956b6291e8e45f4178033846d5c2f96913525d205d26fa02e4ec012100f977c12d9cac163a3cb040d92a41c286f2a53cc63e93320cfb52b1cfd3aecb57c7dbe77a0ea85f05e9f583fe4103d7c0b93124a9ff1e4bd1f9d6760ae43404ab5f96bd600550a29968beb60e94d85198d6b683bae01ee710ddb9b4e523885a47d9da24b5a9c2f26e92e3e4032350abd81c63e9bca6dafa5c3a85928a3fc9e9010efb982d5b48d974aa76b2069be5c73370c21efbb3274d5a9301025fe3fbbdb2d71fa78e5b64c88ae2b1666b68fda1fb7ee135e77d854a86d2df35b7713d9788ed1d26e39419f192cc4bf3cff244265cdd5d838775153f420a6b0cb535f6fcce2190adc6dba360750d6c4b8d95c98b4fba3a9b2caef3f0d96601f5b69617f983365b767ed31bd3447ee0186f0aa3845fa0092af58db654d3a6899f58ada6b406fcd39353a18e02a37311be01a6a2bc2911ea457c17e4575e75b93fb096f47663040293734473c1c6ce1008577c20510ee6267c77735b6cb1440e1aa2a2fa520c70c5c0f3e0eccb40a5ea3c41978ee82a4deedbfb329f8d34627e794726430585c5bed91b552d4412edec053a4bbafa793f751fc1b09158ef9817fc708a5ace43b130446bc601e00ed163c5d78102a5ce0cf2f8164f0ae092f87a8388134bb16dbe01a4f9540ce87ab0296ef22f41294786650efc4154c50004e3ddf1bbc6646f2de1c9c8a7be4ade083131ffb724251572757f29b1528bf6313e120393d84a7d3858309c68bf2d8b3f096614bb41ffbc0b3376d59840bc35f6ca2f1772cced1418b7bf1d73c3d0fca885a2dec26a7e6eeab0ddf13f4545a801c62317549b3399a4407cdf086eb7e0d826b7d5c0292bbb1d4db464ea36f1781e2c3bedda778cef8306031d47f35feb60cfad20d3e09c65d62058819cde0dfd7853caa70caefe94bbaf8a759888c246844b73b1ea5cd60e90f4913e5c35da6a513cdedc2fe4ccbbb5ae9105e92919e681b4d5bed3ade015dac5617877691a51ed74148a9dfc30fc64b6f15ec8370bbe8870fa53c091ba3e2a4dab6493e95a83b5bc7a02352287456e2e5436a7a892e5b494a801486490460bb9b66807bda244cb5c2a72a3e518e1b3278e8b0c3830e1d387cd0e121071677f0c0a1c30e0e3a74e8f00107879ca1a99df3b7e8c48f00eacfb25a5bd57c4919d284234869726a5ee810b86610e6ed0bd5b95d2a28c763c12394ecb27a69975dd313e870bb642da8dfe20b0f4dbb2cad4927e425f3e5d847873daceaeb610092c91dd9d0a28a16e988b3ce9b2a070070559a5d88ecbf08a28bd22369c076e3d8fbbc681cc3dd57347a726acd9000284422479439a6f9b2a886f0eb50c9e54e56079220fbe367f3b854a813691bef89bc5070cfa7fd7dd1dc50f96dd93ca852cab28e3f7012fd23d00585ad474385d16d0d69e64f78e8625ccf51ede420223b6fa1e305b898af458c19c8a404af27a2dcfa6ef35aa4652b1117386f4730a071a1faec4acd3dd36e4a3f038bf2b4f1b956637311043eaa172f8d19501b5073a5cc416dc4dfe7e6a89b7dfe28871173eaab28ea46a66dcd047562dcf8926b83fe09f8c453eefcebea889bc9a4f073d1d263ea903a66049ba6ab904aca391a055ce97ac1a018734d3b1c80c632eafac0f19717e0c25d39baee2946a241ff63b917a2157acd50dd12731240b4d020f37180d86f14fc3b9cef71dea78a564eea08d57ceb4d0a035bed1afc0da3c51e7f1ecc0534a40f9f4ba2eee1696ff9672c182678168713d19a44fc60aca829ea03c61174ab95e0aa3b8b9a84e9dfdc9c24650a82c1efae6594fdc82c3dd83d263636da6616c6cd4b4d078078b0443d652ec4c250c75a952da92182ff809cbd9fb2b0ea16e6d3cfc5423be84de0f635f1b85e9ab8b5954bfba18ff9f8f8908cfa8aa0420b612ac52d771fedc47ac0dfc69ddf55a41f8fdfb0ccbe69b90ac9e9ebd5562fe4e285fe63d6b6be0a5cf37787f99fd8dafbab48e505b0e8398893c9c3526424326369caaba5f667991212ccb48ffbd6b63ebd4580cc9dc14258446024ccd58355fc3137c0c6992da37ff553d26300163eedf74b3206c8902c77ee0f8d23f458873046f1152622d731e2c347cdb89c6fed535ce76118308817081eeca0b447ffbe80232974be44c34dd57e14bee1120be30a1f01bea68a623660daed143c768e8f1f01eab95ce138f0b6129f1111a6435448a70626f7203266c68dee4d32afcc70de2ee8d44ca461cc88f6f69c4a306f1048165ce9b62e80a31f35591439761e2c452e1a17bab2748d7b8ea1194aa90f1ab06597abf609b48665e26e870a10f7c201f1756fb19775ccab78977aee11baec5a63891278a81e44415e86249a05e0407c93c480e2e26ad22f6071a5e8222beac58fc442a833f7abe68f3190204594e38762d0c82d10e825793d08a08dc43f5cd5b2e3351b08e0011b26c58fdda5a65833a08cee7530a84cfdfec22c3310747421acc5fa04577d4d50d37381a78a56965fbae93529a178349dfe671e8e03acc413b706fd46d06e420ce6d6d0cd63b4d08bcc84c14775563bdc8ac9075db735ce11a61122ba4d09a1baa261ddd61848e75a1a75b686595a5768588735c79471350dba5ad34459576958c79a970da31519cf2adfbae2923790a218f27f759bd8b0cf3a79dcac475b6f3e03784c585446fc803ca1353f3508bdc2179c6c09af17ac5fcc4941172740a4a940cdcae7f8ba0f954e5752a0d5e9abe2379fcfa11358a2b85a8f96d3ce1ae931db379778e2f684662ee621377bd2356b2063cd1fd87905feb95f13c6600f2ff367ef641d048b058ad840e4f92331017a06449f5de52c86be953d2ef209cb28df0530634141ae797170763ff00f0af2a262bae85b873db5e31d01cff3efb3aa3c6892b3f68b9d89b00140b8531c13c1d93d4d34066298ceaf4c02db564070efeb1b4d6994e3600e80468ee127cf0fcd692005125a118df4a0ebbe04ac3be42cc6c792139c7791035149300280dbb87f9fb1e2bfdf731b981e112088baf735c448b705a5f68e04a83260e1bf1981e50cc7245b16105050cec00306fb8341cb69eebd703b489fcb4ecc7030eedfd9d654f8aaf6261c6e8069c604566e0099f909f3268096752f57aed998ffaed8d4bc7e3610578add0c1508d33ed748c1bb4a54760a6815e19e08b9ed7f825f2e8cde3aa6c9a900974d802e0f2fba9455f1993135d0032192d50ba8f133821ea58d0d7f41a0425db47c14d88bd1b3f90268fc91678e74cf24c348323d647f0f0d7e7c4580289e626ab096a04079b26f10e10feca702708a0da080818a1b8013ed0a3845313b113d1830ce8070b4953d365df9b220d01b5a6089814de60a1c88ba2c4a8f4a26cd87e67c45163046575114ff55beb61552a0ed644b5a08872c4f4521e37fb3cbaffe3f0987ad66d0510ce257f70fe78c42fd5cede884c459c0d67e81465744606f78d50ba994b815c2def4df2e69f5358c57f74efd0fd6494e9e1b4c2a74adef810202ce03a48a54d12912bfd2e4de4bb92c0d7751e12ffa1ce39e683ba3a6b7680b2cb2ba1962bb2951ff48762612dba764c6aab983164fb6e84225c0f8e310f758e7697005c542cae9dc02a49a11e9aed6b4746edd4445e6725306aaf7ff9d016ab532b413f4afb5f56b78145521ae975473a22e72d3f284c0d38b4e7e3fdee6776626ba5cad596e2a0e7dee4db58a8c36e8a8c2a11c5f7a39302e0a133ca1a4500ec4c30470b29c6719dd0895ab8b4e521ed0c24f5412b9acda048772924b291272f41f2f1913fbba096b69a0008dd23970c8214f7175d3fd3ecdd540ca587e4c576cbafc734e589ca17f8201d8feeb272cb048c7ff7b76cd70807b6930e81a14e38f94b0fa175e7a9aaca8c893fdc29327aadfb7888d77682cc413208d41b183e1dc911af8c99a96b95204a611c2e8912cf807c7773f821db4dce62fcf3e2947acdd09592bcea0b0ad2827c25fe8e56d987698365f0132bb5e6dbae4626eb3a215edfb8f2c1348511ee7c13486412e78ba52207fe64291eb0e58f2c53da9fa60aecc6ecb20b91c745310d548dba49d303b9fd758ba822716a4c050931bf89783da0a999c2c17bfbe40e67a81b0ce5b367b9114044be911832b3ac044e7aadff01e308995ad04acf45d1f5fe7d8295e4ee5a283b2988591dd1372e117357c317f52fe4501133ae95cad7e7d4e901d7c06f29e5a0b1d3bf1d27ab0e34e712fc58c7aa1f37acf432893a02da898c3328b2f5c5ca1e3694c76ad78014c4dcc7b5222b5db9175e63fa06bf3801ee0402f53ccd91012955b1491e66f0480cbd91c3d013815610cb048cab1e4c9eabc245382bbef6f5b02bb18dee076fae3ec78d5893a0783e5beaa7581a0a49434bd2d50fa606ef5bf19c5740c45104fe4d75941f63228c823632a9ad7700be4b0ca3909d080aa31292bf749870b3bda8711a13f412f92217e1f69568688da55f31d2af9dfa435fc5832e599549fa546b66afdfd175934861541ef320e8961d4df44ecfc3a12b477bb692e8864b290ca2433720662f51f7951b64588cccd8d5ed4b69ab2dd4a9aad0efd5d069356aba96001c56759810964e4bad956d51c1d512abfdee2370aea6676a737569ac7318d34d8226f8395c73ec74ba4bcb53a45c37ebe841b6a27b891d82899255c4808608e15ac466f450a34bbad3b270720b9190d6e2e566c2f08911e2395f812ee1c3b1e73dd78e75eedc6c78db59b1ff76a37989f7838fd9484b5ecb6d849358b56e2eebdf8b7bdcef1ae999995fe49919e7b2621796a95241c22f65c07523e6cacf657bd9df15319697d64a4e3eeba191814db3acc841e4a0dea9b2cf5e451d0858d5c4323fcc5324eb184f3ac108a9267536720516c6e82506c38a0b472acd6dabfc3d05975ad176281a84a663cda7e80d040f3a88717abec8f62616c06fb0d2f26dd3c693f37e288c2e576ac67722636ba96c7ac92a09b50f32e40bffa5a106e0d1602158af439cf4cd9e2d439556c7bdc6b239240d5eeb8e44a7e0c087bc245ec2deb95172e95a206ea0bff799b5d5515d2213372125d45b14ad2ce9c3e4634ef0aa7b4962cd6e787316f399faebf4e49b2f9f7e07a858d00f79cb4360df68db35617117903a147431dff8391cbcc3c8421d15451f7f3c688d9614d564acbeab9c24782138e16ac7e81fd415b6b957d839393efd409f98c4107c86e50382f70d91e0b4e6bab5cd15bd83f326c870697e2e4f402c489b0c4b8b214124c3da8eccd7f8d0b987f33563d15ca5ef17cf5e28ec899c2ead9ee92f72356a564438bfbc134671f6fa071937394d8be1103b6b610762ff535ff8edee6cb390a7cfbbb0579624583da60e8761f176b942d839f8fb8271dcb861641ce4725b8632a190d39cc212951bdadb700b2c8723a7c6e91eb48f8c1ab481b14cbda0efd628ff035ba7c33f5fde8516be70e14059b91d769cf9a0e71d92f64aa943ad52517d92d54525d08e2501271e0a6e8ade644756341a455e5f85915a3bea5a9acd1a627005662c2ab4e96166bab06b2516f03af9cee8ecc95b2b68bdfef98196756a2da801fdee63b0a5426a89584396b32bfd5130c5f7a6b93b8cf590a144fee3d7ec362cb0ddfff7c75c1e20a7da047118aeb5a6069e76dcbb18a6de3540ee0285af793db04b33e86a06403d9872bdca753fd6b7ce8d10311f9dd00c2a41f51af7c1aaf548ca8912aadc1ee5a3d45b8eaaf35fcb70c1ec61e91ac5556e4119ef6a1966043826691f610ff55f0575eee89844a038aff97643e98405d6d428560e151e3ffa40cf7db881b4bb8f50c4541adda2095766892144065c3c35812674a8c440735170ecab6b1a6c41466d6c9a8c4605bcc25b784a673db4d45425106aa27fd3e8f43c8424593c3b4e61edc5a77a12ba29e477dd240b286ed8d0012063d087bfc498cd7870052df9aa4ca9be4cbd28fdd0f11cda884a46ff5bbd8246ebb481e079e10612a80e399ce3d339133606b861b844516027dc02a5a528c5035b68ba8d01bff8ab2bd6812683d93e4b9d4012725ba613b26137455667eb4a905e09a3485cb0c07e41289d1bc0eae4653a78e18ce61ad142a04ec8d7128a6cf3bf990b4ff0105e8e6e74faa1e1386b0f0974d9f39f1b724a94a606206dd793547975560dc8c355926ed7215b4f1a0550635df83390164b2f8fd270f89502d1cbfe888fb6453b8175d026790e5787c802c096c8c90c59e2365bf9488cdee29bb1380ccaa3a652076a383b5d5be06eb27d6805a00ac2df625d88ec0e4905a551d050b5b599b28424024d6d9d4f150e8a0bff443c80454c7d6c13fb0bff493e8c2a6fc449205d90cad5cc0ae139819b2bd8680b01bc46a48f4bf66bfa7ab5e120ea90534272ad8176b06d235c031dd856e5230d04cd0485b5aab827426bf905182c5014ef9915222af6b47c84ca99a75abd1c85531dd081d3b0fa2a816652c5782d8b2b49cd23d8bee83f403117cb4081be13de6138f4a6e9bcfdaf83b72ad182f23a2ad2a38ccc55425b9160b861ac61fb564f220b4448a7ae84544993ca73d68265218fcbb68157b49dc2b08e88e014e248f674590674580623304da80e25a920f3539ae8528fef78262dbd92c3048bdb7138d572e459435824dfecde24bc21a0747158229153f2bae1511c292126f63799d77c3ac20d8d781526d3a9f0693dcd3a0eb191e883a1a3d4800cce5196842011e467c26c214380acf1be9bbe8c984ebc920891c7ee12e9298dede650576ac37739680859e7a9a16b5b5990c8c3b007b905f8ca0dee3ac7982748804fcfcef16741e7e83f24f53c4b3804eb59e0c8ffbacac9799ae7163a837e8f68bcc8c550b562d474c52eedd8d4c97b18f02ea853afeab50fd6efd111b30b882385cc3d55c96ea6c997516086aa7f7ec86f73734541742777114b13aa7d3c87caab2780d176819c9a6e76308b4ef908875e5269b6da53a20b6a0a0629aa573f5d2f7b619057fb50aec2a1624db27005dbcd8e52b777b9229b4d12aa4ca22287131d0eb481376b3570894f108dcaa86f7b649ce29328d401c7a8843fca0acc699d7e8174d8163b0777d627e2d72e7e165772877fe3f9fa44f66900a5125b88f6f4e89abf9269afd4cdf34ea050b6960ce0d233a3799d51b56a1176418263b058fba7dba51233684c94bd7aedcc35d879fe3fa60116388453cd4f91f99bf56d94e8332acb1d6d2e04d1cc60a858b5f72eb72e9d1c91f61ae9221a75551ad87f72a7936f0b59070924d54ae8eeb476411d3b593fd69a88cb8de027d98b984544b9279d2ce9f3004fccacc0f851abb0edae707d4782507aea48df075999ed5d744af0053557f3a9ed37abf0dc15e0be3ae0401da30ff6fa962dcf45bacf19ba65d6fd6b0e62a3f9f3a3f68b614f2a017e0b136b579345c45c7e16d84ffac6df5e17aacc90ad26effe26148c75a597d6bb875a98cbbabbcb469996b00584591ff394c6a34acae3eb83484cd72f107034de13d71685ace5d90651e6e8a8aca13da5f1e9cbf24240d4f108cb249b3f915609a160f8bdb53c610d1ab9e94c64eb6e14896f6a52be6a3d6c461e88cbd70723c8f59fa95df88528d1adc77d2babe720830dfbbe293862c54b8d8d588b956461fe23936ca16f3b0773b03f3448006c4defcf47bf8047dbbfa23a29e2bf5500b7847bb693103fc5b6e2c53d7ab686c0e0ab1c4b03f717d19f27b3c5c3c2830df2d723c16d1dfc7b020facf03a54e587a5c86df58a59d7c9e820471921850d436d8444311c7f5afa974c9f3c22bc4a397ca81ba906349c1d82f0a6ce15ad9932e81970191dc218cf71bd4bea174a24478a38e098fe77982aa8c87fd9f41bd5f09fc49867f5cc0fdfb4a13f2bb29c0977b4c46173b7a1c27d25cbfd15cef58cd7050237d6a606770c45203a69316a8c1421b04815502ef07e8e242f2ce667402e7894332352f44826c2c81f36c3fa68c9d0b116491987395c07fd7284e10c75b41e72670f6cac79041bc2cc2050aa6f39a5502d774c263c5e2a2aeee0c742f8331aac445ca7a4ee9ea587bb8aeca89e0ca8298959d27a01b63eab62c7d1c7c4281a3b0e2319d2c54f3833687e75ef2a277d9b2431682b7665ac180fca2e90380a1c203886b447d9c8a9d6c14e1766518748ad5e9bb265e0a2a2823b42ec210fd91204b0ef4d04c9cc77ee3447c4756860440f293c2c01f390238404f0a4d650f2e9ff014ae51be91ccc5f0a4f0301044dd66edf49047e52785937b3c2998a5284e0a9db1bbd2ba72cee91cb9f56797d4fec002e5bbb00b7398149ef9e896543a09119abf2789cf117471f9f7f116b04a1c6021e828ddac4a916a44a14250c6958f6da081f12876eec779d9f9e64e7d307485d019714fabace9daabc22e8feb2f64543e29e17c6ce20ef8ec84c8fbbd1486f99c3226fe670790d383d5654c8890d866a9c1be8066db211977b0cad47edd9767734ebf596268b7c46c57cc598aa9379e13a9064b64470e6cc67cf338bdb9a1059964fd4b78918de971ab82f7edf524e7b265dcab0a140f978f8688f88de488c91e76e6ba5876b3fcb5fc692ca4072fbc1eeb6ed22193831509e67114a262a3f55073c955801f2b01e35d895cf6384887000257dc6e329ee4b0c5fcb4055e1a3edadbe7f59b9846b89ec071b57263c1edb6641ab07d9aac17f588b8bc3de670a7f082b222afc5c27bec266a557ae3091be7794e0803444ecd4542f3ed98afc98ce4f0ed998320f9e8fdd16e0ffde9e8bdc0b92859deea633eab8a204782a4717312cda55c92b8d5b4c4dc6f7979e6889fe0f2f25ece6b6f0c265bfde02e6dc2629dff78f66242658b646e3156a293727bda6721aa430ba4beb3f8e3956b89f9e27c38e7d18d53507b0ceddac0e3b6b404bb75dd9f85976c478cc8dcb956c7cc6b0bc06911ed5564f2de702aed0e6c3ec9469c0b6d5c7b252f974b2e29fea3a696aed8cb62d2dd529c4d4457bdc3706cbf03d43749019eccdeb9992b063fafc4dc2ed17384d5ac549e438659d1a353a0d7346d585389ea635bb70e75a4ae605c25809ec561434a49c22ffa7829ba5539800b7280af4de8d176eb2044e9bbf964163e30a151421523e6db057d33c0a62123dc0bbb61748219cc0e2d8fa8e3189e8858ded0bcd2d1e2c026cee941a2e15a78be5b832b51e3839197298698ee8013d42f5f9618e4c82eaf14ec97f5a0a9817e267d6d693ad678415044a3ada1ea59e4eeaad1cade5dc11ca617578aa05c4a70b5af5e225f4835f0c9d438b58fdd1b4f140e6cd252bb1ec34dad9a521057433c3f17c8a6f4b3abdf049f9eafc3f127ec264801365dc0ed2b4021ca45adc7071646e0c9052c5589647e31a26d01e4958a2c5a4266bdc1b4dfee7f5a751e0928205ad079d675616c8c5b7c84184321240bf944388d41b2b82b8e0965add04032b8c7b0273246fd47e6428be979221799174ec92ca0a7b710f3342c785b82920eb283257fada9613b3b40f3d3296ce62c1e7290756bad2c78dc1318f50d6abcfa291db93e70b7a29ace7c4e2888f5711fd6764b7c1f9f1e433c104b47c1dd64911014eaf3b73f793c09d504919b68a45d06b6e67c45b743cdc92cd3e57ff0f1a097b6b632011bd0649b685d5d34ffe48a397561cea569d1cf86778bd012e7a680078c6baf1ebc526fc71dd9824fb08eef264c803a2368061a03b3cc0d1708273450cec8bb9b2b0ecef0d3d53d4ef343df42c2f64084ac6a0d840e6c1b335aae6a3f887585d17de3972afcf1b4457139d75a550a9006700a9bc9327d22296fec50843d5f1fadeaf9a9adaeeadb79da5b8a55e99487661bef050f58e92eacf66791b3bd068d1f6d2476daf7e3f584d988a66356f6d69ac5443dfb65fad60a3717bc800b825d8924764fa2a6ce7540e45b5b980859b687e86ab666e24fcc1d591c67e2c616f2f8af15b2ecbab795dccda53a0290ccbc46b5c14a93012d0ac0371536829013e52711d282ae2e7d5f0628278abaee4f1924a1454f1688202665d254ba2a89f31490ead41e8a3aa8c8b599f47f05e20960a9c5c75af0552b27414fcbd272a1069063770db4c55888f9c3b4732f6d996ec89f786165472d60338586d1c7b6d9582ebcbb22a9f8b8418826644e08e5999bac7ba9153e052748baeb03e008d2a239fb70410409bba55c22588544e6ecb8469c54eb81748031f323efbcee3ca2e6c141e645a407d75bf126373a22ca42b3958e50698e10d80361ae3cee047a106d710945291d40a4fdab5e7e1417a05043ecc0c04d1cf6bab68f673fee9804496750f03e3abe44d4e03510d1063876e08c9faa16b5b5214a2083aef8a7739e5ef0eb355bc6828034ca78162daa822452f6fc7bf132096a331844cabc816d5f30a6f16c2659e8266190c5a44d48f6f903eb702ab610db02c77a079ddfdf1ed75ce815849ca3b341c2306d17bef28a2be28db83d5edc8dea3eef064c7111d742ae6cd2a7b1fdf21085b84588af485c7cb5347ba53cb6ae6c540796128283a24ffe95de8e4b112c2ad0f9db01894a5ff2e24151d81957e8e0225b474eafcdc8bd37a1bb7da6facedea0fa2366779b7ed601668d3734c6e31996168fcc8a23b590087866c9c4768b2c4c928ca30373a3ae8cce7d373da2d3923c2ca4b087c6cbc5ee6edf2b4f700207ad3dc7c51e15d86aa6cb16c39d90282602ad8408bc8f75e6872da535e0d05f25579fb2747ca34c9f945d2aa745ab534a378d5732e1c85c9d20e839fd98e5843d468cbaf9c8c8b37a696f2e397a6724429f9c8f6a758100759c06a77d4044bb9541e360253341bd8de1f78deaf5e1583cc74fabdb5089df915fd838990470902571d9b489da403612c227a457b8430986781144fd0beebfcd1e38fe6b505d1ec092fecb4ecdc82e630daa9c81ed9e568b55dbc5dd60ecaefaa38b49dec98b3ad57cac2b19f08cba7f9a128ed766f568ace0f16d5cf3ea3b5dd757e50e9bbc69409228d7558202ecde771d437cc2130be7d5993164436646e5e1303ca1b892e09b66ed4ce1441b51031e16c5b9f72235985463450372451d3e1ee8bf287bb56c92211f3946bb95483141d53e4b863b2ebdb85acc84018b836cc8166bb17ed5d45948771c854f0e8cb4454165707d2cf7c684e2c0cbd04029eaad903fd88f428dd39d4d1e3cebdb4a03d333682e63d388104a01c7d1e00f112030d1a3541f2d5d201a08e9f7e184da87e1c6bc69c03c162ea5ee7bf2f7b6a80b09204af5ab73fb5bf67387295f4ec5a1ba4cab7caf23f2491a33a2c9f14100cf9b86e6b524f8ca3de1750141426fc6c5d8fcfe13b62ee2666925eb6a22aede60eca86ad36ad281c841b3908db388e67a9b2578956089b82f6e30b44b5bba2e9a6357754fdd835b2d1b579105ce378c91f035776f4e1c8edd780ec4b67299724d41a073849dd4f8177c0809e508d5920e98e708370aea43af73b658bdf14f9c5add751de97543d3ce039df9e8d743cc6c96d76540ec6e600c1db2028c307c89b30c3a0f46b01f08180c2902d381adacf91ebbf7f78836a4169d8dc5df937626fbd7947cd3fa5f198a743fbc547109d482a8e4035a3d0309ce2b953dd25d8b92eafdd2e07a9127b5a326f4222f68d253d14c063afffd0739137992c724ebc83e9a4eaaf65245708524dc52e9c06250be4e213a828285c63aa9e016dec964e7a744a81f4f9c74b068bf4561569ea05d039bb3001fe14b3465f97fb32d7bf93f8a326c7a57c8e40006a130f90b21887d079380e5c27fb82eb834d5804d2e1c7d235b142a50eb07a649f50ded1b61dfc341bee97fab36aa50f4e51f6ad00f9d3f3a5d4c90dc3fbe543e32145f26a391a9d38c2f2bf1d5e09cce4d8f67d2227e09aebc1e3044191ff4fd339dc44a94f1e262ada20640e872044ee687172b0b4f444af6b59b65bad264caa85b2c830c485202e6abe788abc52d21a5ee8f7ab3c66def4e93da77b88f2216a7a662add96c7e4d8ac97d284f13a4b8604d9340cca14595b6b3b23875978eb429cc02c400ba682cf0063e58ca1fc88a8c8ce85dc86c2c865c2a8dfe083a17c3c5d1c10513af85cfb6ef52f8b807bc0c3bea35f0fedf05f1e3d184ed1f5e5a780db8861fc5d2b4c9876ccf3574c831c6d282467a43cc8c627010956c93bf0a9206cee6716d22d1e378d63ce9fac4f439f460720916c061852010a45bf083c8f5f9ce201148b070173f4518c7b57d03dc074301315c4786f207bc555fbb6e0db05b3c4bdbe700b087d4d527c570600c821e2d2cc88005f2eaef422ed0fce0a2651864ef5c5df10de9348739aca682dd9c1448ebe53dbdf91d549884d0a743c61b6000412384c1d1485d6d77e21d47f56dede6aba705c355674c33ebc7b09752a997df2d3197488cca0ba5a389898014a29717b629ee33652835a490895f8de5baabb90b54d4fa628cfb081daadbf3a5ad18b83d8d9a94776ee94eb3658e2f3fc653f638bc8a8e7ebd074aa37df72fe8ba982e9646171e5dcbafefdebbc0b93d503153fdbf5195cf1f3cda4b6b0509b4a12d511cf5a2c6f050b641e0b35673cab7c11b1fb208159893415045b5db3ec7595ca7d305c5545e1d91db8ff538b799d1b32d5e0ec27fbb892aadbe51282c02d3e70ae6a8aabf0a0dd814619a69177c6a6248f5ef743b7b329eee6117b4e951b7d301a822cc527891a79f120c48a0d6816afcf168c056b5c4c45871f333047412154b981fc4110d6185b86cff3add9c4b62ba02fa97a8d17e34641b5f1dda9b3b713ab15b9aea8810da9822b2be5a0d9d71146edc1957b26fa134fcc419ac3bf3506cdc9d12883efe69e5df93932347f0963efd8a641c8a080469784645ffc9c15fc6264f6612690579bdffb878c918d17c8ee69b0495d8fa2b0067b7dabf7a05fedcf4b5d89849ec950202dbb06cc65ec19689aab70d593c037edd4bbadc070b4c3a23797f79f6af1cced8a0d5e3b977741c609fe70c687401a1cbcffbd4bd2bf11663ab4301f806d737497174a3effc1120e3844328ceaf5f624618e87a51baa841c656d70dc59d04004e3aeb0035ec073c8581295c48afeb018ed086c85f47ab1fd2a6b904374ba79628c7d454a765b920c88e42f3a873a4760de05c53746e214bf822468ceb3a3929f5495ba66bc6b7a8afaaa933763d552376895803fe0749ff4e5cc3af41fc515af13794835773ae7fddef49a7ad332cf0527cfa47bf84d81b168e08b7ebcb3ba4fe49f310c316225a97ad6bbdbffa8155f74b0c3c9fbe99fd0562a558a9bbd55794e69f8e78a20a0dc9298814ef2ada454058a23e4818d7623ba529d0251fbddee248eb37175d7b44ead23e6ca20fd68ada775e8006a781c9470e407a22c18716b3cb98d04afb7c80ba34e14e33034d7dc1520fad9c73d28ba084bc4f48a9d07c07e8d4f85f8bd4b451bdf337466431e37512e1d706d6a07ad4d1510d33183073353643987d49baba573a8fc72de0d3356fc67b53f78f3d896f47192be049e14816ca04bef447bdda3caedfdf703ea446e1c77b5a5b2acf725dc5faf30925da1179474bc4a4fd58c49496162674e599556531ca53e69622a0c5cd9ef3f178fb30f8086952bdabbb4733aa5e9e45d5fb4d930874de894a951d332939f2a5f662befad984a076e7843da1c61d7c1769fb5224ee2862375c4bfce7bb5532bd622449bd39bd2074f9541ad318a6439b718bce5d8f4528f44f7ee88690332a9c33e5aacf615c551d287c7eb7da258b986fbdc330f21223e23562fc926d396234bad9cac9f6486a96dd09ba8124d7d14dbf8c326dd1b2b477490ed5eab4263d8db4cc7b7f45d438ce332c49838bb833449b264923a1c08ff66889301b8cd9b3114ff6f3222102bd976a1b9af08db4bf40f628639cf87ef9ca25116aa6189cbf456690be8784c6992994e9befb6b244842eef3f52c7f1d5734efdd48231159ebd4ebd34bd761700fc04b2807f05c5696cfc637cd97e9dff78efaa7305eef41aa56ba996c3d79cd7c312c48fbc2d99a17404e28fa091d5fb10ac582ed23cb9047fbd9062be9ee3560b9620da9792b5bc757e363a06baac81aeb28b9bc3da1f3da99d876e857f3860d112c1374458b537b10cfe00c8c278e3ccb8738a2414351d8d46d16eeb5bc24929c4099ab8d95c233353a96e28b9ec3bbb4b1910d312b44ba5919db71a9acfcd1b8f3b47b3951f9366b149fde3d729f682e2598186451830030e30a011f3a1551e371a0f5f22e37dd725a62867a8e67f0befaad0aee00b419507b1c667ceb3494a35776e3463dfa7eaecc1c1382efd355da3651c454ad1802d22ca56b9c440de5a24c070ef0f7c3150a23b7387c20470448a2574240a43175b6c6aeb149f77f4f0488263bbb983424eef5b7c4ccd1917bc7da9e2846db92cf6d4f5ccfdff2facc7c073d1666c6df9553bbdc5936dd8e17ce014947a5e3a21a2b32fd3d422b4cf96336cf3fc3df4112ad785ec0f49d684c5a3dd21346e69db040a0d82ab336fbb350c1a6a99fe18afa62dd638af60cf8b3f422c49e18395e325653bae4417d538a468b2d1efec0d9f5caf11707218c004b4442925749c7e736b9291c37c270eb9a4af2920162bfdaa9b239eb002545484b27467d187f218b8d120c883f84445143d8b731cfc1214c53c598c6cf9cdbbb3a02f1d65b8291d725d06c98cc84910923d9a4018a57265c522c86a40d09d8231d017c58e748b3307cfe0566c4cb01b0c00c929ff7984c90feab4be4fdee68131a2e602fb43a6d401344099f9a4d26994fd8895c5285ac054011722ea11d53870ccbc066b153b90b8c4173ed502cd1f84dbaae348314c7406e39bb2d20f1414bc9091b605c07599212f42af0c974120d019c536ba1f5d75726b72b28d4903d2496d29483b486aa9b2de6a4b9d4ae085a83a2f9ce82755d9208464a9c22b8ade6bd3cebf3a0cb633b70af268d792d357503f267febf40ede1f7ca8484b0a2f023705dd42672dd39ce1b82a27174c02e585fedd1499c93774481ebb513dc57c4345cfba44722ef7bd3ed21237b61324609372256a26060a2cefb8c37dad6fd227b6f889f816bee07326dd13282c8c83208b6b89b3a83d54427589bcf9984cb86244116d21f3426bbda99c911d54c4e2eef6049238dfec3e19f44ce3393c94945a491940815a9d25ed64a7b3b991a81987080d2acecfa8fc815161c6f0366a624093c93449e241c0648d9d48f34bd64c3f863b47b29624fe73114f9103aec8d226a3b45b56e366f2fb751e318d5378205606743c36dc21bbaa08334c1566ad8ba64708e8155f73c7a1b7498c8ed36245eed33f20dda1e1ce24cfa885a4379dd42922f301a42b23f6a8f12a0c647b445a35d1fd60bbcc093a2ddc2aeed73024ef9184711d1e83343541a8d148467cb3e69aa92a701000f743388b71e6fc06d22ce5388e03710ff3354a64d95d41b978e3ed061d51631572677f6a195f2d789d69113bae1655b161a82b598d3581caa9ee9d2e29945e760219ea4a10419b05360fb5f732bcc21d1e2c6d890501efd9889e6e78f12aedd3efd1663a7080ae6158afa21490cb12be1b10f0306233b0d4217f5152e0df0487b9b039c3c25eac230132c55c8af726f550d9dc6c176f30ada2f2d4c7ea422ca753e047e4471f5b349f080d414997bc1fc5fb6beba177b6fedf02d1498b0df161e23ee24434fcb81b3b7c545e7d8bcca3fcdd2b3c8d0ce7e83c1812218321182ae0e429d0094cee1a5417626e5fce3c26d71d56412301e5b34137ad39b74c0f1bd810484084c337296902981d8bc4fdd87b0474023ea4a58d693b8197d4e54fe994967bebe91c6425206f721b049dcf3ea9390aacdd403809b6a4f4f2153c34c03fa8d9ad0be2f873d5d93755b5f0b60281a7828225fe5e427d75ae364c3b7944bbfb904be16568853fb93d6f866f142e1ebf20982c81ffbfc90648e1fb1d9449395e13bf34fb4101accad474ba5388bc73a209129c9b67bcd19a66e66f89be6b981df6b9f34afbff70f0ffd7539e0be4a7884f72110d63e0b45914a4eb1dd6af453b07f7c49234c8104a49d27f5d29fd2a74f33cf13b6e757c865337e34ee3a8aaf3bfabb50572062c1885cda891039b4a024c5f6dc671cd29c07ac057d12d03569846670008b11489c68e3d278850d38f75eaf690c17402a141aa0ac35dac10f0e515968e730f3eac93d04ef8f845749d6dd08ca07e21c0e130a1d1977effd608f3e4778d297cf8d017ad64ef752098bfa3206821a25717a38de00229e41648c1659e18f464ab8382e029c634957918d075238dc126a31053748db028d8da6c46bf4a67a4926afce06dfe856d441ec8ed7b83ed6163f7b4c3136055bc65f9bfb395ab94b133dc94f6115419a20443b0e02573cca12f769a7e6602db0a98bfda8566493f0730262ffd9c3e29f5964f3282a0ff396c95edf43b4ee9470dfe0b529e91dcbbf933bbc580a99028d104e0d7d5664dbf06f57a1729cdd3ad51278906d74ae98868f8aa7d442c6220c189bd13993f889c139698edac8799e61db68bac89eba8ee00579dea4f90472bf2c47dba3a2701a54ff1ea979af7d851c1b35f0017ae0c9fc03a227a0553c5113919a3414b39426bb06d7b71d896e0300a51d69a497e0f693e3389cc37b070dd86cb9093a995a412e59e5828f3cd464f526a963bdaa9977431184eac711b44753dbccef70d752ccaf9c3fb41947a94c35cd5411df03b94289869411eae446c32663d56ec5600f59c6e7861791bb51b8c552c5ab6494352aa43003d182c0e9a52ff0f31e7a3c8208fbcde1b93810d30f0b597c14ea352835a3619991864bfcf93903a7f18bc89bad3f9f4b546adc1d0a020a507393d477f277574440d94651d515ed5e3b1671a050bb9a230a4fedbb0fc9429158c8780b90686696e9d91e9b49ce2b1ca16a67f2f8888c1ad740d0499d26a2af3e077e21348b7ea8eb4f03fb33dd06a248f93ea36a1747bccdfc45b7660262647f449fcad621f79acf35e5a289e2a1afe21213e3958768b988496c9b461ca56a064e8a37e391e4e87412a9e6b2c0bd8ea880d03e6592473b199bbe97c7cb371e646fbfffbb62a6452a0258f9180fe0ae57152d947a29a97c2724fcd243a899949a81285bda242bc8b7e8b9a9f878db0681d5ef04e6cc344662d523fa04ddb3ff1a76f4571e5ef2612607049fa4fc1ab6915669e6049582d3028cccf7aa053a3e8d75828fa7cbf7a032b9d04790dd19271c619c9f5655a033fda16bf076758da265e86a5acf0fa1cbd60800c746c636ef6d3f31f4144347f6487ec40e2bd8c2a6b3d938bf6ab350b3bfea27a296ec3bea14052d18fbf9177d06ec61a9bf247ab57daf7ab0dec2900c09614da22144580f2aa33afe530b705919eb5af3db6777e2de428422bdab0b96adcdec2d9579dd21f0868b9eb438edc69c2a6f4ad13c68e8bc2b46200fed3c0db27079f1917ad12c27d89f4fdbca64bce0d155476a1ac84e2a9c68a7be39c0c186268e49589c19a49403dedd7af6efc58f4dfd4d49bd98983cddde8d1d7a61ed46efbc29382280496a8900045de7372ac5f0dc226d3e5c1797c9a22b99fead30c9c9c1ca86e8ffa4c257fa88fd9f9b46cfa4260c501d05b0500243ae76a7e6424cc08ab57ad08946910103847d100d762e10aae14d1ff4264479e081395bc2bcb8b7787ad73120f5629a28f8281e63cce522bc7e2e6099f3b98a1c842e22c7a1e66933b689ac9c50cfcbf2d8f2093d1ba9cfc3340a29e715a27e1e9c294e1eeadf1f463969e926df4d50ab8e3cc59a06c4ede4b2a9028fbbe221203b595ac742ae2b7d91359c49ab39988d3dfddd0428267a884f2891644a252786eb703962d0600b041c233f6ae6ade28f5bde10d31c66d7e13bf4379d15b00f7252b26b216f44ba1262dea41b37b04b46ff4a04053b2f16d23636c45f494ee17ffd01258d556fd2eaf900c1d7be6f390ce3ffa86a883258f0413f6319d382cf794be8d847f80a9d166a5cd71d954326dc9edbbd105d9f5b0603c811f5ba35d937d7c9899eb238f474defcf08224d803a1af43ec6dcf002611703113710a68e58ce26631a7445207c7e87dc150af025b4fe53e5d46ad98d585e036e82a27fc7c0abd067d6e962893e2a4bf565431375abc3df7fd62fa35ad28044076a2bca7efeff93abd401acbf1e4663b27cbf10167f8205369a2941afd1fbd6b747d74d5e8ffe855a3efa3a346c78fce1a7d1f1d35fa7df4d6e83299797b4cadf8ad525b71c00db630332a5c3c843fbf9ca42959391026153b799296fef4eb9db1bbbecbb1d9142894964418fed539ee089f27a9841b2d22c43ce14794ac074a4781a1c41d504a54af5f367575fe4f89b7382efce635032e8147680fdaef168b1f4513087b4d48400f5ec95e3f48603906a96efb608e374dbef69db5cbf1dae0ad00fb801d02132c537952c7f068479134d8f2804fe64cea9d57ab6e708da759eb3aa28702cd8df69604208d8c34cf97e4a19a11ebce7ae401937eb151d19ea2c320c37e3626430ec4b788203a87a61512578880bee8296dc934569bebe72ef6773e491b91d84497d8ac0e02dcf801465f2dc7803b133271ce2c1020272fb1cb1e9fc75286a41bb56d939c5e5814f7701e4017f9038a4d1d25de66ea445ea5f8d540a1d4357b08ea7a2d8597c07d4728d2051bd144de4549ee408a8fa9c5c4879570468757d3aaad604062514371483a48c4f3ab0ec649d1c8bed386461e48cfad96a531aedd46701985964a37cf2346589adfeadb6126056fbc3bf951436e800d399af7270d45886aff3e70080d05361b4574158f51e90fcbff04a922e31ee2994d716064d51c859078f250bac2b70cb79a936fc011ad7bd359ca5e2829e93085dbe32173a984ee4dc4231d3af71e46d3ef234727e49de22d98fe0f912d5af0c8b0f6c31eb29c993c50464a4b9dd287945852aeabf73e1aee7da4275dedd0d2965eec542d6b6d5933f53a2454a66f57f7ad38a55df2162eb0177056bd2de8d7e8c466de0acfcd40172c2cc6ebb756a110e6d489f4d6a829f56455c7204a2fcc943e457908b7658ef1ec38b8834befef10d93e9ede47c78cc4c722c803581562a17ccb7e4b1b133a8a16001c771a3da77961840d4c0ba70c009dd5529b42791c0c5d583acb0bc3855618d583d8424021cc39ab4a4b78b0c17c11e3febc6375569886ce9aad8cf7c6233acc871be9e29fcdeca79e41ce2f09824fef13ddaaf659cc36fc7ee190985156b85cda4fc7273d321db0f3df8095aa4b7fd0c46323d92d54ae69ac71ac30295f80144f2287a67051b842194426ad82b80790a34cb2ebd253411bb16e514457f1f9d81540911beec49760811240d855929204ba6e82bfff12813cf918dcbc40cca0596b39290622a61c06efc288ce1c5e873b73c82cc1493deb10e716f3b5ae981cb4041c33e61358cd4dbcdd5041948ddd1a30c1bf7bf09c25c3c3cf779445e47574298dfb8bebe18a3abc3a38917c6fcd6da25775bc2a7034119ba5702fae8e4b690bd9a832e3575ae19ca0ac08a02d6dff6ce77562d4c00b3ae5dbfdbe22d817aac4d9a413619fc7afbd5f50520088adc851084135faecb99ba468d81c0b122557efafd08edd1074b78d6433dc4c381558c35bbfcde82efa4b91108c4562041396b856a1e3a8c313977b2d95c5d014c7ed9d3746bc39ceb838c53279ff0202e7fe315a9b20602e701054eb1e2a57889ed87698e7ca86e9bd65d2ae1a042248b6bbcc868cfcb671424108d7645b6114b842cb29aa94c284ef9e75d9ffcadd038fa93f554b973939f3b66ad7fe8fb680083d20c899e13168ff17c10b2219a3656bca2965cac5c79b42a4d054defab0dc3db91f85458c7ec53e7c14ce38a2d6ff0e88f024f4dd9fb817944aef58871dadf76d1b47db06eb7f6f8d473bad310b57a67d9996fb30b060ccaaed0a054ba70a808c2e9e7274e6506b47cf24d50553d4e4e5c1e4243a4d7fd860bdf524c062f3a36409efb13411ac47468fdb5d4930dd25b94ffd3e79b221d3a366457f8462583caed0cf47dbf0877d66bc64c88bff067939b856e2bd7971831733b623a45c163611428d2c18a1d57c6dac886fe0ea9ccbe4508af51f4cbf8999de6bbf10b16eeb258f3861309988dcbd38738ce68caac16c490129d3d1e13842c44ab69004f6fcf804a970074a5690805a954722cfcf2ff17d4919cddd20cac7cd6b6d067512cb69a558209615fe48de363e79ce1962c3535150e7f3e2a9b91dcc2d0fad2aed96d62e2d6bde73ce65d63758d8ff0bee939b67a6b872565648cccd421e0ce1a0c9c1e18211fbcd39eb85050d4a9c8d27ea8bd6ac217cd4f36962e365c83acb8671c0cb060264d208de43a9f898d655930ec90c400ac77cb1092f42ed989df704894db0a385041f0c4fe7761b0534a990db9138fcbf6b63f036433fdefa67bb12fde19238716ee464f342fb9101d22b3223123fa59fc241012b7062629b9c1024858b8b4b677489c8e523c9c354386d64b785879465f208dd7b410857e304076469b4647040d7547bfd2b922065a4010a6baece49063612e00b28bd78893220edba50f5b0a9167b7d818d597680f12bc0aa2808106ea294c9fecff83c6390ff2195752cb532704bc363f11c4cdeb234c85a3f6ab9a3e56e180152376800582f2a0178131b03d0cb534cda57f6cafafe1741a7f4d44004a63fbbe3ea2e540172abee6e43f2ed34d4858dd6a58eec0f241889f501d66d7ee06eb3ca1b3301d4992a71e4f0810a21006fc88e4debf6f403e7d79209486891de8221a0bad1b2b0d2d1148a6e730a96945727841a4bc36242213ae042b1cd4b44e33032b15d0b6ccd1ceed74a2aad8acbb4022fc67565ca918ac4b3ad9f5fd483116687df0bf4346c12e72c6311beb5510687e386551d7b6f32c0741f1a60d2c12e1abdda8f65380f38310fba8105815858c069a9e3c00baf2bbab79ca31318698a0a072a504c4fe3c19614a61746c3638a9532b81e79770bde4ebcdc048e3b043d0e5920d619710ec593efe925097c0d2ffab81f5ed8147d5c4b312eb66c9dbe1dbc258e3cd48dcbde070ca88968af49463436beecaedcfb6890e86a1e1299350cd3a2bd54de70fba04cfa8a3cd2c40b5be5291bdffdf6d3d2929d02c90e5c0e5f0d611592244ddf8fa6ef0bab9876a50fd40249b2a03c81db3858643a82290b93134c431ff8c9e0fcdebd05ac2a9c08f118472b9316262ade6a3cb5306d717e54a850da44211315d0c67402f7293370f022831654396d254bacc2891006bc93f7a3d704d80ed6244c8267724219b2666cf8bcef6fe4e0a1441243976e4789b4f290e424f01302e931cca0e85c9d1e6506559ca4772a5dbad1748d4f60a450da5227083ae81ac168519e6ca2ce441275a3f95541c6134229fe9a31540594202bb62855204a01972045dd67a65c3ad7ee744171e95cbb9f02b966e1a8f0c1f0039fc08260411fb882eda0e44047f4d96ca69cb61d9e2e252edd0e86b078c24927d2b52381aa89d17b200ca311f805c15022729a0f06120c0a1a5911d4a4b4894e46a08cd009540e503940e500d5d7c4f84d38e104145070e0f446cf7b7177437a27d2bdf0631941d46732c350243f91d403044f121ccbd168249144f1244ba39c9177e32855034ad390d3801b2805e1f41e02a54d1c3abd2f3de9fc6ebc1f7d2212c81728e4f8409224714ae2f4e20e94219f873b8b45a27e7097294f22ca3c99313cc677100441f14f26cb9f4ea7d3897c6739bdb81a45a1f3749ec8d1389248f3b4225f14021d3439481a8942a08db804f926f24be493c81fa1c813193e698a431fcb7bd22ce2893a7f8d5633c6ef45b18a510ba4f64e15139e8a890f049d3809c3501445711cc7715431315231a162820a1515133b480e108b3e191f0b0aa54d86adf4d7e8fc5e94f2d5782f62717eef4138c51d62b80ab35082efa9aa28bf178b9e40c23cb1dbc2952b57ae5cb972e5ca952b57ae5cb972e5ca952b57ae5cb972e5ca952b57ae5cb972e5ca952b57aec4f0a7130f516533228b33346da2a37a942ff690a5288a1f9aa68d3cadfc6409224de1bf083f5593faf04d5b8c27f978f11f7ee852922f3eb91a49f25d08ff45cb8725d9c3bbc212b2908ffaf241d264f93174f1e2b7ac6c4664e183e54333a6fcf0c9175731e59f5e8c294d1ee49ffef4e4b7fc6965332207d8b2b29d7e44a2de85a9837ad2ec417d69f6b8f0e6bb90e382e931cc0d9e2f5e7cd2b4b9d860981b3c532ffe0b736543e20c4f273224cb90e54f4fa6c2177decdfe0b943308ca20cdf460ac937995e343da9b28941674bcb9193e5c36f29cb2fcdf245e874f1e54a7c9615aae5595ed583e55b4c9b1874b2984e668fe949936923c390243f1457b61771c5f2e207f97867cb8f4e24694416a78b776186e58a453cbdb862f9965559aebe9365654b7da7d38a245f1f31220b182d9461c862b2ad629016ca131974a2502b136ee8956244162508328184249c5e10c8041290200af900d4c1087410850e98e820498ad41e69c25449c1545145a1450eb448a5c21065a250abd487e50e982a6518a6727004982a3baac05441a23a800a892a012a04883be49b3e092ffc3e92e795a1e7851efef83d4253d499a2cef33e2ba015d04a6825b4125a11ad8856442ba295d1ca6865b4325a19ad8cac8cac8cac8cac8cac8cac90ac90ac90ac90ac90ac90ac90ac882b182be5f7a01553f83d48e691f34389664c0ee9c5ef413245d18c217de963c43f72964c4d32799845bc2b1e0a0bdf19825800cf300cb1109ea1288a5810cf701cc771248d46a3d1080b3d4667088385f27bb0a8880a152c943139a4537c9269eb39c70fcd1e2f9ce30b67680b856ca510ac80832a670da74791020b82ed4c408629982b8061288aa2388ee3381a8d4623982b141551a1e239f19cc05ca1f4dec1f07bf1c39c0f7cd11cc53004c36f44e5fbbcf3f3d2ca260a91a755cbb37c1265cc0f2dcff23b2da667f99dd2f4a927bd30fc441238963dfc3cfd08c5839f2796f1737ce29f7250a616a5c9b495fe7bd0f439c0d514754e03824b9ce023111e317d6011a80879e117c28284848484604c603b5893236451f4b1442a4254caef45d109511443972bfc52188e46a169db6168da742e252e9dcb14c593d3e4c4b433059d224c14445d1474a24ec95723928444299042422318123202a984d22612913a1d11a92322420259c3e4ab199f209d7c3524f9847c424a01dbc19ac0765b54219154d98244c204a22a445748c1624a108a48245f8dcd8331424984053181a80ad11552b0981284222410115d21058b2941288235813d41eaaa1091415588ae98b205a9239510913a581322212121225813528884427a0ca2f8c4c86379d4bf94e5114c26938904934539447262129dc024a1ec29bd48fe90a90a131493155fcd68bae2ab19c929538240d2b9969826293ed6938f25647a62928234097d3523cf24f4d5981e7c9823785f72b96096508ede4f9be8e449124a8ff4354f4429be9af06b865c4b5c4ca2cc408ad3e4c444f4d5d84c4f4427519ce08b51806f32459981ee04df243a310db9c4772d31df7b969583323b5499366df39cb896988a4e0b181fc60865cfe8c5731cfd389ab0a0138c510cc7119ce37b5ee98808db8dfe4153476c1224ae4ade6834f2480fdbc1983481058d56be22498fca29da4c54ced10b45936422721a5d39bea9824109be1133fcf0c522e0293a21696134428de368348e469ee789cfc2a2e3adc6f1b4428d3ccf1bb94be75222be6b277a63381a892971742da162248abf4a4139bd4da4e2b48d3ad209fe5723e3c8298a4e3e1669e5fd875229a0b491866c21151e69c85f309c2c59f88bf4e09f562a1894ae84d3fbd2ca24b41a6d6210688a4f3ed60c9228c5c71a721af0534424d3d0098a4f4023a628bef8e3388ea3189ebe9308cad1b56b6971e95c4b5cbbf247abd2b41d712d71e95c4a5c3bd712d0e6858b31f5245315a50c8542d71292032e5d0c548ea082a292a222524d71ed5456a8ae5061a182e25a0245797a1514e17baaa4a245e7d9480e9c317648622862f1dee672821874bb33fc17ab1944a04c8822df5652010315a70955507467f8aa5d19836d86141b99e40c9f8432634a0c4b2451c2e48928aa8002c5b5732d0972f2446828062aa72bfed5c8e08af34f8f4284e4fc3eef88b7e3238d9e942a5b5c8c745cb494a9d07b1889d424e8ab21bd970304513b587eb46221ed20396c0763e2e7f8b020d2cac56f0592a313e91bb1c450f1cc182aa00d5904ca844f2ac9a2182ab619a71de3f89e0c52cebfe284393d8a14a193f44e3046287b482f9e3290841f53e5ab2199b62332745fcd687e66f8315a7c35e31632921c89a1a2ba40797ad5054a1b197486ef2d3b8ff48d5a865c3c5904dac480f24216d94e3a17a60c4f9c26fcd28cd2b4bd942c31a0d8626471868f5a7d15a709bf650786333ed3f6e22dbbf7ccdd19c6b40c9de1ab969464158f85337c530c9533fcd2ca260307cef0c92a3e9215e415671806e10cb128026dbe9bf049d2889903f411ac8959043cc52130f4c2d00b5f0629e50fca108542a1c211850a4b8f4a892d61880a6151b4b848a550df92fa9622a08bb025d5821ad946214bea5342b026b026b026b026425ab8c1114eaf89d3a3d8404a99427d2a954aa13e95427daa4ca546a58b494a3ca11ee5e2532b5b79c488972acbd4e70053a85ff5b0bc9f5eaa259542bd8bd4bb28cb54e9c2856973ed6c5cb43c09b481f12de6a84cc170f12f5cb4a04661c992fa54cae572b9c2d4375ac2eefc40100453224a7c946b490a8572e950ef5282723d913ab19c4e27265e11900595fa94694bb1b43c4bea53a66d873653743a9d4aa7732d712d712d712dd98d3210458a932837d062044110641147a228fe778205c182604d3c1aa6379d4e26ef64f24e26ef64f2728027d3b39c4e27d3b39c9ec5f491e49f3e9693c9627a950a0623f03b3d6a75fa1ed604d604d604d644141a4f701a4197cea5c4a564340ac3914e67235974fb4492247932575187429dc894c9dce1c8b5e4a524ed4070044720088e8e1819c1763026235814a5d108c604f6c468341a6b50e5bce1f42835b0c20650463610b2810e7582b12295489369da8e8c46b0262f659195dd49ba762490e4da995cbb2f4ba4493e482299369ba216f324ea4e16963255dae1393a9548731575e7c8147ea904be6b896b896b896987fa4626a6a2f0830579e589f499e0277e1f2ca8040b3ac1b7e2c4e1f42857ec6a30821a28394910f5fd16e70ca747b9028bef3dd409c6c712856ca328ab286432a960508ecc152c81b026b026a0a9052827f824eac3f0c51188e18b5584fee308232261412769228da328e31b4718938f7cef7b91f49d327e149fbc40718ee3bb8fe32843868ff0657c8ecf5b913b463fae44a118305c941f8a8728f49936128b67da5ece50143a62e483ed604c425814678fc9657c1f8cf49e843df1c990016ba20a6364c498b6ef246141e758862e4218618cf0c525623e344193d783693463c813cbbf3c0c6c0763e2c1c21fc31016040b2265bc6924b9e0f202e65b48e3d763fc9e4fe7748e5fee60dec1977790e5148e604432727ce1f862cc0af5aa15f9de8f56a48759bdac563bd8ee6389a622520cd34672316198b6f285d962ce38c193a813a1c09a88a3e89936ef4cfd87ea319a8a409bd2f6320324752952e8ec09cd50c74b9931a3275fdc81362c50067c12092c4da6ed8575ce008774a30a0625f93da3cee9249f0582ee51c072e8041fd6c483915f7ad8eeab81059da4711c4758138f86e8a2f25ca0c2d0793a5d3c942b909c02383d0a0d88ce2834088a32032a5168f0c4b53b6138111283be1ad38f2f3e213a11a3109fc0f851dc8da655e94def8dc42540d4112348b8742e920bb5ea3991522b6f7c14e9515fcab5c4837d3ff6a0fee49d50efda9de37b9e39fef7bdcd1b3def337b507f1ac7d11123a411c9f5c4691b7d8fc439ae50e1397ad3bb94b8989c23926bc90845229936d7ee1cfdfe48a4279146e19340128964bead072d7f325da8f756b61fcd9893b8c438ea783f9a9ef42e251e6c3c3fd7ceb53b4d5f2a8d66cff89f6924bd0b13e9c5ca411724d3e6a1486f4b3941228de39b4e504e12b5f2d3881a51abf11c3f979293f423aa8737fee94de10ac6bb4b676ae214c5275f4df930a49c303521bee795de666393c5f979a812ea6d2ef0cbd1a6e81ccd916d87a6f73cd37bdff824af0729274e517cd70ec313f5a9b7d94c394fa60a06e5fa30766833e51c9d422a4e140b4a674b5139c5772df16027d345be4bf7d5b86b779ac6d2388ee3f8ee5ae2d11899309cb07c2e5b50892203178a10a50651763036218a08ce284351525025065288c11651a208a209145801054a6085139ec0208a132f49c4400a5b4449e2841fbc341183229c012e4669b839dfda1a2eb66334b8fce6b7480c37dadc1d062f471fdcfdf47224dd7de4e518ba4cf66cab6a37fb7ce6c16ebbf56f36bbee8bbef67999ec5915d7501a56e75b32f969d8351ef546c3d750b5f6c37abd62d6cd9b555f6717af684eff1b301405271228829b7dda5846551f37bf6806cab11b0a94b219a75f8d6bddf4f6eaeca66b5bd3d9aded1c46731adba8ea6e9dddd84f6cc56faafaa829abc680f02d86bba140b1bc718a7bb5db9aa9eb0d05a2a169a4abface68bc5e371428b6f3ba625c4cbfeb7b7bd1edb638dcab69f20dbbb4d72bdfd4cdbe6e6885bbbfdbd25c1ef5f62dfb493c5184cde65b0e03c19ac5ee4ee671710de7337d3eb87bcccbb006df9847f5c1f95db1cfcb32dbfe903d7eb67d990c0b87dd1ff67dbdd856dd381dd9a7795d31eacd6cf824bed9b7455f071ccfe635b669798da56b0b4ad1c4c320462cb64e5f071d5e86c5e6b585ba7a010aa8f134b435ebd74187df351e35d75a9927cd46b83b115e7e395cbbad9cb62c8d9cdd3da3a1d956dd685ed716a55133cbb499eb869c830d3538a439e01b6cb801b501e334b5b1a10646b10dd70d3619871c6c6c70d140b77e5d1a04d8c9c139819c387fe38152f55f695e554cd39864c3c54bafc8b7bae2f4cb3696c5f0d29b7177175e7a23705fb14f7bcbaebba3dcc50c7838eeee79e9ddb8bb0b5e7adadd6178e9c5dc7500ca29abba59b3aa765b697ba381661f99d72aebd9bcfe8dcfb34fd7b7ade99771f792fb97bafb8b975ea8ddd6bed13e775bd7cdcfe24f33ebbe3bbbcfb6eac69bcdb7bce26eea6f15bbfb7958756f7c735bdae36f7477195e3a90bbb778e94cdcfda75d696ef6693fb75514e330aadd169a7d623fd8a581ba9a06daae2ba69173b13b53577717c1d0ddbf1d92ec800424e85172018a143226908111204258c10eed06392ce1b4ee60ad926043ca8b1f52cb4a90137eac4b4451b261ca58a0869417304cb4409cd611c30e365d121820e960e48329a4434182e474702404dda7d325d185a612aa19f4881f9a3d901e7edff75f0886611886a1e7793dde87ef9945482336ef077064fcd088cff7e2065ffcf1738022281a19c091933432c3558f6816317296cc9e51fcd0046ddf7ba3550f290c41100cc1300c43107c0fd5430af4de450e90fe3df8ad8a80a2e780ee0e7dbe1f5f0c57455ece9ecfdce039be9f9e59c4080fde497acf2c62e41c993de338ae7afc9de47d2a20553220b98a48f5821b24d0867cd4eac6bb411d81c4f72413c9f7deca6f4ea72f8d4ce19bbe709524fcd37bab234aef7d25d4e7f86e4eab23a595123bdc806f5a25d17937e02bb1c34d183eea77c0d3932bbf215728d49bc8d77937a624a724a747bdb73ac2f49ee9bd3f82fcefc6b42a63783894b367646e20f7fd686e2007fe0e24d4ca6f747f637ad22a09ea95f81bd37b281309f8de7b6692239000df64220193e8fe06f5206a08f051ab2390009f349180fffdb003fef799563aefc6f4a595cebb293db94aa2c40e37a6d77937e493a707513b627e081ff543807f7ad22a494988233728f3883fc2f44790374a4c5164071594b2885f3947b36703b9ef37900b3ffcef77c0f75e4401f99eb40212bea380800f7ee30948126863c40812df838f84f7e11b99c24812dddf88afc4df4cb1537af19120bde9dd34a2c4df88a61124c63799babf01bf64224132757f83c4e8bd6882ef8fc4e8b1a48a06e5e729e12991443745911dce1ef0fdf45e89d09ca2c80e27f89e2704b923613b18130f1db6833581058956ac442820d1c7aaa208a54d2c3a3def4529a08d28e40d4d71f05b89558c80dc8155f001d1942a4ef15dbad2bb4aa5cf358ea68be4ae25ae5dc9fb46a3197eac50842142f9bde7e2106823ea3e197f7f27d94c016dbcf7cf4df13d91c9a7e405308a5c8aa03047230d94de098e454d4626424e240a7945218ca21324858aa0307d66aae849692b8988c620a2f34b11c144d484071727a46cd838738ce24824892511481453365419b07103a81c7995d1abf828c528340a11b1983677028954962f4e64e38638924621cf89370a8542a3d1c370143abfa20b7c65161b286d2dbba2f3fb184123c9f4eea40d0f3c9c4c93e94424d3144ddb8c7337c56bd99145668c20a721edce6f864422914827265419505d809402ca784f8e50401b7f4fc87b4f04a4f740cf8928e5fb183e9637f4bd6d8412830a0a55938fa4620a9a22c5940950618a9294b77b520986f7a2e5bf07e2e26d2ea52c49b6f205c9858b8be822ba88a6cbea7481d256ee4aa1d557eebe9a6f7531d38f05bead8ce2049f9c2058ee764ebe1aa1afc6dd3b59a0fcfef4b17860c5b8c3c53ced482ec62a942d6f2351016dbc1b710bd1c51457b0a08f2516199da4161f0b24ab7c2cd0411692ca69e7f223959332fc582d302f24e999503b484f7a65e9c244edf06ca417abf2e5492a3b5c9e44edf844f1133ff17b406923a98c289dd1dbd62760560eca88397c2cf0012595afe67bf04f48442daa9c929c74a75d38fa703147d23df15f1e2686f702f32fbf03f32f2f0f03f330a61198727706f9eb036d604ea7f7142af5a817987f7189c225c8e50917275f8d0b0f8e50c080e2afefc72ae5eeab6979f04b265f8dcb835f06954f3801c5099254aa9ca0f830a219f3c3cbc3fccecbc39846a610df08ccbfeca8fee55f4c232faf125d3e284e03926f23a994bb55c9a40c7ae263811ecc2ae6fb9755cc0f9fb903f3aadf89f9978ff9971fc1ac5e563018b5b4c45889efa8161717179795edfbd1bb188f9c9f8b21a049e463816215a7011f663522712a6550b9fb58e0c350a1fc769f597e2cef5fde4682795b79960ec6ac542d2defc2e55dfc8bd508b5e3c593a0a983d1a214bf65347a171797158c7781e1e2472e3e07f8c2454b8b49b289ba14cb124ec8d50e460b56710828038eccd0bf2f64113fc7378ab61391cfe59ba1f3afc6bff792387dea93403dcb115390fe88d3a77e443dcb8fa9df397dcadc413d8be9a0cc48faf083a1a240693b914c1b8c16a5e9bf27917e0cbfb43a729246e18f21ea145e81f4186c314517d82bee638531a0c490124328f4cf466513f3fe65cceaf4c9a860f8e7322546cbd0c8e6555a865a865a865a865a86c829315ca6b84c7109824b914b162e4e70a1e2520574a2185b0c141e41a587dae1f67072caca46f29ce6f39ce61b5735a1ef93c5b02206d119a6e38e92346da4ea635e3c55ccab7e27e655aa8f9111f332c40f060c17de069e2eef31de259cf130c458f1d5d8bc28662826068a8b5715b50cc5108a3182184331aa7099428433ac327ecc1fb9f94633e607d5c7fc8eea638ccc7895b9a3fa988f318dc0f02af3c8cd68da6ca6802edee632e5c5dbbc4a0ca1182358c518fa58e19b5631aaf85821e8014932e3617852558121aa7fe187c4bc8c23a6d881e165fc1133cc98f15f78d5bff047c060c680e60f2fbcea634673e7055315b3f3312fc32c7da9745a8defa8130882ff7d0965f2d3842ac9c0d4236356244881b2e549217f0d8136311f8e761ec3057024c9101ca176a074305a94e3dbc627a7115558fef4e0eac8f9b1944ee494927f2c3623ce4fb54abd0b2b1b78c6306de212239795500c215be962655311e10cbf654d8dba8fb51a93ac46241f928f1526d19dc065c26fa209279c80e2fb4c2741f8de8804b409c393ee54458c211433e4aff1c12fb90d39059409ff1b9f9053584c1b899c827a316d33a69c603463862050dabc0a901124baaf060cc7074fe00a0614362f523d51aa3ee66db58f15fe8e59c50c8132e1ab560ecac44039435591d334296de494337c5b0ca1337c72ca57f305a1e8abc9c2095f0d15b20a487adb679aa4f7cf43d22a74f7bc90651ccdd3993a4825a628c6f742d805397150f5812e56e28ef40fb50385ea61fa317437912f7ea7c57450e685c9f23b2e4c7107cab084236a07ca2ce25d81d1a2fc5e7c6f6533a2cae9b178a70f57474e2f757a9695cd86e83c917fea118a42e290284485f2fb91549260bc58792551772a8b4a554aa11594e49f4add57a3a4dc954c524248be1a12797af2774e4f927f1a9d1e651eb91981abd17b93694b519112729a9269237724123209a923957c2c128914720a68e3de67821f89447a1be9d9bc0757a277e4043f07482239bf2f854a9f7805e931d89ccaf93991cd894a9b13799e4a022a274a6f159ebe111565481a99313f944a0eca94764a6f7a9369a4641eb911df513b5442303ed6a762f222834969fb21351e7ce0018807c1c1308667e5707ea215be1316dc5f48409b274a62dc348d4ce16f84f425d3a6f4260f7c710525e94b2c55401bbff93e9584c589894a498b52952db0e0391999361628ceef6d21169c38cd579eb6129512959216a52a1f6955a6c20b90e27bde970241300cc3501445511cc7711cc7a222d514aa297a80017e8f517cf07b88a038c281ca032a0fa83ca0f280ca032a0fa83ca0f280ca032a0fa83cf0810f48d101107cc03f18aa27ca51351a8b9c064c71e0ccc25fe183485e2ce104c1d4d088c47c9185d380424327e8815e28c569c0771d082509a4c760533939bd2755aa099cceef4d432928a621d39069c834447a982aa08da80365bcdfed82825442244c0cca1e2f9c2c59c0a05c024c0925b584d3834105cae9c138711acf0483cae9d94c4361a948e5243441100c4240852015064451850121c076b01d2c88247d7c10fcc071e5d27d2c974e14ff1bb94471248aa24b145dae9d8f28102a91c8d02c4924d1d349a556df8736535c4b50b6d2b39c4e27a934a552a66d872a52494a99a994e8240af18993169b29e1f726d28f503b5c4b3c1adf9756e589441aad3cf3e4a474ed3cd43803d247b44515a70da7479181121e8c60148e503ae4e9792b0fa5138aa2777a1f493a392a875cfdc9c4f2dedb5691c5b47923aa07d38942edf04428a2151f4b24f2ff3efcbe3442ed083d4f6581121624456c020b8a9ca2070c2692741ad0945a893b506674823f7aeff34893df40019348f57013163485d236a36886bf1c5c8d270c15c41109ee372ad50aca10c957634a62d27d354a4a4ffcf5fd690b118998e4e67bf0fb4c26d3b4ed901c57a537adc8ff50a6adc481d213a7119d9c27d326ea482b3149690cb2a7c171e301d0ca698b66213bb2c6352059e31a0ec7ce0d3407a15115d76ebcb10ebc719a51b665b59b6faf665b546f36aba84aa3bd9a96836817bb3b5eaf1d1c36de1b680e0228a7ec0d381461c30d0fb3f112e1de82f266c75dbbad1a2d1c5a37d0b43456a5c92b4635fe8d81e8bc5e3502b881871b3a24c7c68be34472e6e04510e161d51cc63d11445a32b21b3a2465b310d9cbe64d6b592c76f3cfeb9c79e460420e262d8d6b3dbccc41c30e58b8bbdeea2dd7b6caaa676bab9f66b765dbda8f7e35aef1f07287ecf27287191c41c091c48b20f233337b7db59aae6f8b4307070d1da6b46c2cf7e02d7b1e56edc13bc53a94e0062f75488283e82043a76cbee1831b49bcb5ae18ad6d15dfb8e1de826d016603181254ddf8d6ee17b369aeedc07080b1bc865ee90c504e6752f58920d292c904f999348725cbeebb7d70edd997f6c264eb8a71648fd9d7a7bdb1d89505d7065c408a2082e2ff99d225c38613dc8b203253d3b8f64410c16177b3f8a6e21515626304368868fd6a5cbbf36e6f7bebfc16c96e16a2b45163e3e44510f97c6bd1fde21f5abba3b4b981cd90bb1741646646e39fd346dbc05043e4adfdb69fbaedcfacb8377dac6ef567581e56c5f80705d4d4bc0822335fd6b888f152005710c00504e0837b114466d816f77e9a379a67edfeacd916f73358e736158068c3cb1c6a9043922288ccb83f239359b79db17eab7a873d81f0128723b8bb9b5537bf457048000e46709041073724e0061b6a04a108229faa3f43049156cbf3b9758667ad8b7badb2d9c7cd9bc5ac9b7d5a9ef7f1ad34e7d699aa75abdfd6cd3c2c4e65f6dbe69bbadbfd29ce2eab956637df729a5bf5dbaa3ed9c53d8a57dce7cfb59d661f35a3d9cd7a47590303357c6abc1741e475e47ccecd6f919f218248cb07ce10f76dbfdd6dfb69d6f8077f8a6b676943161965b39b69364069d980d32fcea538bb2bfead9636d868e91eb45df76b5cd3c14b1a54d8b7a5e18dd36f713abb6e8b7e3eddfd8697349eb8d9875565b219bca401e42d37ef55a5f9e0258d775b9a4a53379b53f5d9d14b1aa39690bbd3dacfe19f6fd9199c5df67d8d7f3ed7765aba968d968c0f9c21a9ce2e0e486df1b432ab86973455dc4c735b1a9bf3ecb30faee5587cfbb6dda191d2da6cd640bca4016ab16daad59fcfc9ac2b663dfbd3fe6e5937b33f343958f5e6e69dd3cf333d83bbfbf072260b77d73594c534e50c13cf2e4eb6333364c6dddd4ca3bd3314e3f4d3daef41f1fa58e370cdcd4058f565785875bfaddba6dfee566ea9accfafd66a9bdd5cdba9e189bb9bf5fbebaa6efdd9c579f669de2dcb62b4076d57f6fd5cdba90189a76cd6ea6bf56ba8c1dd5b3be7dbef9675db8dd5ada62ac6a5eece0da016078ed70b87ce09798d7fe7068e1b3870c8b06edcd0213774881037e0f06e9d531c3ee038d37c03a8bdd1322f5849d8b97b2baf33ac7958757d312da7b31cbec99ea625c3feb46c0ffbe2328ae2cd6634bbbf757b7b1f38435834ac85b0543fbc9ce18a9656330fcbe24f59dcee1e7dce20c40cab7206173240f196feadf3c6b11b0a247b9a564e9f8755f3ecb54a6bdd947d6fb7765ddb0db4a39481e6ee3a5ecae04200b65006000aee1ec4cb003cd1caaeaa73aa7de00cc933d545f5ecd59f5bf34fbbbf6d83f0b0b886b22ee6c9eeebf7733435f3b0edfa2d8b3e76d5b7480ee2ee3878190096184410430562e001004f00801100b0cbc14b001071f796fab4f669c8b756d300635b75e735b7a61affe468d82d4b8356d797a6fffcd78e1d9d1fad9ce21bdbb66c0fde37fcb7f7a602e15bae6dadf3fa5a65dbfc7aab331910bec9da1faddcba6275bb18e7b69f5bf3ce6b8abe8c47df643fcfc3aa5bd52d2ea7afd57ff66cfd4c9a67568cbf346fb87b8f972b1c94ab28563ee8f072456ae5b08fcfa1b9b6f1b3b907ef75c5336966dfb7b63f4d559fd6c569f575ceb4d6765b5c5ef38ebbffe0e5cbf033665ce1ee2c5ece58c18c22ca193adc7de6250c45804189bba35ec220f3c210ca177a50be7080f2051977dff152c60e4a193b286508b9bb102f6514e1adac710d755f9c0f9c213339163f4dfd99a7c9bbbd6597a6a573a6fd2d6fb5ddac4ad3ca9996d3169b5f34ad1b7048734ed9b3f8ddcc661e5afbe7bf643917aba84acb6c9ec99ea6c5aa3144f66efb33321999568bf5339bcd2e06c2ba6188ecf30c5571b9fdebaa0af12dbd81b28e7fc9b6cea9ec695a3e7086a42cfec16e4a6b7118f5f12f592b7b9a568f56dddf38cf3e876febaafe7cfbb9b6d3ac55b7bdd1da976df5a6aeb11caef1bc2d9bbfdd8f7b7f4676cb5b8dc572a6c99ed6bedb6e34fbbc4ccb728a5355ffe7cca3e50367c8a32a4ddda98b7fdc96c6aa5be7f4f1d3da47f1b33c6a76b34fab578cb6abdef9d6ea77336d5d314eaab641b8795d314e101e55bf403986dd176357eb188a672d8d5563381de351756eababba81d0714387e0dcd02140807660f73db1fb9e5988db6ebcae2d0e4ead69b7adedf7d41965f18a6f5a1a9b83bbe1adf34ddd0172cb5be784b83b7697b917c0dd8b088288bb133184bb136088bb7b262f616e780c1a7077ef85973032cc541d5a2918e1014c7077f0c9053800e4450a886cdcdddbc10144e8ec96a04015eeee2da00933645cf18607dcfdf361c70e4858c00c0bb882bb832e0d9002850804559103771f2500812a1e16af2de47077ef085568c2c8161130828dbb8713908d9ca8d1c0360477f7b098dd0003220c282204778fcdde5a4ce7720f6cab6a9d857c58b8fb0e2f5f9eb8ef36c53d6b8ba399bd359acc93aaee8c86a6a1b1ebee4204e14e6b5b77b7abfe1c5eb38bb3fbbb6571429cf026bce1a18d9046b872f70178e9c210aaae1a4c82e371188dfd64d613807b3cdc5d082f5daab8bb0daebb43f6ec5e5f9d83d070f7168dbbcf3871f71adc9d0667b90c5ec690c2dd0310c389c7400280bb9befee33bc8c41a48c01c4fd85930d2d1b6ab46ad0a0d9675df14dd3c0e1061b6876cd5297eb861a14cd35686e2dda9abdb5adf2e4dcad559eec7acecadd7970f1f11c7bbd6e28509ad3166577e848550c24671e2dad71ea4631eea6e668ea8abbe1fcf3fb9dfd8c4cd67e9a359e3deef6ce1effce3cb94d675a21df7a194eddedfe56aff87556571c0ebf9bd55cd3efe79fcf28abeaddfe78994cf630991a1ee666d547ce3c9e86afe173a6c5d856d5acd7e171ea8eedbcc26470ea66a12b46633afcefbcba2d8fa741e3b3dbb23ceaccd6af2b93c9bef5b9b67958357d5794553f37fb19199cbabf65bfb6d51fd61ba16a9adceae255bdb1af4bb3d9d6a5bd6cc537f745578ce2f5e5c92e9bd916a7eec7eb6bf537aee13d6bbfdd2fcb99165b31abd2649f6b7bc5a97b7d6fafd597c9de5575dbcebedd6fe2d4fd2b7eb7abfa989ff78bbbb5e8b7fbb56cc519a7235357dc56d7f7f639d3fefc299e9b7dfe76ffc6ddf2de7806f7af07eeae7a3952c1dddd73bc2c81dc5ba8aa59d5dd40b9d9e7d9b318dd2c565deca359156fb6c559578c930a61776c360bf181bba143f00dbe5955cc43eb8ca2af9096f6813384559f87556fad4bfb34bf56ffdd5cdbb926c4b77276699fd7195e55ec837f036516bfceebec6dd36ff57a7e4b264bdd16cdeebbd927bf9edd5e56267bacfa7c9a597ccbe5dafe55ddecfb387cd36a0e6ffd3af3a4efecff81f0edd39ce68c026554bd613697eab57537dba22faad9f35b6cf651791e3fab6e36ebcfb36f55fc835fab9f5df5f3ebeed7eaaf6d3b637954fdb9adbaadeae2686a3c6aedf1a76cd699cd1aa3cfaa9f661f37ebecbe56bf75b3110fcb6cfb1b3fabf2e4d9eb15dfdc967db7a5b5f42d6ff5058083000450f32caeed77f3c6d9e5f996fd9fd6e5799d6fafd6f8b310df92e9c85ed6a323c3fabd7d76731b77d37963547d36d7f6cfacf82d923fbbf87546d59455bffdd939dfda6ffb5be3756b57a5a52cfe9916cdb3a7b5efe6d46d9f559f866dd9cfb59d6ff5a0ed3aa391e66017037937e33eb3ede7d9e756b67d16a3bff3c63cd9e5e1c139dfd26b66595c431f880f9c213356d5efc65bc8a76c16d2eeb02a8feaeadcd02129be01ca299ba393e29badde541fdceca32384bbb7bc2487b87f6ef669d62f467f06f7ed7e1eee2ee3fe81a074077d727010a7720779c0b8833b4c53dcfd5f3e7086d000f18133e4795855eb8cb62e10770f80fb374499e6220f4b734dbfb8dffab5bdc63f9fff27b38f1f96dbb85bfe3cfb3d038b51777fc11d3c428d9726186ff1b02a0ed7bae9e7d6cde655d5df7a56fdcc83b5ceb7cf46a8fad5e347ce8f20a710da6da5af57eaeed8cbd2107e83cfb7fb738a5d1edccbc3aaee9b7ec6e5f6f3a834b6c5c96f7e7ff8bc6af6e6b63437e39ecdb59f4ff346330e28b32f0edfd29ce68dd7ecba79b36f8b93baf887fd6975a4794710696681e091aa2bf66173dcbde6258901b959a95432a5796ff5969f88cfb59d52a964da6cf6d9e1ee372f492ca552c9d4d26a6d3fad2d954a26191a9a466f36fb641a1a6d531a56c5371aadda6a69b44d69d07869dcde355611ba866e8cd36a4ac4dfdaad5f9c52a964da715bd7dd01e429778fc7dd63f0729cc2bd258b6df475b7665b54f6edfe34a729fe3d03abf1cfc6b5fd9ac5f9f6b975c5af7e5fabb59d5fb1ea7faeed947d5bdae71b66bffdf18ac57ee8e40809b22388d88e1e67109d1d21b1d88b86060d1bd46636b35183468d1bb00d3638a039a438e090830d1bb20d4dded8dd7af66a1a7abf6d0f9a6b288dadf2d0687902ecfafab039679a73b63fd2bcdb1fad772878a62a4e05d1dd572fa988029b7b503c63d51a8a6f3479e3ad69e8eca36ef5a6ba387717bda4420654387107c06ffcff93591e56c52f980115a20b75a0a5b77a5371722cf6d1b63b78f6ea1c6e4ddb9b87e00330dcbd09081c0002a07fe9ac6ef59970252e0110c4e0be81320d765f0c8292fb6ab5e2ac1f0779cf5769b19d75cab6b3580edd59e3d866f366d558103de0b08f9cdd9d1b9a298af02f36ff4b8a17c4345e571cd33816ab6df5e7860ec1f13337dc96c7ba629c15e3bc5ea6546d8378bd5eaf588ccd69aad6622a0ec770faf5a2ad59e378bd70a0ea3a7b81e07067bbf37ac5f01a3f76dff306765f8c43e6676ec0e165b9ad0de7b4c5c9b31cf6b159fcb3559b9bd39c1f3d6efbb3339b6f981dc0ce3c2edef986d9585edfb4bda5acda13735b56bdc5f2c62e1a63d55b4b63736ee81037f7e0c0b1ae1867e71e54dd5bb7b7d8c6b11810bee99c691a08df54b5878ccbed988fca93aab16c84aa6340f876438170b0ad9a7303cd41e0e073e3860e79bd6ef061555cc3b9bd6c2c162b724b2fb06b5d60887beb7df6bc800d505069a150ecf0a750b8ed0cd340f1e284c8dd719f57b5f6f3a71320272faeb73a536bad8bb30014f7d7d56dcd02bbf6870580b8b7d2dcaab63f2c50a30245cebeeeb75bfdd1eaf3b878fd59bbce70afae0006dc0875c7c53f3820d216c51beba8408a025128f0000a14a1c08a029e9e49cf8d53f7133578e2a7256b6b3fb2cfcd6672a6cdc84e207c4bd976f6440e32ac57571e2f27208209ec4ca0746fe5f04fcbba9927cdbff1d9caeecbc3a3d6340fabb2eceb6a55ef96657d4e550964e1de9abd04641278c109226fc9340eabfa90a99fb2ed671f9cd7acc389d60956d014f79696c9bedd6c7b934371f2ec6566acec836b3298d5d2b158cab6b3548d05e1dcdd838004d9e0aed520f79d733a723e0259b83b101120f29d080865f5e666201140e25e8b80ccf3c6a99ab2187dfcbb652360e3ceaeaf0f9bf32cd640fc64b6c90d9a3071f7d4cb2636c8b69a6fb716cdeee7f06d63f44db30b011a40800a77cf5e42c00777999b6bdb7d69b8d64d370d33c9019328dc7dbf2d8d561026350fa8c1038cb87b4bb6f6e0dbd7785afbe7b7d896a77571efe6ad31cdcd3fedfa67ab86629c7ec0cb033e77a779e98027dc65edfe746d774a6b1d4043d9840d9a48e2de92e5d6ada2ea8a03ca9fe6f0ade599611fad7c7b35bee558bcc3c2147642bbd88eb4f31ab082062cd1000234c086cebf642d7c933dcde7d61b3aa485c3b77fc9644ff3d2addc83b7ec69f412202c59c192b58537d621cbaefa9359d9d304c1b55b7ffea7b54b6a60800f5a321cd96b8d717a86191f3843b49034ebd76d5d37e7f09a836c1cdb6cd6386a1af350d3b8c68021ad99aa3f080fcf9e0cb0c1806700beb92d4dc9939612243dedfbc019a22487bb2b61b92b29bd856f1640c5dd5b29be5900912fc000ee9e379034e7f542b3cfeb956e1dc3e9589af51be361d5342755634c486162d76222877b2b65f11255f4123adf5942085fe2c57fe08d75a438f390e25ce361b7ad1b8b6d36bb1817cb46a83ae6d3e26240f8a663d2f2813344574497c35b9d7bebdd6cbeb53e5eaf9d9f9655c00e0aa0a1440f945880124128c123092b24d18224d6248468b5643beb989bd794c5b5cf31b6957deec1fbf502225575c89ed6b2be06dbaa3232991a33d9ce42581d19eb659bcd6eaeb139b2b455dd0ce4f6de5456f521cbcd7e56cb1ad77046a88faa2cc6e5bc9b7169ee697d5835dfd4cdc3aa3cac5ad3988775c53849d836df5a9d442809123f9300717f7992905af64c8090bbfba6a9e99f0990c1de3601a5b772f827f7331affb43f1020c55b08d8fdb4ebcf0e026cb8ab5a0701246f6999ecb637d6e7588ce3e5018666bf6760b7fa309dd5032039000f3f99768097d6c61b23a1e22db7fd1b769094606b75ddc181e3f5dac191e620a104244e80c46a2407463060a40823260344c1005418c088017230c01bb104239818812357254745ce488e059403201800f900d5f073e5a7053fabbb7e1abe865777a6a9ebebade2cf6fde78bfb7af212384a75d593a32d66f37d7501767fd3917b32a9b571aa03dc410329975c55fc30b61e9c864b219b755653d3a59ab3f6eae6d9d6fc96ac8b2faf8f58c2c966559bfdfeeb7cdb140e45b2b44ab39bfae1965ddf635cab639df92b9ed46310faddf15f733aa2c6b7c23fb57cbadf1344f6b314dfdad558c7d86f091e153be507873f052f166e0f57903b0798081724b60f3ec1c3d05dd03ad007d83f65c29dc3d655f5a0ef233453c113ff34af1bf843c4dabc6bf7468e43c4d2bb33ab45686cf2b6e71ad8b9b910901c23e64381c465b2f1352dbedec6766b4c63897866d81789a564de35a4de35a6cc5acdfb2a761312a7b9a16dbe6d893866d7f868755d78cb218c755b9a5224c281245119f223b4560e060802bb2ae18e7f5bb02799accb63ffe75a3e369703e65f1105fc30fc1d269edf55db18ffa16c9afd56f6d8c535d8c6b6b3f2fe3665656dd36e6e6dafebcf2b0aa7e4c83d37cbbe5b82d8e1308fbf8991b680ee246afd807470fdaae373736abb6b87c5377d85cfbc9d9a5dd5a97a663ed6e8364dafdb63ced8bbbb7b46e5777bfac8e1dbfdfd98f6e6b3fec94964cda6ed607b1449c7d718382cbedbc6256e5d1625b34bfc63f426e402d19b7557d702dcfb47abb0169dbaccf9b7b4b46e39fb56875e22bce6df5e5e53ac457d60f8d9e2a4e935ddc8dbbd7e0650f140d847de834df30fba30789e7f54d730dd53e7ff60071576b41f4c8d0c67e329bb34b8bfd64b6adfdac6d3b7bbd7670ecdca0e9e0de9eb6f5419d81ca01d555636a56d49aa8f5e0d182a7083c58f0e878501e9216039a046841d05c72917beb76a3e35b36e7b6b77c7b56d5799a7f16fff4b8edcfc76429fbae78eb57879b797854770789fd6436c6b6afd74ffec1eafcafab4acbb357d3df4ff3dfca6d15e8f13bcbe19f15c7588cc6644ff3ff0ad27a1f88cdad69c6394fd3ca427ebf38567533ae9d5931aa6ed5457fb7acde6cbebd3c2ed6f1342db795c966667065a9fa1651d72c4546e2ad1d1d9d2038ad8cce1e03913f9d426a8474d74adbdace3700acb75d6bb5feb559fc936fea0e80cbd5cab59e2264447cae95a815540ad4083486190e66069809990160f602bb00f7e0173215c88c00e0bfb5b5abea19dcacdf1467f7b77e07f0df92c9afbb598fcbb9e7f366b18bdf198df3fa1bef9c4cd62ba6b134aee9947d69bfaeb275c5319cd7b6a569d1549c8ab65ae8ce3fa367b49b732ccecd302ebbb8b7cdcda83d8fb73b2323cbafbb65d9475d710c97738f8cf53af7c4f23ac3b1c7e86665a99894d802623b14a04a01b0f0966cb7ad2b7badcac832cab63f583fb36275b3796b1528ffb4abfb93d3525d5cebe270f86564392bdeed8e2caf78b7ebaab6d29c5d1e325c80240a7043015845eca095c3ab9b7d5a354d3116f2342dd47d5bbd713332d96b8c817604d16cab71767bd0d60754ab37361bd1bab458ceb49c5d9a9b7382a46a1142b8e3d0405eaf9d1b40ed4d4ce39a1a2f9a83006a6fd615a3447c202200222f108941c411bc25c3d238f67ab53436e7f5daf91a64d947ddd84775732ac4d3b4646e747c66759ea6a5539cdda769c9d460e93c4d4b67227820821cc20943040d9183005120001402f4d87849801cbc1593cd5e1d4b339eb9a1060d406435621acb681a36b7e2709a6dd5df2cfef9f4df3697036a5d9cec37fab6399a1cfb6a36bf6dee6939df6add726c9bbe59e33ecd39181285bbf7e0e510020c61792bb6db3648ecf34cabb95cdb5bb32a7e215a217258554c43f16c5ddbb5adfddcda8d832822002f83b8b167605b2dcb3deaca0201441340e058c20e057678c8e1e50e49480d840009a121880e826c20884e86f3eb9ae25bbbe29f91e5d4d08d6f64b9b671af8b59fc33edceb7b6bebda8aba2ac8a2383c3d2e1a1f1cdebf57ac9302e377badd5da0eeb7958956dddd72a2da72583374ef1ceb76755562ccdb27f6d167ffeddb2b2a76901e51ceba3456b678f83d8706fddd4d7336cf55bfd33d9475db3fe5cee214899cb3d417e28d291f3ed8f1fa0b41ea7d6f40f3aadaa68ebe26f7f0059029016005102880c880c9d2c74a0d0a9b9cf3cadd5fba75dd7b325d3b9dcf32306e58f0afc407fbc7c14c1870a7ca83e5cf8a0021f18e003112e7333fba393cb3dc8fe95aa9fcb3d2f9db7ea0a31d3f134b21999cee51e3650fe21fb19194d27cd09e2f5da91fd4ba7380799e9789a569a81541a4ba76a2c977b5e2f9dcb3dbc5e3bb89c9edfd2199763d597c9d4c0799a564de3ad3fb76e34bbaa8c9bd7b575f166bd9ba6f8f50cac8a6b3a72b0daa27996856c34d36879cfe06a562ef7bc0eb2e29cdb6e9cb2f8b6e3b6ae9b5b1a9ba3c3cd299b75fa7aedd434e6e1f5daa9695c23f21e9c78c6e170ed599d1e90e0f0cfd9c31077f435fe397b60b9bb9f3d905eb2013cc91a6717cde94fbbae034832801cf967e7199a71fa860790f384c77d716ca6615bf6c6cb9c1e605ee694eede0ac26ddd1647f63cacbaae185577b4368add0d9477f09207226fdd5a94866dd95445d557480e352f8efcae38885cee21a72d8a23977bc8e59e920720ee5bbde51e56e80145d903891e3670daf4f7dbf638390f09f0f08107c9dd5bd87d51d4cd29fbbecee59ed9abdfddb641dccf423c0d34d040430b48a56517a7b78bb7cee59ec7ebaaf65084c3cb1d4cdc7138d75ecfb0d97c635b57f561f3e7d6d92d6b7dceb2109907e376cc76f0e02e93a9d1ea71f12dbbb907fb7077d24b1d3fd021850e02e8d0d1b143a903061d2d385070368e0de70777a771e301b0ae2fedb19add2dc4b7726ef649d9dcca3c6a2a934173daa2accf5b757f6a3c4d4b26fba89a7dadfeeb856af5f67ab56a0ca765afd715a3ac97c90861e9c8fe55e369623beb188b51d9d380644264b29cb6686df3b0797d198eece7653242be86c761e904a76da8144faea74d4f3aa568460001000063130020301c128b064432a15490c3d0e30314000783b25a78509b08e32c08620a19a308210300220000001049c20400d9e9a42895a86d337f5a41d6a43b8c64caec4987fdc0d452c45570227eaadb371722c2bedeb4135736c4feab66d5f34525551218d6eed6478efce9c98fc7ab8fffa6324fdb57bd7367c3de1126f75178eae9a36a980bb60e63f2d6802a9f2823c65487b8664b4f8ee7a0dc88a14af2ffb880209bbfffa13e42ddf2d609975aa1ec75f19aecb17e3edce83287d6de7b1490111419f15d56fbfa8405cbd4e3e082c440587c2450361328278d6c7b5b4c1dcaedaf641c07b06d28c9a12a88cf066fe0818d46be6eccc4b36146028b145e79b9041b96226955c798b20e3814c5303192fc5903a9186f155f2f59ad9d4910f367a2b767fdeb26e32276bc99a0c114722be212b4e748ddfe28e38f22a98773988a36df09dcff69fb23800a9a85f22f484a8392898d2b8bfe6e70401bf08785a1a6fa50bcfc28110f43c022c3909dab627ebd18cc5dc4490f40a675f1daa73e304c91b31ed1c38f13b0dcbe639715e5bd27e127a1bb34869a35a26bd54f00ad7203b0c230adf1affdd07a8c98e64a8dfe68616a9e52b4d305dbd76b082e705d663b968ea53bbdc041b0501ca2d1afd82516c976c5f146e9a5866135a68f5c0d0478ec5694271754a01fc5c623d30159d1ac49d803ad375991d22783660b9de62a1ab8247cacb8b519224a272cc73b8c099092a388aaf87731b4ba6af3107eef298cdecbfc8110017d33df388c58f1cd20e0e963d31f89e93fc4516481d0f34795477041cfff534e96a6cc77ff74ad8b1401d2e2951073008e61b4f03f422b5e3076aca0cec7e94add0bc4c3b3ee2e698c721b6dcf621936a438756c00236c2069cbc3b8bb8330a6eb64cbe056cbfe87f29ab4ef45915f38ca8b630d1fa1bef84a47f141bb7686cee0666fffe49df7e01fbe1b26d25449dda9e6623299a406d77e0872087b029c03ac3fc882d0f8a7f4c741876242e22c7b9fb6fd493e0305fd0a4ae7f43a46de745f32037c3a2e88c2df36268b7015771b1df2bd2467602bbd8bb1b371557aa95270dc5aa14a98a5ff22623af3ed6c412ee93d7dd136f3f43e0383502c2505a9ac13d6167668e302ee6306d3f800d6f24e4f1ed93ea44f3a6dc135d3285d68fae3ea893bbd31f3a6e9b5878e1dbb09e0568adf08d2d2c2ae395b512256b40e56e5d0aefc3a324d35106abe38cbe55b81ec667d88de5542e0e7fb55fc3da48ef072d645ecb58819bdeb2ea7c6d1a6d17afcdf61cf46ceb2f99406df5db8acfa592749a6225cfb49cad436bdd06335bf78a5538c1014d0b827b74822349fba0438ddcb0d8a34b14e9664d6da6b103b1deb35ef1c54906f03c623fba2c6c974f54039804692ff8457a57bbd46bcc8f5995fb0ca260f75fc19846b2eaace17fd727ab99e89406c63dd2e293861e2a1c01a4264bc266a66b48e40c7806e675a52fb666e57de634e721f046661eba6d2668fe99f3df01dfaaeb3d5d1aef506d3a3b1b0b7bba698331f618c7996c20606bd7cf13a677642a42fa72803c90c3204c83ad20ec608a88040bdc48377a3732d7ef7c454eae6a6d2c76f3e25a0d4edd44f3971f4c9e0a3ab581d74a6d58a2cbef14d2380fed09c0c92d38727f0a35af2ede738820b98cd743b44aa39b86a1584d637ba8048a74e6fd5843ba5a46d867171a6ef437f5d6f7a4fb84d08888f9181f5d97455ff84e89e69e23d7b0f425156dc91479f29fea51d3accb3dcccd6c8ea592db23f2860eeba6612ce39a55732a7cb27488f20e6a99d62f9151001515da404dbc45b6cd3b46fd85e4ddf24db5cdcf89e1a9746db35fa7f9379c82cf766c1a78fe485454fd7c99cce7b3926e3a7846a279024dcb4dba8933153784980c1a6210e38611553b36ddb6585c8b5bc7e554cf6e7d37ede42305636208cd3a82fe876b828b36368993e59a522176a4a97d104fadc920e4683035cdf6910f25e6e7dd608a628482b3d5339efb947260a1e9e75673030dc8de461bee41729a5987946c4a458351c4a85073ec3e4c2d78295136a18570f89051d3246f025734f6e53927fe44565edf4ff8783583dce0451918b64111e643c6d50ce32992321993248da0b8f6f6e82fa37a9272316627cbbdd6768c318f724cfae772b61ce077b7430fe29749b2b48ad40cc47b613991d4290310f20f1efc0fc1b8a38eb10416d98e3cacc423e8003e5aed8bfc438360326710f5e3ffd294870e9f4680607644046b3b7361edb1e9bbe00d26168e0a423191986c7048e07b1a6d10c390254f6b8e33cf9cfca2746982e5523458e1cb308bfe0d09ff7a2ba0589d6ca8e754e02ec14a15d1f8e2d5eff1c1f1ec3be1d1f9131d41e1b582dc50ff79d721b2b62053100ee621a57c44ce5e4a2825dce908198315c389d815789c66a84fef7c6c24dda39dbb011a36b78be7f9f092aa4311f94941ab85a009961cca9bac01c7c0d13216e356083db14bf04f1cb106720df82ea4b7ef09d84bb11b3ffbd142f388e8f718654d79ed23049610c1d3f17f917bd4f3f2c33bb9e5c567bfb7402f02366d229f9d20ff5855faebf72d7053cef8576958149e1d4105f9bd6d77ab62b8f533afb0aa6e1736a6aada7e470a11710045355126c10d1b6865264602e6f04054c1ea2ec2892038972b88ad2e68b12440349a75923178ecc31d884ec9f20cbc6f140c69431728ca9c42b7d3f13bf7024021951a375f5b57f48c851af62dd0b66462a5b61cf0ebb8c1dc44e0b378eba5a90e5965580665f83b83400e4591e5d0a464bdb672f6188fe8193aabff2ae5beff8ae091c244f9b3320be4f303a902d15ee53cca2915e50e733fcdfe7c74d5f18126649fbff61b274aade3731a0c8cfc5f449a85d1e74f341e16ee2d7a289924f6915acae02392c659c5353249e9b94ab147c35f8d19a9fcbf4ccf4176e47f2ab9fa37459ac81d81f29d0080faf8ccee983eeae1b8abeaeb3cf2ee1859c7d1037619fc4ef95ccbfd963067917eb6563da1c8200a5e012d92a0c2a78e4717bead9cda1c434c06e0e603daf0d30e8784c9cd2b1ce4ac14c72729e00b512e902e910494ac7f54a5ba0f9d2e50c000a5ece98534eee5db161045a8fbee6e0bcd2cb8b381d4a79541d02a7bb6b1af11bcaddc1643fe6879a53ca5f117ea977b5d049818c070ce739fe162e77e175b7296d9fd27ed8b6e170832bfc106888634847f1969d7c0a0e388c7b56f9a22f0f64475517a0dfab12519483efb113c4e8be78b5b8b0d671adc685bedac5b606ba24e879ff0f0d6e45638cbd8f07fb204ddacbf1a896cf0644c5af38517209ed04f6a30f699cff352ea838178dd443f04fdd1e57b0c7768db65fbc8f87174290b88704138c91f325590a0e619bf4063c6b8a662660060b4ed4fbd22afcad301f04626e9fe5f81698bd6e65ffbae1593bbe40e7b0f8e86da0300d01f1d7022c27efef87cf41de675f8ad88bf2320a1656b8beb04137cfc98f2c3e80dc2b02c5f09316ee2a23cb1c44a2428757e8ee979ef19c9eb985bd62c5e633adcf85219fca78db2c41ae945ac4125c818ac5e494c1c78992b129471ce6ec2b7529ce35c749e6c68484900e99ae27f65df823c95905d72bb51cf1509d5fce3bb875ba043d3210afd3a9deb077d12f1d55d79d596cd7553334c0215049d2615d8add592f4a5736918f65b6b4f13b8bdbb39da76c169740e39f49a27bde4340253d9288fa6a7a05fd1abb041961384c761fa3f287b6a591ea95a4eaadcf516dd85bffd4e0cadd69d5e1d1571e62a95f3fdbb79a3d6b9972e15ce8a68d76bbdcefef840d7682d1114e6a70dfc507f8b785974b3bf89fd1fc0cb02f6af4d67d79ac367d388aa66279004c1f222d43efb323ba6e88d237f3f7e63ea347eac5f99c24c46ac690131848de30f6b6a6e44d02dab81a1f9a8ad006944b51fc485f32f4bf93f62a197b745959810239580032011ebf7ad58b68a49be9dfcbcf01b83257575293d31ee5abab115bdb2c970a9ff32d0c95a1a5d359eb25c5aed617f0122896c18695ab2ce03af7972b56a7aa10d004636656e9e41c3a03fb839fffe2101f88f7294b775d9f7880958ec81d94a55bd019b1e1037729d369d5e54c021275c170b0fe97015c6a09c4127a218f90f7181bafd77e2de48f9145cf9a92ebb3e22dfa7e979d69b15a7d758a46bc0f40fd0b989b32f20303af19e64da5ddf4300316bd982e4280247ac383ec1b055e64f67d80b393ec73cc4dbd392f45165c599c8c3be6c77c908a5f59bd2d5e5b12a7ee021d90a0cf4aec0aa63633c27763666aa61ce4e0725374e699174cf688e836c8277d17db69d9b25b9386b408361bdb53eccb242545b987031e4d165b21f131c048ff047ae427f05c028d7df102886b05195a646c9e21237847c8d1377f8a8608627946146b474fa2b7d91db0c72c830d370b03eccdadaa7e3ce4b384649cf256d117dc4418a65fb91ce8e3e5a434c12278537d114f6094b95656abdca0967793fbaa24e3d0c175bbc097c32ad31c8b9166e0ae9d95876921364d4de0cb1034daa69add013e650d1f93407bbaade5637dac52278850b5a09a256dba037135432a260456d97b7ce361aea857e6b3e983ff2a2e6fc62160d9ad83c71ab8a8b94c298cfae9e6c90024d86c985e6f3c2fb7eb5282978e92f0a3829c1a39f74b17daab311b756302f8267d44bed325441c826451baa920d08c24d8844afcd2506222e56c9820edc6beb6b6965bc816363ea78c45d1ac21aa272360fefabf53a06944bde8e7065b690bafa01c718f9dad8cb06a6a31290a5d1f1d4a8637577c15fa61f0ed1bedbf98ff41fb3a8a7f2bc63b023c15c14eeebc77b16899e50c851f66f34150edbef36a775f08da3f0cba5e50587ad923840fa879136beb8ef00e3e05812424eda7c18cf93310400ec1d9f25d65aa0244a901aca2917c567674ad69796a4fdd5ca7495a7fc225cb823d1420a456bb3ec8705014319a3a5a6fd36cd93c6f2e9bbb128c2e0bd99dc731a37a2ee2e57a80dc1867fa4ae46ece2f9759e1da3fba19499176b5e849a5aab67fe82b0a679777189e6841d09aaa6b4db530bc7219b053ac88a567f0059ea9e37985ec0972f039ca35014fd70a73e5b179072368560f8f553d6ccc8c52cb55061324cd591817b338283f131e4d2f5873931878b40a9d917c4b7f5c9ad7361632e27e726f37e397497b4d9b6203240bb8acefc890e9bed00374b5ee49ac0f3d55fcf3bfd0f5277f40e17bfc9be5a13900b92f30e80745095bb5c0273a1c7b705a6386fc7aef7bb69ef72df6e1c22d8280bd4791be6d98eb219a638e2b8d8b784354f6153ace317e873e113f595a24db1970837e42e851ed25ab1a2aaf2aec1505d8a755f3c8c18fe931b54ae03d0b32e159264d09fb831eb58b1ec13054565e278009cab7bac51bf3d85cd653b21e7bf462d1fbecea211e513a39bb4ce19fabdf6f51a863051bff0aaa60990583b23f4c452817b1849049554b62281b96fe4515d2b6a078c4a2737148f212f0e810a1755b17e34a21159935e8689ecfcd37ef79a7c86218cba05e9ff814bdde0fcedf798139d908ed5322e37c5336eef197b014577c589674e4e295746b96b988bd24da9c16f20221f916e1d83482fc0e1521f236d02b791f3d0f7f8a192930e65171292f028128e91f947ae828d6d7a70c2f07fb2dbfe7eee6363415f96d9a6e1f713f5ca72711fa061ba5df221cfd6706761d0cd1308c2f15ed0b80454fa2fc90d940e322c7c710dbb1fd0b0b2a94a0d3cee637e0b86032660256aca9298462af3ad0f28292b63401ec19bf7e0b8180ab330ed4716486c8a70d4c05cf9ee5a5e9d6a31d7cf4f74a96ec83de1ce1031c76d6a2d19d53cb324b6031996985f3111e0c5db92bd061d09c9c9e3a707f4d55ca8b766683f27068ae8d0786f366bcd55ff7c8d901cae11b70e0f8721d66a580df6be739d951f5bda05e4ff17859de2e74c0a48fdcaf12f69fc3c23d38e8cd636b76e49fb7e2ba41bd236c4f9017931917027e68c5ef88e973db3b4a711e4e5983de3946b2e1f1f9d150b773e0ba682dd8bc1ca8dc8101c7558dbc1b7f5f8ea7bfbd72711fcdc8d7bbdc16856fac334c41e3b6bdde7be625555ce5d45072edadbc4dd151f177680bf355917c92ca035a80ab1b17d1e02a00132c30c29703478d60160add36c8d4890ed40fcb256a915e530e0c11dd372a06396ce98b591537b0dc884c2a5bd2a4bfe3f91fd609eaf51612144283f38e5ad8a61ecd81932d298ffe153a9b0ba786b7ac506a34bf69616a32633ac0605c574f70292ef227031a2f1c2caf95762cb9a327b17326f3267dd0f521f5a4882922150f4484e4810a60dd970719d46c66e30a27c73a6f9a0cc17844c8213b2d2cefc094b5ef753645bdd24130fee850b8084019d249053804b0a36f9087f6f34a93d670595dccecb6db9d45f2852cdbdeafca88eadbb7cc5e8d9ecb646ad6f3e4f326be977c868a3c516b6efb21ebe0d612e5fb92e4eab27108c610ae55968b4fba63a22f3dfcb71925011dea76eb101e00ab4dd4bf743e35046d72e5bec49790cf2ffede7ae1f3c5346e8e2bd3827ca172c0cb9084d10efe081fcffcf00e301e8cffa7bf7d4d172a92cf41ea7e9f475abd9e85293e95b45ff7992b6b76409892742d26aaeea08700c821f2e1f98097a05543b1371e9061993cb75364a638e7a7410c7b0269f340e48cd2853925bc2bd13ca0a2556c52d1136a8e6658b8c3cc2e3acbcaa91cbe60d7cd218573a82ae072666f0b5e94b485e073dbd5a9804dabb1485d38a2e7af1e1cd6fd832e096de2009ba4de697ac35d6f4ab6b387f0bf56b54fc91a26944d5c5c80511249daac2388085c46811295e7049a1ce4867e39570c7eef9c53386621771bab8665dd51a512863873fa4d904063e7adc8c6c6b8d286c5b549c066eccb5dfc7cafbd3cbe02f2ae433f574e8468c22954ac635f97d2db417f4731ecaddbcc62f84e8b424f19c806641028c84473c2e5c38455bdcb46fff4c26db1c1bbe1064e776e4818b99ffcefa3b4b78cf7c7028d12e21e2589c03a2a34cfdb4ab2a28c8b05b4827e0064f2978b97f2fa76e84b226fa2795626f444e73b6a24c18d7378fe3cdef915160e7d650734b41f70edc132eb0de844832d6ab2e2a3c041dc364f90dea829b360b55486e66d8a7dc02bf743a2f1d82f0e8512a24168d00945f011097cbc62c30224e2f755123848a43f9aeccf0c5bc108b4adca3588007aa430fcafe4734e41a6048b9355ec154e47b00825de303422e727be3dd43a21b0be7b82743c1864eeb65c0cefc53631e25d0cf3286ad8cae05ec0d0afe588e700920bff7456ae22c3598065b99535fd0273bc2dd11e87c87ea33f88f9de077ffb6dc4925dddfa5c406543914ff67cc7e7a7da7dec4f3dbcfc91344b1246f7b5a43c80b8bf79e652c9f7552bff8fc12aa56df8d8a533bbf80717803ecbcb1ea988f27a4eb4f146ac200b04a38e86dff8d7648327aa1aef02d36ba58d7a9738a275ed0cc1b3e6b295d202e664ef29f39820b438475ce68586c6624e88f2884d4b2c3e77c348a9d10c6c189393ce6774334b510518e51f4270b2cadc2aed2d76fe7dbab0770f54adacb1d65ae6a3afb0ec4768ca0a2e9f446f3185f549b5f70970a8fe5a1de2cb008f5d372db39cf108bf7aada4abba6b66d26ced2081416a155cc08524c70fc4cf2b8906e3d8fdc6b1869bb92284f7b98814fc9dc5463edb2c2d2a77abb3f1e2af39e9835cf97def6fd871b53dd770ef75f348d2124c4957d4b23cb4b35865301015bf681cf99919fe3f0ea6941e5fa158f9da2a6faefcce9f563ee227e8b31ef5edc9fc1e8da564930d6b02495c17c3e7b8826cfe71cb7302ae83fe23d6b66f9d708d531d77b1595754702dd4f86af06f55786dbbabcf83f74ec9bb5f56e9e40d291a6f0d33318426234fd7817946d8dcc884f48a39502a0edefdd35c41b81c385b6c0be4fd7505197fa18e14b21c9cfaff74c82afc84900fbe21d65dfc04bed6fc42a3dc0ec67921952cecca01aca3f9e32b6f0448dfd5059452a5c7011d8e8c65b9247e537c305fe83e8c95de1006a9dec5e3c70548e0cd1ffa5921321ae4a108a9c594cbdcb90df4e2852baa83b00b5015c5f6a10e30f92accf511d896a12d76649d0f9545624a204dce1de4183b18879477e43309c69f29deb3bfe42dc6c09780890472faf83e595d58566443b679602ba8d061839d5dc086967bf28b93e1351d0f681ad2eb6dfc879327e945162d35d5ec33829509e163bd26a4cc529d849d137a3e692207e02ca42631a00d84ad7b981687252ddebba9eaca148df397b91e37ffec930b0e6c43e6a407ceefb40bafca3d80c2f595c927c23621d5a762702d519e88158e81f2538a89a7110e2b1b489deb2b6d82d0f558245a7619e80de47303f06f2e235414f62e260aaf7033390be4e8c5e8352c8c8716d75974660d7338c26e450edbf3f1d07794027687b5e131798564966d996bd9c7da95a01cf91c9887451708ce22126df72785eea47643689dad02c2aa5caa83455e67de6031558e311a1ffe4f330c820b91f921b12bcde8cfac0e4330f2c01b459cb7b530437896a0303266b45c49f1fdbabea0858b0c228a05754244a5bbc9c9e296789b72c8127461bb89c43b3d7bf06b07e09703686e1eea53deef9f94f9431f13dee73cc3c1084d41a7301afbed1294beb7a80695e72e4c01fd43ee4cd430f3a0c3c31c42ebbe1d8e7b74489e8f16c7b9bf48afe0b0579aabd149defde684193623c5c0232347081c48b9baa3f2f1e5c490a712bb0a7371bc1ebc9b89108cfa863aa3a4e9905e7447a413238c3bcdd0717d4dbb577ca5bc446a1163f9a3b5b5cfdb6ebb8a6b7269af03cc8ee6ca8f5c24c37e9d0e543d843f79df8e13422a6272f16e9a05f778d672a9ba66784f6ebe74264d4d97a0a0dc091e3bcddf96a28699af17d9251552b0565aed5e0bed10171404584fe37478f82b4b6c7eb53346af83fb3a6802ec10a153f63a89c39c37567b40bda5807677c76d411a1629031dc76e1fc0a3f060e5ed8adf70486766a246a7e3db4f252978d56e70bac5210639d223925acd7e1d52e5ae996e0e746b478047a3782efcf439838fc6c84d847d3106c4a7801f544f51d1aaaac9158b4bc54d09707d90a57caaa6d6e0f2b70000bc179e1ec550dffa34ee5bb83b3238ee680ae339907b059a18d73a7883e4ca9d44fbba6f725bd154ab8beda6a20d08a70d8470df97c1d195720b7437a7a1c62b7691bf31d5c0a85d2832a26758192011b26336f95b26025d4fd2e4e3f38c48fbd2c0029bbe4fa6598ae5dd295e7c84c08614395b1a10213bc608810fa2db5de7d0704e38eef1a413bf366b94563e83ef63247412bbe8962f3a69bf8c6181bc38fbc3e7173ec5c64e3b3f5d0980703f931a573150bc883103739e70802b70d1873f508a82427aecbe0140303eff9b20f8e2b9b08e16b6925014210d8840f4b988107be3069230aebcd6f5c0ba96f7df77f7b50e469a15836d2d7dbea5aeeb36f24a119eaddf79040654e488722ff2badc7d5e4dd5e15623fd3a57555d806713e801095d17386c7b099cf82dfa297b5c0b8c551bf7c53e0eedee6a4fd8068a5dd6993ec320dc270d48c7aeeb916cedb3d5e4c7199f609a1ae87276e910542084eecdde5eab33a1fb456c1e60370cca505969efdf0356ab969549483cdd4213fa1add40f96ea381d14c109858f2badfde1abe53f51ec76102d689bbd4ff17e1ee6d0b582e0c48bfee508c6707e79edf7dfbaa50f4f82e8a0d92c97df26cbd3b5e0801ce439cff41fdffc79260d87669445ea62543ab2a33af525ed520dc993af52d7ca1f49e166d82f5d4e08181e084ecb2359ab0f801777ce2860d557c4b86abc1dbdca010c9e95bfc854688077a1dbbe5bc077099cf5ee1b3c49d36c8714eaeca37cdbaf25906824163d69918060bc79e6881302e41c5d50156da453ea213f564e8e3a329949db33a319311d7f87813baeb0bbb0114d92e87bf61fe7ec6583df290b746104f6f76fc98b6b94a7c15fa02cff111efba69dc73783aa8b85ad3e753a1ad133bef583981c5a3ab7b23e325329ce81066840751389c053f99acd4116169edd8021a04ffe86140ff583f7bdd6dfeebda7dfaff17a2b39b6c9b87505585b59d408278b42f44f557bed71c0bf45bb6b304547b26001bf19c19c6af58535ae15d82ca566b5eb029f62207b147283bfade0f8dd1536840dde6b8007d3e707d1ee57f34ab4ad3cbf867a399a1327927ea04c27ecdf774a57680c5aabf1010083eb354a30fd0b5e3829eaf6e1a005f16d5fcaca13481631d52d87901cafb043c4062718a306797c883e5c99e597ca0599f083502e021700334d7d55a1a71d9724d1f92dd41a88940419b1697785b44a17341c2956563d6caa167096799026fc01e5059d1e4f5a3e4ffeaf3189882bb08a5300993fd0e5b0ebc54ee22b6a98591d73de1eb0a32a22d23ac851628991f9eef009105e1cf747896ae6cd48117604ef49d26cab7d5bd63044fab2de728d9b78407b0259bbd9268d63ee1907f009cffa07ff9e30f32cf56d25fc0a3410096daf9c2f8990e8386740cacaf272dfbdc185be2726484cd3eff6ebd7fcee7f8eb15ed1a952d34bf88144f02f07bd127218539b74afde3f73a051a5d240085a91c9c6806cd5cf3090a16fb4a02418e77881b952dbd0fd0a0c3c8e81306e38e0ec654d97e2ddb17f4c5165d343e40033784f0668252592e4d1cd95fdc4af16f1ce16b06ad0749e8a315492b11692467e4901a837a443f05c36b106bebbb1d35a83558b76c4c16ded2cb4e80be746c40300d5a5d2500140409833f74557963a37e0888d854105d32d324063d2431edb2d2a6f62a538749dd8b32d83057d551d53df79fbdc4c92fe34883a806ab6910b7c0b4b8495f5fe77fbba14d071c28136c0d45eb02c80de180c846b61ae7ff583d4ffa4c58c0ac0815e9922d68426d5264f7d8061c59ec70d963e6c1f08861fb71ca3e7c6edea3c74b179ef6a04c909502234a0c2493958f464e2af923d39156d61472fc0ac764a3ed9a7d64b0a1a4ef283d2411c22c40d2e7de982fdcddec2023d7e413b27c11c9c9bea9648bec30445e66c71d9b4617241b6a6d82be42380a3abdd35329adf41a1cd72e68ef857c1a9b205859e3c149bf1ef6b8f39ca5c33bfbd8c8e3ad49f617050068765a8f9597f0154b989aa6534c5a0bdd8f060103c8fdd717586b655e92485c3f445c79b3be59ab21d0f641096a566e99385700f8c3d44b3320f9056932420a680b0d8b2614b907709951c8ca6b67cd134a3c3a35f65102c1762260d694d522e0b4973d395a17fa90827470c2f61ce36bce0dc9d2d618da66a7fa5fed6725f9b9f5bef7eabac06f3ba89e9337bfac6660c5e953bd6f41a9a1fbca5ac67579b88e2d5628a68a77a2df4fb508d593db7bf05500da15aba17e98d749a9492a00870642a3881e1d966658f1ffbd78e0ce1edf48adc719336da0794462c1802d1bb0d4f76b24c7e7568534b5e1cb159ae6bec0017ad710a192130daa1d8b3394bfbeccabc04d8a739cd624a50d652fb06d911061ea498c936e4e8801412242acf790e4bf3b43ec1721fa82fa35de30afa5f06b8e3ff34c11922a4c6b2ced320e80e7625793f3717a5c741a2239b1a3eefa045e7dd9c50d87992f9d1c3ce7a0bd5968bc9c77c9be1194f7e2ce169e54876ebffcd7f8ff131456cf00daa3a8a2e4fb0df48c619e1a07106a10c91634e7e1e9ad7bea7efbdaff80b9a1a774e23230493cefe2ca6885eb499c18f87b723760e40607feabfb38707279b095dd009095e1fa505391596db0896732fdd9d3edf8a881d95ab6723025fe3b0d3806002ecab633d0bf87c665551adb9135f8f2389638891d88a065b7f387fc55a5c9f3cc8bbbdd56bade2bfce143356b96d55fc646bfaa83a447f57985981db1368e99c1813e039773593f9c2559a9203f3d0e5ab4d5ac99326a62e7e66c364e6f0582bcae817912ec7e3efa5f3789bd08e8a089a9cf13f0fed1674d59c16dcb72d5c92c7bab0794a1fb5aefd8cb8b03d87e1ab4735fa1219acb01ac5ec9c1839ee735ea769fea4def6dc24898ec612417a8c0276b6d933c080d11604da0dad26365f2d182f6c13ff0655a00a45bf9e080f8af2b9d9e7d0b613f432048d7d806573de19bad791bc27cb1156d4d04b29483ee8dbcad033c0e98d115afc39d87b7b09e20ad75f8df3db5ab3f7cb0e0bcfca6e0e034d2a771cf918583ac631340a52e5e05401aa5b01857843eaaed797ff1e47489eda2732f60a7c06695769b6ae7e48237f51c4b0bdfd9a878ce57ae215610102275db86515e9a9ce76fbe5db30c839e4c2c6d12d5d79e8e078992b3961e333d6ddc75015c2d53c80b3886f052c6708e34dbe7af3eda1de08e0bbaa0420a9acdc0b59694ffab4e032f642dc7db064a1b8ea613b1bb9d59201bb065dfd9609b19901cd6a504a0dd813caecbc167e500e9dfd7623c5e6ca2c0bb878b27f2cd6bb8faf47b96a486b7a909d606c487641614a14a018b2e526a204ce45a563118b121c96a8a52e035fd8dc0f427195664885eb8734dddf531c84726ffcbfb5787844361e98a2ca9043e076652030709cf2c7e2dff38bae3ff9b0f0300a732cf4aff8df65ae8e6033ca8fd74843ae6c211bda28652218210911d41d25b34a431009bd85a46b04b46455c63a1e9de2fdb40ed439116c846ebb3cedcda99fcc6359ba7295b436ef1eea80b7d8442e076c2364f354b88253e9ee7e758415dccb351340016bfef0c479fd11db8df76658916bb895c1750b85f71ce8c600ae89ae791166ab72d161441a6d70f012c56208d16eb57d201cd3fb162c07fae1f331eb27bb81f463efc2f07f72f0a913429a3a0fd21df6fdddec4720b85c33ffef9701050aecfae2b6196c40d91358cc0a41da18cfb23e19c0506cc067dec9a9f281e4e9c21cbdbabc70fbd13baf6465e38e44cfc31a667bc3531c2ba1d238f1fde43dfa7cd8bb8ac643ce15e99d9cb6c8c06f9c5e6722979b9b2612baad733f2276b7d3bda7f0b03a65671e6fd17f56eebf78fc0fec27d493f6b1690d99bba1b9b8420bc9771bd4fcdce3fd19d124e616793b48506d21f53550d1c5cc58a1570ed68fc30bc6837d33f7f4c7e489c780e077333a2429a27ffc5cfba8cc409442242cbaf36d15bc53dc6463ddd85e8268afe20cb0c7f9f7babe1668e60fc9fa95badac268e74d05268a7d7a1a8bc59593d8affd9d82fdc2ce536d49ba4533414b20ecc952261377e2dba83d10ff817706d2e677ad96a5cd36ff800262a58e9595daa8ce293b643088a885c82f50dfb8682a14b6d4a54d540f5ae7e8730ff942f815aa88179fe3b20fa79a615021efe5992b2c6c5d4126b4afb541238112b37854aaee188a293d046bb8cda4a03f02b190e98f79e912afd42ec0ae986f9731e1b46c7b3eaf666131a8e3fff610abbee483f47761ba20a9112f001032124e81cb58fabbd49ff1d7ab99750ec7773f907970b1cdc84e8d2dfaad4744c24e39c223562df169bfb769b91a8821bd631a247a26565541343e173a1c7ec826539994b5ce0d78244af211d67fd51b34c9d4c87358fb2b100cea907e758a85264e9401f13367bded0111524afa8d809326098eafe1ef36774b6e18cf84252d14f906c7e990d3a4cf19c9e3530f543ebb02ee59c75d8a86782cdcd4b02c2658cd9f4c0c2507e7a0c6b26cd3177702e72c11ea1f281baad46e9ee94bdee62232dffb157bbf4a6f0f35274c54e6f587e4c2a3fa91266a0d9a93568bb4bdb0908d2852d99cd5f4cf572d89bffc819dc1fd4b2c1e7af7e78ad5ec46c97a259948dbeb1f6a37f6d598942465f89717f5aa9c86e6b31898a85466f914af9642bc6b8fbb87b73fa245d46f5012001128841afbefa1875cd03a2d80f1728c28eff7137a0677de865c2ee25ce450efe308bfbafb0a73f0b29ad8d0da1e8f864d42a368ec0639adaaad4096ccfe94a64a960be2906372246d74fda3fe7e4cfcad024b20e67fd27be5e591df451708a02476784aa6ce0b5c18acbc602a3ce235c51ced28a7d3782387207511f092785430162ecd37ff7736466f6f77e1a12dc727eaaa975602c4f3fe39eb8d3933e67858cce032323ae705a871d597b2905834fefdc2befbb6982a8bf693702dce9b0af3e024270da9238e74c7890b8a6ac698fa3870d5615bf01a3bf889cc25178d3bf2efb58f975f46f8dfc73f793c53415c3a0da650abffbaf53b1fe8868eb51f5c5cced1bcb7bbbdfe6d17f55f83d887fce542aa46345dfce0377363b4c98a891c90ce6cc9aa2e4794f757999275fd38f4837dd82090c76425774d4d2dbc218c9d968fe62044b1fdf61df76db0205489c5d60e9dcede83eaa61669157de35711cf8fd01f90cd2f145a4df4dc9909325e902aaad9a4e3261411920bb7afaf262f33238270eb68a909f03d495c0fb5b424465a0360684b5a2611a1502f2611837f048dc5227333139929eea58fde39686f0ead48435bf7fd804c935b2f2749daa0d73a329c06b277766267d8c57e7b05c79d9a38ccd4e20231dad12b19368457f06547c751874b10fac5071322a99690512c7ae4774fad306972be80cbac3dcbd3ac59ecc012ea791669d83d291a84976d2ce806942bbc79c356b57e19d137f09c6bba3f2df4a22ed2ddc8686a5ce4664641b977b28999d88107dff203c9571e591014809357e77e86d39d312262d17cc7696793fd0c0d48a308f58c646339a4b64493f26675c3eb5e7e509aa0e7c75ad0797917eebdf12413885f11a368e10b6f7799ed6f4d29c8b79d57e42c0d0feabab48f3a38e7856ead2e99dd94d46194a778f1d42526bcb9d2d5b038dc2153d23ab3c7631df13e2ade1864a12f17cbf66a86c2b6d579284808ffb6832456d558d2ef628a1ef4d5052df5352648f7a7720627c14cf729a390f78f86b9dcd15a7d729ba984edab5134ece13fd022415a9e4e5078514222e517c5bbd675786cecd427ce872bb9bf92999e8d2867857650fe2ce5d5cb78743bea07a3eaedca848bf78812a32c25b4f30c0ec4742c9cdd20647251e5bef123a76ee4139ba3f0f01285e18f5280c1b7b7e8c3a457ce0d5c547f1a7d5cb6df94f9853f9f1a82df23a28498525ecf21efbc714ba817700b3135082c08f9e8ea50e0b7bb422026ae969dce97ea135fafd46c1a55202068df4efe9adbdbdd8411309a20e1bc147dad80db0d469d1fba2a704aa916226fe62cc6ea1075f6218cc2d6eae3b01edd5cfb445053e9c3d7cb30467c337f0fd13f4fc58889d71d44ba385f9b0a5f60ee63969c50303215da59e060947e91324d1233a3363043ba2d3cfefe220c6041b872fdfe0007490563033396085b788f44d5871e6657fd635ace405835f248c33f82f042bdad0cd092497d09bab066e8d3c89af73098d6e3ca6a7cca820895131bad96d20af776d42a6f2f2f6df66e7792795fc130dff9d86eb8b8059cb1c49df41c4cb030df723c92d2706db94415137a495eca46f937ba6da9446eb3d73dcfa59338747665b3ce6a23f7ebfd181b59d9bf7fb6d2c2655d8a11410ed662535b5b5561359cf4f74fa0196d1fbcc4abad771637905f341d17311d6a15cc836341cf79d6f5c2cdbabb33b03d9e8b4facebd59aed1c8a8a342385e65da02a79b48a07700c77e1221b2fe23aac9b794b21eb82ca6b5814466a7acc7add1646716b60cd76ac52898ec0b5d4aa952c6a08203944f0b59d8d1c9632c3e5cff0172ecff2f95768216922cdff8bb2a699442fa04d6e4d2d7ec1825cefa9a63b470ca26ee08c32f4aa48da5d7762fc7087920c060d62f90f6f1e96e5e3e0b6f8e4edbea8780751cdeeac844ea7c7c038972363455d6b68677ab590c08d0f8bcbe5a9a2148da4d0c4a1604ab13bb91cffbcc67bfd0dc9ea641d7cd8025367d306f62556441624b0f308af1f50f63a37c71db7454c6bcd4f41e0baee5f1ab156c7e0534daf0fb61ba9c0313a2e7e2426ac049082a47384159f4b5caa36584c3e8a26c16258e3e22eab4a3dc1a127348bae37e0a254b33206be3c9e548bdfc5422e7eb1ee83524211107b1e1509b9ffc6988d291411cbf40e1335c93695fbc020ee868ee15c88dd3e4dde2cae9c409dc0de562bae4170325c8a58bd3a938c2c1e31507797040081200f3103d35ca91ddbdcdaba8fdfe5a57eca3151fd8260d983eb3669ab2a681276abf7579ce46ebf10d953634f1e96ef05172b677300dcef2068962a2844788e26f6f456ef04e9807f100a5b8b1492258dc24b3a96d1fc07de8f8a52b90daa685baf1492ec905dd4574da5591992b9d4ab4054b97fe5e69a9d1734fa4fdbabb9f05d04cf7161a631ed8a7f706c3484ff6a79e2b0c5308c5f8645f20b374f8f862c3c2ffbb9defcfb186ad91812ab9a6919a3354abcb67171d896827f650d9588b094c5513bf44494976934acc284d68ea96ecc519d2afa6cb5a4dd5a00ba100646cac79f269690ecf70bfe697f31cb56167feb65acdedc16f29f67d84c57350b202eb6054d3e54ee5187bcacbb7cc3f3b6b3ca254197802916cec088933600efca7cb3ad01d75f99ad074b933fad36515fdf2fe1ea2cb333b30d8745951cf81711f80d779d4d1300ae191d8ea5fd6e69f57baacdf9a50fb107edc384264ac6b495590916bb6c12444f21892e79ecefe9d0c8537227403d059faef237d067c1b6b3bc56a15211604a88b6eee8c402f2a5bb26e70382ea3ce4f8cbe7e8ac5bbe9b808ca62d8b3953b4caf6a4785ee2ff5dc9b5e88fdb984fd43b16fcfe1306923e560ffdbe26cec8064580f9875579977d990b7600c109d67c0bc0110235ebcd1370db082900499500812b1f826c64c6a53a30ee3b2bd19f997324dd1adcea36c4d9e4c181f98a761f79b96eb150b49166922620146b94d328b3f6087bb7793194335f0c05e106b0e29ed1fa98a7b0484cd3d912fb19a7b9885777d67baa248c7c0e3ddc45618dac273d5075fb42d0069de73335bff4f1e59c8b79266d93826dbe891039071c3adbdc914211b4189975391b9e04d73c2ea887e87d5c808724ff27b3d2349b2ecbda231e6de70f42e89f569a283b3b2c30f1486778a17aded0cc3fc181a30048e33f3cecc71295d08abe32972de20a568f1666f867d5524769de2b43b349d4fcd1fca061e49117436be8c3c604d7738905083413f773303e38600eab54ee279c013498d5040828575bcc329dc68b751f0ff79d9f62109ac27967ef1d44716026ddf84608ed90b3d7037592fa254274ec3f48480281060ce2d36f290640824bf740372aa92ee7e138cfc932b5ce6799a83bb56e4399c916451e2e1f70ca05232e23d2b1f7b45d949532a841af5cb320f7e47368e05279e94dc0da7a3f97ac7195a3793d1cf9e66bf8b27f39293e74af5f582e47c4f4345abc9342f117444cc7a53df0ac7f5e498a7e91fa302234888e8a6578c200830c13635c3b6f54ac3ca6ade66c4d756a2331535d358f8efa831acbd107fd7acc5eb13b3b8a8c514f312939cc9dee0b61a507c11e89bf815b50f35031e2fb6f9a48425aa594d82180913c3d6c21095f5dc34777f6e37e122522f8573af20afa6e8d7ac349f6555ae987ae192b747d416aa986594f64b207f3f9e6bbc87cb9b828d39ddaa5cf6b9ed0f7510914059c4c4cb26265e844e8a6708bd78f92c878a279a080dadf30ef11968a1460089a4e1e9444fafc25d161f16de29ba7bb711ba059ae9bad9e426a222b56ab20c27f6709a71d4d68f2917d37930f0b98f5cc52df1282325cf7d3aac6e6824ce8a49536010c9ef907d418c5c5f033f3b8c1aa06a1ab06023f4885b36ab8a092082e10c5ed33d3523c30f7cf7797245f76e6d17bce95b216a305fcb90ae9c82f39aa355760be218ec2ecb930279afe8bf772dce359c5e978a1505d1e8e0eae6af119c2223a002650654fdf971ec7d0b8c39231b909d5745e1358c6581006025240951b1b12b11f849b02bdc5fdd0bf159daf3a3c1f9d64a63522bc7e54e15414c6810111fcbf1169e21b009b07d4260ae31b54bcacac0c42046018840b7ef476a63e862130c48b4c7e27d71863a8f2a93150ecc02c998f272cbe6727976be1dd5277a15643a2a440eb3c02846f93696fbb492d7c77f2fa2f70f0e69313a6e8b3c1bc6aa4a282195bb4b6ae0a06c701ba284bed8343617eeb917073e13d1c46171745d4de700e5801a213a657db024122ba74e3bfe9c6c5b7a87e44b2296bceb6857451ffae40626521040168e325018710ceb849c485251d7022e7e44d354031311ec08c65cb2b0f3767ca3d663f8d4db88cbf65850359b6a77df8025c31d1a1a48e480ca0cbfb656a3b00623f3593004eebc69ca859e6d839948be8b834e188093a946aa4b2cf70a824157393b009e08e3f0062a813d31074cdadb209547c1881f5896d88c0ce5dca6b7435f563b9c8094d4c2e85def757e136aa103bab4c8788706a9a6e5c366a000bc13d975050d6c90168150673fabe259076d842fc509a581cfb9e517cfe6b9fe5b84d79812143c7d4ec4fda796b50bfe55eb477c0264e4251a4b7839198b6310797234b66d4b3d20d057ad5d44faaa0e746b861d2637679908b4faa5c7a5f3a175715cbcaabca25db9aa0d9d55dbf73454b4ba19f24231cac317c530286da5f310b0c61388e0c27c8453cd6742d1262828e43542a96ff5788219d081c49536e0bf53c498c0f3580b7ce2553bca4d7fea613e369120e1387364021a1ecce8af1c7dca41ad87ba763b8771c6fbf6b622496a2b857f960bf340570af7c1c8355dff115a2666b82d99d1bd400d0707f5e3a3fc4df6f79b40fc2a2b79c38a4b448ba7d45ab8e6ed9735623d922e71e3ec899be3689a619ad308905ec9a8d317bddc97b9a41fe99f7e74720f3a830d3afd9dfe73b31298dbc1ebaa6eb75b5de00384d199842a6ca9d863bc73f723f4c5873d3377d8964c93f5172facd0c944d54055e755c66ad332df801922a57058ff370b4cacf75fe519f1b5324c9ad26674a59681ad8e93abdafb14d4420184be58e93c0b08aa23f2e08d1446a331a22320e873a6dd672d13c4d611dee84ee02939721b81f25869d3ea9eae9f23d1b7a9d23ebb0ea4d248e4b9c86b9b2a51067cc67b047650977a310f9f589694b6daeaf6a7591dd783145022812813b88988ca33c4972a9a46187b39c021c1a94dba19642cc524429e4c0287f4bfd81a2b21d5e8b4ab8def524bec3643d5aa49c633ed47292214e3ca53b077d7a9002256c14361e4464253db6f037f3f6dc14da8fd3a8e2a21adc1642a272726b9c3c91d6ee374559d303f844b1b131b9a9c18fbf01b549466523168ef339d8ba176270aad4ce4cd4d17c0446f89ef4fcf714c22c1220bcaa1072749ae2c1a2e8a66ed5763e8308046f42ed5e138d26645a4ffd4af3aba5a6899516ca1c9b76064b2a0337c69a594b68481eca72deab56a8c4386c6ff3e84163122349731614d1ad81f042173176e3028e6d8999c308e9af29c0e7279e5053ab74023f28029ec112afc0db8dc7ccc2a8a09eeeee6c27bf7af4286bc44bc931ece25604e7067e71d6ed0b1441305b113e2f690361045d3871eaa07e771e8768a609e9432f22191e13f9a10db0207a99bcd72a7a91a6655e239faf9037021a4271b34650ab6f5ee64fb0417e67e7639a474f67ebdef12b2b87a4d1c432989c7cac25d6ec412ca083cb9ebc937f4335dfb3545962735b6e283261d7785fcef7dfbd02608148cc5a48b691feaaf6fcafd1c472ea294725cae41634ab45af0d12ce6603e1664c0d5a78422383f540c888ce041cb0bb07b667d3ccc5f6b2f305c1e707e091c3f25a36942247e748d7e6789f41df141aa4d0958c15d5fde6e7b79dd7c996531895110efd1f0bd7f06eda44536b961cc0d22d35b31f69a00b696837337d61f1e06305b60de6c51325656f1c207375d12810be8ec485bca9d25a6b9be38f478c47e593685609b4955f9e04e190caf5b9027f63dd1864d8543c7e7053fa7011f1b09400fae271145b489cc91113af4455a2d7e1ea43ceea8c8654c1ff28c505f1a98171edc5420510c6cc9c4f3963ff3fb02dc0473d0ca38af9a4648c5c6766ba01f6e975dae0e8967ecce2a838c40c71c04771e6a5e484afffaddd0504ad2b05978852aab4fb56d93463eb0f0b73047f3b7be75df5f6247f165c580dbc92f0b225438fbd85b7041ec4df50d1f6acda14461461a05c903666c29bfbada809a437f7280d8e7e49a5fc82826dc97646934dc6073b534c0ad71a864f5ed03d3ef300ba4d1aea9d79c686f5b5c30d16027dbe26b2bb1a39d4770b2c5116423f38c4e3c707eb159c729c91bf78e5e15bd65a3b66a7f652e765cd7acb0d0cfe1a026d63e738c680294799cee3eb2d04c57c08d841a39e967a33ad6a07442eee8f2933191216e48d1f7ea48967b7d7907bec1d8ee35b587a7f20ae0486fafec3ed67a0d2f02a7138fb31c9ee2a882a6b9ab3b5cd82a0813298059c349ec25cbe42deb42288588d0a4eca9a8407c988e3692d33f06c8f68a71f0dc9d1f4d38768c6d0d18dde9e938edb28301d5ad56c02672417d004e8a98c74b1960f37ed501ec1bfa8a0babe72c192e7baeef00f3a33673c2ee582ad318a34adbf48d4e2899980635052efda0cbc56b67fb0885611f47713bd520bafe179d8c453d61ace1706465ff052d0132890b462aec70f53f1737b9c2bb5f27f61581f4bf55cdc3d9be7d6a63c928de938a55b12abdae04459f30588f435d1148e7e5026e9d251e97ac425bc1cdd48e7e2a6f789477264c802f10733e5820a8d3381df2371d553363fe6a2a88a89ed8076a580605e0ad9f1726b43b4bbd3c2b03ab9108d26f6b2a66867202f4982658109d10bdae8864b87b8423fd8ab85c0ba69f498baca5b05a027eb86c902cee194be8c13c60c5134e8546e624bbc48ae47cc5cc5fd7e954f15ddf0a9129148bd4e3439d857f721616386e8a5351ecae585439f85452f1c2e8bce4844fbd4d25ce84f2e81230b94ad022b0455a8d0555f0540c914a001ac1814744108217765d53e46972092869fd4bfb2aeeeaee5551b0f2795ce56ad6eb6620d41c5caaa1ad98f500e01fd7c5879388784aba07adc3c2824c2d284416580c51c564417a1ec620aca86058ce42e62bffa27767d202527cf08e614efc38c84e7283f80c5fa0950e74886fe4fc106c18b5df830294425fa8289e6819a0bba8a5012912bbc70e226a31915b6a3b93a1cc8850ebd0c19418b3c55177210146373e15ae84f80b015f481ec04a2af3568637223fcdcc5a2eaae08e7c134652e63f74befffed0e7c93382fe26d8bd34bd4f0da3c0511b61a9ce8a188129a7018116e07f881532642e6646d12e51a070a93e67411b2e92c286e4087485d23067522d7ae981a00e1e88a919c702e4396a5cb6a9f9184d0e30d9d541753509fcd6422fbd02c358d3d7a6871a5b23bde2a3f85f15fb0361d6bd3c704f417f3b9601caa757ef5e37b8792251ee362095c1d2a2f62b61b8dc9e50d5fbfbe1617882921b08ece2a6281fa05fc286585f245a009d8dc209cd8350600d0685e1641117125b8d7f1ef114bfd1c397ad18c0d62e60a40048d1a61a49abd13cf56521239e7bd02bcfeed2ee8360c6c68b0e8eb67e3308ec44713139955efd2888c414d5ffd9477d807ea3e063a7fad80cf7f7824b8fbcb84cc7ba5317913f175a262eecc8a6472290613c2679e6a6952c08644d66660ecdbcb3f9285850ce845d8bd1be311c38d4dfa3a844bdef17c0046fdea98ddd8eab02a63d305a78c0e925b8f1e58c7909fbadcd85941acbd076885dc7b6ea6e78fd09cb0cf690e9b0a8e51f38dd9bfa5001cad537300e82e6e563a3a3b7f089863f5d8c0b0127114e4f4de8d1540ad39b187bddcd0bf45269f4284413fe6b6c1fa89fc844acdb24de947ca4c5766129dda61ef071b6ee4b79bb392c7baef59daca5571fb2f033039a7b5639c42213632c2fcd49095fe307b914a303236dfff08289419bba894c6cc572c8ebb4fde4da3ff74c78c59083410a19022f2b78198afd57d4e9b8c2522cc985a973387e14778c8aa9c53790a9f138cc40afbccbae036e53f319efeb26605d259bbdca6e3524c484a7995975d294224f8bedbb3874ab6e144188b5fe921d0eada71e3b1cf35385e254cac6ad5718af7f3ad7718fe744cf5504c80b99c65f41f551db229074e6163ec7c44f485062802eb18b175838b658e8c57cc96779c710a5e02598513774653b6e20eb40a17e0d2198959e77d9661d192c068c0e40464850de4280b4c83a6cc11765e857c45a519669158b44debbb0223791d6f8507efbc945360f5640a2d89659b026bc396d7f46f5847215ade6b6974ec2050c38e07f4248500b3e5a960a212cf37a4e1ab0653e501c0de8c80bb38ee2593701d781318d1f75dd71d3f40ef2e49dfd15360a109b261fccc75bb11285812104c557026e0832d5ff4983d8f868aa017f3369be4902496912cc033814575c686d03bfb0f448b253bc0a5e0f8862158946338e77911c3dd87ca6ce4c53813f119c4e5a061c43880e883ba4ed4d8cf856c89e4400bab45073f1cc46f3ce9d0455f38fd7785338262e194a2f7b255221d985721d4fc95ad3af74f242476033e50ad0972a69c2d49a5a07c4c7a491fd150cbb139e907e950fbdc8d570322c2390f4eeee6d97b41a19b5d1bd7fef5025c3f9467335f2f2409b566ebba7bdec2a06206d495ce73faad1757f4f1c5b2c3d4800dc198dbfa3bf073b51dfe042489d571c9518f87eb971f72189d96938f49335b29a90b9e9e31f3a61c0c08b9c19600cbb262a946b3e2f740f3d6fe8142e0e57c790cbdd6200196d4938dee289316e0d81ed4a80e79ca3fe6168fb5b3367103b54255317e0691006ce338bf642222276da74aa7303f030e4d997e687f2bc9e5885d92c9fd2c8846413b1f8081912f2a7cd8a2705ce11011aca8680713d6cbad1ed46d9a000223e734dfaf54b8555c4f025dc9e84d2370ede7c7468c1cb857b582e8872ee8a602821e3f5f5d809dcd68044d9085c11e8fb9879c7e3d7f8043b4d0a73606b7cf7fe30829c4c87822cbe2b1b74bc082140f7d1147106268bf6534b3261b2f8fe100be66d22f1ac5ed58c0c922aa8c6a9356442a5f74402d3ee4a2806c7cb64e217bb208ab1f789e7a4096aaf59b6adb29e78a3e9619655588f4c60520337b8f9e0eda793bb96ed7ba796b9e876f9d289669acc326384063f07c5e9f4bd7a8a63ac5234188b9ac87b8deafdd111b3919a5897b7b794b6f5e8712ac6f5d206164b07421e8ad8e6d6e40899124bee6f8e24220bb3d625214ad5e1c7dd8c243caa58fe81abd072bfa2674b41d2bb042fd497c898bb5795797f953bedd8c0ed9b0818b84ade120a2f0dbccdc4ad35f4242e8412d862b4cee6535e14270fc93dc5970f02d04c5b8a46af871c20c7d918ecf5642a98846f4768fb35f0434d3701a1573ab24e8bd0efa976780dc2b23e5989bd5ad00f7ec314225f81178fc48bbb34c85b0fc48842c4faf62c8df32e180c01a2ef0355305ecb0bbda34d4b4887f1813f54ccb60b9ffaf5a01408e4d237029b71dddb4cef3d0a31a3f604371ac4ae7d36a5f4ebc05bf210577897442ac3f15280a7a495862b4340ec20c4ea7663a233346ab03b2320bd2c5c580935e82091001f7580c8a3064c095bca15f110efcf5179b2a12e7cc74b21d04b3905bc87fe2d0ed8774df4fa5f12d7646ec774629cbee9e5d42e05008a57c1edb820075de2bf1da795aadc0afea8cc177f698da6aefce217ca697cf0f2043170c5db0cc13777a2e84a37709414345aa64c723dfb3948712c875c01023329f356251a65a883ff3dc21f7ab5033239632de19523911c47614333ccc9ebfaff2c89a54a10393a4fbfacd91707bdcb4810707564f364875e51670c15ed551fbfc0151d9fc3985cbe8165f38c453cd8cf8602b46c9e72ff4e2463064d7dfd99a805e41a25c7d63bb31116456bc478ed745466bc04550557ada44708bf1728aa82f11f97a52b2df2055972332c8848c25c83cfdf3c650378953709c8355541e457febafde846557b9290cfaa669ff74dad3a0523efd8702b3f4ede5e85ddd6de9e2d2cbf5bdbca4000b04cdf42a9432454ac49012ddcd1bfb8cc667fbd471348889361edc8fa20fa1ab5a73f31dfa3b1a862295aa9b3fcc87d1a1ca4c1622ddb3c41e36e7e9447422c7d3f32323abf6aa350b9ce407904e1b9b0cb23a7776004e8fcee371fe76007fa1715a589ffef4f44ca35904edadd07f455f0a0436f6c29eb83b07b32f8e56f9845f3cf687bbf67cfd6dda1f664a040cf9890bead0eeb65817d7b5fef11100f1ed9d9d227f97987011a04c2576ec8214912888668efb84273b36e0e196a2b34857d8e40d585afbf52630b91a8211bf675ab6021418aac668e044309ec53c86ff044088e9bfac155e70c376023e7d7ad5fb88cbc00bc9d1a4e525c74d1af3871f28f61d3dd0b17aac772bbebf035bfd3b8fac5c6ae2ee2554844a10c5e5b25c9e25698863cf33d0349e833952cd008dd5376e08b7d28f0d8935b7cfced08bf0c3b7dcefca629d855aa0f0561c06fab1998c302136e464cc4d98645f7c229d641c165370773591a848d2832e2a8e0769f83b9353b806d3a3631481a61b2995377335205ad13a111068bb32e221166373e2a5c85c0aec2815bac681c53b14d1c62726f31a8b579afc55cc26bcb2504d66d0a78b60de9a668cbdb252b333adb0d1800769d78a9386e2bb3e6972222c3b3380179a35227c22c9377365977de8fcf32ec984cb2812ea501af44be316f5185f1415b3fae2c2acaf18d821d9f297fbc037a1fb46d78d5da975042f0e8909acb8efd6f9f525271f97a467e4dc36d1e3d47e40f4b6254f15f7ff41e6e023331f0c5cbab6d8c695e3b284a04f4ce2ccdc8ea1957fd56e190449252eb0c6227d1d387e4ef89e757e5486de5f615d11bbf5d847aff212006421efaca47f19de00199b9cbf95eb89abc619375ed8c41265f95c91929959427475521886838c5870c9c9d3ad0bbe4e1fc2bacd349b0511b83c73ab56941ef70050c6325aa2c413fe7a797abb3c9a578d92f10c0754ed7d1e90172649ebecd1a2d9cbdfd4e962c7c20d6031a2db4503fd5355b89235ba762fdac5ac52fdc84f5a65eb9ec46cfa276105cb7e66a7770e50426e276d1f687a734308ce6ac45247af37c8b87c3b0a90ca047a927aa45bbe8dba0bb0524b9016b0cef337dae39d9574516ba89c060b006d4844349f9b2513abbaa78a0b2ee55ee76057c860076660c647597a7ee3d2bc4242c87f93192efce45eaa387cabc8840fd176158fb89b7184e3db5c1374a610422588ac82e8bbe8c1ea74848889c49532ca9b0f21eb134cca8d17079d1756a404e4bff65a381dadc95851275cadb33ad213f6abd8366f80e40fb30e57f966204a951fb4fa8c70633e63fcba2b6440d3b66f84f778388db3f8d2262052374893be79fe2b0f46127ff2484202ef58b4de69bd7d9fe1cb744d9b6d89f84842945a9d865be9923a3c3fc596cb54bd94efe14240b7b99e8519ab2611a19429e7a238abd9f62198ceb7e96cfcf6b3e46b8fd44bfebcae6995b65c877254b7129b396dd6239f11ff426fc3154fa799bf5e3a7b276b38e06d24fba423d0ab4a4f45c2af2fce497b67b667cf3f396fb5871ae42801fc38721efcb6532551e513e804734c5dfa2fafca3d29653aab6473a9d5cc9cf18623451d9f949039265693204773c36de4b0756dc7d71ce48554964978bf114ec191c887a426a2ec1ad887112a4ef2ce0d904454e5614fc7811147b31746a21559723b0cc7fc5a0d7b8ef2f0804b7bde403e3de5ec2c66bd210f0ebd683e9ac91c59b663083540da2e4ec6cdfd08d9f4fb77685fc98bfd63d921f877708ff1efc00c7f0db031ce20047e583031ce2500f70005f1cea410e7180c33d0c7f0e70b88738c4e11cac03674d18050bfe8b479e523046db048a8eeda1081c2bbdcc35ebafdbdf620708cc544bbaacd1509637f2c1f8c67b3f506b50b180f4e032d13e124ea62d90c6c4cb440bca91edb2274c7eba337b89d5bbe502e463c5cb70c6da860b6d2e1f2f736dc8b01161d6262103f21f208dab86de38afcf44a81acf1c4000bbc5c5e19478191ef964d20db15e457efec4cbc436853fee1f580e714374e85632bfc9f91055bddca699055ab8ec9b3a5e4624716731f985372ce4e490daf1327166701c781977b8b7bc0f2f8fc0634114ea73751979b71f0af9003185b2bba13b0521d28c60af921c7081092ef91f2f5326a7c0419766d13a2f9ef595ceb955739eb62ff61b986830c71b46b23cfcba4054ec872785c1512cd27e5bbc4c883bf5c569ab2d32347506f1198a501c355291bef070ee8be0a3f132112cdd209968292f77044fc4a3dd212c5544105e654a6a85b6cd451143c06f24b0ae0a14437e5df66d00387de7c1b9cb6812c29ff84a792c1692c8065d1f498c8aa05c4a199f164aa119744db04dc9e52e5322442e050ffe6abd4f7f91954761904622593343340d88e67feebe74971180d0940e15c6c2da3aa33878e6ee32d11b3094cfaa1a84e4c479d85d864fa5b1185337ba660455c432e34231f1ff56cc1d7122182c5f2447692cde5d268a6e333e771941cec7b3e85ec5d192d8f87352e2205f2aae40a391fbab21ad372e169133e3fe9b0fcb072c7c1e5ec1a87ec37d9eb8ece5ce25da15c4785ec475ad78b731dd8e01a990f48d0b3ea6caa773bdacbb35a87a638bb7311cc6eabbcb28c42694f46c7d73a779b9ddc25f5bc9f6da579f10c9d59bc3dd411500a01f2a84e852c6462b6030a16de9c28be12c5614c343a1d563c58127e64b56dc128a8f35fa721bc400a6f11a0d35ccc35759564ad3b21297ea6f9371db9b15eb9b15ba0e21ddbb6cf255fb9f1555b5f837c53d5a29feba1220c0cb52fd76fd8d9b5fa79522085320d4b0f8aab1ad3afcd63b06645fbd552babc7d3b5729da05192ad203711d956eec53f0634a4e63da45fd11e857bfc575a6c0f4ebad8ab3b68f124ed1db242adc3055de43098cd62ed4bb85423b918465f8de68edcc5407d90162739192883ed96ca237d7bc3f9d23739068e8a854b3d8ae4335a9d6d4da6b84ba9fd2e453ce01ee2abf0d638ad86c1b1204a05b2173ce62e18657887275070ae8e41180a4d0441c75f187508e52682a0c75b8c2a8472530260149a2201835d11020c868a1064312830c06834fdbcb1182f4498c9a018a57bc5df0bb1795f0e3050070c0c8ca68408435bc23bd35c35c1c343576b52027b5c378ce0eb33259515302ccd2f6a1092f87c1c459142609c2de43ab5158bc2778015ea1f2215fdc5408ed1a58920f9181ec68540381f0c60c1355d5069a0df0cc5ea9259b91fef94cf608466a8189b3c901f6ad066413c2cca0c75ef93f3f7830ef03d06fbb7ba06df2461a433343f20c6ef3534373629824e6e62e1755f35a86ba7d7a0218c196efa8cec8e7ca90f8abe09276cf6c29c6434fc9263a3bd7363f9f04490a234067415bfddbe2d380459ec75a3e61059bfe9be03f1b7adf4771b5658d36f913083a3018865e0b062ea372c4d1df1d4df452570cae92524dd80f353f2b5b7f28f3cc1a1806d1264ebde106d47007ea5852d7d3f8477200f11dda120ba7099bc1e5cf2b8dd2cdc657fb08b2139ab7b4c549b70e2ada9472ee78c0baa774b8551c5d6a8de72d07039a814827a216296327f0ee39951d013de455be53007fa4859f5be0d4ea7960dda80063582af7a6275debd5d902ab62998404f405564b6a743c0ff73b867fe5243ad9ea1508552f7f07028a10b139e6bfb282112ad3d0386ae2ef61523626c7ee2d48bf557b14a77afa30e7732e9846cc23539f34241bda2464315b141fbc5de5b809eab4786cab71900f684f5f6dcd8dddf0e4cece5a45725065485bbb82c4ef9f05536c2b6980cc916e6b96ded06bc4dd7d4f478bf12af960678e96d18a1f1510668b3e72b492b128bee6cd88c6f05374ad7217c4d98750b3226dd6d1691027da32314264247f4a7f5ab4ebad5eb09cb0f4528e12b91a1156e623db7383059f4b63ef1de85b82eda5cf09731b3b62124689b24ed900830a4ba5bdb3be8baab0bd86a54f5ff07baf532cee5b54264c913e1843ea810c60d59069921035d1edd78a5ffc31986f493585e6f8b0f61177cd36926605e3835369c4c3d88a039f4ad78c5ec66f79c93d0d08035ff1ce790f035070e41af5b7b98378174950b8f623d6352269647859143d770e40732f92e8975bb4aa3e77fc9c36611807234c175c21cbadcc2f1c4feffc4dc704b621116f3469cd1866fcee88e47c62476d4c5b9792f262dca0be4e01a25c19f5d7dfbf016bef99a509925108fdb549ac4efec632df0c47e3ffa086cb2acba5f49a3e2831df1d4cd24a3bfe5cc5b66588e7c168de6ffbb1c042c4b605ded0b6cf069780f786d9b5d050d78c24bf800144c85658955c9ebff22d2839cef567ddc1012158b33c6ed67942aa2050c85656908067255f828381635431c933fe9a9eaaadb128d6a53fe4617bf90c12e3aee7c7995d8b996a11d899b511a456f67d100a3ca8ec4861e1e1e45146fd691dfeb9bfd2909fb88a784a282aa2541456c300740d84d0a032b02d8b92f4fc901f3cf8bd3b51d7274bc7e07406cd5f8ccd81d94316cf569d19415e8844d54bc614a22a7617a00507d08bc39ec62300b577748be7c5d69d2b8a9db484ad0a13ad6dec6e2242029521dd741c762987457c82130fdf51b5d674f8d9e19885b917908fbdae45c2a257b740b4d7f2de1732a996101078524776983777151a08c59c1a86bc92946cb74d33f83d0afe6402ff97714ffc006c7e42021238536cf49b1b5a46562ad254b7017e0559fbee1508c8c00e5b0f6bf687a9acb06b8e8cda725d2aa4365204ed4352563fe848fa154be2c19d692d2b27191bc7fb584360034fe24ebdb57d622a7e6cad09effcfd016d61292aee859da0c12cba1ae996948f42509606b4d2f48fc9965ba538225049142a84a0c3320028183278518a4a10a6970a0d94711a009faf504f0ded19208415b894badc1ffdf27d0372a82061b1246eb83a118f6f1a8ae6849c2484b2541420b5b72fc373cd1db379d3704d11279c195a39c8a8fa445b0e7664be4ef2b473c0546bb0664be0e7c7cdf49265c2a0d17003a6c3503a911b8839201a9819437b31656abf30fbe2dd1bf3ed04f9f14b00ac4f40e47a9c57c9aaf1fdda895aa66889cae169a1be70a95f1afab1a2da6cd3f0b741151afb98a1dda6ce817185133cefe84b55020cca2ad1536cfe341aa3d0c9b62ff0f97c5af27c5d510cbe86b02df80c923cbd15cf2764b9d15d2b74c8b15674a84a3100b737db4be52c3c30462c2f0176119225c535037211f8026ea06ad0a042854591d355db7fbf539f3c5c2430ea15d360b27f725dc18603e8ccf9251ae69384c0378d3f63d907206dae394e4fa0ee161440ecf247960fb21c15ed3cd3f4b1fc3c006d3386ee3b9cd49d73d0109881bbaaae1db3f408a70f08bed945e3c80e6b2b7fa1b077ae8d5632813cd9abab09fa9512c53a2a95c03341f103d5c5b2e06d4f346e54c6fff319b946685799f3502042d21c16bda0404663041cd11f7ba563c7ba3c602d20b1f7efbbfa273491661b85348028da2e1a56c96e5a4964b009e907b7788691c07757858471b0cc9dc6bd0025e022f0621160b8e804dd46f6977053fb7846ba7b568d20341806c1145771201001c852fe3ad203cf6406d3babab0f8ca47c86c9ba1f39cd6f42c8ab48616a0b52189dc3c571bca576525e8b96b1a07d23427d7b9029e0a8f85d61e7516cd7bee8d5d9b5cc6c1eda847cfadb2707c64a4900778e53a394baaedcb301e654d3ae328d3d113544173b918eaf6e44486868683162557dcb2c4a07de9e0b367fa05f159f906bc2391c4aad631aab3b67b6f7eb68368065076c02f77d1c0a3a721cd4dcf9b975fd57a1878719ad15edebeed330c6ed4d87dcc84fe87efb9e2a8384be93ec41fc4a89b7d61dc1294d3c4b51c0ba1611cb3931a92c463013199a151d53fb9574d1b6b08afaee982179b51542882e7dbc0b2bf2f113cff08b5214a5d151037ef74b2ac4776258ac4a4922d9ee6d8b8e26c4745743c3605a911fabccb9e82d5ee28259f321b9b5664d1d17a171522b6e4c134b28054845d2ad7b8b5b637a16653b0914d18d306bf39994ea54313451e95c3efe6f1e42bd256e6cc84c2c39dedda57645c4780b44792f55eb20eaa338e11b3f78c72cf6f0025a06978fef1097d3e761d97a94ff091c5f389e476afd46054d94bd71819bc2d12fc1f7ba06ce2274e9985d1f84511d15738558dc7ada7df6efdfb7f7e242eae94fd17bf963fb7f49d96dd91efb01800319807a460049ac541bdbee67bb28ea9bbe7aec30f00abf5e6be12655180aded2fc793e07b3539ee9ee7eb56c97d25f531d1b60703e0558d5de05ed6349693d664098afa11b984053531f1eacbafafa85e5cf6e3e4397afd442860418a409cb25e085cfc68a82f9332273588a3c168d98d31d101be8758ce230d4a4b65212707347792f26bc17d899c8a6c36f4c195852ed65c6fbc02313977c490ac6635824b5166af2a2d2d29ebeaba06234738c1abe238bc6ea8547f0c23f1e81ccb4284dc66f30b8e25160c917c3e69a4aa409dcff9a59328b9978414ab6bcb8811501f1c901e219661799fd594575457b004a7f3f644e177a9f2277a0ac30c6f744d6eb0dd8f4987d03e4a52ca5fb0087ab43c97a0f48f6bd25912d44ad511fb7186441c6417e8bea89a73f63fc951870d75318d85ff2b283b93e2e5dc2d4355edea26dd8af0e4060fbd07f896d0c0817205542bfc87b8fa67659f7d46e43615aa67d7331c27724ccb33d96534e550f17c380a26dd6429de0e72caac6ed15a8c31d40a8a1f599c5ae894ea7a8bc9852b3df8670476dd4d1098d38fc48ba8bf4036ebc0c0b7d7470d7903f0facb33debebf82521eb606526aa9a2542a1f0db6623443408d7a7c556f46266703629cc8f8e1ee0202c2b0fb74e97aa4784efb1d35e95c21c065c708e29f08d0c98687a33c720d108cc6b9f8d5c93539eb6bd57a15c1c7b5fa0338380400af1db411db73dced5bc706435bcdead0317272df15055ff92d245cc65d3e103b1b530e2c435a4eeb0b3e3c2996b122890344ee7391223e3b8eff0145dcfdd899640c0bccc914742b3fb191ca0933defbc205c8a5f753e8eabad9bc3613417b404e3a9d1503cbfbf3fb3d2ccf5c5000c0d52dc55605691ce62e5ff4e513934c390b2f8dcf1fcf6485ca6997d22a67a970e4db833e44289577850ee37a233110616f7300072aa847eca751ab30b6ebdc0a4e7b5405450d5d247402c96024bd0e517427a79387418aef3b4b593b3c428e3b340d08251105e26ac39c6c1f3d07d994ea34839c0832a33c0dfba564466443ccfa60079b6b0625d9fec8f2d8267d584ec5870f1de7b171dd09d18d6f6913a845ed684418f598d2902828352d01aa875d54271c4c725071a55e6dcbed569c863fcdcad6b34fc96ccb2d52fdf0f6e56a7d25bdb64b2277fc9850a572e59402d05f78d1734e751fc5ac0b5b6ad31a79b0783b50e36c87b233ff8a0f7f1d9a3f416f072f89a4553efbc8fea515edc249d6d289880df0612d07a7ef532de583e24e4c6463b9e7620b140db87aa04f8cef261f39ef60517d32585bb1529145757f5170ac5fb20eb10642c56993453da240fbb0b4f762f412458345b883e034ab2e2b3fe3f1260d92edecfe6e80f4810408abfdaef63dea0b581eb980fe8919252ae829908b7da3ffbe163f6e10cadf444f5795dbd70fc0d1698e2a570f0b213ffa0311e12c883598565602db6119137f4cf26b68aed6354fbebb6a71410f967034d690522ecf47dec0dc8a50b6e5c7d98b4e56594938b158055fda5389e82218b95f90fb95c31dc6891a500069435a118c98325e0e5bd6a72c31e3d1c8aa223492d6adceab315b491368e2f00ae84ee3b0339f4059d6268edf7031600cd89eaa4a623ca61a192ca173faccb21c0f4fb7d7f7eb81fced078aff8e1ef81d7570f0230504d711ebb5b0f1825cc6194c7e0498f98fbfcce8e7e76dce8987cf513c5ef4a8fb2d4e6c2e095219a9e3d5cee89d09f91be43ad44b1c4c90f8315bdb23b952bd52a0d33cbdf461894674752dee25290b94d03dede4bb0ec0f8ccedf5b5ff1d24ad6a35021fcc89a598797faa17116e3a625bd1e7efed86b4191b7f477e228440e1f6beb00d70e31a8160200ea8459416a88000e6448780937a511af9ef26201b5d265026515bc0b6a08a06d70af60521295546290bb5d6b172f2f809ad8071a4c1edea2962fb8766497f825b337453256785c0886c347eea28d430bed12d744b11318098240b2085435aa9bbdf040edb3b00fca3165e0f78896d5b4b2d47aa5d3ed64715b2501a44ce101ac14e03ae10f432d4b300d1fd04a75e5fbdb2216d5da7de0a41e790c1771638e0f034f8453e00f491e793d08d2369dd1d5de803fbccfd92b227458a60a007f949f34b5542db52f0ae330eb30055660c810c5932616f63c9f72f57db108095cd8d7d9864a68fc70bae6b8fef8c3ff6c761110140b28ea54eed5ca2794f845a038215da53ee31e928bc5d9598119c3a45e1c63b2a8cd2b98e7ccc6e1a0cd5a064ce58b997a172025234922edab0deb64b13d63edf546ae30353ac7b4776e191a2bfdab7b307815d8d7702bee1d312aad9b8a10056940497c98891f6ee37f85c686893ab3fbd63e6ca4253cd12cbf9e84904a85cac54507970311d6a0d3eb1116e2b2d3cd00077f1f71ba5ab39559f150ed947cef4c07134e0cb3b5f92c840e189e05243ff331471e8aecb2800cb9e7f7e02a8e5930be8b05647eaf6d21bb6a2e2dee825a1cc28b8d733304751d8230ccb52b2049a29d0ec78fd615bc02b7c0761a5aed6d6b7914d2b3a7ca85b5483ad83e9c8c27f3453cfcf7401535a39a42524d133c445187b4ddb1f443289b03fbc14fdc18f7cecd7720237d15bdcbeab7bd306d30713f1049e3451141f34e9669b73cc3bcb3dad408a0c2476a0096680311aff4f8614a96f2be719c9fba01e147a8c31c30425d236b086445d5df0a9933b8d86d331e7ff5447d0b90d478c3524f0212abe7e258d6ab60cf3f0ba1b7514187d5f2b3723dac2c20cb9a86cf61d1eab86f19a7dae080bccd059b215e41ce482c1db6d9251b7b03583a24b459033094da0be16005e4998464629e30391788a68c200502b1811597a48522778d9c32a0f9b214c44a614f6f20f7a53edb517274fbaa7849d8b107ab8d67f290588e8f3eee40bf86268f3ec4c764307479f34f98886cd871d8f5477037415895dcd110ec126b570ac68536a8e8ca9509be0d5d41ee6c604fcad0da320a52631310162ae0b1addf8a7600840dac64845eaf2179805b9788505f8096336c6a7e153fa3eba92d98c47d6d194982f85c9e6560e6593fb42abe298717021bd5e93d5d237659c2f2ca87ab7c1b3cce60c4104eb2e419240c2c7d85f7e3e5efe43ee00f6bd4564598bd0e21623d9da0636cb0cb851c5357f6c8804b8d2e92b80a4b60374125b002eae0ced5478d975ed86502fcaa6e9304d605ef56a6e0b5863432a86443e9eb37aa62a7968348f9cf5b92af06c7fd04620c41740ca6d5233a6e9f47d2cd9c6d111bc21d702d4e09723307b04514af9d8ba5d506b099bf05de5a92cf706a41ddc2bba7f7a90f60696c3fcff9a03233c908044505f6f9668ad07c13827e1e3be2e767efc2f5bf5a32b2cec0546881cce7055ab0a0fc7a9f0532ed189136b6dd3d0e907c3ab2d8958fe9ccff5abc6e0833d22de8357d1c7f255bd920c31e3c13e53812915a7ef47750761469980c27de04ba042a63dd448eb1d86a1cc3f9802e045e2afe7203dc346d5d636305c72fe59357eded6c511d3194e116a2292babf76a9d5fa5e28e5beb8ecf27286fc49a548de16edaadafb8abddd3fec25e2a1b123c68dbccc8bd3d328b1e24eee190721729ecc79a15c781a80d3b4b860cb06b74b053b7b1b24640e1cc6b7ac48b66a98e1497f7dac429146cbde66c220e995838dfb857e65d721adacbf4ae312184ff1794d75afba0e9985016d7bd5f39b624310cf73d4f94a84ded87c0fc5622e897d4f490eb6576c719511e4e97d73f1bcb8c1c4010e9c2504337a1145b09ae26162fab079525c753a7d584c29d246c138812348e63725403d2d19497b52487f187949d0058d7a874cb24abee1a596f082bab2286fe179bfe6db4903edcfaf451e4ed415f8d64fa6262436177ccaf8aa6e13484bb65917b912d4f8170a48f74ad451fb14cfc4d14fe8f6e1264aa025599359a224be6040680ad7b251fdf48a8188fc8a3058e62d2ad2952d74ecb19e31bc141ab8f09c7237d3232b6d9ce9bc6a97a2ef31a1a1d709225af0e005e5fef75cc3caefd7ebc4b8ac4ca1918700708f9d12b57e0091a01da0a8fb89a22e4fb8143d101ac79e00e4666c0c53e6ba12d9bb413e2fb01c11e023f657fd8f1646569c44e08436949c5b0593e1cd0fb3f3046e3fdc804b2f5becc2b77abf1e1345a24c1712ec126c99f2149da8186ca7c7b14459dba329e67795aab7b615cc4fa5679434a94fea8203c5c48e99af4e2f1dfec1ea832d167a57857886727c5fdb853e7a5e6d60b653e426a1d53e10b23f8eef3228e436ad0e720d2519284a82c94fd8798dda2c5d580dc71e50065783557e7048fbcfad7a4f5ba7a180d574854d8bac4fea3b089b3e4b9160e27b4561e2a9d7f56ec1aa9d9e1025436ca5eb0b58b7337d1e61f08d1683d5ecda1a1176fa51436cf32d94b7284d2c483c40e263d8b46e705a05e3f0ff183ba74e683566f8124fe5baa7e561749294102b98021daf4c66aa6466cb0dc307e836ddb8da84d1f3f3641ccc143392ba7703fb37430520029864e3b225b153d1844ec87c6a52030ebddcc05f5018edb111617102aecf2156f290d744ea028b45f0052b8c4b317453e7f156d02d2c266c8d5ab09382e3ffdd2860bfbac23d40def7303b425e56cc3c55d1c52e4e0f6ead94347228af0d73c03fe848b75065eae7040f7a47c7c8bb295d653acc64c23e97cdf36f043356469744ff411daa5c88744103a19d493df5afc3b13840b8374c2731c37b313d65d594b8cab0482abc01ea42c1eec9c1e4032b6075b7005234f7ad050d01294dcddc96c9e74f20d5d053dcabfcbea36ec405c678d84ce7a7e8c2ba8ef021163b62a7cbfe7fd0363575627ec44386dd821582a0956ea5ba58c3699624194086045ad6712d6a272c7d53fdba586e859a429b33d1bb642ea2b110435d2ebef1b13694b740f5a6c5c294765537bddeb1d9f8c030d7ae0b0f537162caa535f51253b4869b152dd5e6404d14e65036f0c6d044e3145f110501068ab26070077250ff0a79348c2bfc2b61b81c0cd19096e93ec2b496bc30c1dc97e33b237a147d4999999b2e28808ab3c9cc7266a6f8b29af2622222222293a4c5c5d8faba7ba6a4442cdccacdd2d0337127d137a0f35414cf06a8294f16a82b8e0bdd742109ad00b7c10e0d5f0b18057c38716af860f10bc1a3ece78357cbce0d5f021c7abe1e38e57c307115e0d1f5778355270e1d548a187572305f86aa440844c0ccc8b55bdf7de7b2fd400c30c7b0ce0d5ec11f46af6a0e2d5ec818157b3c717af668f14bc9a3de278357bf040a6063d12f06af478c0abd18302af460f0ebc1a3dce78efc58043e8868a17bac1e2856e36f042372778a19b3a5ee8c608efbd1821425c00d2420c0c41725ecd1a4d5ecd1a545ecd1a4bbc9a35b457b30614af660d04bc9a3520f06ad6e0c0ab59a304af668d345ecd1a6dbc9a3566f06ad6e8c1ab594309af660d27bc1a3680bc1a367478356cd8bc1a368c584198b2021e6e1e062a27325c69f2aa0084a4b071a30816e9346d5381a582344ed001313c507d21f29c66e217972e05745d284d335df90144e437cdf9ebea74931f404e278deb7f99b496260250bd285576218623d8008a1edc26eab8782fb4aed3324c49f7285469eb389c13a7b72079ef8df1deeb5ee8883e8e70c011464247e07184099e88f3dbe5511ae7aeac34caa2fd962cda5f79af92e140f5ba38428617236e208df802014664efbd911145424600c0089a1bdff98d679acece1d5074c9ca0e17afe7bdf7c64e0d4fa4f02408dc26326246f7848a27677f82c4e3e1726278228388cb3c4a2be98d8909d248c17bef47971772e2c36da2ceff0092693dcbb4a02bcb6912c66b624513d2bb706e521b0787abf2563085aa0858159956e2464ce86042c67b174ecf4a59b8d4e651a91e2ee76dc184c97bcf0a42e78ef79e91d18973c1c1c9b4d349e3234ea788f71e958b66c90cb0be69dc53d17ee6b3f9cd3f31cab46c13857238ed6f7ef358de7b2f3c265e2887c97bcf878b274a5cce172c78a12ff478a10ef8f0deabe1f5108057430e7901f3425ee4f0425ee817f222032fe4451a2fe485105ee88b202ff485102ff445ce0b7d417aa12fba78213086bc1018392f040617302cf0421d78e3853ab084170283e6ce10c47b0f87f77888083868801022e2e6bd272f21ba494369fede0b29b982db44534b92245c38ef555648e0bdca011178af824075c5032a2bae78afb2e2bdaa01ef3ded859288de7bdc26925a7070502f84e48913a1235378eff9d0afcde7c81defbd27f34247c63802822356dc5c3847fa7bef0894d011fc2e1c8db4e5ba3932c37befea52da48083876749ab4e5ba19659a5f2084c34574e1f8906925bf048774e1e024c1910f0aeb338da7d3342a7d8ba6c271daa4e3a72c0046b19cf850be79170e152954a860970f3ef860c30b6122e021603942f8056ff32323174ef79b116e74330a612eae244992bc57194008026028efbdf7aaecd211ba2db861bcaed4fde8c4b9702e978aeb44e8fed0cd79ef11190db92e9c9b0b877465a5ab7b2a4754f15dd3b173846c077aac9429b8f6f46c9ed35aa76d7d6dd1b22c9cf6542e11f728eed2a6ee8726b872dc0f7ec3b5a72703ba444138b9361391e69cee74ff1a89d34f3a6e2ba536d4d571be9bb421a72b0a144ec4e17001b848a82bd34aa41fbf693feb880cb93c67d24d2ed18f9ca99f9f1f7fd2d98fa8e33493df5aa6715e4265bff443e466c88f2771fe6bfe73a54c93b83fe9adbb4a9bd7e24d25132fd291804a265e42e520f1da6f43ae4b47b97e94f820f93969bf7dad4897d22e0de8eab48c8bb6e41215c94a977ea2c45d56b4293f2b5d5dcf529768f33797e8c925faf9e9b94444b82038943e0db92e11a7a30069ddd5a550264d242b0db92e11931d7fd23cdca37a76341fae7bcfc3351f1d2699c6a36d1e4ba6f1741f434548081e1840e23449e3912334440ac4f040688809848650c0105d42436c19620ff133c4e83d9476110162c88563e42202c475dd0071e1a0b4eb06886bc875e1dc7017134a848680a1216878170e91211a87db449bef50baebd185f38c8488dcf1de7b0f206285d35bb8fe4532cdca08c571a32ea5f9ae796e643295b28cb26cfad4d180db4c26cd2b274cbacbf416afa50484e2bcff5c95f7aaaa972a2d3bbd5799fc4967ef55efbd2acb00d8a84aef55a4f72aa0aefaefbd181e0b7cd5dfabb87eafda5a974c39bc84d27c8fef5a14cefb269deff1a6ad7da7f154c9c23528dda69934b7792da5accaa6bd4967d3b60ddb524b66a544a7ffe57da608fd6045045610046e3ba25dfb94daf8c5a55023adcb4aa3aee53d274e7070baa944e238ef554dbc5731f1dea379d5125a423ed0c76da2900fcf97b68e9fb4df3aee92e3bd0b2774a15ec7692895161505b0c8b452018e78a11ef0cbd19c701a4fc5e5d280aaec5d5122c48315ef8578100093f79e9217da6105594903e98bcbb2e91389677e5f596abb8ef85c4a2e2efac44547f11d97d2242e5848073c423a5409e55085f7de7b43784c00f0423018e03d9e27520b0e4ea544b5840eefbda017c2c18a97798ef3a3912f6d9df542e8863e1ee781bafff9b9b6cc2074c312ef71265d52822468db61431242369011646a231432226403c977a9ae74250bd73acd440a3208d5f082f79ebeae2a8e500d5810a1062496a84107d12e6ddd9569250b4b88863c7c68c8c08f100d37cf6b29856668c21375eecd10826c8b961d119a81149a61894a89196a5059152c881792c18df77a494f31792d1e0a4af341694fc209c9408077e134e1b84d6444db341fc304dec309c5b0dfd5692e3e0bc5904331d8f02e9cabd3446e827c9621ef65042118ba782f04031021186642213742a1351eb7898cf08d2b72e25c363f3a712edcb643355278efb9f042354608d5e0e0bd77c30bd5b071e1f0d1cd85c36d37174ea9fb4dc767d13e55165fa0518223a7d2c5e92da4aed4b5932e6dddd72e94d65d9de6e22b07f82053b6e9cb6bd1f68eef1acf1226beb4f95c3d3be1e0ec536ad3a9a208b93005add39bef4a32581982068f2666fc3842119800812b45bcf75ee80c213ff0017162842a1eb78938573a19e1b8bc500b58704648dc7757a73713ea3ad2fdf7fdd247b0e3bd4a008f05d5944a88055c49925c5b8abf18416448166dc4954444b88b004446d70d37240004b86eb821413ecb28688f46222e2b19e932dfd337cdb912939c269956eada9370707e94f8f9b9bec6af9c4be433ed864957d29ba6fd2d5b3a1f5465e3b688782eaeb46d9a5f5cf75a3477f54c6bcdb4b58bd35bf476913894ceb86b6bae64d21d7773b35d9b2b69d4d5759e2b91ae2e88ac44e2a5cd9f3c09e545a5d375f21d133f3f4a7025ae6f5ab673894c1c4abbb29c4b746da5adeb3c133f5c89dbfc941f257e89c4b5bfbee677919413a5ebc2b934bec5675c4c292630265274b28c4c26bf45092694d872dd98baf6245d4403e2bc961250a669dcc5e55ca26ef2a5af77aa48095ad2fd14a0d2124df3d19d6692d3693cbdd378349e9e55d9c1cf4f25e5bd8aa782f25e75c47b9511ef553bef554fdeab9c54d87b1593f72a9df7aa255511ef5544bc572979af4af25e85e4bdeac87b15ce7b557eafc2ef55f7bdca56f4bd6abe57c9f7aaf85e05dfab8cbc5789deab8abc57ddbc570df1de83a984786feb03c9137d9dde47cd23717ad4b557220b59bc2cd4e003113fa351e781fcd73d419bd7a271aec4440a2cc0c2e9bde743d056da7d87d350320f85339972b8207f04eab43de938edc9a635d97c964d9f36dfe92ba8d3f6c4673b725699d27b4e4ec7c5f37426266f4295361fcda70365a52ed35abcc953e19e4cf15dd3d9e239ee4414274e4c3a4e43d19d66e2bba6d3f99e5e62a2f17053aa749c86e23bddf558e1986c7e0acf525a96e5f85eda3c909ed2bd49678be711c9790165a5de378f12c919e4b37441fbfa2142e466c890af0d71d19f8b2b993c69d3feb5699fd33bf328ad7b1e8d67f37d93f2a5742929d94e4fa7f10065da76658b0645d37cb8e828ef55329510cfd4d33b8df2543adfd3711a948e4b31e97e8bd6332c0a5744a10528a060c764d23a5c749453a9e3fcd5af4ee3c9b4eb6ba79447695ac77389b21bddc371fa120599328dfbf9e1523f9bfeb9b8ff35dff5565a72897e7e525a1205b82e254a74a7995c377dbb6e7a909c4aa41e948e92e4f29bd6f578541014d77569d9cfcf0f7601e0d23a0e75d25c7ca6b5943aae7dd71dd7a5b4eb6b22ae2b65291f2a50b21dafa564ca41797f440f5056d29e09b7898c90384dca5238384b2063095cbc77e1fc5c9dd6744e4b102da146097528010edde93e1a759e1b8d7ae6b991d653dca8fb274a5c67de024938c27b03c84adc496f1a75e78c252e88d3dda6458152ce2d9a4adfe1e27ba64f5a8fcf341e9f24d0c0994c7dbcf75e1172700428d58b55550f0b4190600412f4d1a54e6abc5705752a69930e17544ee77b9ef81e2e65426da99ea0d412a0acd44dda13bfc305a39279ce7926da9b7480b212a79974baef509ef31cd4697b927994149d2d9e0775da9ef8eeaf482d3838d38ab472e25c4e1c0922284104fc7eaecd934184191d1c9c2f86d0719bc8c8c86f1a1f6d4f507af3e1bae734141fdd69262612a79f701e484f117157a6dde82d95736d5a93cbb44b5ce6b94b97b26c1a97e232ef398dc4af2da5257189b84da350fa4a756d435d4208a1b7f8259788431151627289c600021c4f03c21640c0de13fdf41d8f0af209f247fcf82c9afbc9b49f4d7b13bfb8ce036db9348ebb3a94cfc2bd16d3d6416c5ac7795277dd7057aeee535d89e4f70594957ca9e3a5939669dc9b7cb84bc4f9af69db94207f4467c205f923341e9e1a3da0bcf73a6d1bf20050837e353d30e3bdc76d26cdb5f752200023020ee88190474551148b98b4171ae0017d3b78c2d3beef20c9dbb2d2b545337d5e02d2a014c943029e1bc2bb428d0ee87b2f0befbd0a0b0fa274c79d4a9d91ce734c78efeda1042bb3f48b0a449cefbcc9f71d19308228227345049469db96cb9fb49e4bc4ed147769d995e96d890c1625548a73edfadd7329192578788121a6c76000460b283c81c89011571205f92c23a0ace4c34b1f0fa6ca83c16e12de7b48a099811294e9aebdf78ef0de334211de7b44f841086e40df7bbe6b99dee2793660832964259315346cc085688957e5bcf786f0de13c27b0fe60725a86a70849a1aa05e50a635d7bdcf3493e74a974807edcb6fcd9b78d6142f4bd7e9deb5ecf2a91f9fea3edb22c5778de7c76f3a08ef3d20fc400545e0c1e499f0a879ef074bdca1c58973d1a78cdb7c89e3383ea2411eef65a59e2d403ea29f4e337133e822d232a01dbda5f40c8c98c190f780b252a77996dabaeba6cac0083f9d66ead1f9e14a5a4a7df3bda2b123ca7b5c89f39977c280299a90c1e3b4cd3f61eada9b2eadbb7e89c45da983dae181f71e9c4dc8d336456f76c000d5a105b789bad469778d4b9114cd22dc778d1709ea4a9b46bdbc57bd07430714de1bdd408de7fd1f69dd880e2ede7b9ca9a43bdf47de7f3aac784ffb191ddd7b8f0e24e8c0ef3d2ec86719f94ed371bdcd67d9b42da3ff353a6092f0b8d11c763cae660e33e6e0e2cd81c51c5ce6f819cd31e5cd81e4ad214710e490e3bdd7479d66e26ae428438e0c5c5ad7f512003c17de7b971c327023a0acb419f129277c1f71af25a68e1890b1f9ae6464e7bd8742fdcc34010332b84dc48d368fe2a5ce9f70800757e24a9de63aad6d5c9fae233f5cf4c9e6427211e1a24f36469c18622a797e19b99cf851c00be678efddc0067854a99a38bc78dc260adabacc1b41e9531c3ad4e0bd47830792ab974e5511e0203d5257dab4110ea56d1aafb2bc3185c76d2223538b11be713d3c52767c7478aa1831422227ca4864459bb2792d97d67593e6b9d216eef25baecc3f5132755d69db74e92271cdb56cbee79aa2b78e0bd693334ae1e0f0d2e6330f344261dd6755b847715cba0e07878be2052068c386f3dcf602d37bef3dee513d59b8e7e293857b92ceb66159a46028bd6d71011e170e4a6f5b2eadd3e1f414cefb2659152abaeb1180a9a49b44f1e9d1d97c329f45fb786ef33da87b9ea0aeab7499efc961811058d05f960a1af9ae679e6383882a7e4b994aba49cf7c4ff7deb4755665a7d378823ad409f35474b8ae97f4683c3d5b34285c16ae41e9e93a1fc537e9594a6bd2693c59b806c57355b29d13e732ea99e7d6a0618d9a0ba7e37c9f61e43b2d53a34811d9ffbf191ac15e6a4f7ded577e3c212d924602d220a511441ad7ab78788f0a687c81d2a730d6a860aa207888de7b4f38f1de167998c1c5195378a2cc775cfca5f194008e2a4a8565435d57d0beaa2cac9757d9e0bdc7c4ab3943e6719b88fbae653ddc6b19e1e0f84de32314b7843d92bcf776f05e1eefbd245e4d193bd8dd97b68e4a112cb27b115fdabaf728f0d028438915bcf75470450ad8502305dd6fd1b64ddbefbd34d038c38cf7ca48c1d37eb6d37b0ecf16bfc5f3a0e0840226efaada40011926dd95b8d7925d287d1a89b270bd7f7e2e2e6b72893aeeb74de398f8e1a2a3fc28e1b7ef224e43b94437415d294b9d4e1a1f72c36df14d34cda7d378b85910579920d503110a9883c9a3611292038ecaa202c5821c362e88017e9d0b1bd040063260c57b0a50c002a840000236255d0bef95a210a1b3d275445e405c99375df04ae2c39579530dc131052d39554e158242123e4820821f34b0c402584c795688d0e10dce9bf62e655dfb8dda941b75482d239c118a73030a374e6e2c41e4c2b96eaed1f7db109f2d9a0e8753dc5be14aa81cae84d2409909752ab5c144958217e4f19c287941cf538284f35dcb5c20c71b713e9def79ef4579ef15e1821fa1162480054b7817a840d501a0ac5405154ef84d0b1b4caa2fb2a07c9795b8ce5fddc7a3a4683c95176d3ac867b9366dbbf9f1e3c70f20995e12d46da554ce0a42a001152421a40614ba08a9c1bd0704146abcf76c2a04d29061d4850050a0417a4f779c358037ceb843a6f41e1732838cf71e243d1b3368dee352861aef6965d494717a5c7ac66d229a2d3e8ba952806c899b9b244a925c44b8f4d290ee7b2838543629ddf750aeebbab225a0b8b8f4d2c803753f7a820b5a1033c61449900c7165de348a32833198f07cd7b231d4088df19e49fb1ebf4de97af37ac36aadb5d64a29a594524ae99c73ce39e79c524a29a59452c618638c31c60825945042092594504209259439e79c73ce39638c31c618637cefbdf7de7bafb5d65a6badb5b5d65a6badb5524a29a594523ae79c73ce39a794524a29a59431c618638c104208218410c69c73ce39e79c31c618638c31bef7de7befbdd75a6badb5d6da5a6badb5d65a29a594524a299d73ce39e79c534a29a59452ca18638c31c60863c6d7563a6534e96ed3a29c769278ef0de085c4c0416fde8811be711a8f2f31e9a69476658b66f24b74fc13dad6e43debcae6495da76559d74bdeb33e158d87f3ef3dabbf67f14c2b55f1548234946de9f7ac24ac1fcd758e6140a54d87db341eae43a53c15ed4b7d6b2ec5f52cd5a4fb6c8b46711d57f29b0fd2a6cba4b3d49569225b673b7e4b75a9bfa5ba7d5da46e2bed4b934499be4c294e5f5b9b44dd77fa085089e3c015deb39a78cf62e23d6b8917e2c01d4abc67d22927ac2490f099c6f39e75c59fb49ef72c2bef5955deb37c7a98c0b0ecf48c98604ca4e8f060232a52a850c14618942a4ca44419219113050727f359341f53aa6b51f0c9773b409aa9eff8ac0494613a5d542132e4bd57c998b62a0c2e3ab78982f688e3348a084b4997e9ac742a6d9c2bf5eb94cafc89d35b2eed095056ea366de75c227f6d1b4882b5830eef71ef59395838dcf01e93ee4dbad34d34d7b9dfba6782564b3560452f6956b40e15b471aed34c5ca7997aa84dc13142a1340ece08c5e558abdcb82ddecba9a26d1e4bd0922c674b71ae6539252d252658c62a345b602004efe1e08c505c066e9082011a6e1375a58d651c719b47993c09cb98ba8005a4e8bc67c1107acfb46d18d74ca61c0b10216481295ad4f17a4a51a8086941ca228c77f92caea0514682ba1acb056ef31d97a2720179ee22751a75994c393838ef592fb8f01e0036181db200800f315ac45811aa00170a4861025d24a0045be59317eb92402781ee3d2e30011180c2ebb292861a454006ef4d915a7070949038fd04091017a44dbe6fd1ba49d3f868238d4ea90c0b3b1e16501e90c7035af0e44c3de088f77ab6665ad231df699e693a38383a1c083900bf670171851defbd2bceb8428bf7de9504c975e1fcfc5c1da7515ababe3803a6b8a2c68a095851a5013bb068ac991347c287cbe9fee4bb9d93ef76b8ae74850124782106fce430a026b400369e48932e9d135a4015ef3d11b70023ba9ca905b45085194f6432f92d9cbe6e762e5110e79754c123ad6439d18aa7a2002fde0b29c086047c20014b7820a01477dd709ac4d30493298773a528de3741401519fcdea3f2425454f1def35baad3fe5f3f5c961a69c99279dd65fe54da8a04f92c378aa8081601d24c168c65bd10153f5685650a286cd1db14c9288245b22ddab6499c2685a6b0e37aa1295ea0fd6c27c88442e5784e93a6f87038386448415fe93af233dab4d10f892b65a57f2de13611d7954e5878ef555778405969eb7a7070b8ef1a9733a584e3b469b47914177d42c2459f3ca7b712395348b8e89349fb7441c1e3369149e31c00044f241205d17953a7fd06c499bc962b3826afc59b46389c261921719a640028bcd76d1a89bb34adc3f1dce6b5f8adfbad49e6b3685d35052e484ff1fe8fb8208de2386de206b0b49fed44316929417a0ae793d078420438428800450811e08ef7f35e058527bcf75a783e2f44801f6e13f5235030e13d6e1365a3cd77a5d1c9a33823dc6b09417147080a1e8484f746244e3f51a20489497799f64469d3484a463838beb47523143702e24ebad39d47ced4962e2653aa89c603545a42eaa4e84e33619245ca153953da343269da1e71262544ae1b9fed70a921ef759b574224e7bae93b48b8b74244ce1477e23472e2d4392e5c0b40f8810ff4a87ac083d0167282004ebcb7836a07efe570a5289da675eda9046d5d869974d79e4aa7997afc13a56c0775da9ee860a8d3f6e4bd2a8f4a0739786fe47b94d08118f2c083080e18410871848103244acc2073001a140009a1a00e085c693c61654f48810e0800821940bc80002816f0018b162405b620838c224eb0a10236d08187184c0c30031f0624e1818c0d4259159990d0a9a6c2a39a4175c77b150d6610caa24708de7b220beabd2c36bcf77ce0aa3adeabe898233400d37b4baa24da76f9adf150a14446144a5c322874ed6f422426749ec34224dd692621a030424037a19f8451f7dce63d909e929580423fbe57c50006af8a23032a99b47fa2c475292d484321e23d2674f97933a79907f36092546f868baac784aa99f742154343e542452361ee7b99000c0f33160d4d0ccc4b55bd1a2cd1b35e25001822aa377324e6bd2053bdaaaa6262a815c47a5555bd584faa6aa6b2aaea45e609abb2aa198b062a552553cd3cab6a41f462c9c80c017255309605834505535516902a0a56f5e3c55430d68bafaa01585565d154b172b02a4b06c6aa906055958c5509a0aaa1aa5e2c1a17c4bcccb850d150555565656b069a976a8bcaaa64acaab25e46950503e407b584544a68aa189b9724d58c65c1c4172096551179c15650c0c4204d5ea6580fe6591da8605e86c0c458d5cb8ba140f583ea59afa6a6e655af82a9ac6a09158d254455593196f55255b33252d154422ccbb26474aa202c0bc6aae08b28c80d3401a85a8001072b8b2ac6baa182a95eaa674db12e2015ccb34a32effaa9ae78793eb8a07a45b861bd543215cc4cd542f5a28565d1e0bc54f8a5b22c98cb12f26348155355331026f6002b0b880c8d555555355355389565e9e045a6fa61c1bc68a97eb05255f552a4fa11c4aa68662aab088b078b076b8797f7f2aa172a19cbaa5a80a97981b16eb02cab92a9607ef5c3a60a12635531950b37076b6726c80fabda344266ac4a00154d55bd58154cf5a4dac1ca960e56106bc68aa95e2aabb22a9c6a072b88350353bdc4bc54d5ad5eaa21d58f4a485555472a1e2c202f33150d4c6555154e55c9d060c950c158550c4c95ad20d58bc543f5f2625930164c952dabc2c10252fda86860acaaaa70aa1d2c20332f150c0d4c5555f7aa6c108206c9cb1031d54bf5a382b1a1faf10327881239f0500100a6b22c196bc6573533c0204faacaaaacaaaa8abc99877a580e5031218925bc2b892e8a6047123e04210957f40f4650c5077a3c1f1f72f07aba9081efd1753c2a5da8b105151f342902e862004c98a2691150bae0e1094fb40e3077618391ac5d00c1f5410b36d7072095f5418505fbd38706ec958527fab1020f457ec2b06ef40043bbb9a010437071b3470f3f97901eae1a60785cc4c0c4fb8981c0bb60a678151cef5dd943b84d244305102062d065e6c7cc0f181768eccc8f971d84f844c1f303cd101920341846c80b158c109911cc9697165e42303798e2025d645cb0667ec0dcb4b0031e411720568474981b17a2b0680e3155602a19242de892040a93d014160c10182844a4d065085208614714550c4ea88722a2b06070782982aa7c501233041e5d64647a9842c50c2f2c41c08b932814d0e5861f5784c8204486279acc80a2e180f0d10549f7c3c94f046a667ebcb4109305660156444103e382cc0ed50b330a2270e0871035a082660a59b860058929223493618ef04a94408a1862860069022400324bc0083193a538a30b27527ce00134d4402a5ae05018f0822e41521f0353b4205fa8ace8f07264e6061b0590992c0384c68597bbe3e46507204df8e8026466a7851e9a2739604d80fc7822a4a72339a34b0d303716880c4e0c2dc8000982fdd004185d80d03ce16137a04bcc4b4d4c25230019203147648450b22448ea4710344f6480ccdcd002931f36303c3f6a90418700e040831034431c4125005100a111cdcc16e6dd99322304660687189c17fb43084c105711333f6680c018893902061751c5e4f0e2430c0df0070d7fc9d8111b6880d0f0e346a1c31384d20c81b181b191f94017215c80611233440c0f3f6c60747821beec2045179191eae5bf1481798981e2872624b0022d23c108ec60a30424f8c0170c384001b87059bee73f4d2c8105092b557aa64031e2090e9e43020004002e1837dae8638f241081082540fc80c30d335ccc218707c010004604ce0e33080922f30235d01041181ef8c28b2eb8d8a2ca90208c883070019f9e3eae00858d658f25ac31d242117840e92b390264260c0860717fe0e006628481936d0d3204014233a3430e65a46009dfa5f018b1d304d3800316a00018f4a82a20c1083e70802b56aeb541061819d8f1042b4a92d81f33322648001a27e0400524d0002836a0010d3c400a8f92234108a9acf052056b0a304cb8966015018608960f62f4a87260d9c0aac10f3c84dc61c9c0aac352c332c10b09ac2c3003a86caa1e687688d1a1851bac1aac192a194231c4c06085aa1a1817ac203140ac1f3434d6cc4c8c0553bd5495cc6be185971c5e56d005e68a2e30506484b8aa992844510346979818213301c84114305d44981a847c01021906748181f28306203ad83045971f49c06079e12148272384a6090d9601f272c406203131e842634617199688e2c77dd9c209427ad025a68f2e314270a8411721dd0f2be8f2c30617ac99233146622650c50c416ec8420a182bbabce0c30b3ebc140919a1b121d487143143d0e019242f2fbc20a1f9a2cb4b94684406884c08babc0491c101e626487ca96084c0dc00691233c44c123238c800911980101984c8f0c3861f34cc24f182052964707829811431707401620030a76b04c40e3038425e9009c1542f455e7460a608a941c69ab93293c30c4fcc0c2e5432415e626084bcbcbc582f332f342f3f80e800f3325365068617a60009cdc8cc542f333014c6084c4573c34b0e51fce82106045d5c0841142119981c68984801d303297e185daf8f2c1001073790811d71c09102ea810016d81222925c2ddb63094682a879816646092c5278faa0e38e19f4f000a84516455ca00736a8e38d35ca2081078c8802508154f7006e8b42139890071e77b481820318a08925b0202185c749931e78a8810635d2380009466080028c76d041cb7a70a1073c70e2d4a58f2c48818f2594a88186900dde7083056b949102133cc0010b183591c415293c3b75d0e1c61c2ad0e2890e7250c71b6dacb10230be680002a66802136c80c71a2b50e3045474f17d070bb5c0042104a10771b491061a648801812b7c1f35b184125776b0233844422dd441471c5b60000254f8de84113b4db023382eb400f38410843ae880811b69a0418609c4888003a860c2889d2447702e8d446008c1bc3e8410041ec0200e37da48030d138811010838e00a2a7e30626209228c88ae60052847bce0c20e74c0c28a0620710572e08a06047111c18f3e5eb2606121c60a5615684000f3014b0ccb0395b4e20bac44418abc0cf172d1d083a54395c30c0e2f375436c0d450d1f02306186078a9817941880b352de020e486203a0009fd98a19199b1646462625eaa870390257a9795369411df355eca52334be025802c612991c7cf35e4ca4a17570adaf4a649fcd24a7c40093094d0e2bd2b09926b481224971224259878efe7fadad5056d26442291123b4f64707831477e880902cb0d36df751a6564eb42582880a5cb4504cbc602e55d9deef4c585b0dc5c5c7cf749542189225c9bf637521266709b6823f193ff21c50f28def3a9ad7baf4a830d23494c79d51bef556ebc57b5c146258497e3a5e4dab6141722679c6fb6b9669a679639669833c6f8628b2ba67862892386385f7cefb5b75e7ae795375e78b3c5f65a6baba5765a69a38536575c6fb5b5565a679535565833c5f4524b2ba57452492385344f3cefb4b34e3ae794334e38b3c4f24a2baba4724a29a38432471c6fb4b1461a679431461833c4f0420b2ba47042092384900bf448c890ca8c74a7cf8412406e8600195280ab001714d77503e4060814d7755dd77bd50bdeab5cf05ed50236aed871e184e02701579eb842ba22e5e7e7c20172f3f373e174df9bae0bc80f91abfbde34e4274992243e542c60e3ca0d576cb86e8208220b13dec3b132871511bc8b2bf954942555bc2712655680ac2079442e2448ae38e4b202df7b3fd8bc97d9f0de26e4bdceca7b0f2e4173c77b5c967855c8a8c2c67b6f892a64bcf7c3fe40a80a12556eb264a58dc45d5ab7857ce278af22e3bd6a8cf7aa13bc44e1850895094a5091e0bd6a04ef552278af0ac17b1508deab3e9081f75e9517ea21a3a7043e3fb811b789a62816b99220b9deabc478af0ae3bdca034264783e2ff47e5ee839f142af002ff42ef0428f8c177a68bcd0a3838618840079afe6046dbc9a13e8e0d59cc009af668c985733c60daf660c205ecd18f5d58c41c4ab19a3c9ab19c30a0c428260f16a826ce005374269e3e30428d354bef650eac45d55034cd72d7ff4f37aee3d176d8948d43d176d5b8c0736f1ad1a5acae3ec5b8a442291d442eb1db4421af5d7f2ffe9a984dd738dea09f247886ea43ba8683029adb063096d8f5ec34bbad193b8d6f1a5cdc7a4b90645244a8944dc6b09f2479038fd44c7c656a96df1f159b469c912265144a2dd47363e506cb025beb4f98844a25ae7cb06aa1960bbdf8fb3a451d77ba5fc32c0fad5145bfc23cedf665827506a7b264da8d8d881c138eb95545e9eb9c63d4a2980aa0e0ce67eeba7d86ece2dae9e0e6cd27d3997f96b9ee3b57c0e0c428aa3a5f77e0f6dd7726095c30eb5c73efbad2fd631c026e5f45edc63cf387e7a61806139f9b6515eac779431c63830a9bda657dabd31a4397238301a6fbf90d6a8f7ee79ee37301e63955777ecf9e49d639148c651bcd38dca0d4c728e25fed35ffd239d93c634aa363039ad8415df1ca5ce5656aeabf2572fc0badd144e2c37f6995fcd99a85c80612def96f5d35e2de6d2926e8409a85a80d1fc79afb36efde18d5cc6383aa3620136e5ef16fb7d73d7f1fb6a46c50676f1fdb7c22a29be5d53bc0696abacd8ce2871873befbb02ec761eadf637dea8b78c28a85480c5ece3cd5afad877cfb2db5897a8d4c03ebd9d6e1833e658cfbe4937a681c50e6de5d9c77f65f6fe926e8cd122a04203d39e564839c5996f39e926dd08e52612c54947750696259c79d76831ac7c8b4453c2519981d57a319eb8e73e3d509581f5c8e3fdf3e6df6fd49bd75232f97e6d7c9c4c2d15c61460d7ea8f6bfe71637d65d4a41b475a37f2379e32953c58463c150a304fb3e610465afbfe127bd28d344ad0d66598482412894422518c58a8c8c0668df1f3e961e533eafcab31b09bfdd7fd4b5fada47fea29149f00f377da5b21ee764e6ebd370106a9ad3e7e9df1e55ac609a9d8e8d84001d84c8162734da85369e44da85437b225c072a6f64ace6f9f1cda0e3109b0ba63ac36578b2be572ffbc816a0458bc16428c7dc4564b6cb78511049508b01f35edf866be37f4d657d28d9d8e8d4824122161a36313a5c746e7d471a901f41cef9b740f9b5085009b5c6e386dd43252aead25dd88a38d8f131060dfc3b9b1ce725a1867a49706d50730efffc597dfbea7a43677d28dded44ba34cbb3bf0ca518981d9fd39fd90ebd937d43b926e18989efc5ebea9975e66593de9725c74141b1d9b4c8a8d8e4dcf4a47d8e8d8d8e8d804f9236c746c364fe2f4131b1d1b1b1f283618a3f469d47d8cf54e0e541ec062fc34fb1ab3cf594b0b45508121e9dc137f3e63df3062d28d262d1245cba5ea0026fdec937bc8a9a43d7349bab1dae8d8e8d8e8884422112f8944f803d51718cd534e4f73d476cb4e3de9c6a0ad8bf146cc83655444e505a6f78f9bea2da3965ada93ef7644221b1f273639363e506c442293499f7a44a239c1a8388059f96fe499c6dc65be18936e1c8da4346d9d551189a81c41d505463fb6d9ee79fb8cf85749ba116b5171816dbe7bee146e68bd8579926ee434d4d440b501ac678d3e76a879dfd15ed28d5bf436f2fe8fec179506b058afdf3b766ca99d9277d28d7e43496c8b6a0b8ce6cb2fa6dcd27f79bc957463a6612922119745d34822d18d5e5419c0a2b75663cefbde10fa2949374e99a345a2c200c452de6c63d674cf5c798ca31883ea0257560de3f714fa6da7a5169079569d6bccd35a79a7d7225a1aabfcd36eb8b9cc346717545968eabf8f3cd7f87594174718ad7ca3aac0d6146f9a7da41f629c6397792d33e398828a02f5decdbdef95eb3e2fdd22914874e25cf228d278e25c6609aa09402feba6d6ff696bfe516fdab66110c651b455b6514940d25bb59c10724a7bf759c7460747a08a00b5feea3bb385735b0f01bb2b847a42182ffcd04b2c62941ffb3c399f5c73efa750b15962a363936333050a7540f5002cebacb8da8b67c4964e48b3e8a4c5641261ff5f5839cd77cefc6d8d1e15d4f5ba695ffb9948643913ea54aa232b2a07547aa7c553fe5a35e9c651e781aef6b39dce3b118944221f27229128c37881ea0acc6addb1d69ff7cf2fa4db0a4c6eb9ad9eff478ef5e59674a3f75b378ad1a3827c248d78540dc0aaed5c424f31e4daeeeb1980e94eb9e7dc6a6ee3f4372f0093506bbb2b9415cf4e39ae02c395fe7ae1b514c6ceb9cc624aed6ce3e3c4a4b34d0aea54bad1567c540ac06eff596a4c65d79eebdb138079c82fe6bc46bfa5ed1723009bd4765ce5c5bb63893315d8fdd17aaebd87b75a0e2de946a0acc46d29eeb751f4401db3f17162f3b587a26363c546c7e6081b1d9b2e154524da7c964d9fbea7e2bbc6231279bf755b24d24ca627304adfb58cd618ad0c5453607176c9e7e6b4ca5b69df36bda66c786cf64cd9f8d8ec9ab2b19707cb48aba4c0b4ed91cadb69ddd147b84d9ab631962a0a8c7badf79d57d7ecbbc69edaaa0ba6bbd4727f6c33a6d95b395337890360f46e0ba5ef51f6aae3bd06c024cd9f663cb5cf52cb5a0b804dee23b5d37bfee3e65c24128990a89507cb6844008c635daff4736b0ff7e5180a2c4fcdebde3ae6febbff9674a3d62d7902e35aee88edf7b84bcabd24dd38a3751284cd0ce5c775df0e65ceb8926ef45dd0ce5d0a95edd41c2e18a433feea6ded765a48e7166c7e1db5f557cf9be5f65a36d28259db31b617d21daf97f1a7300c79c532cedfad9cdafa0edb5bfff929c6904a1babe7b0ec69d652577fa1ed77fa0dbbf8e3df319491d61fa17702ebd55a2d75bfdc420ea14761f6539bebe472770df3b66e4dfdbd527baa73cfb06bf39ed4de1d7396dff613f6f1d7f7574ca9e59ace6ec226d4bc56db3995134fcbb3607d7348fd9cddee01603df6f9ab8d755acfa5dd258cc24ba58db7d3cf7f949b84616ba58419c28a7bde5b0361b3c7e8eb867163182bd51feb9dc2c9a39c9be6fea5f6d89679cf5ea9b41e7f1a75c7e695b8cf8eb397fa4ea83946bf9cbdc2c97ffd52febcb16c739cb5ffa9fdc490678d55c939acd2ca0c2bf43bff605eceb8b7a7d3fabb23cd23ac76be6fdd98e3cfb3d6b809aceaaba3ed7aceda6dd498094c53cfe7f73e66ece3fc7709acc28cb5ac95c7cf3bde5709ccfb9a77f6d45f0927b7170b4625d5126fff7f9ebf779b04b66584d0461e31125896b5f67c6b9dff7e7a05fbb052c861e5f9f22ea5b5825d3d6bce9757fdb9beb60af6a5bc57ef29a9bcf6471fcceb5efdd635726b7985b507bbb1d67ea5a47e7a7d37a582d9fa67fe5f4b2ba3e55f0098e479c26fe3d514c7dca760ba7229eb85fb6f29f39e52b05939a537f7c8a1f7b27b1eacd77c61dc5ecb9c25de51b06e25b67fe39baf8fdf42c128f55cde09f7f730fa23b049e7bc795a0bf7ad164e23b0df7f9dffe3dd7196f0ef60b3ce0beb855f5a58777f82796931dd934e4ce1bc5a3ac17ac61fef1f67e4d56edf04eb9677ab35ed98e35a31ec463929855676282f132c5a1be58d5ddf9eaddc3a988c394bb86d87b4daa89760b8deddb3cc3defbf35cec13aa67a564a798451c61b8bc02c84345f29739416774e0456e3e7bd76cb238eb16b2598f65cc2bf23eebd7779936031c77ef9de507eefb545827d6bfb8438dfde218f12926eccbc69c4bd96518e7534c29107cba8c9114cdf9db9bc796e9a25dff07f2d43c1c1f6f5324b7b6f94d1fa3a3356a7cef842ba61aed0e64fba7134a3b5917b2d3b18dbd5d2ee2bf7b0e71d7f26dd3892d176a73fed3d69da08681b8d682c7671dcba6fbb6fdd5cdb4cbab1db701115fb15d2dba1e7d9ff093727dd38ba986216c76c2fad7be28f3bfca41b71bc13cbfcd7e8e3fd314a3d6f26ddb845db80a2945894155efc2bad9e573e2de9c6ade322267daf7de3bce78d17fa49bab13bfd5c056294c7ba29e734e77af5fda41b7ba6475a8ff2266104b3b46ee8f9bf3bc32d6925dd48e252a8d1a6fd91cdb1d1b1f1b1f18162c3bd952d9a4a8eb7f26019411161b6f238bfb494cecb73ada41b374de223e8bbd2764524ea4e5f24f29bc6af74a9d308561e2ca32b45b0acf7bed2ffbe23943073d2c5299b26546c6c7ca0d88cb2d2955b879a7ed338e5c1324a7283f1fb33d638723da7bdff926edc7c3604467d8e74f62e65f570634bba91ebde73a3ce03d568e3e384d33650a66c3cdf525a0f15916874d27aa63791b6f1816233a29907cba8aa42881197da46231c888c6c95420cd974174410370400072084b0c101003cfc70830f3a5c437af881871c76d041071e72d8b44ee3f0c30dbf4bd910479e34d2a1066a77a0818bb6a5e361065ba50c58c691f459b4698f80b21289d3a42b062efad4030c71a49946405909084833dd10ba6a7e78614217b8205a909da609e9da6f4382dc00e93c50103f2227048d843323223241c44800c0c411102ff2a4f191df46a398c55689e29ebbd6902a8e8246a351c7c503e0e140470d6758a0f2279dc1d470461d4282bc37f2d023c78d9d274e9a604c7496e4149104c9119c8cafad74ca088d888adc0c21049121410400081b00f8605d560f3cbcf7deb3e185a830bd101579bc5411e4bd81831be4bc2400cd1183f75ed50024f4f71e50d6696e64d2dc26e2e478efd1c4e00837e8e2084e2c185871bc3182e38df736cd0836d8848aa00021d404218ff72e9c50102e1daeef488a6ddc9a6989e582d00f98c8400b2c16b0e1032c5e480f217041598e3c71243cd095b2d25f81a974c564cae959582ae85e8ac994f39ea506f79e954696faef5968f452181dcf79cf3ac39b760988a7fbacf47ddf420b6ac6c365d818a4b70aa4e03d3983f4b6e570ef59639c40a2f4e6d3f39e65020b84f1ac0a94e07151c8c111a49513e732ad643ba6bf7559159329d5c4b475a7f17493f6c43f51ea61f29e35826ed350da96553995b449c76b3e9cf74d341e4ca3004a6f3efea479b86026ed99683c59b80645e3e93eabe24d5b6b3c5d8ce7359e2c5c773d1cf69e25822c42f09e0582f79e55810fe89c38123eabd2fd7b96181605ac304ca614cf7b9607deb3c0b03aa0fd6c87fbe23dcb0bac7b1fed73c0caa28b142a0b1e3f782c11c2e3ca7b72f69d12b5d606827c96f72c0d4019e48fd84277babf676520c81f6172d24d25928e85816ed3a8f7ac0bf4d296324d79cfb280496fcde4c4f3926685dbfc3ef9285b938ed31e4a973325d3241fbf6951fa4e498bcd6729655a94f7ac2c3093e6a58cc4bd8f892b017928265de2a59e32c273992f95b2d2a9e7046d294efbcd6700414bdeb32af0b26c5a93a025faa4b9d4113df31de7af50d1b8c6b52bef591498c07ba714e6378dc4699daca4f1aeb484f39b7f129190484c24281215098bc44502238183c3c9a90507476ae1de8a12ed673b48b8b7b26959e9e44f3ad39dee4a4a2312a7499bdf7d070767f3a81477d232df4f5ac6715c3795ae2841c2bd951250966a92a57edfe13b4cd888bb4d4f09eada926ed3a8be13d4b5254a94c88944ce2a1d97693ad70d4e21c132a6702ac867a136d54b72a6ea88c29267802a5a7807a8c3e6554aa89650e5a052a352011d0480c9c102e8a8792f4cc0fa9e5dd7b86bdf03fb50d66db79758dada695f0216f19fb7c24a6db5d9d2ae04ac6a4fe5beb942afa39f3d0998b57c726ca5d433e2ea3912b0ede3bf1d77ff6ddebcf3236011c25c638e92637b67e746c06eec7adfeb39ee3572cd8b8071c863ee9347ce8980cd9923f4d0634fb9e7970f01d3bf43dbbbd49147092d1702f631fd1fc29e31ae3b531e04ac620d69bfda7b08399f1c0818c5be46fa379439c73df90f30986f879efece65df78721f60b97a1ebff637facfe7e47a6090e6dd69cdb76b1a7fe43dc07ac45c4e5cb1b5136ac87980ed0f618411cef961b790ef00e39067ec29affc4719fdce03db985fec25a5df62e8f9d601c66facd352087df531ee9d038cdf6daba5d3f359ebc61b0718fef67b0fbddcbe4a8af70db0cfa7b6bb524979bdf56e1b605a7eae39879a4748b7dd35c0b6d5b15e593ddd78605c4bcab7e41e4b4937dd77609b53f977845ef70c2bdd34c0a895d9c65af7873beab96780ddabbd955e5b3b39a773cb00c33e46def1e5d4ef3fe7b603ab3366eff997905f29e7ae03a31b469bf3af927218e7a603eb9bd65cebb5375acabd9e0383f4622ce7cc56d799bd9603b31efbf8b79edd6b38bd8e01966bfc1c5accef8df66f0d034ceb3d3dfd38ce8c7fbf3a0eec5b4877bf927a8f65bf1a0e8c773aa1c77ddf5927bdfa0d8cde596dc450e2af7bb4da0d0c7b6d7be6d4f79d75a4ba0dacd2dde5e57ae28cef9dfa0518e4b24f8bfdbc5cf339b50b309dedd41b5f8bf39737ea16601d4f29ad9d395629b9cf2cc0a4be71cb4ef18fb9629fd9c03a8e9f62cae5d613ee9dd7c066ce9e5fa8b5ae95ce9d57805129299656460e7dbc3aab0083f3768af9a59beeff715603bb5ce329a9ecfd5aa9714e038b9556eff7bffcef9c6f46039bb76f2a33b63d426a6f3e03db9ecb8fbbdfb656bf6b36038bb74f4eede7b2efd9672e03cb7c4fcdf5f5b1777a674e01866d8c5be27eb3f697c78c028ce27b3b97df6b4867ff980c2c7f3fe18d7d671af7fe780cccc6fe3dbfb4fa6fe7f4f80458843ace9eabe726c0649511fb8871cef9668e4b80d15fe9ff79c258e5bd1c93008b927aafefadd1e2fe371e01766387706ada37c6166f2c02ac7f5fb1bf1f421c6fbd3804d89df76b0979a471ca5e3108309eab9f3bf6b9bff696e20f60d55bde318c3a770b73c462609a6bbde58e98624e39c46160b7471de9dd7f5f5e21c41ec0b0967f522f27f45aff0e06d667e67c471c21c6dff70e605fdb7ea1e55d5e5e3fff029bd75e1f3dafddf2bdb917d8a69d6edb75cdf2fbca3980c19a6b86f5f37dbbc078e4785f7835b479cf7db9c07ead59cffbbdc5f3c37d3780698c6ba73573d8e1acf96a00c3374ea9e5c574771ef3dd028bbddeec79f41be2bcf1cd000679a7d55bbdb5c773de8b014ccf693fd497565c35b5f70218b67f67cebdee93f24faf0530f9b3bd30fbcee1e49e5e2dbeae384738f3ce02eb126f1aaf87b357396705b06ae5e41f5f7d3be7555200c33dd2b865cf13fe8c278071f8f5aef143fd2f95510298acdcf64a27b5f2620b6f0430df73f5b54f1a67fcf94300cb5d721c2bccdc6bfcb1c074ac376a5bf9d7d5fb076013e719f1a7b6578c6f7700c6bbf539f76ba18498ee2b30cc6d96725fcee3a7d30a6cce9aabc4f3df8eb3d40dc0a69c93663df7adb86e0660d0d26c71a573dba9e55d0016f5c55f632d2f9653d72ab03ee9ac73c3a871a75f01d896154bce7fed5a634d1380f9adadbe5366f8fde408c03ae4bfd7bd6bd7dd6e2a30aa2fad934a3de7cf704e81e51fb1a57df23e6bcf520aec5a2833ce3deefa1205a6f1963e7a69b3fe3ffffad205bb1e5f9e739ef94f187ded03a3d1d60f2ba5f3ff0f7dcd02866da43a4e6d23e575f68a050c5208bd84365f2f6be7f50a98ecd243583f8f5746cdab15308af3dff4ea4921f755d72a60b0df5baba4d4dae9efad54c0b4ae17ea7bb5add5ca5ba780c53bf9bffa775ba5804d0e27fe1ce28c23ecb4f281c50cf5de33c3e8e5beb44601ab57631fb9bd18db7a678502163da7f5778d63ced5cbfa04accb683bc7bad66eb796d509d8a63ffed8e7fc9e56db9b807578379e55f79c75a79c0998de7e73182fff3277c8f7c068ddf04a8a6da5df52bd04ec7e0ea39d14e6b8bdce4ac076f6f3ebaebbd776db4c9380f5993b8579572a6fdf972201f336d7bb63bed4e27a2f3d02d665bcb55b9a75deb2526a04ecf6f9f78f73def86f9db40898adfe76e8ffcc90470c2911b0d861e674d7af79a717d221603ff68d7ba5f673edfd17022637ac7a5779799574fb2060ffcbbd73be9def9d71070296f7deb2630b6da532f31f609a6a9e3b8f7a7e7cf5f601f6e3d73fe798e9cd926e3db06cfde799f32a718d52f700fbfaff3a29c6f466ea330fb069f18d5d7fcfa58f36ef00c3d5ca8efbded3de1d711ed8ad90d638efc553eb78758049da29b57ae2a9618c76e600bbfce60829ecb9cf8bebc4013635f45d430b21b772cf7903ac5f3e23ce70e248a59dd30698ef3ac66da9def7d62f670db0a867ce3dff6c2b9c5d4e3cb099318f7f7338fda53fce3bb01bb3c5bfe6fd250db02dfdf7dce70e339cd0cb19607bc7ede3d7bfc6f96d9732c0fc8519fbd93d87f5d32eedc062c5d1523ca3e6905a2eebc0fcc4395b6c3dc73ce32de9c0f0affa4e8973fe5fda2be7c072a5f8f3bcb91cd8b430fea93da459e36b638049d93dee385fba33ee30c0a0b7f26e7cb5b61fe71a07d6eff5bc72acfbfe394e38b09c3b8ef5ee5f27d65cbe81f9cc63febd663d3bfe6e60d65738e3fe13ee086d1b18f63ee3cea1de926f185f8045ed779c556fbe73f450ba0093766abdfded5cc3af7f0bb0afbff6b6cbdcb7e7beb3008b16ef0c398f16c659391b98cd766e8e69df31ebabd7c028a67fc399fdf57756bc02ecce08398739e74a3d5501d6a3c73b6fb82bb77b5e3530fa6d8456faa9abbd3a0d0ceefb3f9ed472fa371a58ec397fea31b630c27906d6f5a47b57c8adc7175633307b67cff5f3d9b1dc909681e5df3bd474c27fbf9d29c030ec50d6496dd731428902ecd33d7bf4fdf28bb7250393374a89aba7d8cf1b631c03cb114a5bb38eb6675a4f80699da38d78cabced8ede04d89c9cd37effa7945bd84b80dddce5afbaf70e6f979b04d8cc72de3cab8e534fad47804908e5f5b4ef187ff55904d89f18e38da98d7a628f4380412e61cc90724e71b620c0fed673cb69e5ec5bd7fa014cfec927fd9eea4fb1a66260f17eef7d9473ff2e7d1858c676df5e7bfff3723e3d8079ad2bdddbf27d37ec606074d69a79e592e7c9a3ec0096f1fc7452daa9e63c4648ba514b132b3732b1bec066b61e660929af7f777dad952526eebb4884e2b064c3f202cbdcf65f3396d27200a3d1dbcc27f4964a1867ed02cbd9739fa1e57be30dbbe502eb9b53fdefdd7cdbaaf5df000661ff36fb6e7bf739ceab01ac73cbff9cd5dfeb31cf520c6b0b2cd2ecedbff5570ee7863f0358c4d2664ea59d3ac6587dd6808501acee2bb99df5ca48a1a43604d60530ae21debce61f21b6806501ccc62b27dc51d79a31c5947423be98a50526a98e9dcfad31b4585adead2c30df318f93fabeb785d56ed28d38f360191dc0aa00366dd5534398ade634661a23605100b39bdee8e1b5bcc34fb19d0016b5cc96d31cefff506b0960f65afdebd736c72df7a511c0b09ddfe68f27bfb0d63e2180518bf3cd77fb383fae3a6281cd8bfdd71967dd29a5fea4336ae3e364c204580fc036ed35e65aa5cc53fa8d25062c0760ddea5fefd59fcfdffbbd364ac0ba82da68edaf7b667dadafd464ca816505f6e7b59073ee37d739fea0adab15b01a80496f7bbdfd43bcabcebf936e3c69dba7363e4e4edad64424929207cbc892c262c0e497f7af79bed7578f171025dddf5e2ff584be8eb08cc3aa02fbb66bdbffd7fc634db55600d63fa692fe6ff5cc515348ba1146085809c07efd37d3bc398eb84aa97746de090f9611170b01588fdce3afb5f550e32ae9161615989430feae6ff477c29fabe7a24e4724d2b1d1b109daac441189aa64a92722d1e6bbf6242e471a79b08c8294614d81d97b75e5f3e779a1cc9d86614911454f585104595db04871c55debab7fbcdc62ba75a83e2ca617ced96b977266d28d7e4b719a898b4426931ef5aebb92de7c44a21ca775852a0b9763b9a5c6d4735f611789301cb70e5539a1c2c284b94ffca3ce1d661efb1538d4706beca9b5187eb9ad00739cba5f7dfbcddaf22af45935b791767a3dff74926eb4e93765732a913891169b7d53369e671aa49e6752b226960a13efc8f3af32fafd35ee5251b226954a35050ae5c416ce4ca9ad12c29863cc97728cb1ae74cb4ab525dd6832694eb326127328ed884a0a18c533d3faa3e5d577d9291f5885d95b6b75fd7c67fb2b8c51c078b75bdecde3adfed7b9f3285e0905ec7aceebae14c7a8afcdfc09989459cf5ebfefdffb38af13b0bfbda71d579a37a674da26dc9f71ec7753b99980d1fc67df7c53afbb9cb2ee81ed1d6d87d8eb2e65ec7f0958cd3bee9fe5de996e8e9580f5592fe79d774cabb7976adcc8036dfe046335522501fb38fe9de1ff3473dee114894e5ff7882212b0da29c53e634f6d8c7ed723601077defddc1e5f2f35c7bb6432e99f95e04d6504ecc37a7dbe92dfc97385927463973a8d68154555044cd2cef5cd75f711a761e47270012a226030ebfa79e659ffbf698543c074b59a675ffbb5bbe693bf5b2a216014579eeb9c31f32d61a741c072d41bf6a8718d3e623d49574b0504ece6eb3bd5f64ec92fec3415e50758957b638871b5907e3b3fe946ec030ce6ffaddd9ef6be6bc59c7463e781a68f8d8ecd93254c489c7e42e234e9898d8ecd1226560f4c732bebef1ffa486794506f9848a4373f310f961157f500f339f20f65bdf1da8dfbe601d6afef3077ccbddef7df1d60716b5969b554775dfdcc79609d5e3db7f75fff48ab8dd2563ac078fc92e389a5ff76e3ac7380d1dfbfedba4f3e7786d1926ed49dc9f70a2b1c60b4e78aabc59d5e382f9ca41b475a27e3d7b46d8a8c335e1e2c2323aa1b607d726efbd4ffd6fbef8e9a446d7c9cd89038fd8407cba889ca0698a75bd74c2bd7f36faf35299cf6a8d48f4ad6a11ae4300a190000a01ecd000000b312003048241a8c458301a1683cd809148002539076b63e984984c12c46511085200c02400c430020c418420c312ad5d8003bc24126f89a4c0ae59310028a1ca25b2a149264a202024f895b45b18068874a96c40ad9269502023b9459622a149b240bc8e950cc12ac50691259406107f49fe4f5ef91a22d20a443314bb442a5496201d90e952c8115ca263105143b24b3e4542836091650e91099a5ac90d224b380b2434896628568934a01891db2592a15029b9405c47428664956c8d344730c5ba12f46bb12344589f7296949ad906f523220b4439d25cab26afe74ef59a657db0faf6ec944839afc81fe3ead2db10af5264907e43ad4b3045d286bead0f7b29e655a5aece979ab7e934ac687563a35d58e7e75a6cda15eeba549bd5b55a79e39ebd7aa34f1764bd7c832d97b4feab45328a79569866d075d283c8923a0fa90b0258f42f524c481facfd7ef64039260924640ed43604b1c65d5fe84dff348afde0fb85a83105b5118228d4f6e4be1421853d5ec11fb6bbca74ecf78bf467d6873e1f738d2abf713aee641a856040c51e313db52b8901c13a2e73a6250903a26b9030a1fc2b05417223c6963368ce4134c0a8c71bc59a727bc9f476db541e0371bc9d86885d3d3d8cf5d5fd81cc66b759ac4bb35ea50cdab719a8dfdd0b5854d72bc56271446c923cd7a3fe0fa1ae6d8ef85d3d3d8cd5d67d81cc66b759ac4bb35ea946d3a856235cd6c9c572d897d3e8d7beda1ea0ab6f753621494d493f1cebbc27004ac22ee301b5ef45f1d0aa8aa6313f2cce12cb95a6bc708da1d27eb413024b07479692f7161c47433c7bf2016e48a1b04637a3f0ccc1a7971ee6c21345e1c7505ba4c67be0babc22197af62f78d19904b5956e08d764832231f1874f13a03371e6a300057c3fc775d35eac5b6a5e5329005e84c02d9ec2c0959e44ae5bc5316d11ca6061a29089e8392ea0c3a0a532a88cac691a2324f684c6b776964b704616a08dcfeca3a97a417c53487e9e0e3688aa2ed66013db9e291812012da846ee35531c9969ea9dc47252b4b6d98269c44a0ff315927c242d1092d707b2e3d87e6425fdd4322cc2393cad59009fdcbe52104264a6014915f2bf147c5e531613d16f4c58970ef9d0e1ce2a77e47ec7c1654a8d58f0ae633e0da2c604dacc1471c4ba21affdb5996532887d6de7b2066249899d5d72ed5c672e2bcbeaa7d5610a334e195b30e9d3d45c862dbab6167b6533a4169bdf9818e9e7e8a8758b13f9ced590c69ed775b09c0a06db9bfa36b56f4a8299e3879f8c65d83850ee3ccc180043f6b7640c47a5b6289644a64b3d62ea344e251e9c8e7ed432fec9b24776a76925a03a743b1a14719a24e1af1bddf26b33804594abd4578806483ec3385479037b821319230af2f0fcbf94b3598c3692f3efb53b3918d8325de986dbea7c9eb6213c86a14862b3b8ca1963fc1716fd5eb6283fc6588b26308612e1c8c268b5a6c924d3f421b0b375ac35ac59441e661b3ae26824d53d8d3bce6eb7a3f33654d1812d117d6c85a76a37f8ce33a4aa7fd66d74697d91e43b8c955305f937c10dc251b701cb6a0fdc7e28d87163b7db733785a641f52cfe3494db8889016f6aca15e8c9093a310d2b01cf4715ea8e92526d0f834533e6e5c4c50fbbd7fbee02fd02533ebcd3d5aa258ec9afc7332d278948235a41ea8d146423b062b153dd63f1518bfa12d16a6be13f3aaf8d5c1dfdc3033e088147323035f0d3903b6a0bb8650b5746df066184ff01eb87ff8a6dedf857914691caba6351b9d211d7adece1411532be99c6988cf1b73f23654adae67ecf9e8b7e891e9511994901de86fb649fb1a534ca3ebaeae06a7726be8b8188fdeb04ce0f2323d53d5810e849d519fd703dfa8d6712945341118c7463f266c9ec8b0a16e21c2808fbfd9d4a0035408763a88b83453282b3eec46a6447d0d718f4fa3470c174972bfe6c2e87156d88265d92385b46b03e6c7cea98e2509485fa959b428708b2d9f17ff82d78170c5b7d82bb85575109d47ff7b03710d0f6f1691216fd8ab0f574130df2c1be0af5c52ade6ddc2fc0e993334003184549cc1e2458a38e148aa4a752277797a74a965e92ce1d0520c2f196959f56c8a8a01c86a9163d62c0442526f71a20f0cc26fc1af8b15cf3ce45d230791c7581e11a5746fe559f19bfed35b5a77fc593e362749f74650ce112b07d02bfbd9c501f740e9d7caf868feb52f4488d14165790e68b342a06beb0648dce6ab5758a1cf02bd5b60132f012ff9b6e6ea36b8c6b685d90a7f738a37434f6e03dd2a02d927c524c270f4964cd3b85478b52df63942672fdb73c706b568353b65fbc347ec466736691997576cdef35870705182fd3794816fc859177faae033a74081859ce114fa0b7659355b29a532700e4e5e128fcb45756e6ff2d2cc43db9fe4cbb921edbf2844aa0e404d379f7f869fc2f6d6d83981f1dbffc0f3818334a026ddb732a39d72025bf3907b71b87cf132da70621fd839492f9d296267a79c137c92fcb6c529c2ca24adea3ac8614c4592db69ee518e579c3612ef99ea89cdffa6e311e40e9b29d95632e9cc2ca3957fd47e956ae60906604d1f9d087ac408f42a497a4484e82991946904c855b685747002f1223682b2101826836f160ef00a1f0ed4b0f7a835b1db3869250f8647d1fc202d32be11b2d1d8224164337edbcd27a8b43ef63c0015bacfcb2dc275aca7c025b22021e7509cb13ef1c43352c73c562370b4f78bc42f8bc9b866485bf115da959b769e5c85008a13f5fb9d4675ef71821b945e4700196285036e21efccc259fe1684d163a4d03b49bcd0f495dd1db16667c46c18257eb93fde3cf6407093d467f26bbf58b71a7c4cdfa13a1e6d7a739dbfc7e141696433a8f2245017ed48112d8d2b86aca96656b73a3474cfc2e3883fb8c0472f7002c2ca73d1acc905a08cdd0577e83d199d9e8747148a267c4adcbbc4ad273b26702ed500cda1eda32100e7c14b557bac4a242ab81946458e3599575016b6ee69dd0343b45a4ad0439b1380e9572c2de92f40f900e46923df85193b3300065a0e9e410fe632d65b2b728e8bf62dee5b99e208589366e8cd2b6025557c7cc0a61dcff7164b1cdf13eb4197ed2a509086c5795f515e57d4ff1a9434dea5a2f1034c21d7809789a0195e36154aa3d43477d0f4121de0c2f5b2b4f890a75cd559b0b64765f29204a9185e0f081093a16a84b648524e122d3574fece9f3bd50bc424063de6407c1cb2809185d171ae12d948914b4823ad677c101b419a91a96050620819e717504316a2f2106a0844ea8141fe0cbea40487b3523549beb322c11b36215690da033a8c13b25cbe7d5d836b50a34d59ffb200f82640f978972df9da5034834817fa3aa450b34e85f6257ba0e0a79b7750f68bc1a301f83b2c4492e405ec64568ec302a33c1cecfb5169983623686299fde4385245a11809801029eb39a4a490a56db26e88d356ba97f88f525de2676e7b6e1bfb7ba07c4b2fb3645dfda5e24c3af9080df95e98044baaadc89080523f7acb5bebd73579606f6e7db349c0adb41cb0593152282422815be214ec51c801fe57225c6b5b278551ea3f846964bb4bc9d452b20b0fdf4368b89454a2198538a49ba5a23541a6301ed2113536b7242f60ed1844c1433b2db55a53518884197e75e0fb30dc6a87eddf6cbdb67b93a14f3acf84c638512c6b265f6fcb75d000ca654805a7c987c5120e38e367cc05d07fb0d91d9db24f06306556d56ef621d03ccba938ff1f23ab28c15deab90e2efe25272af2886f71f635ebc83e51ad552b0d798994b3a9c8bc7ec4f06b58dc18b9f5afba2ad6b4100ab7f7830e0599b587b1fcc919ea33b85607860803733eabc3e72bab40d9e84f31c80210cebef9931624ebe29a1e669db5c95686a2b0694c072f3d2292b17010079001805f6e6a88f5ef30463f34acbda4df9df9f411c31a882ab3a45bf6e76e7cf2984507b31d2848d8f082acc0d94558da748ce68ac181646f50aa0d728292c70d0861d55ae27ef519e5c477216f85ccd232993cc395b7dbde81577c4c5264c411c499b7070cf63728886dc85466aec5e5f7c625ff9797b09dc975bbd283eef22726cf7c85ecc5d0dde765329b2bb28458c52a92ae3c58c1ad6c0dbd43b24e1459ef1c6eb66a2b1af3cf225344d95072485124a2dd0e8980d4439830e08843c4831a5bc7a5ffc9dbe702e776c90ac059d5cda0d086f309e469780f0311ba556a396343b112b944ca3910def1eb2d9097fefaf6eb671b2bf82f65e965caae7794fb204baf9fbf92d4f8dfa8d74534ad3da524913dae09e8828d2e671888754a9c7616e44f5cc0fcebcc30729ea9fda53e0045775d6ffbb299ecaf3cd4f35d0bbc6e2e0217568872d9f9bd22c8df0840742eede1e912cabdb9c95258a781c64635789a726a4a5e488b7e946a632b3887c230d1382fa15436bb02c0717e944c8e4ff6bf5b70479b444ae819252790afb839fe251b7a3f80ba8dde2f93a85f6fc62f0a6304bed0f9d161f5477724f0abb320e11acb4d68f8a43e78e79d80db1a52b1d8345a60a56392d9d6d872bb4fa34d21eb7d5b5a53ad743bdd476d3218dbb79e356431b6695d6092c7dcac75c520a7d502e31d4b5a532be69b960c0ced58672382edd053c8e7d5bab9ca27de8be96f2ceb7a26a55f747deb59076db27a912f691a3d559a7e1bd3e2a176ecd52935df559a7a7b5a57ac88c3ab336d92f566bcb4b848ba181a050017047ed7d392526cfe3769c40eae04e0b1fd57e0430bf062473818fed82e4470e68b8cd7cf9d359bdbdcb1018b23c672281e9e645d1e1a6cbd4aba5884158ae0386f28fee5b42870b746776c2f10aded28742d8e4a4a402fd4c64af0aa030be4fbeee9957431021065f7f2483f6fbaa65c3a63415c0f0e8e8fd96914907df2acfe4b51eb26daf38e8b9a7b2a98f7efe9832c7aad986b1c9dde15735b2854af78d71430861ac881f49e6b0546d4c8dddc892af43188fb31c470ab59652e609d0ee67d142a5841791f284098bca5ce4f10e9e0d320524710e79a8fd07f4265c7505b9284f3952bf4328c222f1acd1b52ed7c4677069392304229fd1332bd01cebe40cc4b1e31189d98c9e08d757bc321b24d86188d53388e1376be7738fbc7780c93a90eced54e340f1b1ff276280ae06d48969d6b051e1ea5c03800996a4087a428e4ea8afde1cc511674a50a34a4c79553bf40115c57eaccddf04ec164868b5e1fd507899263da0b8620ffab7673da4ad792e1c2cc26b41ac6286ba4f0b9d4ecee64d25c51be7a2f8170f35ae1d9b9d3c085ac07bc6a65b3b4eca698aecb945b00b1c1d5539a6bc89453090a4b55f572cf0ca90533953102dbdc889b36b64ca7cfb745c008e19ab0d17dd4a443fc85ae9d0219c388067a76b5b1ed9bb35d48bf0cb40c8e69099cfb615559c44a7714805d47db24696d205c15cda6048b057832acea44bcaa25eac2c18f3cc56049199bdf531ef994b0f18f48d7579eb21e172d40002b171f6c5e32d6a1147dcba27cad0b80d573410b30eb789cb58c03a98b428980c37d80dfa38165ffdbb73fc7790b76de1acb87637cfc1c043e52bcf1752b2fe5424a3df2135d4136574fdbae04a4f3b60ade4fe864a2061bdf8ee85966e570f6218f456756c2b9f8958a651b40737e64cb2bf545de9eb0ee0b8ae4b44b992c83d9ede8ed75083d017115b5415fd1117a0a2ce1b610641dc3f71e774bd7e8561f5ff4d01a89a0c21d5a1a07f21fe4f04a8b190f67eca5abb047f4d1ef21a9151428a8f4d770f02923a1fff1e3871a801fca7f8e77bc47bbd6c74659cb0f07675e00af1e988c92cfd7294b5e80ae49ec6f78d67b9b613158f6cc0b75a6a16135d034ac9bc8e0cb0ede9bbc7c227f8710e940d762d5b7acc2a85c7aacb72fc90798645e066ca14cc1518f10c5fdc6768a24c931aa10688c16707c72d2e4fdafb2de632ba16dba2c2c87c293ac430e3e90fb692004abb091857e2c981f877d430c77c2430f88b371b703222b7ecd5df4043eee788a7b0e9763ab93f1200eba85459d157d757b4cbb5c207205dc19eda5747523a65ed895ed2aa29ddcdcf278d25412636730b6906c03a335dc9ab3b72d829ab8f4f5cf23fc8438d59e3fd7efd50b9b48666d8391c42f55d8cf1a24d12bd1dd4e7551298e360770510f52e08a4e87a0e19ae852e2e346d5487443e4b78ce0bc352a3088c1b522de776befbe9a791a32dc7f18459da9920bd6f19385de9482d134919f921f2f244f8302b38ad0a1834240bdac220fdbd80a22139b5866a78a6d4abbf3b68b52b09dfc982131d4f6e555d6f4066a431eba37dceb42e83a11e77c20b188ef278ab71647c0cda04d090431b029670b64a3b8266846fb307051d4835942b5b1c5e22000d91e679a3b39a1d7cd2017a346e3bb481788e1df262ae5d1435eee24b77a9a3bb443892deb68f67fa5b4db836b69d3f398f4e3715e8233657138e3e51c489f22628bfc7304d1062aaca27bf37a9affb38bc4dfd23106f7b4305c7663740c9171c539c9b1af60d074a52879a09d087c480e601346570024cc056ea9838572e7855841fd512d13cbd0784d47e630f0688e798affd20c5ba2be52df7c3ab5f629406a147f48520c3547889c390ba077cfb76657ae4a2dd453af77ef470d3ecfa6a20b8cf3c3830d16cd7c051400d138a83c3ced17b146acbe097bb506fb14b6a5eec4b2d9c5fb8bc369f29e8bdc1c13a51c30f38d517b1fae439a974599bc706dccbfdcabdf63433b10a8129b8c942fba380ace6506259433bd577b6cbc3fca2fe649c9629e3b0704ecd89a7b91e8eb298b881995b387a270578626eb48f825e5171c2a12ff483acf737ff80b1725abded5e8b72e507624e00ca7281f1ed3abb2960c46d627b5f3dafe3fb75253817aa5235a989537a119d031075d3b02245566df7b56d001dc6202232a37469a9754bb7fb2c1dc4ade05f346232d7738f02fec538b295017d6c273ab45e9c7124360633bc1f9d8dc88deee2e69c94bc58b0a5a1bde487ac22ca851382dd55551dafd073e4b4ebe5fb55f33087dd4629778a58119551660a28a9f9742e1672e2cf1ba8b3f5cc303fd0bc38d2c99734c500f94664ac7ac43e7b74144ec68c9ca59592779c314721fed02e13125f6404eeea1634f5046476dfa8f02524537c682059461946bfdadd8a334f22c9bfa254ac9ed0d0eb06530fefcc9d43f7ed50f1e487fdf1459c611cf574b58cf946ecc90e5eb53ba3ffa25eb3c39b2842ec37e769817db8eebe828b17340dc346665d96fc71762ab459558b0c85d1d6970dbe43c46fc3431e8f78c7fbd56c49c0ea84b9abf68fcd788d364f725a3ba993e6c79eb87b00a6d7041f57bf85dbdc97f9c3cdb9792cd6839d71e8c4f3017bcd16efa8d9454e62298f29845d0e7e6887c2dc9ce1c0a63d190b79a8fd64a1f973ce9bedf81530729187382a92f378c3ba1781a7125315bf81e901efb6e36a9751d1bdc287cdf4b80b9d7394b3b1e1e51f8153f0f9ab5e756d5c7e087df7bcbd2a5e08195d32e4f265e4c0ffc4e9309cc5e29d3fdb5592bdc92c2932737097e89b53b55c4b4c329f4ff67dd1f1d643bbef1ca4bedb775727ea9e6cc19471f51b9f963422e425c1fd0cf3125885c797e502e62c397d6e027f783718cf51736e234ad3ec8f508504eed2c734d8c0e4113de47327322dcb0356640dfb617dc25ca421d5eaefc26496e1eb6d9499aed079349529755f1adda69832a17af8b1f0ca656cbd08e8900c2b099cf11a64123cc7f310041f52f7e92b5be42a01e016877eaa4e92dd9ad79b0ca1e9eafc9773a94520b9cf6b73025cd928c311476dfde0ff97cf08bf56c69f54cd8b726c1f40963d694650d6a4fd02ce9896bcee3541af2954444ae081bfe4645b3d762a82876c810281603428ab186ba0719cbb4af6f63dadeb3dafe660473d040296441931558a3a0e3fa68eceaacfc9f5a2ad077f19f09ba9e6a81bc3159b99ba225f53863e89f15a5ba350145f3727066b2102eda00fc9a3c8d8f212dc5ef3ff7c8a42399483c8f7fd9772cefc9d9f2f8675361aa7fe3be64359de33f79fca9960a22a56ed66728e833b6bb2136d35a91ad679c0e2b0b06f01e5b193b9ba39889fc019930e50847ef17fc8e872d7eb3b3a11d61a910a02709f6000843c0b0277fbdefec4a741e6acfc9d7dc9b46b07837dbf1938fc5cbad981a79e8fc6d6dda3e85aeda6e64cfbe3d4a43abfb539edfb429a7f9ee9829010a759e44b74b20d10cb31b05f4774387ffa952af513c4681cc28adf0d203fe888782313e341700711fd0996f61a1eaf7baa219c2ccd77eb7ae67c6bcd215a9ab997a532ed64ab82c84cfbed806ca1c685bdf6e509dad7271b2e51980f95c498011226ef4c6eb79cba2567b76f131a713b7ce56c8e40489f33e14613e85ba2b4b224ed0d0afa82b1aa653d479371768ed871c5b30802cae6e2b893f34b1b79dfdf0dbffd4ddcc7ded0c23182f4e12a3bbfbd5c2fcc68da5dbf416a0a9bbffe0b40633b12ab12c533311bb70a1aa99e8c4a2fc703fe7a38dede21d617766cd9d2ee92140395581d13daaec4534a61963e2ca9f74afd14940220bead20fbb45cbf35b6d285943f6d3d137d76358683be3cce76a4a76e98e059e5519fe52783396123616abbfe53a32978d21ae433c7e8c01d0974d5504730f60b503d7ab589470a7b1ee2fef142c3364b102f3a76a4f3b3de6c621286ef2566b7a44bec89a40f85463560d95141a86252833e8a4bb4a2abda109c07bc72fddfdd213563f4bd4a7cf881b2e4a2cb5c36f6041458c35c20cfbb502ec9733a17f003fce2bd461da07ea10f7097d8578837c219dc60e60074947c85f802be01dd335ea827692ba047d037025a6a644b7bdf1a09b100ec8f266e0e6b932daf65a582ddda69c572636839ba163d382d7d06a64fb65b1b2bc993a5b4dd8066d438e270b2fc395d1b6d7c26ae936e5bc32b119dc0c1d9b16bc865623db2f8b95e5cdd4d96ac236681b723c611d6f978c6b09895be36d12694391ad6e6ce95dfbb5c6ac6ab0a8d56d329ba8e42b1334823380109b2a780d4a098afd655155c9a6543294899ac199208d4116ba0ca784c4cebab0aa6c23a5390a84ada06d906225085e855643b265455c59b6956256150266b06668b148052cc32acc2467c9b4884528454f5f67dce6960cb545520617f757f6948ee536fc5c6552d9adca3fa0ff0c662ee9951bf7f226760587f1b9ae9bf4ae307f1143cf75766def210010a9f0d6a33db386d677b0f0a7e0da4342d13da6a8c6c8a503a40537791ff51459ba299819c6625c3dbde7b9c83c2ec1d80fe1da41305f07a5083e59389a43048852f4bc371a6d84c53074a333e4b2ca5184d5c6d58735e645c0195d605700012882e360e52b433e369529a657cf071a85c87095b3c1e0769eff6bb43cb87488d171a800da0db6c72e36093069a149b68f5b4f8627bce56798e785a94e6f06dde554cf489dd7d3a60a1beb783c1f2047a3e30771a821145428c10d317ce9abb96d855a41babba66df1ca598a6f721735145a8664da061eabfb7a548c1b19b6f39b99137d9f247df9674389814c0a68faa506ce5d8864341ea33ea6d80cdd1172144bb9b93e5d0e87cb177b9aa408a63fee4608a5cff3b9788deb4141488ce2547b3e932086f266682b8ce7e9036026ae372dedb1d30787a4a0892aee1eea9abc763157b0637872e8219bd3d525c3d09938e3bbe70d193b3402e2f73e29dd12c47bda7c5f5de5786fd3adfe9a932d6884385133de1e9f6869f50faa22bf107641a2cdc1062966483682ef0fcb40c06eaaf27508d204c2089205ca7592d48b4028e818a2fda219b0d48a36728798ee09629226f6a987ac07e9edc83870ef7e30e6f7913f77cb80bb56438bce624e9fbd545cce9cbaaa0bba46c2a5accb9facf174b84fa26bce0f3e34b9374c144096535348ce02877004832b3e96548919685e3658023e3134c4caeba337dc98e55e84976581328e29fa574778c46d126497b0620d7212d1730886f1b65ed42e5a81e4280629484a24a1a8f3a04ece4e7fa12aa97dc5b14f27dea526600cbacd78f0331d46a2e6a0ec63402328bd10454a6294b85d96a8accf85a596706247348760e17ebc305358171a1510552dd571c6453e8f76f1269cf86d5c95a0bbfc51766a691761f2345890651729ae091a45d85c7b7d47b32fc2c749cdad4be1147727198a3ba75c045990cac2b5e079b995d19c2b187b588c5e3e3138033ddf8ff2ea3ec2e91f1f2c90db5e9db3dc2cab917662ac68dbc52d75761a138688f7d748b43aeca1ecf3055e3ca9d2abc64c7d16831a291ed6a6fe68e0315655c4fc13f243e7dcf07c63bfc00db4b9fde19d12720838d59fb4b94582b716e40771be4ee49957be5ec7e2363d6d618061c0df03ae0b45ffa37e9a891404eab72cdb02b562fa248baf56d998de8ded9b13e01da86826670026dc2a8c6ff47f6af707d60b2a8d3abc3cf797bfde9c3a4f8533e58bbef9069c60d3fb6fab97d20d85fbe78a43791e3c47d02ce35e85cb1c8e71e7492f66f62f954e2e987a7a1d1aa81815c77d3c272690e576dbddfc706f46a0c99403787f73bf85484ffafb0939b413cbc745d34968546620b8a76c083975151224f09ce89380f298340ff9340f404c0493d872cd77e50d6a48aa5bca9dbe245e47e924ef1a404fb6046a60af3924d683a734b6190bd4d23e4d3d13f4feeee65cf584c6a58f2d1f1c01a00da571094e018d93f2cc17121d22cca3a63a6acf01df11dd459c2b1c3dd2951f54e0db8ce33a44a7648f3b9f3e2b23e7bb74e37df4e6ea03962288580d0c4e2ad317f07b5d706a69d7c6e709064933168f0caf519b244d729d433e827529e0a57c279bdfdd098b029df11e6dcdb97427e9b9cdbaac9ab80fa7fd83390783161aa13eb44b6b29411e4879861352f9affc5791707af336bd9a8e25d32eaf269e1e37133003f4cf5a099a6ca55d1adad6b896b5688e3bd38b86df2b0a961739936b0c762e82a73ed211448c0b7e9ed3cfa272a7754d9ba94831869a626b56936313cb9b0f7dd35ca3307a068ef176ac2084cbf09e574f0b6c6ac245d8770dff5feb96046f3afd070a64cd82b6a149f16da47d586619d2e6370a60923f67fcf65a0a64351ed8f435232c25bb00a967a1bcc3d598001507c2861ec623833d3cf7ed5199051933e603a86a026382d09931211d8ee82d9fe99f1e6edb8c4199517581f057161b01e5ca462057d867291a0a62f33b7e46451d970ebcbd15e354cbb7336135fa74c5d1ef91211eb45b9b2a66d844b9b6a76a8a6368a0af5d6985c07c81f7c252af58aae4c4959f5f837413fbd4e4a67a378c3d846c60c3aba302516ad0cb464a9f61ffaf4b5194f44f128f2a8d12a4f12b1d1d155496fcc629aa2a35a311d11983c590b2a47b57a1fff243af85ca8b0b0e967ce5fe7a28456f8f8a4be00b00493abb640d17c808c27fdf3af1a20238afce053595b9da6d733109b9c8076cb488f7f58521d39afe2ee50604a88318ca43dff1d5758eeb14c6ef004a4b675777d669a48b780d4ec9a657167d409d00d36e12edd6afe9810e0fdad518c4adfcbc79246828aef0ce3dc6c8c04a137555ff9ba701e3b69514c30312c14aa4bc5324927fab8041cedc71800fc59092a1655ecd8498713f6378b0638b97c3f9ffdf95d4d9e0c043b6397ce56482b3d6bdf6f048af7a978361ab566bc8ad3323b255ddd7c689bcc0a5005e94dca7406c6f5dbdcd2f7b54760f2286dc05e88a17d878d4318e49c4b253bea679c606b98389204ded649a9bd8b8719b00b9c62ab7a9a9336d34082f8024e4dbc1f0e213d51085e6f8f6a61db258de2d3c81aea5ab1478cc0e7273fc35d0ad81e7b33814531207cdf5c2aed92097008ab18ded4c54a8272502664c527b64d6522d4086009cebd8364a6587faedec011447257d6503dd382ad51bdad7376212a33707ce8e7713c1ee57995cf8909d5ff4e0d423e7f33c86f6c8478386051e8ef13cdf8944b590df81196a00eb1ddc3dcde0e71d0d571af8d679e7febe9619d73ba5270625ca57a552fdac4d86fe606e6d55ca74b0e9147f8b73d6782be036d14dfbd4a14003ac9506e4bdb8b4e10313880a54da908ce64d15c5d06ffbf3efa89a310f18a5ff6efb1d8a34c4b45a553a4b79fc098d5c93ecd7a153beeba93edeced9e566bdb2fa0951ef8763bc3f3c78c3d6dde71722d596def26f0510578006745ec247ae192ea5454c0278bdad6f2f1b170345a8cbc2a601920db6da6e87bf81eed2de96fc7d4b432ee08823425b5d525a2f531f42edb454df4c5702c3b99c13e962818002788c7d78022af70238509ee0d2a7b4f1b05937672200259f21c512d07b94090b2aac8a74d69d68ca73a81ed4ee7a7e5bbbbd44b9afa82d122f2373d38e059b0acb99fc1df2442222eb7b94eb80c18d36b63cc6b0aa33ca3a7bb4cecd2054fe486ddcd290cf15a2c567ea285850ff416348b36ffebeafa63b84a3c08779c341cc470cb8b5b8bf8929300f786b3ee839de2c690d55f1660e30d1ff576182839c6ae66e30c9097d41a471da0398ce0dde7c70f19025c0a158a9c99636b8eaaea71bc5c8e7c8988e73084b93a8e54aa82cedc3863260d54a71b27a6d95a5e9c03dcd4ccae5abb1b2b1c6417adafc7b56630fc0f2a3086efc7288706cbb04748caec40f68a045fe8c154cdb85200f20b3165047859ee333cba61dd7ecfc4189791d774c8c808f1cf7d70be91ff14f903f1f71ceaa510b7ae72afeec561c3159013732e63c09932ac37ab430668d5cb2854f4b02039a98fd08f7d2dd927df435f70e758e690462bd9a593d55e6024d031ea4611fd9894e021b482bb504ec725e71afaab65b275a6f2c65b9d151bc3f62c8c29ed42c4cd6c1abdacfb1819dc45638e721ef887018dad4fe83f274305f38201dde67a16adcbe3daf076bc1853944560eb41e060916dea784fac3a3d253b1fd29bfe43edabe9c967ee368244454b94fd7211e4b4cbb6eaeeca87b1bc9cfa3df9d3620e0525b62eb0659fd6a981a2cecc3a7a590cb1a2656f3307746ef6220763de50ef85ac5e3c444044c2a46ba6670c4260fcaaae5e8dbbfa0409989dc234bb92259c83464492b61e2c927f3ae7c569233043bba1f6e4907e2f14a2cacaffc1e118226f0111beba9e72ee2e07ae9650b67605378b8da4d5819eed7bade09ad0fd60de6f65dc641f7ff31b06fbd2c69bd808c3717eb6c258a7c1198785a9a67d6ece67b5c3a3936b95018fd4290c6e973c2edcf50ea41b0c9c87750e0737c4c62ca0c07fa163f450c3baf038ec7b27f14be00ed57a2f6d0786632be7d7e69802ea79c026ed096d3ea0f146075487fd2259befd0a902c37dc02980a59407a52a07544439cb3b75e3448cd36f78813fd1576f62a1c8a2a88b0abbed47a0bb4147a1ad20fbe7976454a22e2319a7c0becf7d73f41be4281940b95ff585800425d9bb4fd57b333be81674ca5d32317800e6cef6fd5f9c4176c46007877c7aa7b68a562ba045e5c912dc3023690cebf452d94322852738e313d3394df2695f87fbf54dabc5cef4fbe24c04885f32ceb3073042347c9bf3f40322cfe3fdf0d77ac2526cbd9c7f280242ed2d3e4ee91be17d8ebb2f207e7337426fdbc0d3aa3a9ab5a66ed7cc8de15700c2f9d1c0e4a946fc82e8a121bcb5260430e153191437918fd86818be65ae4f695f5f07dd8ea2ebcc5994bcf9fcf79ec35cfbaa3c57edc83e5926b175d6f339113ba482b8af376e94c5eef8aff7fd435f7fc29fb60e34a33ba98763c6557a5bbd98c7971f9d9eebb30134bd3f6c68bc563035329a1c75ea5fd5d8532f3d17971b132726aafa8e1232d4d99ab6162d2776fb802a927fe60268065eeac0bc15ec4a745b3148d65fb3e8170659a3f2b87bea24cdeea4e1a39e7391738501fd7d3b17f7ac878db21ef7c487f7449b4211843d91729e59935f19dbea5da7fb005dd069f8d3d37c91ff29eb91e6c16650de5eef90f9512d04fe4b2fcb5b7769dad8d569eb51a18cca351943ef2c09dac9dc6772176c98bf50603166616cc777c45c414ca63cc708afada8573fb77df95fdb929f9f9e3af75fa1f10c3792210fce1912d88e030e551f7f91f312a7ecbe596d7323d10ef18c63321938692ecadd94e837281eeb3ba328d6b4cda3bec5603cb828922f2c4e92cd1fb6b4063473af0184d97f0513e4b4252e23e69cc332f01bed3f8a888fb1e67e3069dc93b35085ba0af865175db4903d1fb99f712384f6df2ad3dc7a0b87773a30623d48783de0216ed2456730a22c3e32979e15cb91e6b1b5ea79540efefe99abd27c13e0c902e801f714cdcc2aa90c7a958080e8482b1483b0029b05598477d4ee2cc47de77548e6aacec8dd109b91a2fd7c21395b3ba09cce102b24d9bfd6ba344f593d407056787319e909e7e8a9755c36f46a51a9130550739cce318dfce8ec2ec09a786c8a3a9996c5e7c08db919c49cee7b3ceecfd09744135a70ed56a046cfee75d479e83e0898a7a1892746f0d6d12efa672e08bee6ce64d87b8ee6bf8f2c68c66e7319ab7f2b7d72bb6bd4397b8a49005d0f93e1432c00f5cd628f05e9564116b5c85ed5edd7ed4b784c87b5654775f98c63e319229e52abd41cd7f90bec9bebbb7f4268fe1ace55e7b164d5ef5f73122b41e78abd901dafc1d068f96bd073cbb14e766acf235252188708823917f7496d0957e472b58a538c7f40773feb90073c1213702d3cf2be3aa177a8f244b0aa657553c81499a77f2d92df31d0137ef8b6351527eaf0e299427b560a8d4226a9bed18f3de2c88bb6011baadb2ff7d27d1df779866e230875900536385409f2a5f271307071a27fef0a284ba1385bfdf2b8ee235aba570fc66f1b2ddc2f996335ada3557e8d04f8945c062143e40ecaa6595a02d920ad70852a49ccf801dc5db17957c46eddde2abe765a10c6f60fd0ac0d05f05ea5c1a29fd0eed613839b12f15c11e17b2f80d01cedf03e3b7a35638f190df3047c7e377135e3546ffb4dda9e6d6fd727dbdc8876d4edfaf7b6d987b5d820d1ae5cf49496b11e91f8bcc6021ee3761a94bb545e67660eef5c4a04ebc4c2c149749641058705b44cb6931fdabd4a7c29d59627a657d3406757bd586f6dc954b834640c14688d7bd7686e21176b35bd01a0eabdce3c738b67427b6ce71f5e36a5d708a16614c534c77fc9a74cba3fad3e60286bb80fcb7b0cd948f37093bc33cd025eab029ee7d2324b9c0756abb6dbb044cd66f8a9479f8f5f13ff089c2fff0f5eee0a323eabd92fe51ec9be25ec4fa2d90115e777cfd2d850578111cdf55b2f835c725dc854a084b75de0cf5566d5c5b70f60010323b08f777b74143c380adc6b20fcbf7b5a4975de8e7d8182b39ac2eea36c2dce7f41f4330d3702a6cf732806375962fa040a4f25798448f3d8a3c6bc1c3271b9312f61de102f625746a0d5ef9fae4db65c1b6a1fe0131b1c8a5d7080706a12d6f1b1a1a9d05c6e471dccb8bc49e473f7a7d5fd4fa4362a46767d3e22d1f3ff81abb91f7fde7c8cf3c78ae6ecd360b297b487681f5e400856a756f95f716e82739d629dbde29cbf3e030066344b2a5069c2b62d5ec651e0842e9fcabd93be392be30693167a14931135c663975025adce5a8d902eba161b4ea745070ea0f7739de3d262e4c47c9aa9abb66845bb40f84bff0eebe6c56a1f7380695067846f3fee5b6265b1f8a803760fc196fca7c80c097e4b206f5701e92b5a5cf4f088dd595aca0485d759de95193cb2d8e2b0174ab7496f5b5679a59268cca75437bb53f295b9a8576c3b94f43fe28453484c4ab53ef6b7b8817a7752c51b40ad0e6a924bca3640f52516d1be856de98884fb3423fc76b0e09a32a67cb5776e363b8179ff7b18b4cd9b2eeeae0fba8ffc7db3393e3abc9c3a205f400de5aee9e9244072522815fe290147f82f5920fc044cb8ba83ac6a5b70cd97497f77bfe2ad1cb21c0d592cb6e0c31b2b3efae41e9ae0ff54ea2565c6a354d2a6ffd27b440c31b10a064b2b09a4a7376973828d5ff8659cabe9865b820930c192613efa98ea44275238ff9e4d6412bd379bbb22fef3559b149de67e1e368929ba510f3759d708ef8f3e5ba890aed6a61e831b0b64d49560ea0bc56d9c523d5c2c5db6d2b0dcb409c50df0bb814d3c0467731e308834cea6c894bde75086e819e55363bb249116169d80a72014059984d2a4b4f19da8858196cbea2daf3caa112d6abb8baa2902a335609212274d4b907645a255fa51c888e87b414b2ff5d55f0762c73431d987e46dcb225080e7b64d3c0a7e54cd618a12c7e4980aa8394a0f63a7b9a440320a875cc99cfefff0a90a210fc33efc3b16fde5b5c006418e68bdbc78c9d946c18b17a70201065367a26a75352bd817d625d62a6ad7234e65706557e3967e19256f7bd0c3f81a6f3b233566130285c8dcb1a784662be71c29fcefccd520a3f81da2b78e30aebdf42cad6c9347f49db4434950ddec83f41df7255a1b48c85fa22803441f019fcfac86bb72642e3d84215292a6ee39ffcb384b58de1e06b2cac7bc2af89084370df25072d27ccabfc0c100f2a8319d32c07e384060d0b34d1c71606e9fde16a9151ec5aacc71029339448cd8e28f0778f588bfc020130c4a6c103d76b7fb227563f39609d4898a070c76ed567e9b20350441f166eeb76096d0f086b8c0c9bb30ee191edd7b7ff400d404509827fae07d7d3c79578ad6d599c725dbd8584ec8f853dcf4eb4f95f70930bfc73c6b4e746a43051c334785129b7dfe080a4b2b91afc88268498c2cfc76ba5cd32a04ef913a58316e37775de75f36454e3606857df3cf8b74f5a8662de4951fe4e04901c6354a4ff5aa364a02a7aded3f470c6e6a05f158843882a95d2317c81945b1ba1e465e0b9aab88bd210175fc9aa90e9902c5ecc27f4435ed4a24c39d1883506c06aa5d2ed71e54a95b8138067f987311f448ef10794035c59be1b7aa10fe219afc24c79094c04fae743a4a9c73ad1b0a8cbd9446ad49aa22f99431f21d586c6ca4dad5e280883bd1e4366a62b21f37e2a42d3419d53837ca684074c7ab1b83c1a47ba6e886ce3ba5d953f310fa6376e6d08579e70d24f59998fb92708b76ec3bcc3128cbbf7246ac340a06b984ed57f789582b529ac153da2d61b8470f822e58ec238a1d555a95ccfd8e5be5950858cedf188759f78c5f224b4f261b49265a581a033af366e029783cf87746df08f07c15b0cd8dc5e6973fcbcdaf7f647382cbc8a3d82d2cc9f89ff877532f44eb07659e6d6d7353e57fecb49da19699c12c489892aa4c343572cf930864ee1a37da4d7d18bdcdef573d693a5bef82bba52ea6e07f46b88227ea0ce7e5880c3bb2245a5743ebd0541ef457395fa30b53124ca08dfc455fbc0add1e261f2e781a151b20c49871d9ae8f0227e00c61123dc8f2805063c9595eda40e9d6c0ff26ad221f14bf52fc63a620c253c7ee24ef0cc3013f1342313c099fab1ce99265d71da8b8639f810f74070595fac36a1fdf72839b9f15edab30700f06dd5e9dc59cafc97283639d0cf12bb8222998b71e907b31c19ee6af314b400c07a447979f07ebf2baafd0e1d3d6c7547096d869e0fc1858664ade6f08075f60a5b91caf398da5110a38b98d402f727b082618fbc09ef4317ca122aff27f87108d821c534352d29925c7ff41228d3d44fc324be71be7a714c1b1b5432d5e203ab383fb37b5e9433561a95c098e1a44f22daf3c03faf72899a17d89ebf47d8774898ebbb3beb5cd45e33e46673e9c84a9ce95276ee93d6d8c85f147519b0424e67e8ae27a11ccd5cacf01227f98d2a54c8fa7bb71ca3ea2ba7eb0907b559a197c7755008207a17d2088ca62910152302fad599b8fe1ac45bf77e9b84ffd0f03f27fb03ee83fe618e657af7e534043a7d134c44c54d64b546ff4aa9773ad3834397761efb8a5b0cc1f736f4760be44c15343424348bebaec5b70430bcaf49e70392c0a84950c8a27f28cd9b4e17db9dd86301f0507c3c325a8d93d5e7e35b4a0835619b31e2e6fbb680c38a876a00aff4e744951743c6c98c8eab6d5557984e07b56cbb24d82f3e8e01e231483b27e8bb08f1f3054eac19aecea9601bc0606bf6ce08845972baa517713555595957601c27dcf07488908afa480c321b7aac83f814e8cbd82ef05afa8f3996eb1bd5a047d7c4e030bd86be4d8f2a1b244a1c45fb6a5b307ec504fad776f5caca7d380f9c380a1209d4162958697493e6a34cdf2fe46836d87ddca6d46d2d1120da1f9f0f843fd988a32335c6f40a2d9a56caeb542c099f6bffad560205a4b51680932d564d4fc91e8cd1b900fda1d1a67e5c83bcd9e404d1fa8a4c03a724e418a104364e68d6261f0f3a20bd20b2f38f5e6a1ab20fcc403b299b3721b72a40aed7f76ba8e6dea8026ba5278b9a93fc306d4a083c3a0fa432b747a3ad1eff4d86d508d4de215b855d15b570735619680a28a2e543c11ac95aaf58da89cad6eff4f66e516dc483ed309ec747e16a39edd3ffba67e60317516318c233c3f2fc5f8d72d22ef4d9e3d4abfa6cb3b54f9cf65b092cd2f6923f2382e7b736134eb23a0c86668b1caffa3dd32366c21cf08249e8b895639c0f9bfe945645a386e62779b5fefea005ed79c97d169d2c4ae4ee30f4848cb63f530e22f70cc8a90c08c4faf05468c23c5641304ec6eb43c547533b8ac784978912864c14f9976d3fab8b56be2d73fdf8b4ffddaf7313fd20131696791f11ef2f902ae461588eb85ab1a9fcfc7de50e6eb77d8ac2f605c73e263570a9cb2c39bd8aa585d7e6b31acbe817b121b45dbf87404b5746a2b7028f9e0b0a17e31fdd590fd63929b6401e81a82f82efbc487657b90158bacdeb083683f78f2f56e6dc4711aec0721920e59931ae7e0deda7ce8da5dee0e38691ee8d9aa461c8148c7b2aaf5812cdc4622a4d997a5e6e01a84026a7a2264de1bfba5f325effe6067d11fd74d6c023e1bf507544169f655e945cb933ea317aba41952324806d340a48906bdb91d00e83df5df73ac039bbd681e6a1d1d63304da72d9a3574e4075991dc4f5ab796643e7fb0189a553d46a89c00a770926560d3d812fa3722c9b6c2ca973c292c0b76e6560728a167fd4327b3153b4f6a1bb1a3e19055e4f3be603ffe591752436824f77bd29ff0ee863458f3d044e2e50b56e26925c39c02715b7dc2cb7f078617d5a0d457b2f8de9f2a4a36c83645eada028c3aadc382773419580ca46497bdf44c0fa39a47f951220a8d4ae72fead5e6003e3cb79a1b10fe3c20f3fdc940056863a36fb3eaaa786cb990da4bf2bf634730f92dc124309e95f1f1400cf63f562d3f1a47d6648236f47eab105e96124a55ce8cfe6121237c2942ac7f73e37efc321c2ddfe2e3feb466500fea417d00d5b3ed76e7c5589f27fc68150578897cb5bd0cae856b904cd6f5704ea19f2c4dbcacd29630edb554128fffc3051de8629d0a4853d929d25336cfb2f334ef021161cfcb8577f40b74ee71b96ce08ebebe79971a4a5fe36f48a87d70d40962042a002973fbb9153f9f35e46e7702d5cfe49cfa8ba15a816de1f532fa126a42d630125108e94d2c037668657ea6a1b90c6a1c52e76fb23b703c2351216bd2cc92bb888468aaafb4ed48a23a313b906d1c66ee0e4aff22335021fd4e097554b0ceb8bb41eee65e70ba1fd34c1e760f9cf1dcfb4a4d66e2911ed5d10d716877ce23606457a92f99e0f66a8966a055a331e2976f1c89f5574aade59582787432398302f5bd6e2385ef51bf9c796e70fe8d21fb64ec626a7f38fc8b62968d399413e7bbcf32bdfef6b33d46714bfde7079689af4539c0955e63e5e5d2fdcc4366f5ed78a182e11922b570933755d255e7932dd8edd6c2481e0a8317a79cb7ec0754303fa83dfcc4a678c2ce3a035ac8747917754fe601ab036b4104f6f242178de8506b3ab0113505599cd450d5b762be5dfd2585f6121261ee10bbdbd2488cc1909528279ff3f0d18d7250a85428599391d3547562051d094a78f7f8dc562faf304dea81f9663093be37b5d0018d4d952469fc633cec3fce3f75f0687ddddf7223ecc4d9b29b97a9328ef96bb07e319d499736a24e60765767a07fa7ad8d0253c04abd943f4e4c7c99e2247cb32d442edd2f6518dd09508eb18da97db6ad0955e8545e0923c993392963698f9aeb1f812d84791fbec4da22eb3e479c7d2cf4e737b5686573c0e58ba07a4d3b9f87ffacef300089653e9a68e4578a29c8850ff80204413c26100ae7f95f3c2c0584675bc6a9ac70758bc22097f580e3c72de81c80a7cc0ad098e60cd183c74416157edf9d0914d2daa2c64e60857e788ae26e489d6c0799d9e573dd5adae444af6873201fe5bb8646c5a6078e354368deb82c05bb2935f8db26c38506326b821e34aeed817c453e6cef6827dbf89c1d12c2e9a3a8939d8732cdc17695cdb64ea568c4685bad00e6a5163d1fb36f46e00be93af50e96ede19d96c7ef79cc60568e523eaf051733ed7fe859460c77c36fee1785d57ca25e7439da6bd588d87556874512c463b6b2beec437182bb86ed440e2b5ca0d1797150b354b241dbb17b76d95abad4a422b0f332ad6fda31ea8d4974b1bfa650cbafc526e40d5df74f08bebdeda14b74f9d3c36bc474ac13fb9a8c40295343ec4056d7981614f84cb5b713f4b5abc7bddb9b401324bafa6a44d8787ccf64bac1eb1575f0767980145cb41b592b64d043924cba3032740499d6b285a5a8786fb59e93635ba67c8b8f242c8537d0d9cc3369dc2bb834d3c5643a3646686151bde0be0ddaa2814703d985ddd761530ab15ace456a3d909aabb48dd87554307786179d536043c4049a521e06a82b9716eb28a4c943b2665e67a46ebe0ffb81d2df5333f8cd58adcbbe07cb35ee8ca739058cca257ca68bd34c4488d729d4d3ca313d74257f3ada5be9af527df90206e23cefa1ab05c93ab4c144833fed3b82777155208283e10c6f1e6d3c07052a570617745467d8ee91052bd65f8be2629b66f6663923b0b0b1d3111a43c46d18214bb88b2e286aaa3889abb8a039f14559e2bf0a8ed5fe66cd794eaa037c82cddbb8d337d36917c576933d93e8ea0e102baebb4bb6919123b0257e54694a7eab73e377a0f7600344221570d0bb4963d5b2737586e552615377ca62f5238660d1f30b23ae64a588f01bdab52668aa2e0e89777bb6d3ba63d4056858d03f88c5d192e60c78ebf9533a1158475c1f5e971a51610d52c44f6b15bc030b4fccdc320077ecbaec50a0aa471a82ab93f8dfd1634cc68d853f519d54683fe0dbe9ef3b76043a610581c495431de2251166c586064f555382fe170d8514409c99315a4e3875ca43b6ce32e06d69f296bc1942eb5357c587ad274d501264c3650e49dacecfc759367778636e6ade4053b379f436cc9682cb833f0fb75d794838132c032bde85b1f0ae483f6d3d1da28c140ddbabd7c28976a4e4ab9ea0bb6d3af3cc4bc278b5d78a9e1541ba82fe5ab4af18122bc4d4848ba5a1e10926364c4a6d0460bf1e2e1044752e7400e84090474648f4c2a37d7cba2ce213fc8d37b5a83dad30060013892d6300190412017e07317334859c9eeaf50da6cc5cb4d5531b029eee9ecbb64104ed15ab5810221abd57f635bc7a4faab9adf0a1ca1cdb83878de1882035e436bd4dc300bede11cf9c73f32929a070619868175a4281b3901267b03603b0d258fabeca9a7e6ceb770b73099ed2939dfd0a1c3540902c9ac189717e92d7550358a3afe4eec5a18eb83966256d560d798cc6c15202e0bbd062af62a46c8da12f1258a5065824009f706a48395e3f22fffd404a5786aa4e21e35f1972edbd50b73a3f4f4830a2726100ef640f1fb8acaa4e7e2d2399d75597fad1291d569f782651ba960617a978e124938dca0c98081d743aaba47ebbda41112adab58c4bb94c142be34ca879258d3eef840d05e43a5ce714b874025173f2a491b48ad66ef41727b043404dc8500a880582c8ac780aa59aaf090c035553401166c614d2142658aafa8d0cc849060d47d082b3ac1dab2940295d4e951f427b0660a971f0d29164f3e9a69a0f0c59e888ef352be25c389a2594f4f261d9899e9735831d98f90f7c6c14a8af42b3e64c80d085f14809bc4368480f68f1614f1781ce329655c922837669f2d3424fe7d5a1ab5ac88890fe999fa65ec1939e89fc84f490e32fbbf26677d99b275144ccd9b52d1af3f3b7916784fdab320284e93a2f547d90cd017a74d0b1ad70188f6593b236f4a320a6195f54573732cf52cb27570405091cbef9ac601c86cd313432e744a1f380a1e121415542a83282952079cf046ee4200f848468462a9b9047b1e04d7c252f3150de672cd0979fffe387032dbcdf9eccf674df1cf00b68f2b95049035eaa13c82f96d3488791e8738b390a3ea0e841b07d8b350aad9a0267396345b6d01bd8823f9640ee9ef6cc434aa55ccf9cd5dd48d033ee3216d3839a2cfd18c6e5fbff500536146e070ba65cb83cc3d0b5fde8730abdc18d64768a70198254b4868bed17cf727baf11c23ec5971309150fdab0636ba96cb44552a368b85a64933a68c5761857473decc99106331544b26c8488a442bdac1dbbd70af0d29c870a886622be3c0e6557c4bd57a9b2eb34e27a25aadde95be0ecda004b94e99786f9cc418d687b14fc6b5d6b02572aba529a084139e770ff238e396ac99f8ad477a6c798faacedbbc46c5d0110bdb8f9dcfc5f40772f7a3d52a41c14e121b19b638754a15d4d38d7fec13cb43786d8a9a86992f4da5287a808152ed3561135ebe03abddfa03fa1699ebb2323f81466b41e15e11c20c1c08dd0b7229a3484c8f942e0cc059540c315681f861e759b2dea8b66f6494e75e2305544986c50d6436c162450c808b97d1a03219b91f61ff85255b49f57403813b4d074cdc1f0865969800ad265fe3243fae199aec7039dbe61a3547d87e9c4cffabdd83eb210f2ef07a261d27b7a3a5ba9c82d3d0fd4972351f809397b5a4918db895f979d796ea63e197dee40f24f9bbb4ed832b63dd8d4a6bc49376178ea86765bf160d5fc6da5f8562c1b58f01302d4bb3f522512ef77f6a58d94e8bbc2ca69ffc1e83e705f84d540474be44f1d8f309ed3a46fded70094135ae1eab2e7da0d8652df4e704e82cf4ed72eea220d1c7b0f1d4d6aa94b4b7ef7383355c707aba6c091ecdc1930d4dfacdadf70374fdae9f127510ba0e564384e9653908be365ffe39cef6915af290c14fa4587e62d13fcf521e3fb04d3da01064b4e2cac88426df55860f203d55b402453b08426cd5891ecc8bdefee98fed8091f6415989a1540b9f5d34eaa84490d0cc4bc8971bc933ce3ff5cba1406b8c3f7a7a93f83bea3ed6f66d2a2e6ab79a530a7517f7f912788d91224f7a79c03de25f4ff1c89f91d68630632580e2dc6a3c3c0fd49e6c8249eaa371a5c157eeed12dd089fa0027983ce0cccb66d30e4a7d7eae9d68d0d8841c39a27f02a66b598fd97a44339009179b884b2a50178c78e13579234ed3f489ae5b6f3ded8ea967c1ba83c49a283304e7c4ee22320214646ebcd7e95f442cb3817ad3af3957fa7ada2f96dd6ed09f2118b96524d90951c978c273df21dc2f9cce22e33e6b3f3d49bed412474849f48bfc8633252ba1d4a087e00b3bd2c16253c5a146567cd7430be585eaaaeb62807d76c52917faeae82ce5b87cefc22edb2b6b74a0cbdefb0569758cabbe48b996018dbb87226404d36aa79c69a07079a0cc4a969f3abc11d1eec169a15790d476b58ed1d170fb1b0df6c33f70eb68ec1a287fd4b87db466d060b096ffc2b75e7fefac8ffba6d1486c505437805f422ff7968360ca61d1c1b89a9a7cfc077197e35f55fe085affa4649640e20c920ca38c7fb1947fba79c22571e73b0c127109a1b38338ca4bd41dd457b74e32049e9350b926524201b9c535e0fd893ac31ca635b9e37a9f0d921ffc9e7e0106866d909ba8867405606a1c6231f2e1a74150ed6504476467922c67544e1f9ffdff68958db680c246c1bbeefe2e355a82d9490db8886c3a1ea0b149f305d9f632ad3ab40be4d7e8966b314b083f85c4bc9598a6196b304990f33818b2252a2a63929f4e2fe38813efb2ffb99b031639e5e46a96091718ef628a4bddc3b61d3bd1c27af734a42cbfd888e1136e73150a1e3ae4acc2c9e36eafd3f92718ffaadb28f36d982fef4fd856c5935afb782684227d267ae678c79823c4109c72f62a4abe99dd3c79f29ca194f6105e4bc962397abf726567818534c11ad0d0727c9b7b4c840f271364f749cfe29cf5edcc8fe923c2b22241fcec88ce54c26de6735c59260e49e695a85b3a7fc06ff75c15656474836171bdea1862e7d23e8027be2e877d7aa260cb69eaf8d514a4aa41a91125c9c172d11e1f578f54f741950ebf63e564fe01ac807559fb84076e4f6087466b8d6e50ff1aaa42c7a1b9dcd375e4539b922f4ddbcabc136b8cdb57a03b0eb7af6894939655c6b359ee1853e6efb104de95ab89259079a17f33722ed69a7de3ab42c34dcda1cd80438be4b4157b7f76aff8ce0fde8aa5c8e382240b04dd04c508cdba167126ca6c472359a8a10561d49aca99479d43a6972e955aa81a5a222b8e3fe2d8e6a2fe7165dc5e9fe85469ea8c751d851f2d489d71e2c598146190499fc1917bde4f3fd0b1fde754e9b6963e54b14c2fe998bcddf6a4494aa4578236bfcd91e3da804f5723ffc256e9babfab8a8bf6098bd109dbff1c71b38f16e8e3b281426fca1a089cdbe0f035797b0ae50710e50bf4946f0fcb6cf7e0e8d5119263f76fa59301f895cdf272d16f625aa227ba5cd7789e7aaa70997ed642a472f7f35d8b96c77df82efa4570476319f287d639dcae7d4e1f973a13eb7ab9c8d791b459c9ff0467c060c7546e1facb7b7b9e39624ecd7417ff2cc05e87949b48e454c06f7c333dba1b669922f7e0a44bb87be81efec93fda3d0e6ddd51a96798b81343f39535ab696c7903174e22157a8d0327f61e1da52c6d80c67af50341e4761a1b3f104f15f54ff3690e4e037396005a0f53bdb95b3371a065eb733c345ac38965f4c71189af19744a33c8b95a9cb9e877ed3c52f2a08c728178ce244e76e640dc91c1d3fee2a7f23d920753bd1961ddcd5082b8b1fe1a465449bc3c04f5c61ffb64e235da2fc0d39a2a8ba9e098d3568e02260e6675ae053b1886e2b289587b21fbf7f6f32c5e4d085f306a49d91e6a2563644ae1a7573a0ace3277c2c1a4c50acc99aa58ebc56927cfc7f1c5464c5e0f5df3b47a0899f6e3602f74d53a561197347c07bfa35c46d7ecc7cef14bde4423c505ea3d53e3d290ced952552692ae2ba5a5ed85fbeff514341af446c12994bce1350586eaf2f716ea32e7d9b65f6c57164bf0caf8891a1ddc534388fad3c145bb1167a23788eaadaa40de7f5fef3582f59f10c4e917406b9b84252e13bcde617eebe907f769485b17d59733a564249296c0f4f133c2b54e80fe5650f0e244c413578f0e6cca34f076a74cc912c436ef4e0630dc54cef04073d63e0991f2ab5541813ecb80e27169d3aa490b8c1293f3623673928fea85069fe01e85547917a0d8a93e9afc7cd7566c687b7b47a07c37ac1e99e39879ce4240ae4583db772b35ac580dd5f20f19322b63bcdc597e9b2065743942c780108262ba62d2f3ebef4d7ef5f34c5f5529421e74df11c1d16fece6f65da3c7e463ef9495eccabf882237c7f7c3725673ff444b026035bc22171f592ad1e1b3468d4bc9042ec832ae4ebc1633f135b8ef29f321fdf58ad55b4214006e6e423078f8040f2fff5b5900762e9b57343979807c8cab31d46735095f18a046e4df4f515b5a16c86cc8e789b501b57aad68de0c15baec5e4b79d35066c36cb5245fcbdffdbe8510e10bdedb0315a0d46f90535a2c7c736e35c5ed5a8a17cd4325b26088edeafa9ed53382f97257c8683e5e5fc65b8810463c1b96b949da87b508046979fb94e599cc17bd37ed858791a2408f320fcf4ab01d245c7a0a626f34cbbc2cff1a3d7e41581899c6c8b7fbaf8458c3a1d30856e8986b33c84d1a5e8e520d194254221edbd517dff04a60508ad3a69c63d6092e4e2519d905d4f1356b6b8c3201e73705cacdd90e7a1c60f3d4408e3f371ef137352763fea7314989959871ba0ef3cdd6e6de6f5f1c207febfe4186bc5734e1a91f9b74722671c0e6e2ab97ed5c5202b4dfdb790ef5b554e9a2f4d3e33b44102d2868bfa6d9c05ff34a75af59d96b9fe929abd07807de6fbc80106a7ca5a6f50fef7ba2299118dd2cd672ab5ac00bc40abfd8cf727c10efb2b76693248bc45a9bc39b7dd48fb2ca98be27ae9f0a87d7b55df7b651a0a96dde93b31b9b8089119abcc8654fa1bd077bf1fabffa5b32bb7cb1d0569594a673b69fac456a27ac0c3c47048069e3fe56815049d8ec33460b098cd2a5705a44c049b4602c1698efad5e74798d68e415c3267224bf974f84e60e2641590dd25c71b0264d9026ef144dd0c3740b0a6d0013c0c3c0c3c0c3c0cbcc6f0f7e66e6d6649482949a299b0e0cbb097049629a594644a5eefffb3fd57e340cd7e676d6dcde881ff0cf30ca70c663f0dfd0a343c919436978e97ff62d68bb911343a9120e3bde8855b0d3a6947d67247185fa820687022c95dcebab2ac9b388b0282c626926406b75423f33aac9a480e1f5e7eca523b359d8944bbbe4a173ffe69aec444b269461ff1f9f3f0e5901f9e2e9120d63e55ca7639bc7b236bc5c618c30712e221d8320ed0b044527ef71873ff694ce156225143e4cb7992ab795b1a9448ca73ae7e6a3fb4f26564cd0cc8901f3ec2481e84043c78f41a684ca25319faa269c47b40da0e0734249138f25da5b366542b9d051a91d0eb3ecee406d7533b0d1289e16e4bbeedc39a5d5eec28c10e2f767060c81923033c78fcf02143ce18cf834719341e91203e6b3c99621a8e4890f994a7bab47a182b824623122ea83beda672d023e21e7634189120a3626a693e5c1891590f532ba3ec8c1034169114dbf9f2a5ec8511cb0205df40431149a14608a9fa79233b968c614611682422f943736bac2e866e1e110917b469d6d497b6367f88a4b5d3b3b7d1d2524d86485026b498d65688c4ed8d770f623608552244e2a68af9afcb2fba6910c91636e7cdeb1e5c7490209274fd87509bcb2a320722f9e7ef92b9af29d10191183cbc57badacce9db3f24efc9f1a0846b9ecb7e48ce18f47aaa9c731ef521d192a93042a4da858bf22141853cb9d6e173252ff79058eaf26bbe7f4c83500f4915d3438970fd7455c9436214cdb9d45bf8db1e0fc9c1c5d2cd8ffb8bd01d12d36586f2b218762bb343f286eb571279d52161f4a6247efe1fed5274480a968332519dae84eccc21c14f531c1dec5b1ed09043a2c9381b63a756309dd238248b4c3e3ee31b96991b593b0b72849c80070f0e020d38249eda58ecbbae20530a5b81c61b924d264f517683d27d7b1568b821f1e7324b665021c4c6db9078224a5d280d93c1563624e7177d496590bd7c7173028d3524654cea213f98f6f0e2faa0a186c40e334a59929bb917ae1468a421c12dfecd28cbdd9a311a9264a3e8da11179692679640e30c4959f971c77cc3db9366482e25839d900fcb90d8315f92172e8bcc54661268902159f46656c9cea43dfe48a03106affecd6643a7ed9866d01043b256e6badb6d50e1411a61484e67b2335f4e5155b291354e34c09014a2c94e098fa946c8740634be90d41b3fb749bb6e0795193884861712347436255df3ca6c7c64edc75d17126633fb2991f3153a32120acaa0c18564cff6df51e12e074873fea0b185a45051beaf8414a13c3fb29662a0a185c4d252df7342744d66481928e4c240230b09627f373ff7b9f499ab5848f4f8ae418dca5021fb91b5e3c1e3c040e30a09fa9b97fe37a48dec053f7c7019685821e1e2875b764f19660c39434850f4d0a842e259cf980c1d94d8ce70d9000d2ad0984292d8253d4afe8be6cf23ab0986183d4e40430a88788666cbd8e65ea94c2134a290b4fe59252f42c64d062e83648ce363481032121862f44034a090a027d6638b9c1373ffc8da0f204f48f80b1342e83855ab8c32820011624646aa41d1704292d0a363076defb19cb3051a4d4876f553a5ad9b47b948830949b13d67860c7bef234281c612126d65af36e93919c2574262770e6baacfe246e9494812baf74fff5f76ac1212122d9af65122ee72597884e4926139065fd50849f515849ed1b7f049a508896baa7995d7a33de6899034ff155d63ca68a7ba2124e9f2503e16bfabafd4031a424810dd59e46bd79cf02025d008024aa48bdc131f32da913533cae8918ae50f206378c18387ff0032463264a00104477c7e3a95d7cf4ae7434818f6041a3f48aa0ca1a9ab1e4b29df0749b5a22b56d566d7d11e24a7d99f85d549830749392a6c8a97cd4d511c59eb1e860822bb48121654b84f32c31f88e822c9c6c5b363c80f5d25ca45527cfd20474fec3de58cacc5c0bd8c1e3f7c64488fc34582a6889acd1633a60ba281ff38d30b81c82d926da3e6b93219645d1d59eb2104480f1a1c211d10b14562277dc22d77f47ca61a59334bd35a246777e55c1ccf7d0809031d20428ba4bb144b32c5a4dffdf1314c0e44669128671efcda4e8cac4916896e67dd1e47a5fc098dac0119d263a40c3382602c123e6ddc5032bfe56e0de487c122d1f3cfe92426a217ea91b51ec60b21437e244230a0af485277a9fccb2109af6c5d919cacc3f59ae893e28f334610b31d6168a00c0f445a91acfa79e22db57376bec719428694954b81082b92ab62ea8b73e72a92356553b57c325524c59c6affc2fed846cbc8da107f01ef084303ee4348186088d1830c915424f5a92d1d2e7e9e65b71be265941188a022492da58e9d8be990b31822a7b07a4f43c67b0a2173051153249c6ebb99a8a56c0c444a91541784e5b01747f6160622a4f0724c55efbf4df14f20320adc7b45caa7ca67e1913533815a1b4444919464eccd2974fc7f51f1e05104915074252c95de7461df110145824e6fc972da5cb79813f9449252f92674accc2065630a114f24973e69753afe06cbf0e081d6c3ea6c14229d482ca536c65530f30b9641c611724260031f64f818120404683dd00c14229c480edd7eb5a2540e61d15207914d24481bb70d62a4d7c93c1d443491a44b5ccb36c753bad42299488e15d964a3a4a85a1507114c246e8ce5379e83169dac4b24bde5136bf23a6d456c89045d1ff22a63eabaa966bb9548be207dfd6bd48da78a12099fb297e45f0ca7746e12c99b15e37b6cfc3a289941441289e1848c05e5c1e6ba8e44a27c0a4fd3659f9409412229c5a376c8b8a75d7acf0007f4114916638e6b5d7ad54fc711091eb6f3586c4f315976644d2920d288a472ef98dae182cca9674462d48d22449b7f98af44169118c307213bbfcfe80af26247816087173b0a8c1d5eeca80fecf062477db1c38b1d9507114524a9dfa84da5d444247a483dbdbf4b71d335b2a63bc2d080ae8121460f20228848fc9f2bf50c912b8b2d25440e917025f38ab69797577064cd87fc3817868821927743a9b61421456949c89d08440a9160c236985ad2ed255e337ebf102144f2da25bd4963efdcc88caca90744069198baac2efde7735db69b880822512e2f5b1479418a5aaf98916498f1a30c21e357201288e4ce5096cc4eac65108dacd1c07f98bde0fc381f506384082092fe63a8baa6af0ca2aa1142e40f892e1e436be98e7cd1bedc8e3034f00304250041185fecb0c01989078f4b3b84881f92ff7bbec2d9c92ecbaa20d287c49855a2f3e78e1744f89024b692eededc3f32d67b48b8d8d15295696d75480f279287e42d21478ab8a6209ab205113c2477f8df14544f7a588d8982c81d92d53c5cea33b1340d324241c40e4917725ea696527e50cbbe300602913a24598f5ad6a6d78a51a14382e9c91c434bb78d8c043c44e69090952145abce236bc57684f1c50e1e1cb83188c821c993bc4cd5cd1f2a07d5201287c48c31c4799e4def988643821af16aa6bdf486c42444f556ef67a6d3ba217153d76fc99315bad486e4fd6cdbd94f84d420b221f95be76cab838c96be35249ada6fbfcd5d21eb125143b2e76f112a689a14dbbe209286e43d95839f32ed6a258486c43caddaae9d352769e9899c21b9e37de7b31c2b998a8b9821316bc3f3ac88cc0cb2b1824819129496d16b6a1dbfb64286e414dd23c4f55eea519571867b600c091a4b07b558a75abe1643929fcecec12e655c8a5c4710094352386d3b61514d33c52c41040cc941ce78e6af5533a17d21e945878bd1be74ba3579214926d1f42946d4473f5d4838fd614e6eadd39c9a0b09ca3bc4b87a251d947a0bc9b639ecb8e5243b458b16922e6e0ccba42afdcb998504f9d050196f63180d0232e40707b090603a5ff3edfbc3c694107cb1438b895c21d1348e7fcc5d418a4a2141c40a093296f87855a743b4f2211cc01a82481550b554abd4f20aa3e12d2b6ee69c47f79a791506112a24862e9f91d9548c963485c4987274baf499e7d5238584afa4e6b9a3a6888847d6820011d2418008c1000f1e3cca080224c8f940904386481492845afacae6a523b434b2667684a101328008c940183c780cf132eab020028524b11baf430575eb9534b236a406cee38b1d617cb1e30cf7c00530801a7599c813124683cc172c468dfc2fe284a4b03f31231e6e377f9126249da5bc95e692d21f7a112624f6a825ade6e9d59a17594252860e7af45797eefb224a48caa3a3a2a7242eaafb22494812f2b3a794d29d17be081292d3648cb98d19262b2f7284a4d3a473a5ad3d6ff52246484ed194c996107f5abd481112d483c8aca46674ff2e4284844f7284250d625ee32e3284a474f17a2b7ba585dd458490145757c23d99ac64729120245b12a75ba49de80d721120248b8ffef8d147798b5ce407a66ffe7b0b12f141c2f5a65349454d6e3a223d48da94d9d47b8b1ad911e14192a6148b41ae6babecbb480ea6f53a3497461b5d1749b55b7a32093d9a44cf4572c93f935961cb34745c24f66fc6c85397317c7e8b049faba42b95874bcf6d91bc6964decc994fc8ce6b915cf98469c7bdef5a4e8bc4ed7ead386699d79f4582a9958c8d1c192b2e8b8451a1b39bad5ad98e4572503236fe08f9164ab048964db2bb67d36f4dfd8a24d9f0b77165d5fad3ae480c33a5e3bca626cd742b92cbd243668b49cfb43fcedf5faa60215545e2a9ec68aaa91cb22dee43481838c4462a1245b6490bb1a62b9d0e2a1246c814d54f9f8e41c8180c317afcb0718a246df982d0cf31e9bc2992d2935e47933f6bed8eac9522296d4aca375b8acb79ba0d5224ca9c8e1afd93faabcb2892948a18d978a23d992f8aa4d297f3ed7207153b038890216578ef85223975a87928cff31ead063ede8022b96d5375ce21f489444d252fa68dddc85a7ae22af3ce596384963a9118ddb348b320a33adc9c48cedd59bb63390539901e6b6c6ca2deca3799727a1817d8d044c28db060e14bf5648c8dac0529e3870f10d8c844df69377e8467cd31061329ef4eda2e7aa3c6236b9748ce94febd624c2a89e8466c58e2fa98ae44c531157f54893c684daf273b74654b362891203307e1afc1944ef54f224197ba7d3a5bafda5d128923547c839a7ad2a68e44f2ee6b9241a6886f918dac95c12cb00189c4b67cd9afa8192b9a47248878b3cd1ffdf9962392e4c650ef58a2d9616e44b2c9ce519b3994f68911c9317eda672a333f4b5944d297a8463f15b4fbc7ce5011091ac2b5db2ca66f8a2622d952fe9ca6b631aa644424e7a89bdf52fa5c4fac3b44c2ff854a775ee942bc91b53444f2abc595eba7531e2d85488ad7196233ab377f468884cd78413fe73237c34124a5649fe167838c234741248a857d545f4d667f0622b1b293c6a7526a1b8048f8701735717e6a7e21407af80f1f63fcf0811bb0f18704953fc5cd412f3f25cb59f14382c8d4b87f734a94b646d6bcb0d18784f1301564da9cbb6f980c1b7c48d27673f3e1c347c3de4392a9cce9d154a38e86fa001943ed0336f490ac1f3f7c4b4ff6b2e78c0336f290a027a34ea98f711a2a2fb0818704f394b5e42e9bb8cf38639861ccc78f13c444c0c61d92c3aabe6e1875cb1919f2a34cc0861d92f24533a9a229a71c2a6356213ec40766c0461d92525ecfca962b6f203f78f0d0830d3a24a7dd338f1d19c3726864d360630e49413d77bf3d97ac9acae4905ca637ef594f27bd66998a43e27886e93fb3f43a42704810f5a5d944eb865bfc8604f99c2a8c25936fbf0d37246cf21f3da1c36d4c4a23eb3e8484a118071b6d480ad7ec96c4b66ed02c1b927ac42e98e51591d790e4797c4cd5680c63393d7c240531a3470c800019634f043bbc30a633b0a186e4947e63e2efb55942316ca4c16ff7647153b05e9fd1909259793d7f9530bfe80d6c9ce14e42a8a0aa524c6a064696696dd752a2eb3f633300f0818d32247aa5b47c6b1feb37371b6448b44baef143e88d991f4362b64c221b762b6e6e6d88217184744fd661e51d0c43c2c5d992f15da752ae9b60030cc9a35383288d8d41f6e947c2041b5f484e16349c560fc2539d5e4838b9f1edb1b4b878b60b49e1c4fa5daed85f137221e1e5322b5fe5aedeec9460630b091b2b4ec520d4d3970a6b21f15232b74a49cba93d0bc9a16b34574c8879b260214193b44e0d252f566a0786183d02a0041b5748165d9a64a78fd571638eb06185c4f41ecc6414d3549bd440d8a882ea9fefc47929cb6d532171dc63bcadafb975680a899a69aac4a8f2d05f4921496f29cf974e7cd0452151cbb362b0132696e45048d23aea4efde5f34e7e422a9784b8f49adb2ae7041b4d480a8fa6dbd94ab996aa70b0c184a40fbdd934ca5d872b066708bac1c612f4cf5af952ea77aeac12da91bf4c4a26dd3309c6d4f1a2c8243d844791909cee633cdb5bfd4cd236d83802fa6b44f67826a56484b4dca9aca26347cfad088917d66ddbffe737e844d8536c31f1ffeacd8eac1912d81842d29f8ee371d172fe7a3f7c1c217d76676778d91d6c08212d551936fcf8090b0a02cae7e7c4a8ade867780c7af0a925c10610b67011d36c29c86c251555593f99d19f31341a380fecf06287f91828c821a34c089021c72cc2c60f92c285e747fbf5b41c3c4348182018418fe163c40b1e57b0e183e4fc94e1732aa17c34b541d8e84192de27ab52398c78311d2106860d1e2407738d5155e5f449518ffee1e36d64881916e81f3e32c083c71162357691bc7327566f69c4923cb236e4878f911e6e031f659829d4d04552d4dc9a4567ce3b27e591664ea8918b84dbdc5e59bd2f9f84b848d4dbb81f3c8d765dcd0a356e91e4d9359af3325b25750f333bd4b045721e55aae2458b91ae153ed4a845b2865ca7f3b16991bc26ef2b9c124f56a759246d52f374716cace7934592e68bcb95a64908bf4c146ac42239b3988c5d9a84909ac924d48045c2bd7c8a1f33cb65505f91b82932275b398b913222a1862b1253d6674fb2936ed1502b92be928fea7fd9f1fc6145f2a5e47d35ab19eef1d92a92927f2653396232545615492dd67bf22e6ddc13a622514345ec462d9cd60e151509d6c94f9c128d1befe3427047181a3845e25cc68cf6ccde77b6291235638ed1b4b01409b61746db74e86cfd4891704a76ea4c7165f36d5ef0e031249d2064588d5100f1e1c5036a8822143540d1801a9fe8e123c8026a78c2d30f203f7c04b180a71f401250a3130aa8c18932cef01830a0c62668e02388054e000206d4d0c40b5e70c278408d4c60a28c05d4b8c4016a58a207026a5462003528e1c300352641801a9210408d4894e13e0a5003123d7c0431408d47249ea99f4df1bc94991c91746dd6959b41c853bf11c91d6356d0e13a277a674492f0f0d0e77976eac28b48b0944fb78c6ac5265511499fd3e6a02a6e63ca2422c1defe7d6d946bca8848caac19e46e4a1e2269546f6ff29121924e583c912d4dd61f2c44f2be257f0b3fe252120991bc232bafe893315c89834810fb167117d399752888b552ad5ceee50291dce1e4a924d37eb56c80481ebb245ff152ca49e90f09f26a639acf9131ac7e48ca1c37768753e9999509428d3e24afbe099997f7b6e33143a8c187e40fdf20d3ba474d9b1ba1c61e12dfb654104a63b83a5f0fc939274bdafa275d2cce43525b859efed0af381a0f1e39a881876435f9cb9bba648607dd2129dffa9b0c66733947ed9020664c5fa6d6e6fbbd98371030906bd4214945e54d177f45f54cff4103203d800c492bb3400d3a24e81c95d3e6ec27e4fe3924dc58881d7fff1b4fcb21d176c3a7ab364b4da73824dac9af519f794be70c1c12d353dab07b2763dc242f1862f4f851e30dc916e446a5d1a5b2999d6ab821a94627ab74f7667b1b92f4a652796e37e64e3b1b92b2ad2fcd7b7eb1d45943e266ddab54322de98c5143924ee1d927a6e9dad9342477a8143dd6c8fb949435d0905c169ffbaba566d3c42ea8718664f7fdd254eb78a7773324754a95b62b64d2664a6548b4d92c1762f1744e860c494254cacbf1e1923c8d2141a54b3188ccce69db1443d2bcfca68bdaa520bf302489f6cffbdae0f2160343629e884d6eff49cbd2913d35be90343ac6b72b157fc7c291b51e638c71766448106fad410d2f24edd5c514722d3498a70bc936523fbb9e7ff04bb990a0f9738cc1dd3ad564a95b48da523b566e9e21e2d742721022438c0559fe199485a40ea53e650e7d42f48b85c4cc2d1dd90a5ba374850465c2bd9394199b8b1592daf407df68615464578504a157dd3b6c36bd7ba0a1061592c2767fe6d4761af78eacfdf07186b81085408d292486178d41880eda83facc2a50430a09426e7e93579d6452711412b32d5727bd2514b4d33a8dd538e19b213f4e3a26e0336a3c21a992a67879c3251bb58fac09015276778690213f3c831c325a50c309499fab25ea1d5a3b8c359a90a0db72b8a0d498fe52332149d8b505ed4926213b2f215944e78605dd62f59511a38612122df7d6e252daa6f49390ec7b6db131efa3490d12924545d5d8501f21e1d328bf249328fb0a1a21693658cc6c4a152129cdadc52c4a4de5132242e206d11bc53d262df31942c2cff679568eb695540889a2449875b8e4c1728290bca77c84341545c58882ec510308499f2a598ee6a2a2dbc8670809030c317a9ca0c60f92a48987c5ddcb0f1f580220437e702004357c90e09a42c9a41f9392cb21cfa0460f8a0d6af02041534a297f9478edde9895018d5d24bd56daeece86574e1927850c09424317af7ecc7a1baec534bd5ce8c1346dc5d3f549b5233ba48c1d1918c10e3e1ab8485a3729dad2be870dee18346e51521a3d69750c47d6d436c083c78e30bee0c1e307101f43aa982d1c1d4c5816319d52d2701468d422e92f5ea9a8942e46899a062d922be3e66421934aa942236b6a25a81be2e3878f1f66f47074c621e38c0c27c304346691983c8ebc2044d345b1659178fe232c5aaa943d796291b4398797de20f37f33b048d097b3c635a1ba7ccc572407154ac61b55273f225724852c792d9ef5bc62ae15c941e81e3bad4c39268d15c9d12a09bd55dd41837e64cdac58b132832323d5a0ac2239b9584c4fd994b4a039430e067a181b68a82251bc2f26b959177533e5c010a38718345291f4264b9e5cdacc7fce0c3123c8103340808ac4d49a729a53a11d93e71489a682a99adbc8ec569a2261b54307177d2353542840a3144921a45f9ec999679c49919474e98abd316ec91f45e226213cbb76d80e21d4020d5124288f262b8bea1854a74391a4fb74b6503a64280b2892639a5e26a931c8b4f413096395935a0289674ae74e9f3985a7700e1e24497dab0eb2fe54e565170973e321f36a5ccee5eb22e1bf52862dd351acce45d288d1104be64954e7709134f241e9fa54e1377fb748acdcff49fcbdbe682b71d822b182e8bb312563ecb947d68a80a316093aaef36d7d9e1689f615bd2c1d010fbb001c01c72c924e6b76f98d3601872c1274aafe9495aa47476d642d1649e1de92c6b8ddf4393bc2d040ba19639c19240f70c0a2d64b59ef9bab0b03c72b9254d62d63aab679f028c30c872b1244a6f42563377fed6664ad87cf600c20cc65280a70b422b933ac09d9a73f08cb46d65eed033c78bce0878f1e657080078f1e3c78a801072b92ac74a36cf6201cab48102ee2cbf6363d86f80bd070a82261541211c23eac9c0c9732e0484592a896b7d36b962984a8484a3a0615562a44f69b7b384e9178e2daf2f85a4ca9c311c0618a24a53eff66ac8e0c384a913c7aa365f7a4c5119b0b38489154f9b3cda7f4ee622930e0184572df6e59cb07f9ea6c64adc776018728124fa5d64ab2c55385b204aea14834eb8dc994fa3d2c05810314aeaffed897d8944de0f8c477a192f29049fcfcc61309d7efc1721c2d8e4ea8d1dd445b4b369acc8c095d97a61f3c838a58308183138941e6f8bf398b97d1ac81f78fb31e7656071c9b484c522b5fda9c9f7da389c44cd9f228b5ef75e56622b97425f9676f6a2e8489041fd5f92cec69f56c5e2241f6fb5ad675e6a46489c458a1ea34fa27fd901507014725929458d75325549690274a245cae3f25747812c9bef23e763aac55e54822714e5c08bd74bf504d249283d4102db79ced164322d9e405152fa6e4d6461f919c7f2af73e77db748a2392554bcf3b3798ce1e3722b9736adce071d532891189ea9b5e5937966650c1b18824a1576bbc7b53b056d707381491f4296839e5714da95c4301472292ac541ab3b18cf9c48488e4eed1783ace07933f3a44620a9b69b9c28629e53144b259d0d299ad16453385481695291ba6553f8c961049ff797469394f11251d447230797742af2988e40c2adebdafb22911062261f3694fc9b56425b10022d9926b05fd249e79fe213974d4f08b7ada72eefc909cf73da427193ee4a70f09166f9b627a8e955f3e247dd29b426e470ddf590a70ec21e983284b33b2b62ad743626ada67881cf1aa7c1e929330b59753a624a2773c240921c74726cfa7e2a9ef907427433747a8f514b643c2ace6ffac17d52141e97cf397ef438704d5db7ce2e1994372a8b5fa94bbabd63772488c9bad56e4760e9e9b3824c694f752f80f0d3d5238248b363dcd15d44bbafa8604f9d1e5f1849f2635dd90a8b137566b93a50ec23624ff577b7cdae6fe0ad990e8c9a4c6ed4a9a7459d690a44c5ec7eea0d7727e6a48d4f5f01763ee3e7b2f0d8962d94a3ce6332e7b68485c35f94173362c577786e454a2357dcacd90dcf6b12cf5fabf598624dfa02956995a4386644fbf29986daa5b660cc91d843ebb8d4bd94ac3218644b5b2eb360b269b2c3d7cc8b130a0b11acb2cc9bc8bbcc7f6ed6ccc73972aa81ec00186e450aa3cdab8b97c0947d67ae4179263c4e612321eadf284010e2f246bcce9bf7b42adce3fb2d6037ffce0c01d0d8e900fe0e84272283b93f94ee5e8412e24285d7237f57c25c821030c1c5b48da3cdf54cfd551a3e442d0ec6870847c81430b099eb2e56026bbeab3d9011c5948d01fb56a45c568d9a59135be20878c62c010a30707706021b93ba88fc6dbbe20b3241829e36ce00a492745c5f454a95deb61d0e08c80070f1a1c213c78182b2487d8c5baa8c7aed96c159272b9ada7ce59ae67c110a3c70b7050c178241c5348d0e93477a7cba758f2c6218504b92636261590213f38e0051862f4781c5148ea50f31ddf628f5b2a060e28248ff8fc79f4daeddfa9078e2724ed55e5ab960d8713124d3b7b143d7273c8dd84a40a1a7e2553e9a4fb6142623875595a99d483079790a0417d5cd0ae1ff47a894309497925a6a9fa373b880c1c49401c48c0cf2f5bde136d3a236b27c0718424153407993eac88c6130e2324560895e526b45ec9f966507080a308c9314c4b9cda65bc6888902035d529e9bdf67ac2212497a95cf14f59fb524f07388490204fa73ff9526139087380230889c9d38605370fe24c0d8424119195f67468da577f90a02d6c674f517ff45e70f820e964caa41bc344d5a5dc00470f123f9a481326b3d94ca9063878902494d4506b294ba8faec227994bebe788d8c3b75919c47ec3366d505f5331709b22a329c5a0e17c5d7b74b56aafb2d123bae8d75e5d916c97562d945da09cbe1ae4582a8912d42c654d1afa545b2ff874ef56bcd2c9273faec68795a5924658cbc658619f5518d45e2268f2e7341e94ad1844582121ae396f09877536c6453c89020375e91ac71edc445a6600e6eb82241651d110d5131ff6d8c831bad484a19697232588c9da921c20d5624db47d750d7faf9cebf1bab48ce9b1e6b66779492bf0d6ea82241e47b2d9cc789bbdc8d5424e9246e33273956953b40b8818ac41969b952888c6df62992622d2c854d415dafa607374c91749a2e3e446fee9a6c7c70a314097b6976d26b4627719322594b08dfa04e671449493c6acc15e5ba1a333bb8218aa4b829fb4a5cf4e5380a45e2ae8f8e85a8eb741a0f6e80a2dc7aeff48c31e6a470e313894f412799ebb745ee6137837bc20d4f2406cb71f3eceec7547d2712f4ea080d73318a26b9126e70223973fa3e3d3af5797e1349722efaee4b773ef49a483211a1e1a62374d59389e45cdeefee22fd336e3091a4ee438368c7ed797989a4cc568d17d294d0413bc20d4b2465514af996542d3d3f196e5422c12e75f27819a744827cdc796a8e9bd1927b78b831890415311f6274fe52b64b2251acb6c5add5674f1389e495f534172ae5ca17128922723534fc5c8ac17d4452d2bda92e8c08f1204724e91352338ed5a720d34624e6eca8999e8316338f1109aa7359846d85f1942d22c9acaa720e1b8d6a2aa38a1b8a481add7afa92098da1831291a4bf595f4f745df418056e2022692f08ab4bef187f458748cc0a931da5a53f3644924e17fee45aaf05bd0b91d87126c49685d31d674224b5e8d89ad3cd2beceb613788c4d09cd36e88a5d5d80a22595547f7d37cd21c36d7861b81483adfb424dc825e1c151009baa3cc2c8dda5fb2b8e1c61f9276e73c744e29c585cd0f89b132424c3786d5bd6ef421f137b7bdc187c494793695529e2f9a74630fc6430f89d1475f7e4a15b1a35c8bc48d3c24c757c6785183c5d85770030f89bf239fe4a5dd3cdfddc1bc1e3b6cf6b452e1861d12eded5258b48f0d7212e2461d92f57b6d4f9376ca327be1061d92ef54a8cb20cec4767c0b37e69014d62eb5522cf1b811c10d39245efca84b9fac54b8e8461c12674b8ed4a89be54ee6061c923e26f9fad29e4bd90348973724e5d4204f45fb0fe39f91b51e403a81dc70431fec2d2ca51ce3e76c43e267b88c712f42ff5dd890d8691fc2475b884b7d0d8916df212ed9a7243aab8644cd69ca82d6a034246a8fba86e5e9f833a321f94269aed88ba1cca26748cc318e1a2ddee599296648502abc749eebcb90a4792bd56dc66fca111992847b256d9b9292a3b34eb83186c7aef45ad29f6a6689c11c759f825fdcdaac85c1f4c12b66753ee9a3048636a55316ca3305cd17926d6e2b5f4dca077dbd50576c1619d9f69ec42e9c6e84097553195b3b17b4cbdf5bf3224e8bbd85e473d7ae91d94653b325dcd042c2cb065711eb8cacf53843c890d5c28d2ca4a6b2a8dbaa683e168e93fea57fa5738524292e322283d2d0ac9d19073964942adcb08299d7fd94bd88edfdab80b8cea482272917ddbc4185b5f33f5bc898cba3e5c61492b376ed58920dda3597425298132edf19ac4493ce3842849c24e34614923a955dc865f5e8cd504892965bccbd934fe871c309494196e97d1c8ba5ae35214136bb5356fa7eb1d2070d70cd6ce00613124e5acdad7b90f99b5f32120af2fec6126e2861557023093790603c5a70e30889d134af3daf2a2d08bf70c30849e284da8ad5b0b7495e84c4ab39fbb01d4f53b827841b4448eca4facdb5ff1d617cb183070f34c38d21245995978f92a7a56cc20d21249fdc269133426e1643c08307136e042179c5e25d8cb081905c9942e86841950aeb0f12d4e53ce71c261f245c7de568e1b94725a122dce84182bc78bf3f71964246e6c070830749a3d72d9d27b91cd3ddc52946cd2cd645c2c7d550c963c7134d73613c70613c6e917c69db7b6ba22d923f2635e13e1febf2ab453dee714f98e774591bb4480a9ec26ed4abb567701609171f67ecb4e7acf6ca2229f9e78cdbf62044bf36629198c4a89e3f71fa211a03c8db8045512e3663942f0db31a54c4e8d43fca74b42b0b72c82835b0f18ac4d223df2edf67363139f0020783070f327cf0e001041bae486a3519691a3e8d8c8666012f7654e2630431238c1d21f86287eec0462b92e653a5142e648530252b9232a9efdbd2b626f25b4582b8253cd420802524659e3ccbabb6f95317801292c62cdd46ed6a6c0c024842829e1759325d4cb5962400242468b7f61ff1bf594924802324b56c98cfdb1ad5a3a905011821793645e4729bf9e74d11923a877d4c95ad3cbc4a84c44ea65f328f7805010c21694d5ceac88ff4bb5a5700424892a1555e67fbc8da18020842d2a9f1204c87ddb8d3c07f943d160010cca6f32ca9c866b284f88f1f3e8c0d02f841520ab3ca7ae39d739946d67a001962ce10800f925ac393e9a8d98c0af720e976748bf230b5ea5901f020497ef0527f316b748df12ed21584127a7654a8b4c740af0a3a749174492995d36a10f3ed19592bb948acdc983e7e8fb8485cfbf428e26a1b3f213a6ee1031db6407cec0bbd7e326fbe2c4b9deaa84552fa35d1b97583e52c1ad964e73a689114b294e6304d7fa9fb99176a6b2bd0318b848ff14a745d2bc675b248f8b2d8de4906f911532c92af2cb53dc83211eb6091d872a22dc37d236baf48ae1d6919b2346f6ed1bea0c315c97d3a6ed9c88867ab74b4a2b07495a532648c011020233e46fbb803840e5624d7769ecc99ed91b504838e5524883ebdf09dcce7a4aa4810322ec674988e05931723437c9ca08c213ec6183bbcd8b1c38b1d3bbcd8e1c58e04cb7c063e3215c91ae316aaf45312d7da41072a9247884dab9e722f2c4dc72992324bd3a6b80211e243cc00c18e30be106246193f9211ecf062c7171878102448071da6483c3da2f14d9b1219c531c6385e646064888f1324ea284582b07496c236eb358814c96223bc423eeac7d48f2231aecf78290d27d78b2239e7dc34a9bd0961872239c7593169eac2ea0914c9179e933ad12a624fff44725c4faa3f9f4ae6a9f64492888cbf2ee297fa4e248ab090214be8689fe644d2e5465341b8ac9f50da4452a8609e745552561b4d2479061b95fb52a50e3391f0e76f72db435aaa204c24db55cf77782e91dc6b5fb2614b2458c753f293bde778a612896a7927a6a29accded14189e4f87cda6236f3bb958e4924a6797ca8593b219a91446245d5fc9ef924db1489c43e25e6a367864482798777b30fbe9af2239252ccb8fbd5d811c9adbaab394551b12b6e4492fb6e96cfa6addcc488a44badd91c2c558ca645248bbebc224e4611c979ed3106911b6bda4d4462a6c732f5722122e13d8e4ecffe39acb88748f474fa36d3869fc6d61049f35a23caf367ec7c210ebb797e722544c27c30fd39efe5b45b079160de2bb22a664ef7aa2092fd363dc8e86b26460d44629013dd3d2542545440245ff2b079a3c99efef30f49da62ef57d98cc83ffd901c2eda881b55e9ea937d485ad3a4dacb365ccc241f1273b6527aa1939cda710fc927cffe7a4c6d67473d24c798e35c65aef3d1310f49e9a583a72bd19436e241c71d9282671c8bcf1a539eec90285e9963deca7b845887c4b84d311ea262ae60a143829529b3f3360d9fe790f4d59b4665fee6bc72487e0fa192b97971481231177ac48443c25f295d2a8d8cb0cabd21b9d72f26f5a96efc77439269368fc973b849511b74b021398c9acd1c7329a1af21c1764cc9fa6067a3ac91352b26021d6a488afe7f721d45bc5c4b460f7c838e3424d648d32976e73d68660d3ad09018ac726c4b7ac1da534810c48c760c0431a3bdf70cc9494dc6ca5cfec81a9b4187199234c5d8b5d2515352e93224cd85b34c3a6a75273519922aee3d9836d1c9bf44061d6348aca4b47e9985d279471b08e38b1d49161d6248fe2017c56438df93513382981e41ca381d61481e13fda1af3ebdf30c86e494ca63f4d5ea8d6f1a597b1762fc85c4f47fdaa57365640d9dc759de18747821310529ffa74d87702d75742149c56aae7453613f2947d6ce1032c4b44007179266efaeacc7e44955a0630b09e26d3bd73236fdc8c67684a1010c1831e8d0425207adbc319dbbc728ca42825e6a48370da7b4a35848fada4ac945be42c2a80f77b2f6c35936cf0f10980e2b24e618dcff64dffba9bda0a30ac6ac216b4973a6572a8ddf519e973cecd9b8c38b4c3eb6113aa890bcfe312ba9f41ce742314840be80828e29247ec65f9259e3d4a9ca8e30bed851061d5248fab1684a8d9cbc105a22e88842a2e50771b1e9bb329396a0030a49e972953c9ee5e4bb3f21b1fbdc3f3ea3ecbe4e480ea2b4f6649df6be3421418ed01b663fa5941f624252d82fa5d6d4aae3659790d4b31f963d07cf41a84a48d2b725b64d6e36aa9984a4ea50e1f3c5fca68b84e4ac98f5f75ee2d4c319e8384252de4a1d845ce5dbe84648aecc558be17111124ffda5705a5a164a4a84e4f02c4bd1ac2b864d879058c1ebc2f6898ffba410ee94bb3796ac83906042fce8f0e71f44884048cef9a3c3757d5bf4941f246c363bb1abd4be312b3a7c90d4733a327d672d6b75f42071573de8b0e93f08197be8e041a265166521e4768ebde4d845623499cd55a3c80e95d645a2784cf28295862a55ca4572090bb2d253c84a318b8b64edb8aaddac5267d15b24988cae4dfd2036e6cf1699a316e5102322e4a65cba7f0992831649279a849865a664529f45523a3f2b253fa3e787649170d69d763a7755d24f8e58245f25ffb8d13a569505168917ad8312a3745a763bb2d6a39431e47845621293f1f75645865319593b2ce47045a29a1aeb6c1a6e46b676ad480c9afe7444a4261039589154963965bdf4638c0222c72a922a6bec3c32464cbe574562e54e557ee1e6d49e8ae4987b65d48ca69444db871ca848caa1bf9a7ac45d30ed144941acf4a99ca23d5a08e53045528ca54258ffcebad974c8518ac47cd2b4728b4c3234d8630e394891a0744fe8d2973527d78c2c8ee418456252a1d35bddbb938c552187281244dfcbebc7e3bf89c8118a4413baea43848a0a9bcc018aa49c63b4ce152b9dd142811c9f488c4bb7db204aa6b1bc271235352ceb560e5ebf7722f14d268b9e547d90f3e144a288d53c72b3b5a8673791204255fcbc6617b2d41070218726126459ce5a31a3287264c22463bb72aebef8ffc85a8f1e7800f8410e4c7c67163aad1f59eb31a40c20236c39c8718984cb989774f889dd1c8eac197b22872592e47a4e2754c6778e7125922da58b59dfc7ae662991545e296fc54bf35d7012496a2968ef9cb493a78d078fb293c82189e424949dde4f9f236ccd1189441b4b513a691f12c969b16ef45b5d1e91ecfd351e66fce4a9100c391c91dc97732cd9a7217dd34624e724c358db09cb6c3b231294299561274b4779691109bbdbbfa6e9c7c2da8a483c4f66a3b63e8d9a4e8e4424089d35676c88331dbc2ee44044a2b85bfc689f5590e310491b378e28a13e16ef4d218721924354b6eee8ee9aa5b31472142239354e55d968cd1cf32307218c478e41247e3e154b6e6386b2f8c85ab11d6168e042904310c9f1dfa363f8984bf734b2e63b468e40245aa64aef1b351e20122f5850223fc93f8fd1c85afbe8a1f9021f65cc20c71f924fe58ca1a26497cbe787440d9d3376a6d8235cdd32e4e84382654c7bb9a4191b6464c8c187a40ef5b2cf72b283eaf790a4e7d47bb80677ef911e123e5e692e95e1ede3250c39f2907ca5255af5734c554f8f1c7848caebc963ae4b6a2a868d0972dc2169358e99b08a192d34bc420e3b246e6a0c97368a55ea78b1428e3a24bf8679ab3efd9cff34b2864a8724ed96d94376fcdb741a599b438266b5f60d2f574a86450e392465691dd7cadaa33d3cb2667701f0418e3824096d9f3d64f3c9c9f020071c9283f74597cd7829f319591b03ed90e4412c1739de909493ce6e5a961c19946e48ce4a42830cdac43253da90e039dc7768ab5f758e0d891a9a74e915bff8e84b20c71a124d27f1d86cf92c5e5a0d495a7954799ccdb312a5212947dfafa0fe83501da2213993cad449ffda4ba99c21c94ef3821cd118d139332455891dd93d3716968a408e3224a885ec97a5aa12f5c9907029c9181dc352c592194362f897ceeba48a21497f59baac964d9d6463181de40843b2661999c2e51473b9074352dc5162bafad293e97c21e147275921542d335d2f24c71432eba5a07525c35d4812c25f4c93de20aea45c5873ee1819bb4f69f95b48964f4134f4e47567500bc931c7b855e24e4e8eb29094f762ec2e3367b3100b4942fe25f92a7f57dabb42626f87288b967332655648b4124d317a5c1321e22a181592b3b6659222d3b226cbc80d724cc1a073296d25fa2c972785e4dacd0edda62e6f2d67e4884262fcb5128bbb0bddb6970185049d82b6b990c12724c81f69bba24d98f6de094979ef2fc7189ff46eba09494a53e3786dce1f221392e42931aa328597f4e012924e5cef5a89c878ba2821d9f3a554ef996b20471212359aa67788cbc8ee909038b2cfd297bed0e89919418e9054d262c3a891119253f6fd24467aa6b57c1152d263ac1462d66522aced769e9f1ac2ee625659c94c5bce84e0fa5f6afb0f5959100e2ab4ac72aabfbc66c80184a4d5de3291715d3dc63f4850273fe5b82573176a0e1f30e252b693b9336e8e1e048e32a82470251351200e07c38030000c088488b5be01831308001834260d0663e19058e0f6001480054c382c4a3e2e1c281a12160b05e27128180c0402e2501010080283a06020148a4372a8e47dfb5b30c11637330b5815fb1cdc64b018861757ba7ad042a046c3fbac9e7b2c3ece4335bda879f05fb5b36a9b66b787eceb173e5f51ea627556602e20121790b184fad96e401a28dede294435cd3bc0182675f0ccf7a9bc2efd1007f02e47421660e59886a0fcfaf72bb925a450e063a1749823642402bd5a60fc92896305af9546c0c9fb63912116a97d23a95df3c9ee2a5c511d318955bd7014d91b9d85e415e873a89270f29694c43d97f19b31a877baefcb4931da2c1eab3cf54f0d00fec0a490487d1de573439e5e45746c69a3eb7670faa15dd0fd2f272a4a3512cfdf65acf24dfc859022e7bc03f28a7d9c207245f76fc254dfc1648425a4b36adf33e95f1801c386e903ef7c5ca953edc5736e0365c963cc0f240a40272b94a5afc8d93f3173bc6a728eeea35a4e6acc36193ff4369e15d62937646725f0ec135c72ed2b01a04d39bb705d7f5446e18d09d6b027499f97a4d2fa260781c19b848aea39dde297482a1c432adc8014a12dd142afff157dc03fe787d3f743856a0f85a13a8a59680bf0b70c71698490aa379abe7c9daa32b85c1ab67f41c5322b8d18918f934250ea9c222dadfc9c1a67aa05dd709704d8e54fe3c821d23ac734b09b14c910335ac88ba4ced5fa4ae5faef03401282b1afd57333abb84bb2e159a8286ef9c8faf52c6d518029fdee54f07332aa2d5359f63f8b9f20a265ed28044a44c1d62480cf793e5661320052f70bbc91856b66ec9b1aee513bcfe9ff81fa8b171d910f45573832b544249bc16e6b8621ff7d19a5ff124cc3308897c7c51e49f2f58f6413b98d6825fce934633ff675dbe4ec31006ef8f00bbd174c07eeb848790a1e6100257f7f0eca80b4b45f832e14f04de55763108cf1db40eafcaa1473e6522a4f71ace24985b062eac650469ed3f2a9cd0b2f29b13e544f3be1c0195657f6205f09b48af529144e24c2bae2ee81fe89e0af2b2480f79c83ec56dac7e28c93ef7f71895c353fa253ca99f273ddaf37e46f94c40ad9c901357ea51f04036b185c63110840cefdbfa7585c1e101bff0887cb1720c5318021cef12026c339ae461e72bd46ad5afc06078513720c55986fc2bb5d52a34360c34cec2e00509363213720ae8e1c4c6581a9a237e4c53a5625af7080ffc64e915c2d7819f1febf2ba5ca3bfe5ce554381865baff61d828287e2c4bf386339791054c4c23386c6420509f0ca75809bc758e5773c442a0b160bd3d78a206f2036d854bf7891aac98e160a106260b91d6e2b3498028ac5f3973db23ec6bb098d307173e858b3890e1237c949a52b89c2bbc936d7ba082966025d077a9ad499fd95ed0d96f870e868c86a86915695ce58cbc5c232efc67496153317518616bc1bc8776c7d9e2b6452495afad916f0bbb8ca3d7db408eb700ed38474c5b440a3e371d45eedc41b263ca22e0a2c880b7335c1a456767e1d4829223879eaf9f3252e5bc7279ab1b32213f6f4d58b9a28446dec492d6c2959d8515aee8bf6c4a76c110395d51b7d5302c56c622982813380c98f0fef60a9cad42cbf2594ecffd9d3a7e7da44b454561e304a6e7db2fd85f8494a26e88620a30af4e016976127649a529114eb2e29c707173c14ab96506e9fdb06212e55a6dfe70560b88ea180e0c22a2b888bcf99927c88522e42f598f902063c00bad93b02332519a9519cf780582455eec801d250fdc5e3703b162e9c82b5652ff4deba956ebe436b1ded8777411a247aaf769facc2a42aa664982954e5e18be80b1fa72aa3dd7b522359e317a50748027c8562b900e26cf94c5dfd7aab807464772afb489292c6c1444c821445cc4ab4972157eb5d185f3b1350e61fb71e2ad9c421a412021ddc2b66d874a5e93a85fd82f70bdf2d95bef0b16941c10a8c41e099c831a5cfba358e932dbade27ce930a9525d553f2897ae3adbb76e756477960e35f45fd0f4041aea164178c299efe8b42761528eabbb686340d380a6842802fccbcb55ba24514ed839ca3728407955ffcca70cca5ccb7442f846d0cd3e9668e4bd9e62b2a7ee16364f39d739f8309842f8ea6e472f33b42e5522cb1245406c1acb8a8944a93daf4707aebb5a0a7b5b3164b99f0b1faac75193f58e0327234a3de0f007aa5c4ca725483c26a9c5acb82fc2e5cbf95452fb7c791d96cd67fe8a71c4a4cc55155612f0298dbf65c53522cf3f02d99bf34375bccf30063dd300c4ed6b44b3b2e715417e4271aa31a0d374ab6736813a54214b6e4185973bb682a8c6fc8aa7141cd743be40b7deea4b20f1de1301ef21993ddbc579268a0501898740e09e62cdd06e8682d35bfd386d404e995ae8799cc43347513e660b2c0ef4b036e36befaacfcc01e93fee6c70c37d80f049f98b6dda7a06583e31463e00006de35203698ae37c7ae6c98e55b449082152289918a213eb8a0851d29930859ba738758eb030db07f475295fa7a39fbe8cd8e80a267460ce37bd5930ceb897f135461764f432e3ec0108b56e6d6989a78786542dd34c7f78a918647e9c5dfff37d752c3df56c95cfc3fab36ee1f1d13b37813a461541ff64f3a8efa84a919db548a95f1a724b90d0f12b4262a4bbadb405f939a811c16223aea13d480f0e42b8b9ab42411450160f221093bb027a45e484a22da07f524a08864426cf45d36c93ee49f33efe511ea48c7c1a180463d825749ec8139e3d00e6dc1843a75c67267369ae793ae36532af9eda91e1c7217d663aa2f8df6916747b61a7980e1a19b4ae3e8d01f7c9d064e153b981897e1bfa53089088c1ede82c31d30491095b24ab50cb78e44a12b42df2a9b476f00cdce0034614f425f385890d198a37d1e0242d24658815605aacdbd878480e68cc502cac84a961152e519dacf7c276a0c71120fe92d8e3b48362209c8028af85c2a23c3612aa36a63e8b51af40cf830d0db4844beff43035867b8644dcfdc79360246fc571134a5f9116be8069941e5708330589933d4275ce66eea30c6be96df40657dad5b59b8f833d75e7f5e05ff70887efc13694a84086093bec5e48592187529e5acbea9af015a0b4091c8b4c4542cac29c1c30044c1bb61a818375eee204c3805acfd95b3da64f3f2f72d94afb7f7d247b01f20740bb8a0aec2f2417e0bf0030e4166029b5d5d233ecbeca918a72ae0c0905dd6e574751073b45310227c85aad8d112e9bfda9cd3aa3d51c3bfd694f3a97469a490069ce49f8391708505c6f523accbc13a56315f8ec0c09f452c019b11651202087093b4713bc9bd28b4eb1db1048086d221b21d0a0090250e67ed8efc648f7cc5065c0a7b68113c5e4d0845164230a6b62cc17cc106e48ec849dbb13e2601920d198cd10cdd90afca4f2df86008e3f68c6660ba88a15481980b2be829250795db6eac188347800001dabe6608f8b57b801c47e798cc195a245613e858461fce8b0b8ce8f5696e5b268d69f86ff3ec4303cbbe43045c91d7f2fccc4f202988dd62301f60730b9938f2eee52787f2f4f6d6d39c605cae5f1ad60390166d8e6004a37689f4871a8c16182d7ffa35376a0f2a829b0480b2d267ce758c5e69d37ed8e67861b0683f8ea207465d8eda9e35bf40ae3914882a3f1d0e0016811f270d63aa530c5818d958cba4ed7fd06961110f10267a2827129fe27bec55df7580fd2ac412736e3f60d6cfdcb854f82a91084262c090c54185e5c473617325c9af8108b1c43e4fa780ed82ada575f69e30beec371822170c2a205d8d15fe4741e4630c717bd6955de3e5a74434f49a3dad065b1dc219ed6d0de229a4421d7942ac0932e7f10f42f8734cbfde5a056a466413f26a6911f1021dd7c947c40b72c96addd8c95bbd7356dec95a6d0e6651c3683ddcb271fd2231d35efc50ee0555f3f71b949af762021c3dd20b4e52a801e0ec9a112b101e651240275cda888325e8b7dc304ee0326eacd4bc0335beae5386d8daca84521cc7c25c3b21ea5eeced3d40ab86082646ddf2e1008d1be8cb40d0d01a0e929d4e393863095ff920da8465e300b1f67815cf542acdf96c4612b1afb2e645059a8dde01e21c8e20e912f48ce1c1d25605df2b0014f073ccea84df50b60f52cbbdf8fba49c74217bc476f54d0c60aabf8e70e88ef147cfadecb07f376e454bd8b3b686e5485cafda1f117403aa66dcafb4aaae62f2c53ad89aa621fb1c6dbaee91bfb82b396121e41d7ac7a9600efe239504502c6812fb1ec54442d670a83bc1b385f70799a43a8b20e7001811f4334417a5560bb72246f4437502f3f25aa82517a6795f17ecf4c2db3fabc384de7ff65ef1043bdbec3f29cac5fbc2ec2176f2e265e22c68bf280f7c86e4f81bf97ab288188ece0072b80e4db532b4029690787f8e5ccb7d52aff45feea9ffb0d2ed85a40e31ca5d23c9cba4e86bbbf03dcb18cbf435d293be2b0e3cd99d873074ae5c5849820f01b69e8251c6333327809158d6c59399fe45b0c419d0f49bac98cf7e5b10cc0fe572f39c9f3740ef18926235548244a396a8ecc23bf49624aeaa41f032aab67bb753c79c216144d62548b0bc66d9af91c820180f1d98539dffca0059c8a2d0b1f67de1a67822e2f098881973ddfd37afd1e157bc01c02ec296a8a3a714513dbf54b3ff53c235a0377f3678890fc2c26ac8da07d2836753a7a6eccbbaeb297b6926001e76ad0f808489501c62d8116f6ee1d0d79f2647af400df4db2e01b847940fb41078313d8777550a09e243069abfc015597d59b5adbe4fb4cc000f21bff925d392d3c3954270b547d032dda3e318f380178f93ca180df3c79382b09d8e830800256f92249f465d4b216fa91acd4051000814a86a7c90ab379fb11f5d084f933ab7bd5d2d8e742d703ac9b890fb9889e602a55770919f13521c1bbfdfbc7062c6b8af4d5d282a89ba047efc252a42fa3d510bf00b82ba903c035ad9998f069c94c2019fabb0d3ee812e8e89fde5e51f7402feb0729d45e2df49488ee6f7a142c39ef66314d8d7691a4846184100d8f1e4ecf4d670f8f318227335b011918000a656efa31840d9f9f88083d17023482600362911e31d2d9583444b0237ecac3272e27c83ae7ae08bad14916bd68b842c500ccb90ab0f4425dc7182e6d247ec53a1bd0ab9722b4679e74dd10e182f46a7e0620c5ae28d492b4d77066b1db8dc87800188e0600d17c66df80268bffbe41655ffbac42bff2cf5acbb8e4957a1a14e444a13d71ec09c81098b3b28f42e63ef9978e8943ad945ddc30ebb0973b10ad6215309f47501b980f00d8e0c0b27de3751ae37bce6ee115f7601e8a9c07fdaea49f9f27072f908908b38cd03a150160d1dc49dc0153431b1125161591313dd4e025b0155e91f56c775aa125293ff6000bcfe0baa3f42c05837a07196038691208b58381453a3537cdc8e7565b18113890690436962b9709c78585751b1c130c1ca08183202e124dcbf8f40af35af85b415713465f34f62efa3e9a224d262d81018b15813a74c377ee0e0f47cf19b84d16e6c2b0e698f22e9f316169f743212c1a53d8db36b274e272578190d5901fda404f81ad44a2a0d2e40245bfbc5451b2576166562a2a56ddd7da5584f759ef12c30b5add7f75eda65bafe538297f04a16083c89c9e5253945689947c84512324d8cb1f9493f0544806562eb29d12833cf21d4db4494f4a0e1c099cc1309e73f7b2f60ceb9f2311cc2bb147fc694b892a50af635a0e433e21a0a303ad61411cce290b3ac84d795f190e8bf404eaf4607662e4b359aef1c004ee32e5b4318b59eb9486b4d377d2005e33cac584a9c774889257551a4956282ffb0c8850c8c8df087370c53802f99791ccc06546390a69c833909c940a30d1827c94c274206bcd52edc5f035048d4f63e03862e9f7dff7e195ad869e81c3122a835cc5a4a10a784650b274f925e3f92e426d08677be27c89588c7e8d48c0648b30d48c6f58b471910d8844c5d79373ac760d6e71b59e2bc9a115510c764443ed942ce7e381424038d771c197f5642eb3f3c6b7f326c1b490751b1ca44b9b986b085eb5860b24fd364781cc48bcaf02868bfd2bd2cc56a02c818f10c808aa4b3890f00b9515a0480bd09f4046cf87f12daa2006ac80743f5dd6801b57027cefb66b7a675e75f7e00fe06c5dfafef581dacf251c5ccfaeab4bfc906ac95ad5e2ec402387a3b0bbde6137e0b065a896e068323be71b16eb43806c0e0d05512b36259e9082c71416ad704978436bc40a034d663324b667d11858c84b5833f786a7b34fc1d6f72110d514188d1fe7cf916fb47c25b47feedb1939a679fa34ac1778ea42f911631c3b9c103d3a5c2204bcb8eac9e104eff588583548e20fddc1c97d3ce2e4497f695042a20bf94b91561a0ea01d5f478e18c5e2a96d062d89defbb03261548ce104a0dcf77338ffc03e38bd91ff8d514886eac5fb53ffdb1ae1888e8d182e7b2cac33d39c310be6553d8e74879d94d6f6d8d2e15bb2561bc63b48423b3a5cd5913b5fd2aa4838458ee17f9dee4850de11fbbc1f876925ee287c4f22c789afb808d325c491ff49beaa865cc2cd87307b74aa0476416eac8b78cdd444e6841a4656a3ad224d1711a6824286a71896719e46997c7d6ae850b9872d3a62f27686700307b8350c9935168f07c5ffdd1d14cd7f48a64845c5efee90f284d43b5e3028d1974182862fb0513ae29fccb0d2bed0ea8b2b37443d838c0d8d94e8e83002f3231ba937216f6b2bd18b7638ebae5a18e43697ab712c5e422f6eb077059190b0618e2eb2073f1a0d6ca975726161889fe7f902413999e7f5676f370e16e011817f408f31dcc6688625eefa2ef82364515018d60c6aab2f1db03a09063bfb38b0e2dabcc87213260ddcd7718a56550a59696ae582c83a41168360fe6de2e7939e8d25d96810e36802142cb9038782961740db9320e7800c82bdd334ef96f12717631ed60c2b11cc76abc5ff7aefcb38103783c7128784be1daede0dd87d72b0949d59141e204cbb658b2552264e270424763b8e9512b943abe67a1d6efded5c95821a7a9017c7d80a298cecd01882e72e57b5c22b4ee39382905a9bb74cd1fe895be751d4e4d721aaf9341e5adfd61aae0672f52419ab1c0411a65c3761770d8c315d9f54ae4e077581707d32c38b406dc031cb38515e6267f994f8748487f12ed83a2b898c39adefb6e3d9dc92296d5d8fcd4d63cf7445e56f541f831c01f2c322d762d2501d1a21cd21a563cd261418e34f2cc90bab5a47820f7187c02a42b676048c68106840e9d3aaec24ef4f43e4901344f49616e8c72057ee92cc32421b920214ab49b6e7481ca438c2bb0e53e2205c288a4119699ff8a575a7b75984f1a5edf65a6a875022612e79963d866543b61795a4639a5212ddeae23a7236689925481cc65927c5c65ffc6209263257ca0e46f5c44feb6dc605d808af9adbc5f6ad02199b84ee5f9d9ce56feaa00124d3c3672d9004fce365214dc094053b4a2538151877aa0e420251ce60ed0149b0341aad326312cbede0dbd2b621a93079d090ae77c45398ba84dd548d487e1f7014649006c87d2b1064c357c74e52a7e9b41b397d9753c3200ed824a3c51d336c4bd3d51f9200933c7383194344d70599914ac6ebe280305c70b353d1ec2520f44f00cfde183dd3de2983eed47959be66dc191a7eb10dfd2b0d82fc622c3ca19edddb31edfdfc8a18ca87d5f6d2aac303929ea8f847a120320c2bdd2b4e011ba89b7629aa3b1d2ae143c0e2332178d134ab06e080b6076a7e1567e2b3885939724706b2b3cd2d5dc8abab483706c620f9214d5710505dd4d881bb1bd6db70000ffc69a50f4cd8441a8a64e8622314b70ba8e4ba14b5430c597b00264921357990a02eba055e6bd219f0187037e3a6925834492def0b2de6e70f5f6ea06e4eb425938f5ef597dfa6dfce0b4e9926dc045da87adbbd543fae8a52199858e04c7203f76c93e660e7106f2143adcab7f72e0a615ee5e2fcf347bfe2b7f59f1089445c793e984e9a95120b38d61d59f6040c1047fa825c06f730e5ba66b934dcfa77349617dd9286a6d22941bc6352174a8f68a2c4fff189ebfe6c6435134f4dac67d124401f0c6cda7ca35dbe8318068466ae8dddb68027907d1a2f30da11bf91ae68820623a0fffe0e77a4434473a2017094c42f9e33447fbb4cb661aac97ccd9ace7e9c3434dc43d4576518942c4ecc8ca4fe380338b9af041ffccd8926110ce3298bd3383c7b2a0c148b0ea34481fc970219500f220782f4b6a31768f40797405d7089a20397c4aa03815b12fa4516490f637f22ed65b39587bd931466785b4d4d9be47cd7cfe241ca5144cdaa2810bab6d445c0bffa700fcdb0f8ed26a2c57fdbad585c49ed43df753cb13e8e8bb92d43506240ca128c21eaf3b44ae2297f397c49afd4c432fc9ed904bd367ff797f8cd605713d0d1f07c81c259ba9307014053298288baa2b4515bae43a7794a9d41d9a8c3d57dc4ef008a5bc70d28e3e97a7a734459c60aa61bfee77c6ca1c4b99a80c0a737b6d863c755c53840495c70684a25b751922d29ebcd03249f754f8aecbc95f888f4c74600da1dac7e48bae64046b12f331d03177616e83f0b776c57547ea60b5d4c67e958042275e862e87d71ffe1a8d251a323152b15bb2aa75a37d603833fa0ec455e416d016e20e9e2dbcbf4e2852c8be67d8d435824985595d499ca0de668efd13e0305158fe1fad660876b18f6a33c8caefd4180829093089c58d52b0b4b66d4be9f56aaa79a71424092073b7a4edab542ddcfac37e6211b94177cac36b92d8f386ff56afa645f8168590b233bcca52a6884dd7168456d75220bd6ad03b3a6802e337216b1304029048d0a967410c8d458aa0d95e291428ba5a771fb595cdde8c3cafc461e67255cd9297bc5a1c3ebef2499991ce6b47ad1d7abc64d6a03ab0d3990903aa5476d55a3dbec1e60ca7f5de9ab61a3b71354d3a4db8f2e7af25192ae70c9366c5324f94c2a1afe2bc865926321499fe97d01c8248be998fa9e2f198d7074224badf231fcfc8964e0f1f2255d4af37452da4308e4f431e4dfb360fe73f39bc8dc9266f26e4932370ad146d83e6d3ac9a032ae24c37f5f7c346420d6fc673d09952496e40a56b4c6f7de4d0d47b991d6a6a0470ebcb2a588d49dc49a197b83beff3622c2c59f50a9c55b644645a8d6cbd661d2ed1f450b53b5a1f6d0f468e45365af16bb320a4e1f94ef310a2bf19d9c7e553d3a38ea1d4d7ef4c4bb4570c61ead4c1ade6b782a03469f07f52392652fea23a15891f1113abc958fd9db599f9754e3938ae789c91c3ebef58a5cdb1d176d19e359ff887af67def7f47d2104aa6bc0f2a00ff17a065536ba064288a8b33e48c3ea8604ba8a668251cd5519e8873b352db59a022f07b5480a8873b92e8384ed46fc1146f5aea1fa2db3ceb8e1b31b030f0f0c1c47482ad329f745ff63b0bbfdbe4f3bcf6213153e266cd73276969b8fc8a601b542e623e623e62f211b5f347a9494e9ef2362a7dc0ca27f50163e039c059046788cc01390ba0631eb095cdc63ff37730d0a78eaa54c78f0d58baf42371233a13356a932bbedaa80da4e1406f6ca3e5051ef969c764168d13b085590693b35f5af07f5a0ed429917df49a6f0387cdf4df386b4e56712290cd0c022f0313d2c467414d8b76ba6094bcb4d7c7c6779a314d4dc515a1bc8707ba55aef9a60b065d2746af6c91019da166bfbed684b302b894d00adad22537263265a41f1ef00889256702d0bb6928b6c7f439649ab54a2af850017c2392ba045288cca32fcb9dce1823e751a97c563d004c7908fafaa529c08b44aafa2bd44d694e9924b146b0ba59ad5990ab9a1e15768e505747d598ba0fc85ea6c41543ba69c808af6720b9644e3b7f8014e2bcccf02df6b4e4b2a6c2ceedb96000f817d546c09ef568eebdbdd0880e8de867a4d4e8b5cbd203141d58ba61bec705f328a286da93295bdb817e87c76a0f24ee9fdcf1c180f5b37b7a6111ac9e7472e4be6477156b9fefd2334878133d21dee73eb44e0fcf0dac181fc311ec880a279ccf37ec1e608e546868d042f19449cfad2529ad1490284b71b5b00f31049c8aeecf8a1e9d55205495f3c79168d5ed2015e0f75a3dbb2eb43f6a9f8795f5d8ac7796d44082fcea6b65ea6ce06a02fb4a9f369e8782a289f948c738ae35a50aafaeaa078ef50513efadd467b59ea63f4e9b966ba7525b23dc354a2ea3262a1aa82b7f4fa25351581df30a050266433fe499f91e0412c91ca1582988ac5172ac3e648256eacc940627b28b768e7a07ddfc6b17eb7b3a8d0baf55c91211c03e1b0cbdc261513bcf290c551618db453247b9c7090217f2101b41b9ef4a6754b8e525767074be4de3b304f410c1ef85d3d7f70d474a450516c66385e8a9c417cbb8efbe4f5fe96f24260b025cf2747a89b3071f226d5e496593697490ce161ed4ff08d47c2a5e05b7a7ea105734b607703648c982ae42146f58935ec93190302bc222428e3aa937944d711061556c2ccb4b2e1804cbb2a4e6fef022aafe323161204c173b9af5c0215ba272681caf2bcde3eda0cd9a3c8ad6617aac76ec95920d0dcd6970ab59b57011ecb8f3ce1af2235f142e815a3ab0e06c494915dfeadc948b8176fa7f348b7e43f7c3e3acca7e9d123e7a307927f709959f7602bac45db13d83061e3919d33923dfdeb443ea005ef30d38163c7ef10bac65627005259543fb2f7fc3bb7843c9923e410079d2610f113d2d22e1ef1b083038478241c564e3064decb7699e2defa303c2242bcb47e0fbaab3e2c08fa5c152890ef538020003140f5138ac5e1da2c89b71552b3f73bbd50e4b540119492e625a8f84f2791962f482d0f62003e5f844509b81097c75278aa18c84f3c36442206e2d1023b495d90a8ffd56a486146743ee8614e3d65c2431d5ce7b10c899bc0b0662e5499ecd7dfb76c0878886b782e83cfb0646a2c554a34b491265cd9d80f76f1b0da1441647c108a110cadbe071e7370497bc73202848fd4f3ee8c453c41704d88d9f8e411da2452f2caf91a7b44f54a157607ac53b84e5f4c46a7b83f9bc7566fca50db7867a1d222d1500a8f2376e1000b63cea646abdf305d14aaad9e829dcca0a5bc9284e4225953de93660b82344d2867a598d4213d94a003bb556405611784b4735f6023a1a0c1d1b0a7954e8c02f854fbf3d7198acc3a518341298ba6197c66867f2ac6e0c55915091cc870e0346ad7d548d8b1898b77c3f31796702d84f4833296003fe5d1e923d260caac6e1403d5fab06807024428841298475ca24c0ad3e62cc025aaa14f1019652124be00890275084dc056088995ca52139540bfbeb536452ab661429089569e9cc01a58dda2567672870c50f84fe6a1de1da11802edbaba82a973e923d1afd2d51c9662ed701327b3c3014e1440ac83eea644261a451937080b531e2f351a13d3b8b504775cfc9553abeecee931100a8620f4a97f509f88c2955cb33b5362c539023defdb331e8a2a216806536cbacf7c46a99553ec2dad3c52421cf69465e1444c80f5b0fad439c816440d00a7431215b429b7861096f9f4e151d2335f3795cf4d83d875839c0b8a65e616dc5c3cda616e45f0010b2e02a30b0c1f460b6330a75b445a94349a501390338ec2f3750b8bf3b01217ba3a445257cb818141d3d3426d6b39ce37737ec7600c88e5da7a2a74a9442305199be1751d4e6d3a8c3def453f7a94f0218f6e4990983dd7768a5a53ee63fb7bee12ee8a53ae4d4a3939500d2bcdea7bdeed47a5f1830939a157106383c58d26d5e1bd497b8b7514c0f6151054f14b83b39fc3f781ba28c1c599d97ffcbc1b05245aa3b93aaa80b186645513a30f741c370ab9e57523577433a207f73a1868c92b846b61f0dca036d9c861d4804e7d355b79e0879e1cd8f23556bfd07245273b80f9705cdc3a57c91c4d6b4284cd71dbe1d93d3f0d8818580f6ee3b8a21a5242beebab71bcf71b3e5a5f8bda8afe6ad80b3dc23caf8f8f2811e6fb1cebf6bdcb98fce8a79278edb47f9302808bc03764257c4a5cc941685c45519619e1f02b4bf710b877e42070b365cabad21a86d7369511e1302da76f1320e77218cd0f1eac489c8e18287bf92cd384c546986b954d3badbbec17f40dde31073465d525cbc2a19b57d438909199bc826b7d5513203dc64b55ebfd1c5b27c7a2b22dc536484c79487ee804e1645137a65fd896e636fa250d8866d0b5b2c1fc6bb5f323a3c3a0f42a25d5b49437e88af2f157ea2cd72f2b79cfb2d9b23a55e5fb1e8dec0f32fed75910072ac8bed850bd8a23dcf4bb6a11cb84192ddf33cd9d1a16a1f558d58f766668fa751c5d34d2971a01ad41950419d874d3853934fe10379651094e890a318a0ed92f33084ed2daa530e12846930c5dacced6b12e0e34abbd64e6419e23eac6e4c8cc96b8ab8a24bdbc0244d0961b1e8ead168ea512a932fc4697f45e6e9ea8852141ba0075e98dde5bbc0609608f83eee107951b4a099c4744b87c90bd426ee4a195c221afa86822f219b9e9e407f40bfd3bf782b6d652fe30b7271a4bd52f2d6bf6aeae9005c8b9725d8975818e72e1e862ce39da34b1d65b8a4f47ecd1708127fa01a537d369ec41fb8e1d343764b839cbbcec0aaf767733fe278456449e5303d8f98d69f7e9b240057ce7e4e37421d8938e76d051bc98d3a2c60702f6380b22dd069225acee50c1b26d1a8d9a29d8badb49845edcf148ea4f8d3f1320b929c307094826f4737d11f46e6d6d16e5117470ea3b0bb1617440522f391bd43c594e46c75c3b741a132f30536616d9031ba66f95e86cc0fd04e688e4cbc4f9ee00d8982ea60010059ab716020b89cce46e32fd1de6372fbe84cd125beb05b2890a5c151952a74911e226a941371ab7a571fa51e916d9797df48038408d7895bb479b789b2177c8ac3adee7d05318818fdd446a98d4f797ceb001754ae83e056312e9c7e97aa2dd7796bd78ce308695554b3ba77a2fad57b18d7c84b2e04d551c33f12eb8c83e48ce8b47a7c9539cc67c1adca8ff6b599de21debd208fac40e0f3d857fdc822d4ecc07af9efaa2116d0814c0f4cb435ce5ef223d55c49c24d6e56d4cf91b3071f7b72d020d1f7d4e53915d2d2408afaa9b7a0480cace484c58fd52028b7cbaede128a3bd16a5cf8e97f0503d1581fbe8670ea07407fcd6d2b23e6267fd6768adab5ff4eb760c8a400c8751cc88b008d83a3040a5c2d29239d10a75c07e1903cd55ab179028773340b5c38b4b87b5140a4e21e967695e5d3ab713c574009db2c45f9995097ac968cd9ddde82769b31ed3628cb9b4eec4b5d615367822c7162799da78c249c4759cd6480c3e4bd3b468cfb46eed0462890d1245d942b205f65c3546a8500cd9471e194223c6e00926e35634614af0ade33417bbc72e90e5df708f79f4f950263ba64906a803ca2d0c044a6901425b498ada950af1ba23696d821a2375f600a391492903677f9b4b4a1e81f8cf6efc2b3c5c9d417d319c9aa663a5b05d45216055be9401c1d7e643118e9c08a0e2eb6c4baadbc41cfe05f378d6ab0f65bfae75297286bf48a766f2aa432e4e004f6b6722425e6047f56e08d81b604e64aa0e15282c2958d6ab86b3df50858e222a68febae14f9a0396d1fd4be46d468d09b40c7630408ad22c19b1e2f44cf7a80d29ab8018820f69147eef8453efe3dda459065071a6b1c39622e8aba59bac376108c7a76e174c89f60ac906515f19663f08b98f8116c39db9759c44e18b1ddbf74b7d1bf682f1cb9c63f7c0f942b13b106469214d12109b6daa6a325dfd52dd310223cb14ea45c9cc9805a469a1ea70288d8d78c0bb13a9c8eadc9066519361863b7de910d37f02b6d702abe43465385a8f2c0c03ec8069d9efa307c9449543c13218b2533f7cfbcb2a377f97eb1dffeac203d525d6bce105f9770efb3eb12849109592915ed0c0e71c41691c78086c4935fc92dd528a018c8dd8a16d01e05b9dfa0303bdf05c6de85e5edf64c91b6470f8d94e47662bc203c6e8df95391a9b6903125f6f5cf8e3c2f00aad5cfb466fd8417e831e5b61265640193e4c3496653eb9c05e0b9fe805b1ae07f2c6a962f34f43fd59ff6c7f171641c9a8c4d23e3d038368e4dc6a6f1383c8e8fe326a7c9082f4c48d03ae51639461f240689417a400e92a35706b9063f073f07cd01ca38354e8e82b11d955428034e7d85230e3850b2a4d001c33f3f3f3f3f3f3f3f8b50b66d0bb65910da824c3295f77b48c800b5524a29c99492d073a761b7000000c2d65a23840580386e560e430eef0db6676da5cca4006183e945e828e717456c675080acc1ec6e72cbc54a3a85fdfa13206a30a90e6fc1d62411564ad2600ad53d57a7acc3529813206830d9e959afaf33132eec005b02e40c06f5d25126fe3afa491721d840179500318331ff43fea9c58eb8d08b320e185f40ca60124648b5f477aa11e0bd00840c6617bf4bf1a28e748461653d06e358d0bb4f52ea2d2d370740c4608e9aa1c35b581bf1f3580d8084c11ca654909ddaa963e21de7c1700483e1ef6309cf3a26df5338d6b007205f3007ffec54faedb42f8963cdcca0a901f182f9835877af2fd14304e9823154caf515b3aad08e2ebc300408178c1df6bccbfd4c12ac5b03c8168cef7fa6a9fd96cbf3fa06102d984a74d11f3cbeefeea588e42040b26030531f94d84b2fef130b06a12d4e922efaac29b14b03c8158c79e2f7de5a6405f35bcfcd27f5275bb20a3600a182299eb65928f9925f786720009982413b4f2ed5b2ca262b102998926a3159163f96fc4919e828438ca7c08e1088f138425086184f01111111119028184eac36497f5e57bfb49501040ac612f46228eb2b417c65878e917300c813ccc94b9d78d23dba4c32041be8c208204e309818b1a5d7ba1755006982694d5a951c36dbae752c204c300525a53e5dfe124ca9b33f27a8e8d91e3174886107a20453121eb2fd579420d5840712830c1d13b82c8024c113cb2e4c54eb7712efc1438c1c782048e0c52e59d7678bd75a665676738491030c0e74e10509ba08c106ba40349023183bed495207cbe2b13c4630d87f09fad6cb73be2e82b974e9ed92e24451e91a1440886092525f12b9ed2565131b8249f2925da7d504536b44e100220493e01ef377a3d272091204b395aa5a124a5f04102018c77fc45a763019262e04901f98830aa2e71f96458d8a08203e30c559f1e4957b4ee6640709901e98b3c7845a08f160ba40175e7461812ebc305d78d10505bce02380f0c0e49665c2c6d6203b30c949b8493193f1d0370c203a30baa62953f36b2e8c1f3fa59b32f5254738820c7161921542ee8c9a9c993f8e35345246323232068f09cce06f61b20a66c9e52425f63b0844443e6c619ebd3456dabf1a7cd4c218ab3617c7a46961ce9dabe48c3d414c8a7fccc224a8f168caf7fb9085293ea724f62cab84507dc4c27463398589d71337b30f589846a55a07b7db3f2022e23b3e5e818afda39af2ab1a5a81c153c07f04769de3c31506d9dede33f2d30ae3fa27ab9ca197275a58612af33dd1924ad6927315c651ff0baabc947bfe4315fb918a0bc1072af2b47893baf554cc71ac88081860bc6f3985f13dca899ea4c81406cb495c55d8ac56eaa530964af1d35f9d90c268e2d37c08f18cc2a0652e262c498bc21c7746e8caa97f27bda130453337e94c1a51aa2d288c35d6c9c3d3d394ac9f30c9766366abaa27cc734a4b3cd98fa7bcd2095309756f97a3e8af1739611c37e5f22944f667f5b10993d2d1ca611ec1c1838c31ca78b4268c239f2db7a5cd84d9f349b94488131326cf925fa2d97d12b92e6172ef5c1745cbefe2690993526ea7c3b89f94f657c2b02689e8ecfcd8fd286152e92cbe33e499ef098e7db330bc045f10f8988459636546fc4d340a1f92309d852c559a9ed2848f481845c517fdfb4cd51289f00109730c115dcfc5e038f0f108835fd015659da4493e7f38c268e7a604b136a6a7a47c34c29cde4294a043d6afa800f1c10883faa8a07e4e7c0ff3da1f3e166152622b85a51c2fbc8e1f8a3095a79cf5c46c9e8712da88d5e12311e62e0b272bdc8bda0b9330c8f8e20311e66dd36372380f42299df37108b34593e4b0d19e3aeb640d1f8630fedceb09e2728e7b298968f82884490a3f53a27ac4578f67f82084794cfe9fd3b2272fc5ce0b1f8330b87cb433d9baf02108a3fb87a74e75e9849304c78a408c0e9c3506c25c164c8b29f9d6fa791e1f8030a79d894952e76757f33efe50eb6ac5d6f93a921839b28b1058a00b09a899995959f36a164cfce2042302e8c1871f0c6a9472f10fca8f3e98087ff0c1443ef670a6874c0c4b724ae2c944a804e0071f79b80c7ce0c1205a4f8f92e40ed5967b1ec57cdcc1a4d653883c39a950a9c2b1865650f061079394f44513d1958298201c6b6544f8a883498cb9495d26753dfca0833995fcb49f64b93ed90b7cccc11cbf5ea1b22e849e11c71afa2ebce8c27b78293ee4604e6f4fb2aed85fa717c7be7b60035d78d1050f11912ebcf0428c1c0787172222950398c2471c4c72166d216d4e48b345f00107e37e49f14e927369794cc8e051cc031f6f3025e1939d906ac1b13652c68e1ef7c5871b4c2725fbf0a7e338d66030a2a3471b4c9d4f9b6cf9a757a2c2b1f63bca36f0c106e3a57977969e4a27d7153ed660ee73df92cd8356b7560d26ef1827aedaffa1240d06e1e9a293d68a9fcc42850f3498dd3346bb44d6bf25394379e2f88e28a184d70e1f6630be8773bbaaaf242c49198c59d944c7719125bea7860f3298abb265d12dc26275b0041f6330874aa79e1eb24e84d9810f31183cf674274166bb848f3018456f67e7529524259bb0123ec0603041589724f47592f4f505b3a8f59342ebf66edc820f2f9864fb4b6a2688e80ae947178ced49448e7aeaeacbe358e3516e061f5cb88f2d18f4847f0f26b6b3ccf13d74887117830f2d986d2fc74b2657dfe794051f593089ce978a9652b8f160c1a49f4ef21711d65b5270ac9d5dc124eeefc4855750258a70ac95b9e0c30ae6583d3a6b84e8af98aa601879fbfc71a944ef11154c42ad8b2ae1edd32939533029c1922749b68e14ccfad1c4bb5f9ae4f246c1944eaf899793ee4ab20205e3baeeb4dc2b5dc659344bfade39b4be93568c8fc127123e9e60ae64325694bd580ea3138ca22e2bc7c9fa4137f3a20b8401f423e502a0868f2698d49cf04b7e63b19324490f11111e3d728ce18309e6a0e25b844a5a3d5d8d634d078f4444a4021aa82c7c2cc1b81f54b02b29ac8a526fe14309a6d322a6fa5f725f9a48e12309e6dbcdf6e4b1dbd6939060dc2e0fb99021efc63f8249c8adbc114a76ef958888348f277c18c1dce6f9a747fd08134b78347e14c1609f65a1e3d22f3f5c468f1c7cf8208239866a8c92d3d5d56828878848193d72d4d1e163082625bfa492acd4e2422d049338bb63a5aecb04fd06c1a094146ae4c44eda712e0e3e80605029c6754e4dc9f8f88141fc7fac3749f6991cfee2042318f8f081f14f4d524b92a0e922287cf4c0202a29697259b7d2c6f7830f1e98a45f105925a4f5c9691c6b24e8f11600e36307467bf9ce2ab16f42c9f68b138ca40f1d18cf4411972b9fa79a8a692e8c39737264ba68ad24c6857974d5e7afefccec740bd375bc123effe5c6a21d98618b4a634cbb5e64aedb5e359c510ba3dd79e7e8e023a49c7a062d8ca271173ca8986ca2691606ef0aee25a90d5d9220599862c467a598183195c7c2fc5ff1926687dfa5092cccfb9533dcbcef2d3eaf3049dae693a0739cc8b5ae30cc49777ac209de1ecf5698fa63878f1f4ae98d9e1526257f36d524a982d025ab30c996a37d16ed518561743e693daf3849855361362de5a1629bd2af242a4c043330e314863d93bbba60d2f9a97408334c614e3ac9cc6d0d77352985f9cfe6e477ed143df7a430470fbd9d5739633b5c3d98310af3a8c5754b26adb42b0a63c5897dcfab18d143610e25f6cf7c8c91bf3e280c97e25b2971923277f313a60c4fe3ea57ea42c913863365bb7b82d0ba6e270ceb1eeff5973cc917f20c4e18e49a9b14cbb61ded944d98538a23a24e5e76fa90264c1fd3e7b7e3a7f18e67c29c24c1f2cad99914e629983049bbd0179eec2b2fe912864b520e6516b43e6b640983a753429c10fa299b67831995307eeccf9b992dbf4b29614a714fce1d2d754cd59330872e498fd0a173b82f49c2f8e796467888b0fd58240c6a46c8cdf0689fca04120653954e69b5fcb1d777c6234cfe73b16bf5eac56c9ce108a3a524d2535ed98f091b6110d5a1be742c71267b3298c108538cb03d6b1121968478e880198b3076b4f13c278dd6250d6728c274d2729a3b51e3bcb74418c5a42fa1647523469881086396086982c83951a19a71088399fa5fa86cda3e4962885bc18c4298acf259f59810163484636d0621ccf9b5de4fe8d4660cc2b0f6ebd5e76282684f10e624c80993e59360692ac6e06604c270eac4a7a4c4f0d02903610620cc97b48e1253c993247738d67e6d064644a467fcc16c72a268be8af6b8257e30fee7e5248fd0e983490e3a49dab4b429e11f1fcc67a955d7ad3a65b47b30770ebad5cf249df91e8dc10c3d9873ea92e48d0b5b25863d66e4c1dcbddb5d7a5a4a251319e8f0424444063a76ecc083f93e97d0be6ad9faa26e60c61d0c7a62def3e33b577e9d618773f0943e5a3c657ef2827f1e6633ea604a6f95fbdef39b6c39eb1974308ece2899a63560c61c4c7bfa8366a957339131430ec6929f99ad96add49130ceefe801822f4e300283197130973a9d67e2c92bd1477030a75c876d93fd2d999c196f307cf5ee276157dde72e419e60861b0ceba7d549cea5a7bfd206534949855bd28c91aecd608349dd79f09ce470f9adcc5843921233e67ea5cceb5643299bee389ef2899a0ad3b0999f071df72776c5c10c34e88c33cc30c38c3218b764a8eab59a6c41fbaf808e10a4086690c1a4fd490e3d32941acf8fc1d41b16abbd3ca8f9470c26496665fb1cb3d4877646184cb32e669f46ca8fc7c1602a79a226bf49520e6b7fc1944ae4b745adbef7d00933bc603615e3f3f2243116bd8cc28c2e98f54bb6a4269a124ed533b8603e0f4ae824f49b28eade82398730396bbcce4b526ac1a4b7828df4287adfe62c1844ffa8d4b3b8bda261c164655ba3b47b5ded5dc28c2b18e64b4bd025991ceaa478f038650593e65cfcf5ff23985105937bd5d758480f1a3f150cd23f568a9fef5d93c561c6144c4199924b9efa7b1b1d0e33a460f2384a4a9bedf639c56d98110553f818dac2f89c5c6bcd808249ede3f485ab9c67c61ec38c27985c4fa9eafe94448c8a186638c194c5fd627578dbf9681d6634c1e4395f2698dbc3849ccf152f8f7e7298b104b3b855588f1f943c135282b92fe8f98b575f0428f94eaa3ea952c91026513d9ff09c3f673985309f3463fae6eb945c9d10e64acdbd8ba7b17e1a84399d5c32695f7be56d419804cf3edd9fdad7e281308517557e926c77c70b08a3a9cb9da41369b29bf20f86f54e956a2da74e92f8c1a46bba4fc4d8f7d87d3009f27972f3c35cddc207837d4aeacf6584af8c7b309e1079f62e6be2ae07536aa5894be6c1a0c3559267436a676b34f06096f7173d6b29df529cc61dcca16bab4e47b1243f1a76309a97f89ecb4fa30e06bbb0399d4b39f42969d0c1f8717bd4fa7534e660aeb2ef58728f70ac8988f4f81688888888e85681861ccce92f272b1542b68d270ea61c64ab93b64c030ee62da182b48fa53767a4f106b366659392fa13c4e48ed17083d1c47d3ba91926798a6d305a658df0945f1a6c308985f31273b249630d0679a2e3055d72dcf095861a8c71d9c2de499f461ab2b4a9265a9f26737d514d7a516581061a4c37ca6c762d7b0663c5bc24e531d972b2140d3398b637be3bf7da650ea0510693387f322a5fcdb708d1208339e9126b4c84d29593308d319853559d2428416230a7d4dd965b64857653184ce7e124494e69d4ffee6048bcb0344127517fc16c1b7ea6b73afeda74061a5e30975daaf57e49327725834617cce67633aa6fb222632e982ccb497d55f94d88121e0c686cc1282688b338255bb604f10634b460ce41558979fa932c2266c1e8f6f97ab43b2fc78f05c3eb283979ab8a629e2b984d879277a4e5248a9970ac8101468e17345ac12427e5b0d4d11e0d6854c1a44adfa6bf5a14b58c0715cc594527699671e256740a26dbcb3d71ef9ca468a56050cb0d2fd1b24966d256068d2898d3e8d3a9a273583125d68006140c424982724d53a1ae840a6740e309c64aee697f3f5a97d8e9a0e104f387edf6f04bb993f09a60922227eee97430e1da3c1e349860d44ba2e5a80aa692092fc1248feced951f71ac29c1582765d39b0f2526093b0c1a49309ade9244b5094a2a756901124ca572bd62c557c58fab0b681cc1e8e129c5bb3c514bdbafbd8086114c23d5e489f459b99c1e078ddc0e1a45308713e2df427a9c9c3b3ba04104b37e2569decf56d7771a43e0c25e3d2ba805efaab75799bf74332a7dae280f6808c128aa4d88b8a97049586904c1a8a7a4b974de97d3ab348060d253915d928ed2f881c946743c8b9e9a4a6a1f18458512422eade4e237722601cb008d1e30efb5dbe1c215a0c103d399e888eb18bffd221a3b30557d92b55296ea34260d1d98735d7c1175b15c98acae93246239b4fd850b930a17dc474b505b59bf85d93c5df69ed9cca75c882db80ab577d9d27ab9944d3ca9f4229438c282492d4cdee94c4dc5cb8325a710420b73fa7eb693940c85905998d79430bb24b6b2306cd8874813a790589824d90ef97a2f2caeb1dc9aa2de76ef6aadada2bce436915ed1905798c73bbda9aca23384b8c268bde54195ea1b8b72482b4ca92ae604bb3d8415ad9d88a79b6dd67d6dd649d73cbd0642566150769fb6e65249d16755984f6d564cbf754b135241482a924453963aaf8b9eb4a0e21245d4528b8a27768a2fde8d650a53d0d6b4ab307e495e4b616c53a365495889fed34248714cd9369b3de1582bbaa330cd86a58511e7563acc3966f017d8f132d0b181138549ceee8fef8d550b550422223a763c0dc4d02186884818648811120a838957c90aa3a7567609018539959492cee7d9c72aeb4f98e4e2aec579edec62daf120d8d1030466628cb13b7af0404f98bb45995c79c14b2eb13046c47830d6c6d0e1f9219d30968ee7af6ab324eb9d5e8470c2a0bdc42cf9c363fcef473b745c044236611e69aa4bba7d35611243dc89e6ff2588c997098464c26c8267a8ec8bb330cb4863c2e496de2b174c90a67b311e8c914b0a845cc2689dddf2533a25299d821708b1844912259550ea1f55cf3d38bc12c63451cb84faf2f2748e93d476f4e0410993e81a93a4d39556b384634778e438eb49982b68d1e69f4aef74098e4567470bd2cef677e8f00c8448c29c24d90ec2cfd34db71e3c2261521d9f622739897fde2724cc16efcc84871e1d2a9647984fe8ba9dcffff89fd011a624454b19a17209f7d53d186390d1231b61f094edcad762fa95c48311067de5498915d6ee8323237a8b30c54fbb60964f9950da315024441126b152ca677de3f1f5bd904418664c70b1bf4d7555072a963b7af04044989457d6924ffa94f5a14318e676564eda29c410a620942a8bb3a104a552218530f505f5bbfd59d273871006ffb46ad769dfca93483008d3a853627245ef942567470bfe8c7116c60e1d15e81e6124e410417492ca7f59114bf28a638dcfc818e91146620b8404e22dcb39ff4ffb251c6b45c918791e3bce18c5c220430cfc220410a99bf04f164548f7eb0f261933391751961f4cb152d4eb4b25d9963d9c8c1d3d40d0023292a78019f70823a10342fa60309de344cb132b6f9a468af1c124079d152ca77dee85e878404484c78e6f41c81e4c52af7ac74bb1fda544eb0106193c7e871e8c5f9b7b8229a994f8b004be38c1480942f2d0972e615dc7103c9893fc3d6977266d0d08b943b2f7734ea9dbe4d381103b18d49b926fa92a0525e2111e5c07834eca77941c0da183f9d4087d75f275ae9470aca50242e660bc924fd4aeebfde8500e86f8d2692e5bfee479481ccc3d72b3e43fa1a2e83746183930098183b94e4449d9a1357459de60da30f5d9a47c5e52aa1037183d9e9b20544a3ab6589e438ce3011191fde2042329a40de6b82a95d2c830ddb7078f1136184be893eff298fe134bd0740dc6ec6c71cf4d7d5ff05210a206835ca9b9faa81c747fbe38c1880942d260f4f4b39c434d1244fc1543022222658871f08b138c98103498c34af6d8ef96950f73ec9041f608232120e40c18620653ac183129a9d2ad58421810d98142cac05b57b8f43aad8f8d1bed64c1d4c8984e517b0e3078a0cf31c6e718438757e0035dd88e1e637421840ca6202b8995dd94eefe8f012163300725c749764952fa0f680bc8481e658f30128e11220693f6d2f1faff93b42aa6111d3d46100321613096c9d1f5d8bcd66f878ee41c20040ca6581779b14d271393f405c308e5dd664ae99bbd6052e2f3c5aa5a1284fe74c16dd94d4ff5313f87908efe40081736295c90771f25a4630b499da3bafde45cf727423ab4a049b1cb913f52ab522008c9822947cd4ef6a89139fa1d07070fde102c343a3fbb33ab27f6772208b98249b87addec39a5734f64a0030c300e0e1e6b1a6285ae54955b8e9e945847183a768c611782902a18d6932cfd3615fddc5a8550c1245f7e7b4f498dd2278a63cd3f06233a7aa04dc19c97fc53ca1fc3b136e2397a9c1e3cce2c440a66d5ce4105a1ea4e9e404814fcbc157496655c7a90a1a38c0386884808142cd72c8bad70369edd154369195df5255e8ee1d320078f0b7902488813cc5adfda5f4159c93ec78e1e23650b08698231bd8470eb94e49ce5c2b156831026982adbb7744b1274f2c7c821835246c812cce9d744d129dcfffc83636d87e1134294607e0f2aab9628ea53bce058634248124c6b4abab026e6cb892a210409a635f10493730473c9e3c1eb62049394626ee6a9a49d8e2721a4084693927671d19f6d2c49045369ab1c4f25715f56bd3342c8100c5e6265bfa0c51ecf4308e6bb58e6a684675afeeb88101204c3965c6ad35310a662d743080182714b7adcbb966cdb2623608091e3053f3029c194fc7a99a42dfa3e3079ac689b192797cc0ec79a0e3146eefa8b138c74480fcc3ab7e356a288fd9e6c10c20383c7bcbc17c4b7038334cff494764a29b18510a203c3b6db491de369299d0bd3c7a5a814cee3885d38d64070611a5925d89c708ba33b8e5b18ef6ee7fc4c12748a1a8fe203105b18fc93605ab155dd64c6a316c6d1695afe2ef6e43071acf5e091038cef9103870c467a7c0b6861eabd91f1dc59ee4d3f0b7368cf71d293b230aa957c4a43277913672c4c23fea4511e7b3a3c1e80c0c260529be0e94ac8bda8e800e415a633599674474bd2eb892b0c26c45ecf7f90b2dab6c2349784abf1a042c7c4405861acf34e49475395ee470ab28a035185f15269efa98e1e94ac0e3078ec90c0998b51068fc20090549863a77efb9a4f1f55840a63a998d021f424b1ce013985c93b8eb89bf8f8e12710539884103ae98f2799cecc387664478f314ac70e052905082932712bedb97a54df71ac29c8284cda7375c5cf935b4b9228cc265809627c2e2b769540074261fefc4f1a57957a4d0e020a53102fa2f6a43c66baff8449cc74271952f78469f652c34c8ef0103648278c1644ad728c30f1c40a454038610afbeae2c1b4209b28c78fdd0a3a328068c258714675ca55c984313ebca95241c684e93d9eb5472d41eb209730c927f78a2cabee402c610e4ae75c260715b409a33b904a98720eb293aa5421548477209430665dcb693dfda37d1d4ec2203a2e97bc3815aa7449983ec9933ac32f69af4e248c9d7316b2592a5eb294134020614e52ac3f29499dae217c84f14aab44c595a0ef7b4718ec2459cb62b316449e0248230cebdfa13efdcba7357be4ac00c20873f495af915372ecacdd812cc2f0ed39a724499f57e9bd035184a63652dd46be8930e969e7de561322cc49b0a0e43cb73f997808739f1c3a7f756e3e3a8630ccba976e8f9fe7952d3b7a8c0152087385092aaccacad3fa3b104298e49c274fe94cc92729772083309a14c5db4ef83d49f98c8b00118471bd04115ab505c22467cd89f4be193d933f8000c2245ea94982ad09f778fb00f207838ed61243a55c89ca8e1cc703360b103f184cf46407ed265814a53e9845893b1f4cdb9deadd55f7352c207b30092609224f4aa146e818881e4ca9821e25453e7930d7de9f94dde9cb528907e3c75d11b32d1fc3c63b984a12ded1ee73b585cf0e4637ff244bd4bc852d0d01a40ee6fd8e7f92e42164c9613a984ed949c1c4bb73309a6de559ff93d262052207c3f85ba80c65aab3ad2071306753bacac4e88ecf4938d6e06052b71f4e1a25ed84ac099037982479e729974a8e23103798a40c93d3d327f9244a38968c3698c6f7c4025d49298c5e92b4f6a7561ba4305e272988f08ff9f18a8d51e0ba27fede2b51984fa82c3988ca2626e3e8713c202282a3c7b1110a935431cfe74b440618bf638c651ba0309fe7b8784ba974ff07478fe38182a3c719a394d1e38a8d4f982b892e493ecb86278c95a13f89681f9d7a2f828d4e98f37fc59b4aab8e7b8d8c71c2d80bd8e084498cf214f7d944da48cbe88156c60ee64d983b09a677c207e1581be9c1838c1d233c72b0f10023470f321e604313e695b9cbda2556ac14ca84a9ead2bcc2ab5cf3b6810983f2a4b3e92e173bf162e02e61d29fd3f89c9f58c224ebae9a149772d025ab8431745d48b93d75a67f4a986dc7e3a85392749f3b933028757ea61e2e9a90ab244cf2cde73cc92dfd9a251226555236713b5792eb4a9030f666ea8ece71b9f547184ce8899572d8ec27930d47a8e631676e97c2c5b29c3357322ea693798e8d309bcd99182a4f4698c544dbbd9362c72c676311c6f8af517f3b1539491b8a30d6af4956259deace211b89306f29254fdefdca2b44844907f125c9254b87308fbe88f877dd5242c9109cb7b755acdc8867aa9ae512ed64edea92fe42649e26a90925da11e39146084c2ba75bb070975e5e36fd45c830bff5330dc2682a84e893ca54d23d128449ac1dcbdab1e44cd347caf51023870e0fa8d9888d40184ec977da121e7c2eae35041b8030cf0875418f49133abbae828d3f98bdc7cc6328e1bfa4df56b0e10753b4ecd43986862eb574c1461f4c3aa59c88151372cec30793868cbd0f8f6300edc1b0ff1675e73e7b2c7a30c70ba34b6f437930c7ca75825d875151a4783045b97eff5ce927687b07835d4aa72d9dd2b7faec6030b9354dea4aaa83c9547ad3b26923ae6a3a9844fea3dacd3907d39cde975436928329e8af3775f6353ae7e2b0959bdd58f0d2f0f9d0ea13b327354ce060122d8472fb70798369943e7923649a363d93c1861b8c9efd74e53459a4fdc9461bcc5626be2de7e4613596d96083c1cc7bc5ed242965371b6b30e64965629b9cc3869aa8c1b8ee57278cb2f8f3370dc6109553ff4915d4cdb78106538919ea04cbb9bd3a66e30c26cb2c25feb6554dbe6d9861b1fe932d8379ffa4977a8768a9d82083514f8a1ba5647b13deb63106f38968ebebd777494b0c9657ba4a15adce84b85ec758cf9eda088339b6eea2c5561fdfda06183e1345282df94c36be60ee0ea343e5fc1f76e436bc60f26c7b7ab65f4608a98d2e18ae4be9cd9bc8535ab4c10563a566959cf2ac6c09da82f9cce4b5785af9314b74f0d841861736b450c7a59a4d116d2f910f6560230be6f324f4945905b99e62c14ad7ba6e8bf22aee5a512ef6d3a7bdec25465730a7d4f30a7ab9b5d91d8fd8e1c086158ce921174dbef40d6c54c120fc3494ec698f8bcf0615cafb24a92a8f73136c4cc1586f31f73b093fbfd0166c48c15ce9f77bcb4636a260acd3db4bb93d237d041b50304925766c7d12591ae3130cdafee97f174708d1d97082b9e6e3457b36a975afb3d104d3767507cf498ac8047312dac389d9fda1dbb7b104d3e568b2434cdf24715382495beed265f2565e5b36926038d5aee3a7dd46e9910d24985fdcb254f49344d1d8c6118ca21e3bfcec67c8f8368c608eb2bfdf27df16b0510463a7f4add75f2a69fb88600cd52688b25cf2894ad918026b495c6ec4e552d7547e0f4a1b423068ef0fd9ea211b41309914849233bdd2930a8ed8008241e9e87f0f1edfe36cc0c60f0c627e1e54c59096c432011b3e3057be24e8d5d2ff91131b3d3025492ceb24289f07660b19f59453b664e5367660b46025cd770a7e27ee1bb0a10393a0b355d0a6c49cdc7a2eceb832f11af54eebacd93fc174ddc38531e5f357ccbacab3a41ab7306d293f49baec6c72d66c61ca3989189331792aad8561dc646ffe52ce94125a18c4ed7596124a3eb1eb5918c3f24249c9446561beb51cfc46fc9b074b2c4ce24ef7a7609672c3c2dc71727eccbcf519ed15c6efd03929b58a7a2fb9c2fce1dda2637b5ebeba1558a6ac566e37bb9226a5c5cf41e7c9b2c27c927251395a92146aacc2282a6a3b4a75aeec5e15c6d14eaf1dd33ac7cea5c258525b0e2f17a302b970332e97565b43a4496652874a76965398e43a2d53984f30417d5673bf4f580a83752871428b986de9a430688f1e94bcbf52265b46617aed1c4d4f6e51984fcad151d27ed2fd9650a4556d1b6f6b276b17f4b40932f6bcb5ab041446134bd962c9b7b6757650e313469fd1b9d53244bbee0993af97ef8fd04955a83bc1cdab66da5710cf4e31cbd924f9d7928436e1c30993dc9a32e93b6b688b6dc224bf92b85f982531c9911c270639768c3132f2c50946446a68c26c72f62b49b2d31db723038c9419a89109d3a8929275fcebda5c70acb54007185803130691b21d74aeb0d42e71acad8e0d5ce230cb15e4d6e2c5c53b669920fba4b4a0053a3630868e2f44445aa0030cdcd1638c1a9630f9ba99a8562722d4a884e9c39ebbe76d33b97447ac8c1a94c84a3cc1c29c609011068a8888881cfee204233b6a4cc21c2633426f8752aa8448504312a6fb24464c3249bfc43b12063359c2bcb2579076d58084494cbccf19d294c7f88f309565c95b727f76cedd11863fe9753fc5aeaf2835c21454b81613849b9ee5cc841a8c309c27257aca6d1c3516618ee3f329459aec972e351461ec24769f5cbb9c936cc231814e84c9531cd13539282989fb4c0f1159abb99ca564d55dd944a77d7d8f1267cbc4b126c24344e410a6b41571532a6e0883b62b4189093ea693ac1086cfe14b8858e8e4ff13c26872aca8d369ac31089312afd610844994b096d11a5ec2f9350261f6512b2223644c4a926a00c25c63b2bce435499063a9f187d45ac3aedd662cb4beabccaf24a984f1fc60b6203ba75812e45bf69d478e304a1f8cedf92bfdc97af12509831a7c30575c32a51b62aa4f4c0d0235f660f691969dbc8435375f0fe66c2d8b553a79308a554af24355ea49610d3c18ae94dc95db42fc841a7730c8efe9dffe24ecc8100f1e070c2fa050c30ea61377d7501a4aa5243d47a85107f327f943892777ac9c950e591a8b696dd9d5abe53d73e7cb73fadfb16accc1a04ac7537147949cec6bc8c194397bf29efa134f97e2601491fea7739244e6e4e1605c8fda59c4e4de60ac9467fc73ef07cddd60aa586da5f32a25d1736d30760525b96e7ebb497a3618de743e3bafd43fe56bd05d4e342b4eadcd6c6caf24194a3afb507f0d3518ee7292a2b2278f932e35d260dacc9acf6277edd9a3c124e6ad2709759b16eb3318de4d9652aa3783c97476759127d766b635ca60f6e829435f830c26bd9fc49667dc78d08f5146089650630c664d3d53e2abcf6cdf0fe3ec381ef831ca08419d180c424c989f53d2160693a454f8e5360fb750030c2693aac5b3946cc2a41cc7da18d663870e0f94b1830735be60f88b8f3da215bab62c36022f6a78c19c93a685b78aa13d45ab0b860f4a5f0825286b70c1f09a1d3eab6a5ee8160c164ffa87af12c74aa7580c44448ac5008bd5d082e145d62961f4c9e126ad9105d3c92a9d2b26c5a7b863c1bc23adedd34db8d73304a8c6154ca225f541050b4a556811189fa30222223c940b35ac60ac1291a1fa556a4c1611111129a347193d0e0c35aa6036edf94b87fc932aca5430070fbdac7042df4eb0c614cc66e2976052c5fc93f2480d2998dd4c84f7290f172f55230aa65fadd08aa7e33cc470a80105e3883137cbe997e65736d4788239598f5c874b0e359c6052ad255ada5911213b333bd46882713f5a9db0f9d60e31c17cdf9fd3aad4623cc902359660761d755d4afefadbf8c5a1a186128ca334fbfe93defbeed448825945a868d1d35e03090611ef624aed4879d43882712b27a955634bf5eb358c60aad2714fbb67358a7049f59e939c938808e6bcad1ed76e8760ca3d9693206ad61082b143c88776d3cd16cb04358260aea46b72324185ab076b00e1b81433d42a2c8ab8dc0551a29399249552a97d8d1f984d8b56b9ec8993278557a8e103535a9b8eae257b37e52fd4e88159fe54bc3251e228dd77176af0c054655212b45c8ea2c4b90a357660aecb41dbade9562929156ae8c0ec2fb626a77acba83417a63a93d159f726674fc185495b363b55797953c75b18b6f52d4f126267e2b7854992e2e38492dc249de46b61da2c71c2e4f0bf2047b43095e898dd3ae29f4d3e0bb3a7af97deb0cb9eaa2cb62ff9aa97f718d194cb0cff112d37f2d6d758983e4b2e891f2aec85889f400316a62057c57c5dd42f582840e31506cd2c61a927748539e8e832ff68263d7ead307750f31d2e8849c29dd06085b1626a8b49274cd8b88a4a442c058d7313b9e4a9654a7d2e5d5285c9a4dc135d52a575b469a4c29c7b92d6d1d79d63e868a0c244c4a0710ae3e9f0bd6c72aa18217f8186294c96bf334a95a814e65457b12f7a92e70f29cc96dbe6846813c4098d51dcdab1596d95dbb3725766774e7b3964e7474314c61babf4ba8d7b1119258c3030a0d7081aa130daef99eca26b94924409a0010a83ee943e477bd16b717281a443c70e0f9082c62718fd2827e5496ea5fda5e1897225f10a9e69736ec92ba688142d1f3a343a612cab1a2da59495bf7881d2061a9c30ea7e29bdb9563672b209938e517313ed0e2db7266864c23452774f3ee5d1c084d124958408b52694d20b8d4b183bea89a2a584eaa4a338a0610983c94eaff7b1e4c7e98cd8256854c214cd3abf9e5ea724323174e430fc010d4a182b889cd4de1eff91111d2de04998d489bcac354aee73342461504a968a7f13644f2ca9c3412312c6d2d7395b6ceb8a2e818429afa249ad79162dd5f50873e724faa7cfa9021fe82277f4184305341c61dad5ec3b13bc4db449238c6fe349845279d9d1630c1a8c30f98c3e396585e54afa45987784567dffec52ea2bc27472aad026428930ca899d3584d433c10411c613ccce82fe52f92d3a84c90ea58d7d0ce6d131b99ebfa453178331d43e5cc949dcb03b0ce6ce7fda2c96121a623018f6f6ad57b577c4fc05a38667a5ed9e9cedf582d994ac1b66214f50d92e98cbe43ce2e48e2723e582494a9ec47e1243883db760becc933abf3c5a30c7198f9d334e8e9672b260d61e19f723c3941c1e2c98a4e774cb39bc82b1fa0437394f50a63b2b98ee490a4af96f55309c9cbea4b04a3a4aec50c1a8a52459eb3c9e5775a6600e33a6e4cab625ea5230493af89b641e6b3f51309d0e5f927842985c262898d38952edd1975aa6271864fb4f2c37f7a4bd130c9f9e6fff479714e44d309c7fb8b9d7fda99d09c6da927d7e76dfd1b30473ec8bdd211e2598c4934f1246defbed4930b997f02aa722c1302b7729777a049324eb884b7ffb4ba9114c9ee197cd46adc6590493d23947f688a9b19208e67c5f4afcb786604a4a89a14f905626772d844a5a4be6a6b420986d4c7de7ecd549be1a08a6989d7f75744f0e57ffc0f4b6f7497e75137bf28129c9edad2408f5c0e89d742ced3d99ef06e081e13d073542895795730cb003d30735e1a7fd94a43d06d081b1ce4d2a373fffb773612c95c4649c50212d8c0b939457413f2b4c32f71626b12a7755fac753ad2d0c16949949a7933441ad85d1c452525dfe9ba0246961389df3293a09cfc25c2a999c6a45ee7e6459184cadefcf6468bd90d1d0bae51eda6358982aa98e176b665275fc0a73f2934eac10d54969ec0ac3a5a4742859ab152e6e8561cf6249692c668541c9392959b7db7315afc2e0964ed21fc444f6af0a63a5b8a763f57f50a154183b85fe977b4b9d765498f78279c7abb658fc14263b25cf94ae2eb724a630f9f86aedcee849e25218442e5be9e7d51c31294c52fcf2d013fbedea284c77793ea814aca2294561365d9e2be72f58284361126f3a7e157b1b27288c25bf6be8ac7cc2b4b67e2dae15ba454f9883d88ae7c1e3f3a913c676937d494a61ef72c2a0e2e83823dd8471e5c38cbc6e35613c41df7bfcda4c9843ed9724a65abc9c840983924a6c334bba84d1664669b38d1365b784b963f9af8b8ea2049d4a98f7458ce55f7a36694a98f29994444971d47a3c09f38ec936fa490ed6b1244ca2b59a4efa499ac69130c8be3b3929d95bd9a29030e65ca792e3cbcb84fa0873d026b9e5b78cca9b3ac2a44596faea901b61ca69ae47d5ac2dce087349277c92e4d637cf228c1d64fdae8692e27e45986e564dab2849844984665e7c10617eb79adb2b93c5720e61de37d99125de49721bc27852bedd854fa5212e84614bec92ad0417b92c21cc714e0af13987748f0ec274769593d20561ce490e2ae6399dd52510e6dcb145c392546a41409852ed5ec9dfec8fee0fe65b7baf302d294e7e30a59c1d1643d594ccfa60165d1fd2fb3a7c306cc7f10ba7b407933071d2cc9cf460dab279fb364bed7c1e92753bc28329f324fdafa6f47e0773579d68b9ce04b3123b982cbbca24d926d33a18e6522a19cd4b62c274307c2ee93a4997448fe660306d7df3a3dc84891c4c793fe8939f963898f4babfa453163818c4290f791f5765cdf2065385f4b5a073bc1bb3b8c16c6f620853e165d652da60f4f08af739e3be95c206b39b892fcaa41725e8ca1a8c21bf3c49d94cdcbb8a1a8c6772906196948d29a5c1f84905d55919259c8e0653c9f5a994fecbbaf6194c494961e664a7744a6c06b389153b3f85abe42d96c11c4f599b583aa17e22194ca62e6752aaecba0b8ec1a08425ede6ea9fe68262308b30f5ceaafadc1e86c1f4ef614f76070663a67accfa49922831fc82e924714f8e6a3a3a95bc604e13ecabbdd287ce77c19c479b9c097565a273c154b2e89c67cb948d922d18735bf694e79c44eb68c1e4f5bdd57766c12c5a436eed58309a8e2e215bd1a3e70ae6ac0e72ac3f8897db0ae691efb89466ba2bae82d154afe9cba24b4a4205b3e8ea14ad7f3f340553972cfbac2d2ac7560ac6dbda17a976c288340a0693548be93e15ef040a66d1eda1734e2b25c62798f4e4f6be13474b122798e624b992922595a3774d383f7fce6bc2c4048390bb3afbf92598fc82eb7588fc355f09c65ebf32c90495294249307a091f265fe34f8d90f0dc69b5bee908e69096b6334bdc2e31824197923a3c9ef0962e82c9ebe499579d08c62c49fe0e4ac7f29c0fc1a0669f443f4230691142e7f85e97eb098249764b15353f9bb0190826e16d3fc668f14ba23f30ef6ee7d82bfe39547c6056cf77f28979d22ef6c078ea7dbae6f425b9e381a9de5456801d98a4e9133c649790632a800e4ce993f8b0a52e495dca8529c941efb6a7d125f4b830658c3ea1e32b7ff66f611495b49f2897440b215b98d4c5ce9df6d7c2989e7b3e4dc80aa784162649501d4e4a9f59982a5fee34a7a15a1d5998fc52b5582c11e3e1589842ed7d8c530b972f2c8c76a9b4b49e9612e92b4c6bf5a684570f3a565798f5ec4df4ec582cb5c25ce5254bc7ac30285946ad5d0773731506b3551db1ee245bac6ea8c2f8329761fa47fc5c375261924acb838dccd4ce5e06375061183da32c644d580ada1ba73055123743a7cee12fe41ba63009268fb6c8d751e9d78d52988457d349bc9366bc1c3b7a145298e49284c8872c3f39ba6ba330878cf77ca5633c4461ec78a51d2b542835d95018c4e4cabfdd31d7b9ea4061d29f5d2243658652aa4f18d63c8f993e314fddf284f946bbe57677f10d3b61ec5c0f93f3c70963a8a8559f4bc89b302751a2598df6937aad268ca7948b9fbb97c921ce84b13f9f294f3ae81cbc574c9c24955b77e42c9c87fbc625ae5461b6dde5ed533d4e0f6cc06f58c2e09d93a05f33aea2c602c6186160a08c09f0e0713c1002112cdca8843996a77095f1a673d439521a310c54a00222222351b8410983e59c6fc546bde961e8244cdf95d2892d318eb5ff1da9b4244c953c9465257946c294474e7a9812fe4952c1b10609a39c5072e193a4196ac5b1d617b8f108d399799262c8ea33417fc311a6117a54e720eb64cbb1c5c08d4698e4f06149caff29c69c811b8c305b9abfb019a204354238d6346f11a6bc565a516c64f6b25544183a7410e0462290183964200619356e20e250cb3e49cc0f110f307e64878e91314e186679e310dcab9ae5aaf612aff6d2d2a25a4ee3fdb2e771b47b84916e18c2b0ab7552c4f61f00038c1c1a1011d19163648c429842e54af7b80961924f0ccb14ef70acb93108f3bc09a3834739704310c64faa7122dfa13c3dc53a702310a6edd9eb3839f1fd18202cabd0128f3f9834d35e7d4ce40763ebc993e2754384b8f4c164529266d536574a94cc0773acd87e4f2628a94df6609c1197a753a718a91ecc569da4e812f432c7240fa6efa017f27a2c3daeb4c383515b3d7d4aeaa526e838d6380437ee60d01e21a6afd3df73c80e06a5f5db2985ff532a098e35ad8329aa85d077177f564174830e061d3c9596517b920a4a1c6b3d07e3bac54f218409ea2bc6038c31c2c83132a2a723c7c8183cf28b138c78e0861c4c96e49f30f3b938984d1825bf87d072c265389852d74f75923d37de608ab677d12a454b5ee21b6e30e957132ba80a6e928edf688331457c08c71a8f3074ec4846811b6c30fc5ada4f49eb57fe6f0d0665a1717184ce31b4450d2625f9e7a4844e920693a8917aa27c43833662b152c999b55cd7659669c71f79517fde1b6730b97f8a255f7622b86106a305e56e266726a3021fe8e24619cc27cd052b49924f4723ba01094ca0031bb080de2083d92c49bdaf71b3bfd28ed8e181fc330737c6609e190f934fe34e509288c1b05fe7979377bf430737c26092a27ba31fc777dc1711d9115b3018459bcef3f0125bcc1b5f30ebacfd87a5d2297e7bc13096a4b9986775c178d104f10d2e987385e84e616125d8680ba6abb43c694ae37392168ca5a24b123725bdae9c055312840e65594e97ef78030ba614a49724ed72ec8b3c878e118c581837ae60eeace8f1ab244195d0ef0e6e58c1f4a24edc73f8b8979e8e1e6394b1c3f577e8f01edca882c173d7ae6bf65430e55ce9cc92494fc1a0820eb758495e0aaa6cd5db88855c8e8b6692a022439bd2bd200ddc8882d147c46559896e9dcb1e3ac000818808fbe006144cde41490d4f571b3f3dc1a015c4967e497182e1c6c29eef5d9aa058b57b850baba92587e95df5b49cfac30493c9ab5936429897a5780e3012323c20222222222262b667071967240d3796609257e4ce2adee8bcf90d2598f7a44eaa74ca3e13db8d24183f25657e4a2c1546ea379050ac17116fd92e1575f31c2709fa3eaf590ca123183bc4b5fd2f8a18fd19c17ce6bb278e943d55ed46114c2a2f458b78b5d42797c00f6e10c1f83defe142c9616723004ce1c610ccb51d2b489318e4404881e6b32e5fdc1082c993fe0e3929cbdff4378260f67b952f49506dd7496e00c124668e971cdfd2d7fd8d1f984cd0aee4f1e24bbcf3c195ecbe4ebd6c5bd3e2c3fad2647a6c6903377a60523d3d61ddc28e123a5eace0060f8c9fbdb49d28d7e2c9ba11dcd88149525fa3de54bc93a31b3a307d4e69b493d225a7b7f4183672616ecf3e71e93b2e4cb1b52d4feaf4ceb215bd85b14d9c753dadd2f17f5b9884381d4b85d7ed59cb0b6cd4c2b42725f96413e4884f1bbac0062d4cc1f2c7cffd493c95100c1d3a12306cccc2a09360724ea2a76cc8c27c3baaca3c9a24c9c1140b93989c7489564a9592f20e6cc0c2b827e6e6e9b5e492546cbcc2a0adb5a43cdeae5efa0e1d2362ec780caced78fec2862b8c62493e3e75ce92dba41506396ba2844be12cc8c80a930aa1b69ecfa277d8e929f0639411825598ef248fa6fac367d5481566cfe9e3a98f492a0c4aec9cdf17272ebd44c595b4e452bc82596e8fff947ff2a90b9f47f6400e30c600c18e1e3cfa14e6fb539522dde4050b99c2a4939ff292e27b0f8f6ba864efe5d268280e8703a260281008040cefab0023130000000c1c90c5a2d1704026edfa1e148004593626423830222420148e4603a148180e86018160280c0602828150280602395888745e0f07f740bc92de1787fab5e38e3b6c61d8898dbe50487fa9af90673ba5b947c15db706850a1645464c6db1c3f4e85571413f2fae7717138bec9b43f0141685a492fc6754b5d73e0cdcc15fc8097b08af9aba08a4d5859861a83e7eca5245df6688966ba416391ed82930e791217004453d786b8e3ed7ecdd7818d46107fa72c558c44458556ba98d22348c3a513e96e7ed52b98193de2f561ed18eea15ec4d3dec5cb5b7e121f4cab8c16e1fdb6e8b25f77bdca8c4122d95e631ac18b254ee0954ef6f2bc2d7fc75c485ea966cb4db1701fd263f621e6bc7e975f62e1940ea46f3527dccfd0a25a7d412ab963eb4291505ef2382b562072e7696388827a427e37afd40e15a576a9c8c5c79d103e2ba6e7f24ce698abeff4e1a4b49f1efa31cbf08b42ccbb13ebc1bfd4f6d29bf224be39dc6fcaa4633fcb663c041e4a222e73ea42b60cd110f167746a96d324c65135742a4f6d6e947c735dc4d1947aa467788844a7bd137ec41f704e3a51a395f5e6b57e979b04da97b03f5baab8720b87d0f9dcd965e71ac2e68f01be7b263d6668696107a564a11ee5a378bf7611f93e7a04ed743ed15352c00806ca5e04111743272e5fe8bed665da32f3c9c1fe2722cd7c575ee9a9ceb5ec298b2e73114dbdde29b4a5ff4deb1f48873d8c52203ae1d98fa003ba39f9d13ab752a1e496f8c83fd7a61238791d7b0bd62c72d4665a0d458db1ebf2e44724cf0df06fddd309766e85526700292e03952e82bf224e3734ed45905671c1a2fd5e935b95b7422a2bb8b6af3a7e8e09d617a4bf762a4b9218ee842b5ce442828a925179a78d166e5349d293c6c4470305e1302176a1b3a62b15cb9a4d441101d13a55e995c7277384571466ad06c9b9fd048804222c738230351b5810ce3c27549dc46bc02f89ebeda7aa7bef3854200be8293b7ec1258bedd99655a072fa69290820bbec70b88fad5fddd7fc59bd4adaf8dc0c324ed04f9e2ee951e7a5fd8b7119fb84819c5b8d79effb430690dd71055ff28d370d0e1a06259211f50cc3712163a20854214653e40b9489bba3cdacc71a02ff88548f53555ca02887d0422fa3fd730d6fdd7d9f0ed4967c754e5d82c04420e8a6d2f05b90fbf7c7a48642e00b281bee9a72843f2203e4485531d1a79061edd1ce48e0a254cb4be48cecbf05dc10be05bbb41788620d48a3408ba5e9049310adf3a21f850c689a6202b17dde6f409d22fc301c2f63ac7a202dc9b866a8fd037fc4dfdeabcbd25dca99d5416805af2654717b0c55536e097a10713dba43dd02655260f8c04840f07d6b07591158827a02fbf90613087e7bd9e179084833659757e30d874c0ab231052b8fc8e65da72218b5bb6c4fd83b4c94eb5a006a40928b1d36ac3890dfe5d759252de4a7bc0ad5bb248328f3dab484f58a278e85be8416d6e2fd6d1d13413c092ed641b9d32e8f64bb7f004d84c06e27d41d1c55137b1f11026889f0c860b24266ea3b0d70131b941aab2d0888f6d6e2fefbc16f40d54490cb751f2f00964a1778ea5ee8f166fee89608e8261489b536bab6b7ed0dd15bfc6b37b1a2328dee3873620db4a110f7eb81496c05364201d0d5599e17d9c4900a619b5d5be9039d9bd8486dbd9212f61b825e49c7266aa56706b4f9662b2c865b3f0ae6b584e9748e96fc515cf6770722c06729d4ec0cc27e8e0804c295efc03a76d030fc9da39ff360dec3d655aad24bd12ab852afdab46c69c828082234c201cd7ceb44046aee52392a52768c7f64d0d3452d490bce32e1144463acb7fdd40a9bee04129b8185c15de4897281e225ece4a0df243ecc35933ccabd70ca586bb147216efc0b0eb0011cf0ca07009c64f53a94c412e4035490a1052138fdf44e737b4524e0ac48ae150db0e7acce4e4c7aaa59d470eed83bfb76cc99c4d694b7e0e6b1af39ba9bb9f7bf6096d8260843bb92205f956ca63cf697399faa680be838f9019d8565f13299c8a2168f6ba17a6f44dba8f2be0b76445ea8d190d6c34748a865ec9591a95fb98f5dbdc947e35ac12403c83a71aa6a6f558d7efdfdd060022b4269722b67975fc45243ec1b972c22c1ff7c30b7d6136785a56f7ed6e931255f29cde070dc64a11c6a5220166c44c6c31547474e7b241533a9f68f7e2188a8b8d9e9a1c42fd801667343dde54d44abd1c02eab4f97637decfe0d0e6d6cdcef93d42e69f83dc4a99e226e42ceaf66a00d342203af9d8e48d54b844f592abd77f5cfbdfd824552cb270c8f5f6c836d5ba318eb82ad371179fd5d2f66bbb68833edc52d6d0364a5d396325fc0ebd058398441466e275e03a4275d18f3629a35fe6c27930321e2e7aa031ca09ce1999580fa44713e378e9e8caec94ad1917cd5fd0729ce192a0221df15b78952208b698b1db162f23baed325e0d1b85f36e09f0a7598a6fd786c68868c9a9597c6b193a6d27469d73f2c1885a94971a90208d0ab57332dc20a23adae08d071e6f17ffee108bc15003ca8b35fcf9b5302c71d4e9a85237851ed9da88ea0742d4b85abd799c3678d025779b89358d4d4e90cce8694c78f5a42bc2006583fe3a7ccaa07c6e47314319865b7a5b3907768b1fbf6367c38751d6a6ece8b686f8fd0f5fa010a70f015f9b01bdf4be0371c98fdb8f05d66008242fc1b9a62bc7684ce72aea3143735d15c49400bcc614829722377858783d6db6215745ca0069cca9b072ccd1df8c30d43029060c61b1158ac4ca92626051d40ce2f8c44da6a0978c30d09225bcad0b650a0c9dc69eb379ee151b0f0ad87da583db8048e952d67367d629bd2655a7b58cc70720f236d4f7b4bbcad172998b45197862262a99aca439e22c6427a28b48f7213d57958e5a12c1f5c37f8e0f0ed0a20d8769f8b0e14528d3c480f91646a0b70a3714d07d91f89f64c8e56278b290e00040a80d340ea66b88e72f82a40e37aecbb4e88a2ad4bac04ba116c111855e1f5f21e6c808bb5232109a9da5a50a5b81e8a263bb5de7d0c643e53f4e82131624e2055dd665a20a99a83af69ed0fae63db41896fd0d047fbf12cfb94ca2266163e9df02be69e140440bda82a15408a28895677da224e92198dd30e6a98bc988fae40db589c8e594c34ab961ca8cbbb0548c001855aa154a5877e8ad0fda9bec92d5526b19790b0d3336c8d2a0ef21ef2b69f889e66e909121a8ae957ae966a593b000b86776c02543c594a7566e327130cd3fc1e784c464bb9c9e0ba68a1f1747066e69f26a6870684af4731293de40a4633aecd87d4f4132f168e5900d8598682072352493b92111aea8e10f09733bbca0a13b58f01a1b7520b6c5f4d7eb845be6cf69a2723d1a3d75e8b6ccab9aeeb93331a0b3f0da85d37a934b0499eedb60a2c4fcd90cb5253d467058e03402653f53660c64d0e0a48030d2db300995ee86433b573828130e1df662044749e5132e23f40a410c324751c32659891e7fdf23afcb66e0dab28055e550bf7d974096417922adbf12a9e8aae4ebe49890c425f72890392889212328ef77820a13051d4ef72093be55fa025bfb7606b9a6002731613f6fcfb8bc12e5859f20a685a8d3dab2c5d97572fc01eae327f7839098ca355196541210ecaa5865aa460e31219605de7c62a630908fd3e5c330437f0101c179033068fcd0978c61ba4a516c8dc2024af4da5efec2d61e65326c62d85576e2ba4be659d45a702fa0a1ccdd348d34a265b0d5f2c3c2259d5c815602805a1235ae72a54df006ddbf854ff6afeeaec02dbfe2218c978b59bf0974e9a4a5878124079ac0cbca1c2d41f448e1d710e121d7214d40b7138dc55b2c6516672d2f7e13ba9ce8b9278c2a485ed195011b238fbf7a7a07b76b0a13b1c58043d92af696b7a64228e835c350d47b83b00d0d62f209e26ee89c7b91745f7bffa210e91f81a15a124f291e530d0071baf9a679378d4c8f0a036cc76343ad5d3cd59154aba45a42376e6fa60d3eb4c47d15b62a506602d7b64e2db0997283f45bee9de80a3850f5cb9a0fb8505ca9aabc0b48f5e2bfd19debf82904199c8a6cbbceb7362d21296b4335989acb64bc4842ea94d8fc95100b1ce605108cae56e2a8f73e74fcbe0a318a0aaf91fb1c9e2c3822257a280bc4c09d69a389b83870c3155ab1a7faf05768ccb0441c23207a89b153e4656d6c8eb31c62b24ea0db649fa7ce8514107d4a54a17c86971b732c3276a2c0e11b17f6a2a97308abe0fd1aa886b72b1a2780f05c0989f69d8b8b3d71ed94a8365197580b812e870b9a12b8b6273b0b3af22b90ad142ba732d2266d4b1caab256e0b048172cebdd13bd2d4b0cfe7528b2847ecb696686f810d9b82d7928bb2369a2f1a4f92f13ecd22a78f7ef0716d1b32503d32607df515b4d0320df2f07804580ac8544ee0a304305c55824d879b07f17c78890b00139a706575f922ad738ca99406743357b6a02fa716645f966eb6a3c574f95114fe330d2695c587e752300207287f189aabc5941c6403b12d56e8cd0c6f73e0e0d6f295966bcb8595dcb896e16daa8d1d3eee3da7014941b3146802cf2425c278c01b884a98e9b8535a7451df41bc4e79ca69be91c866c2632ca41aec791888257327ae082328c62f28d35bc4364d05e219fc862498b8cbb57ec9e30e0a38d12acf2d18b90d6b2cb3610b26a3f5535b9e497b87c7a4e47ea6279229d647312040799e95fc176e7409255d3b373ec24e67126a43cc4d73887f8fff6481b9f7d4cad96b21d2de773451704294d8f1e8b53f8d38654554a46faf1e975b8bd7808f7c1476cfc3505bb3b1d15ff6f060e959adfdc537201e0cb4b81bc851c87b9b2bf2455cc3218d3a0cc1be3269eef01d27d1440ad0254098210a6093f7e1d1029976410530902648e93ee6370d3a62b2bb09a4c9be383b746e04a849752f306ac8315a5e32e8286bea0e486dfdbc6c584392e29d72f085e6cf9a86139eb312e2b92e12123dc6447fab35af71e8f91e8c8c877fcdbfa02bef4c2016ff38d99c56995680c754823083da63f041c3cdd3a51331c9a97528eca29a96ceaf45510f8319af33f89425278935eaf3acd87611f9a831dd343fe8f43b4fc4c196f037784ca5586a13d6b9ef438ce86bc404ef55f5de3de194ae97aef54175e66995f8631843a1e4c77dc85623011a6b2244d8d83a2f14a451b283ffc11595b114f73c392fd8856502c4abe9ec0268865f0eaf6b8cb06330786ef8ea0c162b7bf67eef6a574e981344105542e7928e719504c12200790671efc0ceb9043f4d605b89cdfaa9971f4fe7a6248c63f89ea41d5b765b8811f48b96652a33b36663d97b2e091ae8e6699a2d46451eca1e5c891134672395e857fa3b65eca21a256ba468f29d2b8e549a4624a25d26f79362016e2cff01bb2f81e12c0bb3f2d9e5d69104acf6b1dde806c40a56850549837e8876423a22a2d0bb8073a87c7dd7bff2e00ad08d52977da42586b0a05f6d9c337312d5cc66905e2e47ba782fae388e7f2935b0ce890ebc4036845839155b196a3e69ad3fb9f06f3a8d1f6a1635da5b25a2169f0f9549ada4430590a3ed9577fb0fef34d2f07c8d19deea8950b0933b25dcd408d81aab8bf01fbb1bec9442705054145840183f59cf7bfb34ec0e15f0d0b4485f78ea9ab6f331c92621cdf0bccc3b552af5fe44df324a46e24537e3e58eba17fffa13a79dc5c50496dca020bc0c4f74b6f23a6fd601038ba7bf10599427bba10e60b4d1ea55f377476da9a1bbd62049c9e67eab2508fa744d8c6de866c3dd245e1f04aae98387587395c7f7bd833ba41c347530689c28771a89103fb8abd6813b9e3c822d1aef70e397ce54a9b7b8788d34d43e82e5172ddae87ad945ba4e596a6deb2ad3769d60354c0bb87c7411a3d7e8890ba5e845078280918224b1950a7929c436908795d9748106d0a4fbad543491971f07a76ff5afd0280a16b3eb89f342ede065a71d72cb5d94020754f065d5d631c372c1b474b3d57bf9b2ea76bceb3e81088534aa09ba1e8c7595f6cc155096dd28c7b0eb44edae38a106bd50560f395719c1003a5066d321c7ab5522e2a9ea220c4116b065f89ddb43f3cc93459c340cb1acdc2c9f9d56521211c39dcb8409908129ef8029f141734dc1a1b1f7928db6e793ab1d7c148003bc23c969479c1acefe14315d6af451b031286d7a87ed7e913817a53c5bbe7a8e27c9b837084616ca5ea9441a415d3f8f90fe747ec6d4508818f5c9e74738e3b399694821f2ebec1b19cec2d6f138154345a0560ac98420ff3b89724e0a924199a18ef9ff9f2dd5f462fc3114f139a020ae7f3450c03273646bd48842546e12ec946cead388915db31b13b306f2a84b3643af45799f49f68b2ae8f2e30d4f7324edf3f5b747c803ceeed0158e029b286e081dd26bdffc398581ba819a1e135fcde141ec482cc0b8084af5f84b2e2e968490caf9007dcd5f0bce1cf5d75785a505c6a78c87140cbbdaea6d5964e0152b9287c84b0a40980ea62485169852e4d623d613775a325960ed78a068f3ac4fe6d4519612113cba13733bd2c112e9a7abaf11641f0ca7cd73505cbede87664adcb8941341aaefcbfcbd92c04bbc48a5590cffbc3c1ad89814b1288e24293073a4ecd9952baf84c242da82ee0a5bd291ab6a02b33252b6a151d1a861e75c768578e8ea04af5942148cf52b1c41058cfc8c36a0f7c352fb6dd7b003aca6de4349df1b7c4e3388ceca7054e75001dda1670c6df98053ca122bd4a2e3e90fb2f3f22e52d2517ff413205c2002f44534d82e8a7a1e836b01ef8528b23ec3db307cb1dcab66013d1624809bcdbd1c961c730ef6a7f9306c9735adc94ffefb6c322960607804ff10beac4c1ecceedcfd18a03af372cc3f6cb34980e935d25137cd07c616603be0f4b2a07ef4eeef1e5eaed3f51ae8d09a84d1deeef6af7e3699ec109279870a2a996e9e5c270b383649669577d634f5731735826a6da888f2771a338da994fa19db03482cf63c7f4d858986c89d73a61f16483ac471bd5943914db782574664ca56a1318368f43aa2f053c153277374b889b50106cea887746cd5e9e02aac46deafe20f4764d7857ad46394a242e5645c8bd5ec773218b2873583d20fc5b4774ba28184cfe694e1fee6e4ee3ae3a9b9af1b61e2777f68a38c1f72f6266d892240891b4183a407fb87b9feceb35d5cb0293349227adaed99a40f15a038ff3778692c02baab4d27266e2c7d5ba014664887a5fe2feb2f116f50122669a6a75ae4b8cd15cc58c7b8145fc2bda1de8322aecfd147918167abc5be6559478c018373c21ccd187521a5f440c26554f05816b3739aedb41485ca35185268c62f87cca39812baf86aae5c21d6985dc8c2473ab5e4db1f96a153ef05f4525804ac8c7ccd8692d10ecd6af44af3ceff9f22a28f684c718134e588ed8139ca63eaa1676103d7594fa5d1ef0534ec9adc38879049cbe26e66d552fbe35b1bc6b26a176bf3b834986d120b823e99f9acad1561b02250f2965633d6b142783f664d1c380c029a94db6efc0b3ea82b8dbd8a4d393072bbeeada6b172560feee9d87a146f9a6058406b30e16ae1d34c3e5203ed9537a11b70a61c63c3699e246e6dfec7f871088e4e896818cda1aedac26163aa7a9269aff9b8606f807544230a1a7cfd465904ac3a727ef7939123596ae683807db4c88713506ddf80c729205209b1be0f0605ad131256eb677d6effe4902c6ccbcffdb6d4a1be14a816b271509e3bb414d7dcb58a744909edcade6d0ee86a8a755ea69da0473325b2f345ebb53a0424899cd7222a660a3b3cdc76da02986e9764d9ee7781b7eb292d374c938e103e623374f45d860f55701b37e769dedc632108cbded1a188fce19f3e7124159c8e8194c311cd6752c6b60bea4327ed18c309085ebdf4610adbcfafa4e26b525cf32d4fe03f1aaa72969550e097b4c8e01db0c1f8cc34b276bec17860dbd883f8e211cd5dd0b7bd9f43b210a03c934a500edd4029215229896fcca6882ff41ef68bba25e8694c0bc06b5deb0a092a0b283b20bbcee99c2fa676532e92325f30d3889a57bd43a008a8d9deb567a0793b7d0e54a8806d1fbc2f470135ac9342496b140ee76cc343c156717c80d9a96e33c0440977054253678907ffc47128f0f0fc4b02c202d55b0543061518eb029239dda72cd5a4c553ff78df827a0569fc41a055e5db4f0e99daf4906ad32664f01ad9cd287e93460e97d20478024b7c2dc04dd5aa1bab89b8fe23b15ed82dc0b13b3b5f69646d0312d803681a2e599639667168e271239b59b7c969f7c000a36d14950b2610b9823e2c4d0618430d2391de33a34a934b8c36ccd273a397a9ba33b2028391ef17155fac62765a106c8ca4466c21fdc08b4830e3ad701cb09043d8c8653876073976c44f90905c17d03158d47f35ae81a337f27e670a17ad8ad148731d346490f05ce8a0c9db1347be4d3d4e0cad632cf3c5efbfbcf2cac3a1649741129c65a6a18be716d2d711057b66b449ea80d36da878bcf492abb6bc8f8a18b29fa90bd234de11baa044c48c2fb2cfd950ef0ebf632d004484c988c2aae95f42edbd6fca9454868ebbf88fb3232b0760e3f74366a94bfad844ce93d01e3688570c0d36073a5b102a4c5b62ee4c0b1c41f5072ff692d16297d03f4a7982e0b99ca08d16e29fd0041afdecd6a110eeb6e1df2815f83107f3b88ba95e0e7d59f704a38f05050e8cbab2c32911161f97698bd3bcdf88c51c5f43222897c611d95a4568ec9a4d041b00e4d97715aa87f64d248e2e7f6b44a228287b4beaf8714398e802f7c6264208e97bffd92843a5440b7a676432bb1248f1fda1cdfbb098abcd1b3bf6d5c02738d829f230889c9fccaa7cbf7a497e5ba6eadb72ebef2bd9cf1860a6121b20beeced5d7f51b43321775c523180c99614270c49dac48e9712360a808aac6d19c3797b506979c473464326e4ac9cf53c5a5a6d80652c61e82924ac9ace02db6b2c990115af357cd739752d83139b4aa01e1d4a041b73f4568273e9025fa12ab87f4be1fb2851e31813c2cb7804509e4f60868c5bab629457a51a3fcecf6b08c21306b13f0cfaa11e04d82c13a5a79772db16d86aafe16568024f3a6316b0a25d94d63d89cf08cfd3b7e6273dc69e1f56a52f762b1b929e9c8c895216dbcbc718de22fe4e2318b6e5d51c8779d9245cedc28bf1e7d3bd299b06cf916d054167a76973a6c8121d58ed5054a27ba87e2f5a85126302596195aee584881d3121e4ce707e3fd6b30d68dbf776f949631d9178ac393910ee48edd5b64b67f8cabfee0d80123782965fc013dbad71200596b36c95b42483f6c74c1387f6c8e0b5d2a8bbfae5f0e2686123c4270c78852cdcf11c2f24c6ba44c0c7ee2fa17525d4b4caace17531b98a1d5051cc77115128d041b9cf5802c22ad88abf0d9c37279431e955c2dd3de8d079164100fd43d30cff0e61cef50c2bbb004dca57dca001c430cf8ecfb6d6bb893c859454d44808f665845d7f96f28edf12915168d807a43913b177928f6f83dea71307a1455be59c059da1462b1aa1a100b9f33c6ed9196895142be130af6cd9bcaa3707612ea7a83f3e90c7f2a61c222d36935dc4588047932a308cb0613bdfdc1b5104dcda3c765b022b083f0ae4835bd1af2fb389027d567a29cdd90f708f6c9a752af695024771addd52013410560e71d59b4abc1c7f687dec5d55b4ea00915a5191cff1f98814175f997b9c81dd80469c847fb3dae8102a464c8a47a3a7bb54ab501e63764736eba0026a436d90bff10e735b119b464d526fd793c0084a10a2564a468dd18eeb7263408ee3c3938ad16585c0149f8f30f1f9e0b34bdb7c5d5c736c5c113b2bc3677b329c918c40730cfc84fa9b4092fb91911c926eb564ffff602d92c1d28741f4eb4b678cd5295e420c12ed8ff24a213397cea93886548531e7af2cb1c82531c411bf6074f9b3a8e46f1852fbf07ec4f16bd96fc1d4bd31867ac61f98f64c186aa0dd6bf0d2fbb9fa206165ab802905f6b46f60a52b8bf9a6d606e1b6ca4afb6d8fdae3d54dd6905deb43075e60ec128214089a6afff90d7d266331bd5128e51bb33497c4482877e96cc893c880521e511a11c38f0b988488c97316b82f9522e387022c0d0186954b86c897a080806c331f825286e760b50dd5234bed3a59be9124cf3245e354e5b330c018872eaa986e1e74dc0fa03ec7169c8b648d4ff134dacc7ded08c219809e2830922c1cb3994f08a9ddd99656561ee7ca6a4f929175d4b2d33e31026cc5cfe760710a1d39ec6c21a7b5ec25789d765acd4acc912688d6292a451aabb32719508e294d38c8999b7023d9bd17cc651395261c49d716c4e7eda87dc294a930d930834a0e148e799e9b9a0832030157b434decbb93c9b654e44c7231a1d31a4f9ea7505fae4dd0140e00ab389980ddad63ac0d0ad5b399aa00de446d38f1a68aadcb0ac780ac1079c249a5f1a110e5ba097653569155b51d5e4074b788e75fbb985f897861e22d51f2c8dac14bca38bae25836bec1e2b74d43d64c2c71968dff3f173c528cbbf43ae691bdb6cec8976369161fdbfb155038b33d018cbbb50ccddd48964cd38dda02ce73ff7faac9d04a565d2623faa3da43da90efe0aa49b273857b82c9c28d98de45a4056768b53cdd7d6206987c1ab2d8242bb132147d004d18a5acbf727bdf74224ca28c5d9c55046fa1ab180e829fe1e39f6e606538ce00a7f3d7fb664d810ab071d35dc679a36aae3c14f5c8aad0cd92403de892e30e884a74d6197eeef58e002f88da2eaf1aec2e305ac31d867fb1a58a29921fb5ed543313243e0d13bb61ea083551a8445b26251375979d4dfa7c27e196d18ab6615f36672a7da7514180f2c75a4f2148541402ae7e904d3325bc5dd3b41ff866cf95a5009759d24defbd9f1a401b4d538aec3fb54840dc5446004f49aafd0379c76cbaffbf7c53c3af474af07231dd515b288d40baad6e2150112e9b6511ab557301e0962b16f3e1e7cddf7dbcc4d15b732c58813b1bc501d7564e6532f57cbcc36c88b8f82caee9684899822d3e406e8c5541544a9610c25e79a7f94b8185f5eb9770ba7ab57f9f1bf270d33b517503f88966f0ad2cfe249458564382009058d3ff73b38daf8e6d3ae5d1a251cde53643a96903b65a83dacda7d82ebcac221da482a8f470bd74b5b4a26723d33182958bef42859ac342b8fab0b697ab8511b5a5c411b5974d64e768e1587adef59a73a937a1d3434d699add8770b2aff1b03d6505a2ad850882706b0e2fadffd1dfbcd5c36116b6461cd00cf0dfaaa97c4c79885dcff960fb0626f528048a5f1bd23fb1bff25f1a1c4cb37f1299ed8a3d850cca57fea84e8de504711f551511eaee45bee3bcc7eb71e0a1c9193693a4617388f50ddac106ec9ca9caed71d200a83b02c11b673c81d1f567d2e41a8c7823177aab3bec86dedd7ebda4a89c6455a25627e6800d2e34930f87dc1a0cc8de9071626c0ee83c3138409c010c08f0a6a0ea87b7fdb348cc60b64ce4cfea57fee07d16f0479f44cf8fc0eb7f5e2889fa99887eac5f975144fdb3be82ac50e8dc52dd3acbd989b3c1a9ef74241b1bb0455aea85655dc6335f8a83c4d2255a5856b7b0bfef37bdfbe3a5675ef5ccf6e1277016ae4def51343468c2967c6c95b9c21af668068f4127b53d7bae34db806809b5c2bd03d0b158da8069cae3cd8cedbe4c00b571732849ef372146e82768bf3c5e7cd1a5d7d7b241c786b4d9ede613a1f4f800b7acf8c4f3d7e7334fe1ef0ef90360390811143891f91de1f6f7d77b8822062e3c2f10097ae8709782e3f0aff3e0171de43732eff6bd158e7d4b1f1e8799df358b84451019b66cc2e8ae271fc26b383c99358ae3f99075a0220d126eaad31e75263e9f4fe10c898544db94de0c7bb1dc1671138e851ef2ce116c4eef93bb217cd922eba6f4ee0b4538ba54699e3ac3d4831ca91a61f7f69945213e96fe5a8dda63f5afe317c32244e8afa474dd056d7d47f2d46f762eff50605abd3fb2966349e897a61087bf5cef9ba33072f542a1848ca49c6f4f0271cec3aa2e1d844c6f50a8665648cae5f710420f63b0e4843ec4fe32c6b887ff83b01a76e5220d4118f884dbbc3a0e1c9b6b20a44b8318bd07d859d2fb21c05a721c485dae4b9727bd465bd8528e2299d05b5f9624683a272cfa1d26e7dcc05dd395cfa92ee96e1627d538ad3028762c740194d5593f48e184366ed1407edfb78907bf42e9b72b4ed67321ab83345edde00dc797dc0a887a40b9d7e6c04e796fb1f9f7725c2c95ab88fc7ed353df82cc26d7668bacb5ffa2c056cac7897f99e9010cc300999d184b4fe8624d5cb0e280bbe1cea31a0b26c67366f578945f8b9de8f615d74f822c598971f5a4da798414c352500045012ddce4e1584e1d94d092af69041c4eb49b8dcfb5d26e4ab340c89ea1026f54c1ca6e23c7415f69db89145c690f764a42b25d5cc714173cee86846c1e9355793446cc9e25c2a61dec6da39242435ac2ecc6e52fc5c31c891d878575e4224d95a285c08234402a7156a4c12503104cc183e660aae38c59e20ce22f9ea2b79709cc32263b34c6e6dfc8c278a5645dcca9782d4441d078118c376ee310b6eba3dc8ce872a17c6d98267aab5ae29c2809a9b484f8c8452ebe55a038ec1a29c31deb96e56b1789f4088d37cd7c84ee30f383ea19e1ca94fef1b3ad7e6f8f42fbf57870436b8f721a259165d06c76281907f51a08c6b968021cc4596226854ae0f162ec61a6bf9658bab34c553ceb544169343c2cda0c9b502e523110898d59232a28f0f90ac81a098199b6a2f7cfae5cf7728d6713a76918bd33d5907f1f3070afa7c7e53d23bd75125487cd71a01760b36b293d139cf8b4915c3ab8b2ad4c43b2a802a53001256fd7476dbd65c6dc629d437619852553ea3f0a884e88bfe9db4028af1299535150b3205288b4723ad1730293e3a4bf5fbf09de32209bb94aea1e19321009810d1d0f64748b4a18ed298e50b92b23728507558483440d2885af9f2f8e809f26596a477c90cb750095f12c0915af1df29aa46cb880041168c3e5b57ba348b8ebba411e14dcf4f5fe163b9921a3cd03ad24c6bbf50d3580a66f811ac89c453d139b5ec933d1605853d2094930d4891579caf79339ad0476ab9490de2b5885ba05bc4738a971d0eb9a9a0b60b17bf2efffa65e728c6cd18184638521f42bab6752f33608bb196800108d87f2634eb308738049f047a1dab01dbbbe6528af7da4d4519c8d038852047159141ee39c9fb336eb80719cd0845c4c8388323e16c2eb3549f5f31debe0dbf1c37b197b1c108094b3092283a3141aa3de914e7e4777fa24446bf08e6120130d33f4c961a612a585a894b3dd649587996ef1be70325ff061b0ad195e9b366b6dce5a90d6ad504060358b269b0292b8c33a4da65af9f468ee01998ea4542fa29441469093db72249cc59314077de6902dddaaf9580e83c6b89c1f231526a20c45682bafc24dc2b4cafabf6c39d9dcc93f042d03ef307398d06924826b24870e043420d9c40c122f7ba7b75af5d5e512473d889664f241a48119e26ec6bac9914bc56bd38fc650726e04c5111da122c3db54be965988e4c100ab11c6c120349db4870352623ec341c448056d4b9acae1568e78350b47fb5d2a9095995f1173b4248200979b7459b02d84f7c46f0a28331dece0c933138d813e51e1c296fb83143d1cbce9e882b495d04cc84aec4dd80e1892ee5beb5e394a24d58cc182b7c618a7201c1ee88e4a74aa89c426be06f8700f650b32099ba444ff0e7111100e166699627e4b89edb8b2b860b397d59c8389a31fef2b4fe4a6f3876039e6ebaa0f7be923f52e1f6b28cd5092fcf681f5e2e3e6f5c247b2a8181907f18aadb62883a137cdc2c92a26813308869a7e058c472b1f37d0a7db811a9d9702f804877a5bcfda6966460f423486683f3290f0f7fc56a113cc11cfcb1f114d09f349131cc7867159ac69217333dd8f682bd6149602b1fea51570ed72c6b6fc22ef7e4bdaf4d2268a21c465186ddbd428e9120f29f5d82be3906948692ccf196558681d648a1412781deea871e776cd61ddf505af5dabcc5d4608c1cd3d38adb723fbc198b8cc197e2f1f16f5efc6e4e0fdae6e4d675d4f8b8a8c80a21038230e324f1934db31512f04cbbe3cfd348b716515d7d8810571666a00f3a7e3ad44de69401b9501f53bb2fd6405071d2242bc8080063163c9c33e2457f7c7ea4194d3a7ba0a86ca101c5e3aca405da48e64e7dfabe7defa89dfc56b71ccba3ee8b145092d7a2821fa2a6cec31c26b4170f14fc1ad6e7bbaf4e024cca988e62c2b8fd4807697b653a2a14d82fb83e51ab44ed50f814d80fb9e92c70fcd6f84fd1463ad1e415b813d27c2b7cea6d92a2070429f1fccb1714e60ce33535e4d2147f01601587c5cbe6723b14caff056b2c2a136d00d6b402431bacf30bd7ddcaa3d7f2dcc53c341296985a1383a1fd54752fbfee4afb1ab511ad00f18b46fabd05e7085152e359fadddf563e577951ae71e7376d471fa4551b4da7a414ab5a97ee548f8a9017718cd2469f6b0ecc190530a778fb700377957dee1fac42a5c85a7f18fdb7142de099a35472a40a047810930540bdb9869daf2c4f3e4b45c591c7ed0f3c3fa1cc156445c57bcf816e09ed864544e9edb014c1848c23c32382b5bb3200899f53cd62027a6c3c33d037a3bb85a42a917251856f16d27a4d0ad0a03bd0ac981799756d0e3887fc9e4d6c39a82913c08a026bc120022e8a314df0e2850c074207335dc211a503e586e3e05615b451d8d9414bb88d223df1a1d7beffabcc7ebcd01141496cb6d0ab2c2816c5b110c3d4f70a30d7890550cecd9da5d349646132fc0559a1a335d4b33ac15018c356de79072973f5d0055e8b2e05e1f2c576a31a8d8cf0efe288ee59b99b6a8f4c7e5603034bc26350582c842174cc211a3adf896b414135c073b1ea019ad10dc087bc0905ae85e10b40549c2cd50bf3487b507fbcd06652bd8d2c3bfc38c18e10c6bb2729652e80c3cb176d1feb466df525585a6cf87e62f67245583b44aaa84ef1c1e9c5923fc05807f6d50fa5b42bc17e081bb5561122fe545d77063ccdfb296948fb437a08f1047465a5b35c509b808ba449c9fc05d36f55add2110d71f9f85e93ab7bd1b64b16a7e87ef567b9a34806c96a055b2caae3ac0f5ef60b3543cb128b8c99639860b86460705ace9ca4fcb7e794dc101147e29f438fb05040e1ee73309a3404ef1c866c3a42286b429db28100682e36e0fba46572b305992a20dfaeec350eafd98da68f6ad0fed891ac9ea904005906ca386c578ac1e14cef7e005981522198ccf808b978607360a8d55b7930bd80b4755a74ed251b59f71182d32aee5a20910fbcd08851afc63e35a88c80785fd739fcc3c239c30609ec827c2cfece8a96d84e45f0ccb43ca9396db76c6469c21c0389c1723ab2979982fd9cf0feac19fbcfe453f3fea7c17f3ae0e060315a4b5fa82ed93779147f8b020a883d286f8dca83e60e0a21b6c48ac665840febf42ea51eb08e41f4e274d2d145c3435159280f762600c6a9677fac47a02283e45630040fc143733b6a64153dd762b54c88b47d6818120d1bff3a0a3dd1f37758f273c6d81f504a4e3cfa7390fe7988cf81b2a9170faa5b8f18710a432408389a5aaa8b44e20e613f2552ca6b4a6683490765e498460e6dc673a90a7386948c8be5f213f5437f15a4d3e5c294279a57add3c48148290def8490a0dd8f97b748f408b49eb2e085f572c03d181d2dcabcdba6772500916d4bf854719bed7c3da1a840008003a241b758f219ff76bc5514e0deca70441fdaa885737b5f3dcb24a2ca95bbc9b578c6297744216746977195e3306fd6235c64a419481aac91fd7d501a873f3095b76d8c5a7017a04a37b3550b024e9f3ffffffffffffffffff47e15b56d96f83cada2f7792241aa37d0b8b0a524a29a59412c31684803cce35d256c8c3bb8e089e078c07890709326336fdaf438972b69a4c5ae49e0e15ee143c26516e93eb8f137a4e8a5b1225d57c2353de4f64be638c2047b2e3034ef08844495b88c7b7dda5ae7523b161a71ef08044419986b633ddb9e4ffccc0e3112517f90fdbd76e6f18c98e1a337470c3e020b93123871888e6885b5cde4d532ffbbac4d693939abf6f3c1a51561125645c67e7850c6d470e12dc800723b4aeb38b4dcd130d22942427a16af2a8da6311c57c9f9d99e4f45044f1c4b7cf6665db4109135130e9b42e444b88289b9f9c326a8e3944595f4b6c3fc619f99b87218a257a2749d5991e8528df6b4c82690ff22044e92f7333ae5d3bff6ec3b0e028e13188e2268f6bf7d97ab5291a6c3a66182f3c04511e997d5d63796d6a1c38c6084449b48afa2464bcd8ba3372243810c3c65d8243072a80c006d8e00188524813cdd9c4a43149e27f286652faf42b33f99fac871fcaa3a967dfc4d0a6f6f3e84331a387ede8d314f5123e94477f8ea1bea26adea006bd9bf0d843c9da53db7aa710d1be1e8aa74d67d92c4276d00d6a302399c4c68c0cc135c2230fe5ecb99452c275748b060fe530e184763001e313bd3b14457b2a9943c90ea5b5d2e0392669aa4b9206db0c306ed4a80102234712865d1dca9a94d9c8991c5f34a543c1a48e25262549dfa0421a6c9b3ce65012af477fc442fc6395434147a3aa6997121b336c9864878e1935b031c65103e3460dbfe4c5b891712885ea98a4e1397028955242beabe720aa9b379447997acd4c5a3714466acc5b99243fc79c471b4a92a0e56f6b8270f3cb830de5fceb3c237b33428f56f05843613b7cb787d9b841c98d6183c48c6183e2a186a2696e49edef79a4a178e2246bcfa6ad316934d816058e869292df234c3c1327a9920e8f33143e368c5dc7353ccc50ea8cafd161ad3b951e77e05186a277fdc7ace8128392d4030f3214c6d574329563f2d25a12bc60060c3cc650f8d495399c4a0ffbd6430c05ad53b3124d06a162943cf00843316a9754923c4160b080c717cae19327af2a9bdf0a794193321ad3b89c32647874a19cceab37bd2d73b7c38592bcaec992ad2d94e4b64fdec42cd66e69a1589a846bf2af0c1d9e2c94e6c2b7543d59ebc73db0508c9a61f49a92951ff7b8424966107d92581d2b14d3d99aeeb7af4e237a54a1d899af32ddf31e54289ece26a612aace0f784ca114a234e4b5979c44939142f1dca4863a119f2dd3289424d9acf17d835028c724be8ad5c8f0d4d7134a4a66934f8ccc5251cdc30945937df32b161e359b24376a9c6d42c12c36f48d07934f763c98508acdf8b5bf138f251477631cf17184095a251e4a288b868e26a63081e1918456c7cdb65c67ddaeaa3de96c828e09dff9ae1c0918608861e33c9090bdad5eccac7dfbdee8f4eaea0da1043d8e501a53b725e892b5e3598e1d3ac6f03042926cd958eb5852b75704b5738f2e75e3a262313c8890f252dbc0630868a7eab686ccb7e8f5364f0b99c4e8790f2194d368683f2f411e4128c65e13e31fd46db29207100a264e640951e2efc9ffa254baa94f29e5f9a224c88f9bfb35fe9ab01ad08b92078f252f4a22324d373fdd805d946545281b616e757a6e802e9acfdc8d8d97b5f77c393f2ddbcefc373f8aa001b9287f9693acea64cd7dc245c1747b3acd27b728e8a0bbd4eac6f8e1c4162525faa235ec93babf16e5ba5056923c19cd8468511253f847116237899f5994c39b30e1419fd2392e8b729e9cc345c61033ea5814df94ecf9456cbed7b02829efded3127e45d1abfffc3727a1c4a82b0aaae34c781953035a51d2a004d127de6efa2f35801586fd9af67a2eada2b026e24ff7d4c8315145491293d6eb6f4c733e152539d7a3ca859566102aca213ac8ce289be4fd14c530f2f65d1d5394ee94fd8b124f4a514eb25e9396b558c6135214f5c4dcc97773d0cc26a32826e1ffe7f33496af8928caa622d3feeb9e92e492509484cbc6780f8a720a8d6625fb53f5ff44498a13c4c491393b833c51ea70254699cdfa7e27ca273f4288ecd21571a27025dddec56993d7d94441c8ea24972e4967d568a2649a5da3b6e9cbc433513c3bcf9bf194f427268a9f49c47fee1c4cd7972896f8e1da33dc4ccc96287d69b4cb3c6eb556a270e922f39f4f89926a9e9855f99328496221dce3d8660d5f1205f59d1fb4fa9b6df79128cac63d25c674ff690f8992583af595a78aaef58f287fdeeaf850fa7fab7744f1ed4c67d950df736a44f9ef63878769df51c2886258134b45958e4983165192a774f439318a285a083141d497b6a6135138b9ce5478f6294988287ce7745a3fe5bb7f88a29b2c729228a5cd3444c15635087da16c645c88f2ecfe69874e9e494b88e29aea34269e50b11944b9faa4e9646903045130ad8eb9ec5426cb0604c21c47768c1d44401445b46a45c96126bd3f14659492ca6d6333637e2867eb51aea6a64f69a80fc5ac9f34df667c289c5cf29d923d678bf650d630294b57c96659480f25e16272d096bd934d79d83aba67f0a4040fe57993bd46fc3b943dc7c75cdd4e6a47762849fe32abc9c43acda943d94c9031a8d734e51d3a14646d5a061572cd63e6506c35139360b2e9f45d0e7d9615d91ff58943c9f3dd97b02af6561f3894fed7e4f8382a23c3e70dc5bdbe9263f21765b2e386c288128349cb9b35b1d386727faacfd9222709da6143d163c5786776d650d820543f09631b6a5243c963a84feae301c5d8274f63ff7b0e3ec3a2f831a6df983d4a5bcbaf286752ed1f4f8adeabec8a92d4d1deea9e67a3645b51ca93414ef23c2b8a2745cb5ae8f25acf2acafea7be2a4df62aa9a2145ad673522a62e55494343c85ca52621e6554145409d2cb774748554f514c62ba18e5dd9572ad298a9d459aa8763b529394a25ca1849414c5f42749654aba47513a490eeac48a1dddb28aa2203d97eafc9a1d4dd45014bce73787eeffab4e4151ca0ea24bc917ef9cff4449a892d9224599afee89624993a3b99e3a5114dd63fee2a7f35a4e944528a1da26c8d6526ea25c194b29fb182337999a40767c9ef09acc44c1c424defdbb6b662d31515093f29b7e7bafe41265f112319f339628b8bf6909bb57a258a5abae846977d12951cea2ab4e6d492f3ac749143c83ac2bbd126a334aa294fa9fd91d4a5776188992fcc936d77f48144ec69c3256c8b0ed3ca2981d5b25ad4893543d471494984ebc26f51a51f6d7f4fdad49ed99c788b28c7a74f7d7f11e6f110531d91c36bf274f27459493c9e1257627a2b439cfafd498ac6f1b224a629fdce4f7df6dd90e51fcf09b57add33f313344393e79966caa41a9668528677f87d5a0448882e9f212547827b90fa2b8a2e413b1db9bbd4410c57893e4a4ea04a97307a2a0e49c04d75052c7c4f50188d2496f63657566f3d6c71fcaa2f2234583b823d5a0a1c375e01063467df8a12489f327b39c383145bd616c9820793148d0f8d187e29af8def25311a7278de34371bbe489e2d71b6f9a8f3d2417aeddb5258710ea1ef4a18772fea4475baa7ba7cadc2041810c19374872e4a1183baeccbd6bcc7c3ff050d8a47fbd3c7b6885bbb801138800021d400104d424f171074c34ee4b2e6cd63c3c3d49a3aceb4bfed2fcb04339f507216b27e44afa7cd4a114eae126a928b9a69be1830e4599d15837df7fe2836e74e0860c193a1294630c31747ccca11c4b36c838a34a12711ccaa1a04564b6c344cfb8350d361c33d26e7cc4a1203c97ad5e7929df60f201879224a7cce79cf119e9d8a1c3d8301a7cbca1207b4bf6a472fd254a38f07cb8a16032474d76d33ed332517203ff684341cbcb47ddbdea103234d8708481f073948085f0c1867287d8f2cee0a24db434d86c901c4a58a0868f3594d7376990262875a8a1285f9e94f60a258d8f349463dc35937e3526798e64478d1965627ca0a118f4096b6e265b9d60698d8f33143cd55b36e9ec59fd84393ecc507e93dd3c4bb4ef2bbc6172cc50dbf151867c634e4afbe5448c1d8e6ad848010964c848b3c4c639356e7c90a19cb4ecc931cce7071f632889e9393e457362285ce71699ac65bdbdfb0843a994fd7807a941be082de1030ca97bcb9abeca9e768e0afd3e42796b38ed1b3ebe503055be6fa5ae17caa31bb3bf34cc33d72ea85b1d9a976b2a339ee1d9bf262217f2b2452e14c4e68a79f2a4e7c47b081f5b28a7b19cddf0f3b6cce0d042d19438f310f2d49e9cfbc8424963d220ea39a5a712f38185e2be26316d5b0951de5ea1204a0e62a6448fa527b742f1e3c6c713834cb70caa42b1f395b9c8395921845458cbdaedb3763ee6dc33641053e2cc53288a785efb3dd13dad4fe1430a65d30c9b04b7758d7df21185a2094dfb7cd254f628d1c207140aa67774cc1c749cf03934d892496c188e8f2794bddd8369fbdc1baffa40008ef0e18462fbac4956b2a5d64a6df868427154ca67bfca3ca74f3e9850f6d09b4415d1417fb4747c2ca158e27dda34bdfaa783945092db4e6aaf4e3a4a4e7d24a198cc6390bf259bafa60f2414eb4388fddc9ba9178f60cdcdd8db7c8a7ecd969c3508e9a231f76184921c377f9ad71844bdfd499d18e9c6077c031f45287f165f553d39a7f5244458ebbcde354edb4d6c56cb9449b2c7ce3f2d750805b9f953dc0f21186ee9f5a56939df619a252831c23d548a093f82503875776992d6ef1c93f2fa03082599c413636dcc2f26bfbf2899d0d3252e3ffd4be88b92cadcb1fc73e9d18b628cc99b4dfa308718c98bb2992e93c6a3ef98977651eebcba4c42ce06fda9cac04317859131b6481d3f1705d5f5394b26a5bd6da6c19623d97123c145497673bbce69e477b66f51fe13e3cfc949d2a934e83d6c51924fe447354943f694b52809b393b9c46422647efa78d0a25862e4b8073d42b384b3287a9a51fbf74930c946e3218b72f80c22329eaeb933e90c8f5894e4ccb726316aef15c2a224cec426496f62e0f18a92b6d21aad4bcbfb9f68b0b9e2548d75adb1b157f7b4301974f6390a1ead286eec5c52751a3555db8315255b2d35b11d7c6309cb902143860c1945048f5514deb7f4b58386cf7c55519236bc97c63ed3a4e74868e0c06c0f1ea9d0c45c767fd26e29a1e21319262a4eb5e991ed14e55a931f7f737868ada628de9a3831785c0bcf4acfa314a99795edc855abb5958bea524a2eb7b649514eca2f4f14f5f7fd7514c513e369121f6563f4125114f7d724d7edb825761e0aabf6ed62ed2dd5c3957bd42ecdf9ebf6004549449f6e35adee95a94f14f4b68fc87bd913a53ec164c7f89b96f67974a298e3499e24a94cdd34f5e0843396a2b3b5d69db57b9ec37c10a6b2e4cde3193c3651147bd1eaac9ef5f1d34441999b38c946092e5f65a2f02a4a9d89a63df58a305150e24d9924caf2b4dd4b1457d6fc474f65818725ca49d2f944375147e80755a2141f06d9b5885d28e8f0b1c4f6b5225c604b950eea6e4447886ca1a0efc4524d89aa4965f809112d943a89126763b532c82046b2501ea545097af47cf0f8d10816f244ae503a31ae535547b906cd0a451b916fd949fe9cddaa4241281373f6a75cecc9a911a1423163d041f8e59b0c8d8dc814ca9dead5836f4c2a661f8e01810d1c46a450924a1c5daa63c86eef2f128592149f7b9f49e72250409da8fcbc1b039127144ec8efb43f53268bef358838a11c54376cadb22dfce4fb74d80a224d28c5f96dd257ad8930a12ca345f98a9ecbfc526219224b2855e56d9992f57137a44309e53b39dfbbebeec6e4632409a539cb8d95ed4a031124142dc6c6c4a4439a645ee408c5e49efc36f909a17519327084113142513f29d9ba4f877142a408e5ce36596e4afc44e6d400e3c6181d8810a174ade549098d7d8e12586408099ac924b1e4a858ad368808a1dca2e4df0ed2ebeb04458250d8cd75626536b398520408a54d6a5a6a1ee38c877e51f23897496f98cd49dcf8e2d24177923fab78da8bd2cb7878503df2a220c642f9d7a89a279177c175b7cdedaec7beca96c8b8f76f62367a66d34549923e66b11f5bcab55c14f38abebf7faa04105c947ed342e994d32d4ad7417d9a3a912d4a6a359af8a9a3a8f65e8b922094e8d12e1d1ef305428b5269d31351a23dc724348b623c1117bfd8e8263db228efe8941ae4db633035482c4abdf9e42c395ac9998345e52aabf57a351b9fc4986d1b5a73405e51d6fb1c5d7d733d2abaa254a6f337ba4168ff415a51b02c19db73c7b2dc130d36dd00082b5651dca0e4c47ac59688f61444152549eac9964174b693af1bd44845d9ad2417934c677a59396a24bb00082acae673823879fd7a3c3e62d80063c62994556bb34cebeecc35fd4d626267f6099ba2209b1bb489af69d3a468b0cda8811900294549c9498c1a17277cd0291a6c3b6ad8c0a103841465fd309a7ba356d505194561bde412b4f4c9a6af041145494cadc9c464110de285a22ce3a153af887f960e08288a1a7af2981c74e9f4f0139c6c6c9549ed7ba2a439dacc44f7d9ce9e4e9443adffe37cc5688f9c288e140d79f2d926cad164c5edc3b7fa9966180d14e428818d4403a600d144394b74ea7e0c8f5a4a32511621437b57734cba339828491f37c6f1de412e513eb99893c496246e9eee2c51769fcfee2d1b25084f258a994796f84dc24600a14439c96b2589141bedf124f6fc693b8ae5c7242092288b0825c42449982a71041289b289932d5b6594608040e211887d401c91d49e84ce9f411ac18852a6d2feaf729b4fa617518c19f724fe3c9cc6cd8128e24012b1b8e5c98ac97ee8cd76d75757e7078288d2499fda35a90bef1025e939ea6f860f5a259d23d9512319c410a89724b65d49d55d218ad5e96daa3f67dca5ea031042e096162f1a27977ad5a1d677377e9a990119048820ca7183525267bd4014ff4f8a88ce897e080288d276c969adae735e6e7f2828f121ae240b291a4f40fc501665aed53188ecf534481f8a6f1fa34e6d26dd8d83f0a17cf23753a60b597dd2c63a40f6507e734d9984d1a0ca4e18440f0593336796fdf49e54d401481e8a71f59946f99ca41a8303040fe55099e584fa78ed5b83dca16c96a14b122794d02446090b700c103bb8a943c9dc24ddbc01481dca551ea3c412cf47931e840ec564e235e2312e536b38009943a219c2934c3ae7d861cba114ba64fef02ffbb7a6381494bcf2a125f5084b131c0a7a54bbe8d1fe1b4a26e575c918e5deca7743593eab898e6e6b19426d309c1a99eff13be687d88086c9d778d588b99dfdc93179afdb33039035944eff7cda64c2ae3ea38692dd9f32699f84d6b9d3500a0f93c43e51afc56634144f9a2cb17f65994f3d43b9beb4c89cd46986f296ee97d954198afb692b3d579a24c21c206428e8e85a13f77792727d0cc54e1354cfb8d7206228ec55a5dee7141aff6f1040c25010f7bf9e6745580719228080a13c425e8c67d0f2a0c49c827c81f3d8a449c69bdcad05205e28f9c9606fe9d17736783000e9c2e1ed177e174af41c71a1143a9b3c3ddaf7848fefc8614ca0831743035ba8d6f44cc6f2d2b34c3e4965d2fe27a57d338816cafb5b9fd735a83200c9424998e8a5c94491b14e582889b12439e9870a7285b209d5cf491e9196ba8158a1a0266cfca609bd929f278054a12c42373ce898646c939d020815ca9f493d5509f3b08c755001640a25f9dce542072285922454097db5894259cfa4a5c858073d2728943e4db2ec689e4f9c3ca1e8a193b8716e449fde09a53f39fbc973d813d6a40925d1a4fd4f993c134a2a830e793f5a4241bd6ff436a8896795509225c9a7337a4935de27a1d4497d8e329edb4c1609a51913368329d16f74e80805cbd818d99e4666c70885d91c74c7247fb7668a5038f7faccfe5a26732294539d5a37193f43289fc818fcca1742f1c43cc9ec21f48e1c84725fe61032e4281da3204028a78f0a9522daa399bf2869b5fcee10f3ced017a54ddbd7224bf374ac17c5b21bdf924c8bd8bc28c8fa9cfcb2ccc72e526b73725d14b3aabc539c9bd0bbe7a2b849b0fbded01062745c94a4099e454c8931e7a96f51ea4ca6aab22ef5d7b645f994c92342a45d8bf2ae8612444c6fe5dab42846cb727953a799c69e45b94c6ef68e673207af65510c9b9448fb208312278e4512289b80d504f0ea1ee0c709269747e001266357863900edd031468e0204400767020a00c00e1d63a080000148c030638071c3d840800074e448d0182f460e1c09180100020000000020002258000874d4c061141080220040878e23830002303bcccb284000cc0ef362e4907100000ce0230139921a20b343c78c190b004000187000acb123070d1d361ab123d1c188929e7bfd54a121b4892ea2247bac367df40c225344d9049333c99df5949f86061b6f48224ab5bba3428fd23fbf69b0e900471849181a8288e4066284114612c601420e813576dca0c61b4207380a813576bc18618c316346024208518c4943995d29a124394783fb6c8cb330921c336e50e3677cb2831a6e3b6ed4401d376aecb051638c3323c70942068133662020441038c240612461182024105863870d1a3acc8c1909080144f104a59b4e6ddcd0edff508c9b3e7f5a277e4d1de287c269933ddac836e144a90f4591e639d477e6b7cff0a1147bb229a5491cb287c2fe750e6d1a4f875186e8a16082f69f66f542f250900d253f89c737df6b84811c8287a26ef668f2e5e8b89f3174ccf804032177408b0657dfb6157769b09d85d8a1246c9e929386b2ceab94032175287987f02493700542e85092499e8ca67459878fed0642e650181374295dfa674a189510220754ea86730f9ba49e43e2c0831038dc1b4c8618216eb8361c1b780da7066cbb4ebe523b34ef34b43adcc43e4b9698d4c0a860068e903414fb041d6d46941c652634943a97b42721e40cc5e4496f0e2aea56653243b9c4fffb2d790d29434976948def797acbaa1032ace9b1f3b1aabba76bed31296935cb69af4310328662be86099f21a457c78488a19cd6e1448c9019c4630f4248189693ff7027f5243d18cecf0ad3123337fb70550ddd151e9a902f1466b7d34c0eb28495db0b052573eab4576a7c947048178a1f729bccbba4d3308570a128a7d53655eb65d0d6168aa1327aae124f3cf6d742317d503b256859c98742b250b6133eff29e1cd7b5367582869b6d19a49facca7432157286cb052267b948458a1781dfba4b813bc66ec9d424815caa757712bfe5d1d46278450a1a4abdd2b1feec3ca1732059402cab8188444a1f8d194282e1e4ba89ea070c7b77edbbdb7e95b6b37087942f1bd3ff786adefa0cb4172433f9023d9f181048c1cc908f072243b6ac020c409c5dc9fecc3e8fc1983be09258f694ef0fd60196ac710269c17a333a7ea1ebb6174a5f679fd9574c81236440905fbcadcacd9bd5f67124a6abdc5367dda933e464308123c2f5b2fcfba6ab12a3165c99c0d8ae308031da1a8eea7be1bcc102394c418dadacee4fc26fb2214837658cbe7f4ef688710c164dc08194279b3daa6f9fb13975d88104c4648104c460d428070bf3819be88f4a22074b6cecc379f3b877851922588dc126ebc4f54bb3019ab0bc55c14d3f7c64c26de37944e041726e316262306115b14e47fee32c8275974915a742aaba26ab1b3dd23676aaef44e125a943e7d121a7544b734159945d962744d3ead0e3b7b4416e5d13de136fa936a9323b12879cedbd29f35115894ea4f4af55892899d0423af28955092f4deda7bfab5882b8a31526489a650da49b345a41505cf132684758615c58e514d461d39921d35ce089155943af97d12ab63d6ac9e2a8ada5572aa33a988a9a465c7fc6ab2115494b39f3c5ef2e3be7d34728a92bafa93e5459d74f59ba2185ea465da128d94a2dc6252fe97af59074d8414c590593637897f25498a8ca2e01befc6347bc8be58140539d7b735d1d34eac48288ab1f9611e9e93ecc6dc81a26cb29fe9e768b24667779f2829d1691b44c9bf7325779e286510d9142143acaaa813e5743b27e54ac8067ddf71a22027fe89aed8ef3651d0ed1f3575c9969b4a779a2809f93f4a6913ec4b27351325792eea6390d726785249f08219278860c264b8207289721a2145f67ccc1f4309cf12c59349375789c2ac78b07fffbc19d651a224d29324c83dbd22d3c59b444950bdaa21a6ba233a9e244cc645a2a444cf3cf1437589fad060d351430f1225192f83d4d89cf435748f28ac8d923fb9bbb4ec7b8e289aa66bfdbb11dea7c36b44412849ccf3efb04f1bc7638497de32f6eea5f9156a36c7e9e41b3d34d87a8cc822ca2f1ebf46bca71d19bb8b28a2a43232b79ffcc810494431b5cf6d9a701d340611238828df98778e31a14314edfecb4be486065b0d1d5d22862848dd7a4d6182bf9d28c981e3401029440b22842889d1f1c38ca9b69f3b887250c2996027c7fcfd494114ed3b735ef778b7a51488f2f9c7137f1def3a880051be7e91175d3a62fb8bfca1642faa2dfbb67ea4891f8a9f4de99252cc9318eb4369e3a5c6660bf1a1b0714a6c7151259ee42141640f2549ddebabf45dc93ea2076c4eccec5364bcca4a2fff838527d1e06642240fe5f560ef193e09ddd7f1803250e40ee5d5641d847aea9e5a237628e78fce2fbe89d4a118db4a088da374d77a113a9c32b7a3d6aadebade5ecea124263b9356747837799243c14cce617b7473d7e8c4a1a0640eedb9b5c13466e15038539f416daaf45afd0de57d137ddd4eda9c94541b226e28ac092583dce497614a6d28a9aa559e1cb5725a6743f146ec9bf8a05b43797c83ac7e9383ba5045d45030cba0a26aefd44da740240de5102bf53166b0cd49923b1d113414445e6b06f1ebe8da9ea1ba3bf59de48c7c113314536578fb9cac27a3d91b913294d47cbd2cdefc4c8f6690a198b995e974692f328692a8e739ef89416e438d88a1704ad60f5e240ce52c73f6159b3a2961eb0818ca56d523d6424730225f28c838fb590d197f9fb3112f14938f018790a8c3a65924485110044110c4300c0dfb241da313482010401e8c4523c1903c52977d1300818ae2e07828108c43c170381c464108c4300883300c032108c3300cc3109e54d901531cd68e49b2bbfccf151fb3dbd65197a84067fd4d31e6d913d993917fecb3bcf68d29bc9a06ec28cb6e727cc7a6731abf4d1b44b0432ca71da2f9362a51810d083a3b85db60241cf1bcf734d744b6deb9e4035a9b47dbaacb0eca583cf0d0ff8932daf14fbeb33e4f21a578facd2eb19c52bdc8b667358e972b4c7cf35d6aa03edac1d50f32579f2942a04ed4b986293f82f987cf8a55324c3d8f44f8ec4a41f477f759c661a6e1dbdf20fc750f902f48e58a8292b308ff13dcd74d0157b785c0f310c86f2bea808ad7ee7b2aa6a1cd697202c0f8949fba32b6452b568b08a06cdb4fe375e85b0df4bd53558e7a1434a8b9ce81559a905e74994592c4e9633db3d36e368fad313e8118be18f453f62285b9aa0aebd465284160c0e5fbef14225473ffba0295b10990ef0ad1228b7d3ca96b04fb74cc8fe3a6c21062d75130a7531399e6e1a5711b65fe17729c2e775fce9f66c4d1a6aa4ed86592aba897e309536530a388f062e26bc4c8fce41f0a7bc342e252f64b770d5b6cd0a5f28405d139c30fd688f378d647f67a707029fbc16167421c3d3f40e751a83d4b8f08a7103c4ff3a67c537dd9e296d85733cdcc3c4dee018ad003711b1d9f2c380a495e661f5cf56133ab59fea9760def8875fd7f62aa8afa68c8c1525bf0827ac187ef114f7a98abcfa667562c670ccb6361ec722a54187dc96aef32fc6ca8e5870d9fddcb8981a504fdf06bf7ee8c9bafcb67d2f1301d984a45cb8defb30403d9080c6f6ade89f8e0b56f3e8669e671ce6d7896d32ed20e59290d1d50e11d4fddda302fd1095324f1ede2acae0bd58ee5312c614c2a5d324ce46fcec023092202b8e3225fa125669d11da495cdd8a6bf051b20d5719300ed0ff2f7b2ff7731f9e8751033a564e6c71bdaf743025d0e1c8768ca601b440473161efd1ac1229e5aa2a782050d9be05d67274a531a6847afcc76e8b00b62d5328c63aea5487d3c3b9d4fa3927e56f88a4e9fe19c1ad1fee52157ee86593a62b2491efaab8656406b9035ddc21dfdd3dd9dc13c7ba257721684b2dc13372062d570d7934f506532b19bee1c9853a740b3aceafcc138c653c13b2a815be209c2781fbc8636c29244351d7c579d4fc90cc7d73ae8fbf9f1a012d72df0424106be49f4b421c5a11b672b86fce220b23e9ae02af2d5d02b8c416972b7fab25e4c3d83b67efc9ac88c0919b712150b922e412acfd2d8b5eaec9ae88b4b71a516a8879c8849010fc6da58e646f2acfe78f1f275cc221184480c8d4cffcd7b8b3b3d4852416a13cc98cf85a90c12a5b9a172cb1f220df1dccdbde35e0bcc41b3c6cd312fd08c9d217e2ab6441c8c4bdfcec03ff968483d32c156c29a6fcf08568e020ed3071c49730bcc4a4b02e22cf295a9e8a42014642345959bd38b4e601db843e4b19e65b851021b57a59e83d8d7224d1aa5317c44424da7d4e7d51b3cedc546629b6af1bf0744bea07b9353f689fa5f5655bac480cfda5a1f8c5780b48f21d50524794892927283c82ef4abef66ee7b010b9398c052b84b19836800cf883526ac091ac27cd84ee81320816098193d10e48098f28fbf21aa1223962ee0c2304f1282ba43efa01f1f09b375becfa1f105fd53a5bcc650ce89dc211845d3efc872afdb3ec0ad7273f83e20397588b8fc89081358b8333e65e3b200f7b84d24077643d91a086ac68291e37a7f1fca779be41f7e30088be9c8ef22018aeb3bd0fafcda89d6082c60c9b967356d1b4e95b330d63e0d084bb22f7fe84d1939fbf03c35416386bef204a3af3f645bd5aba9ce105b211f3319943cd37cf79f358f6151a639f9703c8266eecee8ed636d61074bfd048d86a56253b98565ddb246952de3f400d44b2cc870fdf8e389645266aca2d200f5e57b35ab3f3e26029468adec36da1f4d615366089852f764c43d4e99fe3d172ed6b6883043aea58934502464afb5fcc8b611ed1fc2b771ced8c66916673b98d5c7690bc5ee2f9f477ec14c889c3a14d72ef518971105796763a78a7c6cc5fe41d58a9c442322f9bd4e08a52091bebe1b1b365b02633c4065b406524963749df700585a1bd09bc9cbf74646a5c8e52e57709892f503df039a1b59d84ac4de3a3fdebf37c8d6a7600fcaa256f4772ae5d193937721fca565583d97f9c145e74074778582a23cb73a59b37db0f20b7a74c507eca2cf44d1596f19c28539c612d9a1d1fc11b04865d4dd731a18f1a3201473d3a09018e9a579db94ec868347fcd482fa8952272410dfd967b9c55409792e2784a68dfd43b84a4fae5b4437b37ae404f92536ba7bf3931080f9dc08ce2433aff4864277136763314fd509aa8dea8d871634e3f6607648e98d8a52a42653cd377ca069618e7e72c92b7b44fbd753cdb5d95baed0aa34127bbe193ead62016950f33f93d9c94d4cf69b388f89dbe54d04c82fd371e45239e15a22dcf9b604ca7e0a130a5095d384afa3c227a877a5172969a3484a6bb58b43cb3229ff939532962a0c53e504ddda01ac09f941602a882e6391852b5746e48e512263048092533820ac71cdee994f68816cee7a0a9243b04c7c98fd0ea1293013f977a081a1a0e2ef4d1f980405ee31af6a08e8732bde6558d70ae25dbd7b97e5ab9b1b09e63a2313e972a342580d06933e0c63670ef06ae7c6e33ec6ae2d9ba66405071f92e28c514f9439931f55a01d039ad620566eb16fc0241859c844c31970189200fe90b66fb58079be224d10c40080e02fa68c5ffdedc4e7aa6ad1b3bc3bbefe1b5aa46dc640c24915c8a75a52511453a21793e49cf7970077a9c756106f3c2450cc18ab2d8de43b609e6b411fd4daabd294d4ac9278d99a30a290523674901563b34998c3d55a43f12380d081a1540e51fd26631962ff6428aa4327d88ebf1153b59e4c7a185cb4482e218ddd447aa8508c691b5560a95bdb1937684ca1c41fb43928bceaf854af2e8300fc63a3a7c58bf43d5dfbe8a16773453b7c23066221b1dfeccb83647352cf210eb50b75b1851ad6f297666e00f62200de83e2d12adf5b65d1423fb11b646525d976b6bbe67ec4a7f39a37d7c2be2b9ea244645d264d686096f6cea565718d578fae49cec69938bdbbf5df535f8c54c5597e839ec780ab73fe35a71ab34d0f31162845e16eddc128e127728e3722c9e7e78fa11bd68406a52629f63494aa39e08deff566c73fa0f6424cc839f974be5efd8b420f41f672d3c2c6204c05346b44d9854bf4281e6daf6f9bf70250c0266573298f25a9395a0b09ff1ac63ff5c59d877475ecac6c80a2258e064e7a6359f1760c8d0e3d35233788ea421d10438282e5c32d2e0820aaf6adda2445708c8f390e5e49633298376dc134818f4187aa32ae4c09d55fd3e13e874728a62e268f5f9a2f3d8c35ba6e6c9274640b6021f5977897c11298964c1c6e28fa2c14a344cdfd2cdc354fca5996b8ec46fd292660dd920303cf0780274e129e56c53f9a411cdd27904cc5128965ea07ba4845d144041966d66b49785f5ba5fd34d5e8ae745b01211ea835a2628879d90a510a4be77faa5f2b728b8a24db94b04e6f4d96cfa60baa1da8460c19fb2edcf2022a6a24983e2e3e3fc7b9e4e031699d91780e5a5262fbd362e4b1af4a58f76e2b1bcce111597a6a488d301d252f005d8947baaeabf7c261bc7c11134067ab13908b7d91c0eddf1298c24b96856baadc794bd394de3f40d80ba99c5c9ab1886b6f591775364e34de5b48c92b92adf384339480bdcc47a09ea61b6d5afb0b64613740c2a5b854330212456b149a4203f50a09411025a80c7752b5ed841d422ee42ad5a0dff7c6b5fa91e6a6e8d67e5b5f435efd09dc864cf8097305e15d38acaf96df4b7031a4b1be54746c7b2d7b54de35db6639336851f7a774e6a1020e60f21953a15b07add0dd3834656894c6188c4c7193364d6223c2875934fe605e6370e205094544477389547fa7201e908b7052b79a01833e6a18c1e2b23bcb532ed4fa416fe76886ad88ece9cc09588072891887d13023069f5b856c6dd287773ca34e2c45e165b4d4397c564c936b921e2361f2edd1aeeb2093318ed283ee4d262b8669cfe661edbc1a1f6a5d39bb9308aefdc9135fc0615670c8e8f23b750cc82fe7560e056f2124479f8e6474fb7310d18fc4d29ae61a2cde39dfdc8ef29b6c9bf4c1a866da7ecaf616a2104a3c3b824e3861f773230a521d2bee9af980d3a4630c554bf2bb4309052206be2049cdaf15aed6c8feed9ea56a55550368f9adb4a53ae6c3379a8085b1ed17450dc3127487d5fb9cbcc1200155ad94cb37e5030cd928108921c944520b4450a4b82aafcc677a5a490f8c84099144c1a044ebb9b76fcc159a263ef9c75860532d713314cb57853aebcd25bd2074f8946addabbdb15d1903ff52dcf8e1dd8076e711cd9237f7c3673c2de210cf4672d914ea2e2efc57a5cb199edfc192ad36dda00caa7c426ac8b131d2b7e0a2c2ee8a3095b97591231b55bb974667af3b9225a36d191354541fa98badd787686338539b6a6880dd7992310ffc90c4dd5be5f5bd2c3c1c3ba0db02e22494a446df93780ce45550f6119bf6e6a33d7b833ecb3b8211311748c733024e289145f0dec880b0ebfa1573a1c6526277683d0d86d7928c373f1f97665d916d317511c6ef8db27a99a958293aa5c47600dc003861fbff5a1b97cf76ff922781f3b74fa0fe677e1ef128a2027dc3da69686f7225107d274c7dcdca3dd580c79f773b6839a751247f01feba42dacb05cd07960f713976aee5ca18bdb05085d2a03a9e9cb9e7476e5b9ebb5a93d38c6fe07b26e34af1d81ecce38ccd9f1a4a811b359b14252796275f12321682b20549dc939e3e156293499c41c2c2e3557c42e46eb4a1daacd8f4c1b7ce9d50a56faac86fdaadae12d44a8f138b71efd23bc3e04671e2f68220083b2106308c8b2dab80cb4a6b913a2af0e39bdeabecc7764016f34508114e4abe4a86c9a6f1f46602ff100a26a0097862de080b0420fccea6c2dc1b50a3494cc1abeb3f8fd1d6346c9318ec1c5e168c0ba45b5d67928bde571bafee3b9c1ae72c79513cb39d24425d8be2f6ea43ed1c202237de76bac3a40f28adaa60f9f75e625408f3b3d61a2aae695c5f4c24d276f33b84c1a454d812c350e7244ed058f103559150b1cc226c26136477569a22029139d031734f609fb2ba049bf0da2b838945a92862aff9e98dca628db37907111473c662e0f09f2290a705ae242143408ce3cfab191243cd5c0882fe0671758f4942401b44afdb7b11a1a070264bcca0c8b151a31f82354580ae2a8a1b31b02049c3dba14f72eba401ce4c1163ff0e4a683c8185fee78221cbcefa001c8415a96792b86a9e4e03923b818d353d440c639de2961ea847fe7a3d10ad74e475631f2c60cba805416ec599415a8c7c8dc883792ad06514a2a6b6fd97e6ac7d8512ac2ca6ea1a2ff95fbeedff0377ac8f327da4253e02226d260015fc2c061735435944a53b11dc5e8388733fea4ebcd43aaf55c9c1441c1119aeb1a0963676325d8a01af5835b8397c68333402d8d64e916ac2b1dc8060c4a22e2daebdea594fc95907918bb68108db9cec9d428ed285e95415dbcea30f915622427b2e461ced76768871bbf41a95075c309a15591807f2f365c04a3914c70587986e8863321d7d8d8333f710e329c4f28c3b9aeb8bd511dd2caf47b0f7c123376a7505fb93a41132f792fdf08251e8ea7ad4802af0e84c8f4f80e90670d07647fc600443b1a16ab464761c073ace92630ee7e01c7325b35fa99677d15b883a33cbeb4a7b275589d8d00488e1fa5e86594a27abc608b9079493855c729c5715c83a41b00e08c254afb34740b91fc6b0dcd977f53121806ab8439a8d69159930966a51297f1989904f258fbeda8bca88ccaf3db83fa7f77b3309bc450b3fab8db79eb2df3c7ac3415e8760b34fed16b73406da3858cb4003dab3388222b230ead36a44e5600e88ef374b934f09374acfa451451a573753827e20d9cc33adf20e291ebdb7001228c8b1d72ddd087fb3e9a96084b515acd2c0130801502f5ad3435c9f744c5ecb001623939cd1cc0f0ebd8683c203a1ee2defb15be1cd9caa104d853691d85649804711b41d121d0bc4b2c743dd986225f2810a15e79f6b0834b56fe8578d248c2796ce4a7f968df709401d10e98b637254e1a829109c03091a090443cb0c80f58eaa4636da7aab125368b83e5c33f0fab78433f5b3936bc1b61dac97efbf9f17430bf4bc756fbf69f4565331f3561b96afe5144836791f4022c9972c255780e547c2d93479569ac6b58a2942bc793725ea337b4e3e784040da50280443462fde0d31a8e54b0236413865190d5b855a99f60881285004c46ac2de2d3305337f988a905947073cc58339942b8ec9439667a5defb0b1338eb83e9a920b58bd432d310f4004c6006d0a6f52c654aaa83f99ef5912d30b5557bf1c381d2c8ef4628e1909276fcfe2933a074de21fa97798a50bb6b60a9d0fcab6fde2f632d92b42532e27e1c659fdf1393e5fa3f37f2072bb70c82e1fca566317a124c6aaae3ce6bbeabb175f455fdea6002edcf4eec85b16594f3205d778f1089d92a8c643a5350872cf38822cf1852c4b67e2681d9bf2a273c244482f8e9fe4c4635f98877aa549a8744d805f10441e021cd8cc2cdbfbb6ab040a064ae6a967a0d356cdd8e0f2dcd63180133616cc6026c19f58f22597306c40a6419c151a90176483f8e901d306d4333d04ea242526828da1f990a0e78b69dd475bb86e5818d15db1f11fc4c248dd57a86e2aa47b4a27867a717edb98718efd9afd8058d2c020277adb43d28e83ad8a13187754c4beda84cbed5880044bfee0b057e2e10febb58d45533f60f9c12010db025bb83708d3758efbca7145740ad146b2112f0002b9a05820aee3f57e81f68cff66173cce337f87b1faa4e23ff21a1f2a9a8adb4203e0ccc100c31334e0cd25213513621ba5d9be66ee1d51c77313b54e42059bf17d1a47a202d131b1c84b2e17b897447c448e1b45bc9e823971b4939952b4784a3637e1562859109eab2925e92e9e822fa81444a1cc6cf0f91c61c200b4e8e8a340bbea4fb46c12fb8b42ba142e4bcd7c064f1b3dfde712bb79adeb962239b98dc782a06796054a28bc510187d6159bba04678497a704119b7807fc4ef74fca1e76fa59951adc9b753f997538eec81c15a6acac8d20671c2a4f1bef1440bcba0addfdabb871c1675455e8f4753400be43f3a5567f7dcfd4a3953ff129e3534018f9e0d44e601daf6ef514b9bf1eac47873e3007bf8b9a67558c0c8b5f623429b141990018f5c825113b95072845528663bac065b887507be1368b3c7854ae8050a6a455712a8e4509c8d516feb32535a2f216d184b6cfaec76d88d46aca1bda70be770b9cf5204a3382ff728a63a8baa942b4b04982610dc87ea146e7cdf8c19a51617df128aeaf64a2f304e845903ee1ee54b1c1027e056ef630fddd27bb695106da302b2f3f2b6a46928cff3aeea9c3d0a1c7fdc2d549cea6ce71d3e7da0e4afd8548f8d85d6557e16c3d9a77cda9ca45d0724162de0796a604cd9747d0109200a3581b2f2517ffe0b0e545e5d0505c1c3f33d356bc108774487c6420665e571f8e4c11a1b2b003607bc59299cd05b9fc2646d2bbcf4c1da0e2ab4e6c400212945b0f8d1e6226eed4420dd4b21a3b07c756db8e0ff940ad730cac56ac89d5a495a36fdb31952b00c0719ff05760674c00cc2b79c036bfe9c38555476233c3774b9629ff0ff299ca6bdd614ebe186eff8571f92eb013c55af3cbe929391151870a499b188020ded2b55a2b17b98695211e", "0x3a65787472696e7369635f696e646578": "0x00000000", "0x3c311d57d4daf52904616cf69648081e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", "0x3c311d57d4daf52904616cf69648081e5e0621c4869aa60c02be9adcc98a0d1d": "0x106c97f53e386c97a7217d23e3412bd98a37ebbd0574c2ae95de296548523235144217f1177620148602f0ce7e4787643f6da946b7c9390422b5b16e8f1745e8799046c7d25f9bc688e9523897ebd59fa7f3b0d44198a0bc6c88a580aa9b3ce67d324ff4d0173ef7f6e75e06b0151998924c1c7b8704f80f7afc3262018a195b4d", From b0715f9bd9f24758c132fb7dc8adcd30551f7de4 Mon Sep 17 00:00:00 2001 From: Muharem Ismailov Date: Sun, 9 Apr 2023 12:26:12 +0200 Subject: [PATCH 35/57] The Polkadot Fellowship import (#2236) * Fellowship into Collectives * cargo.lock * tracks alias * allow to send Fellows origin over XCM * update todos, remove duplication of type * use Collectives location for Fellows body * alias for ranks constants * benchmarks * proxy for Fellowship * docs * correct copyright date * Apply suggestions from code review Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> * rustfmt * remove council, update origins * renames * remove tech committee from promote origin * renames * Fellowship import * test * rename mod * fix import * updated addresses (only ss58 version) * update addresses * doc nits * weights with new api * update addresses * fix try runtime * update addresses * use pallet api to import the members * merge fix * hex-literal version * add Bradley to the 1 rank --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: parity-processbot <> --- Cargo.lock | 1 + .../collectives-polkadot/Cargo.toml | 9 +- .../src/fellowship/migration.rs | 261 ++++++++++++++++++ .../src/fellowship/mod.rs | 1 + .../collectives-polkadot/src/lib.rs | 7 +- 5 files changed, 272 insertions(+), 7 deletions(-) create mode 100644 parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs diff --git a/Cargo.lock b/Cargo.lock index 99d36d95246..034f09a5e0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1318,6 +1318,7 @@ dependencies = [ "sp-consensus-aura", "sp-core", "sp-inherents", + "sp-io", "sp-offchain", "sp-runtime", "sp-session", diff --git a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml b/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml index eca2c8caa98..3f5c956d454 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml +++ b/parachains/runtimes/collectives/collectives-polkadot/Cargo.toml @@ -7,7 +7,7 @@ description = "Polkadot 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", optional = true } +hex-literal = { version = "0.4.1" } log = { version = "0.4.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } smallvec = "1.10.0" @@ -73,16 +73,15 @@ pallet-collator-selection = { path = "../../../../pallets/collator-selection", d parachain-info = { path = "../../../pallets/parachain-info", default-features = false } parachains-common = { path = "../../../common", default-features = false } -[dev-dependencies] -hex-literal = "0.4.1" - [build-dependencies] substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true } +[dev-dependencies] +sp-io = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } + [features] default = [ "std" ] runtime-benchmarks = [ - "hex-literal", "frame-benchmarking/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs b/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs new file mode 100644 index 00000000000..5056abb2e22 --- /dev/null +++ b/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs @@ -0,0 +1,261 @@ +// Copyright 2023 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: &'static 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, &'static str> { + let onchain_version = RankedCollective::::on_chain_storage_version(); + assert_eq!(onchain_version, 0, "the storage version must be 0."); + let member_count = MemberCount::::get(0); + assert_eq!(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<(), &'static str> { + assert_eq!(MemberCount::::get(0), 47, "invalid members count at rank 0."); + assert_eq!(MemberCount::::get(1), 47, "invalid members count at rank 1."); + assert_eq!(MemberCount::::get(2), 24, "invalid members count at rank 2."); + assert_eq!(MemberCount::::get(3), 17, "invalid members count at rank 3."); + assert_eq!(MemberCount::::get(4), 10, "invalid members count at rank 4."); + assert_eq!(MemberCount::::get(5), 7, "invalid members count at rank 5."); + assert_eq!(MemberCount::::get(6), 3, "invalid members count at rank 6."); + assert_eq!(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; + + #[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/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs b/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs index 3b822d99073..22926d1d27d 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/mod.rs @@ -16,6 +16,7 @@ //! The Polkadot Technical Fellowship. +pub(crate) mod migration; mod origins; mod tracks; pub use origins::{ diff --git a/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs b/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs index c928eda49d1..6e53920201c 100644 --- a/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs +++ b/parachains/runtimes/collectives/collectives-polkadot/src/lib.rs @@ -45,7 +45,10 @@ pub mod xcm_config; pub mod fellowship; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use fellowship::{pallet_fellowship_origins, Fellows}; +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}; @@ -622,7 +625,7 @@ pub type UncheckedExtrinsic = pub type CheckedExtrinsic = generic::CheckedExtrinsic; // All migrations executed on runtime upgrade as a nested tuple of types implementing // `OnRuntimeUpgrade`. Included migrations must be idempotent. -type Migrations = (); +type Migrations = import_kusama_fellowship::Migration; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< From dcedafb847478939e8170939b4e3da39d5b89a3c Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Tue, 11 Apr 2023 10:47:51 +0200 Subject: [PATCH 36/57] Script updates for `ping-via-bridge-from-statemine-rococo` --- parachains/runtimes/bridge-hubs/README.md | 30 ++--- scripts/bridges_rococo_wococo.sh | 144 ++++++++++------------ 2 files changed, 76 insertions(+), 98 deletions(-) diff --git a/parachains/runtimes/bridge-hubs/README.md b/parachains/runtimes/bridge-hubs/README.md index 788e767f0fc..27df65c5ac5 100644 --- a/parachains/runtimes/bridge-hubs/README.md +++ b/parachains/runtimes/bridge-hubs/README.md @@ -176,32 +176,21 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ ./scripts/bridges_rococo_wococo.sh allow-transfers-local ``` -2. do transfer from statemine to westmint +2. do (asset) transfer from statemine to westmint ``` ./scripts/bridges_rococo_wococo.sh transfer-asset-from-statemine-local ``` -#### Ping via bridge -``` -./scripts/bridges_rococo_wococo.sh allow-transfers-local -./scripts/bridges_rococo_wococo.sh ping-via-bridge-from-statemine-local -``` - -#### Local Rococo:Statemine -> Wococo:Westmint -- check that relayers are up and running (see above) -- uses account seed `//Alice` - ``` - cd +3. do (ping) transfer from statemine to westmint + ``` + ./scripts/bridges_rococo_wococo.sh ping-via-bridge-from-statemine-local + ``` - ./scripts/bridges_rococo_wococo.sh send-remark-local - or - ./scripts/bridges_rococo_wococo.sh send-trap-local - ``` - open explorers: (see zombienets) - Statemine (see `polkadotXcm.Sent`) 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`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/explorer - - Westmint (see `xcmpQueue.Success` for `remark` and `xcmpQueue.Fail` for `trap`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer + - Westmint (see `xcmpQueue.Success` for `transfer-asset` and `xcmpQueue.Fail` for `ping-via-bridge`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer - BridgeHubRococo (see `bridgeWococoMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer #### Live Rococo:Rockmine2 -> Wococo:Wockmint @@ -209,15 +198,16 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ ``` cd - ./scripts/bridges_rococo_wococo.sh send-remark-rococo + ./scripts/bridges_rococo_wococo.sh transfer-asset-from-statemine-rococo or - ./scripts/bridges_rococo_wococo.sh send-trap-rococo + ./scripts/bridges_rococo_wococo.sh ping-via-bridge-from-statemine-rococo ``` + - open explorers: (see https://github.com/paritytech/parity-bridges-common/issues/1671) - Rockmine2 (see `polkadotXcm.Sent`) - BridgeHubRococo (see `bridgeWococoMessages.MessageAccepted`) - BridgeHubWococo (see `bridgeRococoMessages.MessagesReceived`) - - Wockmint (see `xcmpQueue.Success` for `remark` and `xcmpQueue.Fail` for `trap`) + - Wockmint (see `xcmpQueue.Success` for `transfer-asset` and `xcmpQueue.Fail` for `ping-via-bridge`) - BridgeHubRococo (see `bridgeWococoMessages.MessagesDelivered`) ## How to test local BridgeHubKusama diff --git a/scripts/bridges_rococo_wococo.sh b/scripts/bridges_rococo_wococo.sh index e5c19d3004e..d707dcfb3f3 100755 --- a/scripts/bridges_rococo_wococo.sh +++ b/scripts/bridges_rococo_wococo.sh @@ -161,66 +161,9 @@ function send_governance_transact() { } STATEMINE_ACCOUNT_SEED_FOR_LOCAL="//Alice" +# Address: GegTpZJMyzkntLN7NJhRfHDk4GWukLbGSsag6PHrLSrCK4h ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO="scatter feed race company oxygen trip extra elbow slot bundle auto canoe" -function send_xcm_trap_from_statemine() { - local url=$1 - local seed=$2 - local bridge_hub_para_id=$3 - local target_network=$4 - local target_network_para_id=$5 - echo " calling send_xcm_trap_from_statemine:" - echo " url: ${url}" - echo " seed: ${seed}" - echo " bridge_hub_para_id: ${bridge_hub_para_id}" - echo " params:" - - local dest=$(jq --null-input \ - --arg bridge_hub_para_id "$bridge_hub_para_id" \ - '{ "V3": { "parents": 1, "interior": { "X1": { "Parachain": $bridge_hub_para_id } } } }') - - local message=$(jq --null-input \ - --arg target_network "$target_network" \ - --arg target_network_para_id "$target_network_para_id" \ - ' - { - "V3": [ - { - "ExportMessage": { - "network": $target_network, - "destination": { - "X1": { - "Parachain": $target_network_para_id - } - }, - "xcm": [ - { - "Trap": 12345 - } - ] - } - } - ] - } - ') - - echo "" - echo " dest:" - echo "${dest}" - echo "" - echo " message:" - echo "${message}" - echo "" - echo "--------------------------------------------------" - - polkadot-js-api \ - --ws "${url?}" \ - --seed "${seed?}" \ - tx.polkadotXcm.send \ - "${dest}" \ - "${message}" -} - function allow_assets_transfer_send() { local relay_url=$1 local relay_chain_seed=$2 @@ -481,6 +424,56 @@ function transfer_asset_via_bridge() { "${destination}" } +function ping_via_bridge() { + local url=$1 + local seed=$2 + echo " calling transfer_asset_via_bridge:" + echo " url: ${url}" + echo " seed: ${seed}" + echo " params:" + +## // TODO:check-parameter - find dynamic way to decode some account to bytes: "id": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" +## AccountId32::from_str("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY").unwrap().0` -> [u8; 32] +## [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] + + local destination=$(jq --null-input \ + ' + { + "V3": { + "parents": 2, + "interior": { + "X3": [ + { + "GlobalConsensus": "Wococo" + }, + { + "Parachain": 1000 + }, + { + "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] + } + } + ] + } + } + } + ' + ) + + echo "" + echo " destination:" + echo "${destination}" + echo "" + echo "--------------------------------------------------" + + polkadot-js-api \ + --ws "${url?}" \ + --seed "${seed?}" \ + tx.bridgeTransfer.pingViaBridge \ + "${destination}" +} + function init_ro_wo() { ensure_relayer @@ -543,24 +536,6 @@ case "$1" in init_wo_ro run_relay ;; - send-trap-local) - ensure_polkadot_js_api - send_xcm_trap_from_statemine \ - "ws://127.0.0.1:9910" \ - "${STATEMINE_ACCOUNT_SEED_FOR_LOCAL}" \ - 1013 \ - "Wococo" \ - 1000 - ;; - send-trap-rococo) - ensure_polkadot_js_api - send_xcm_trap_from_statemine \ - "wss://ws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io" \ - "${ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO}" \ - 1013 \ - "Wococo" \ - 1000 - ;; allow-transfers-local) # this allows send transfers on statemine (by governance-like) ./$0 "allow-transfer-on-statemine-local" @@ -587,7 +562,8 @@ case "$1" in 1014 \ "Rococo" \ 1000 - # drip SovereignAccount for `MultiLocation { parents: 2, interior: X2(GlobalConsensus(Rococo), Parachain(1000)) }` + # drip SovereignAccount for `MultiLocation { parents: 2, interior: X2(GlobalConsensus(Rococo), Parachain(1000)) }` => 5DHZvp523gmJWxg9UcLVbofyu5nZkPvATeP1ciYncpFpXtiG + # drip SovereignAccount for `MultiLocation { parents: 2, interior: X2(GlobalConsensus(Rococo), Parachain(1015)) }` => 5FS75NFUdEYhWHuV3y3ncjSG4PFdHfC5X7V6SEzc3rnCciwb transfer_balance \ "ws://127.0.0.1:9010" \ "//Alice" \ @@ -617,6 +593,18 @@ case "$1" in "ws://127.0.0.1:9910" \ "//Alice" ;; + ping-via-bridge-from-statemine-local) + ensure_polkadot_js_api + ping_via_bridge \ + "ws://127.0.0.1:9910" \ + "${STATEMINE_ACCOUNT_SEED_FOR_LOCAL}" + ;; + ping-via-bridge-from-statemine-rococo) + ensure_polkadot_js_api + ping_via_bridge \ + "wss://ws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io" \ + "${ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO}" + ;; drip) transfer_balance \ "ws://127.0.0.1:9010" \ @@ -628,5 +616,5 @@ case "$1" in pkill -f polkadot pkill -f parachain ;; - *) echo "A command is require. Supported commands: run-relay, send-trap-rococo/send-trap-local, send-remark-local/send-remark-rococo, allow-transfers-local/allow-transfer-on-statemine-local/remove-assets-transfer-from-statemine-local, allow-transfer-on-westmint-local, transfer-asset-from-statemine-local"; exit 1;; + *) echo "A command is require. Supported commands: run-relay, allow-transfers-local/allow-transfer-on-statemine-local/remove-assets-transfer-from-statemine-local, allow-transfer-on-westmint-local, transfer-asset-from-statemine-local/TODO:, ping-via-bridge-from-statemine-local/ping-via-bridge-from-statemine-rococo"; exit 1;; esac From 03763dd07777bf454fe1d21ea13b1258dcb7064e Mon Sep 17 00:00:00 2001 From: Alexandru Vasile <60601340+lexnv@users.noreply.github.com> Date: Tue, 11 Apr 2023 17:23:39 +0300 Subject: [PATCH 37/57] Companion for #13302 (#2357) * primitives/core: Derive scale_info::TypeInfo for runtime APIs Signed-off-by: Alexandru Vasile * parachains: Derive scale_info::TypeInfo for FungiblesAccessError Signed-off-by: Alexandru Vasile * parachains: Fix `TypeInfo` import path Signed-off-by: Alexandru Vasile * update lockfile for {"polkadot", "substrate"} * Adjust testing for the new API Signed-off-by: Alexandru Vasile * Adjust deprecated methods Signed-off-by: Alexandru Vasile --------- Signed-off-by: Alexandru Vasile Co-authored-by: parity-processbot <> --- Cargo.lock | 531 +++++++++--------- parachain-template/node/src/service.rs | 23 +- parachains/runtimes/assets/common/Cargo.toml | 1 + .../runtimes/assets/common/src/runtime_api.rs | 2 +- polkadot-parachain/src/service.rs | 20 +- primitives/core/Cargo.toml | 2 + primitives/core/src/lib.rs | 3 +- test/client/src/lib.rs | 17 +- test/service/src/lib.rs | 21 +- 9 files changed, 331 insertions(+), 289 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 034f09a5e0c..e20de817a01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,6 +372,7 @@ dependencies = [ "pallet-xcm", "parachains-common", "parity-scale-codec", + "scale-info", "sp-api", "sp-std", "substrate-wasm-builder", @@ -523,7 +524,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "hash-db", "log", @@ -2213,6 +2214,7 @@ dependencies = [ "polkadot-core-primitives", "polkadot-parachain", "polkadot-primitives", + "scale-info", "sp-api", "sp-runtime", "sp-std", @@ -3368,7 +3370,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", ] @@ -3391,7 +3393,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-support-procedural", @@ -3416,7 +3418,7 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "Inflector", "array-bytes 4.2.0", @@ -3463,7 +3465,7 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -3474,7 +3476,7 @@ dependencies = [ [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3491,7 +3493,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -3507,9 +3509,9 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "15.0.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" +checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" dependencies = [ "cfg-if", "parity-scale-codec", @@ -3520,7 +3522,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "log", @@ -3536,7 +3538,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "bitflags", "environmental", @@ -3569,7 +3571,7 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "Inflector", "cfg-expr", @@ -3585,7 +3587,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", @@ -3597,7 +3599,7 @@ dependencies = [ [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro2", "quote", @@ -3607,7 +3609,7 @@ dependencies = [ [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "log", @@ -3625,7 +3627,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -3640,7 +3642,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "sp-api", @@ -3649,7 +3651,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "parity-scale-codec", @@ -4618,7 +4620,7 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "frame-benchmarking", @@ -4716,7 +4718,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "frame-support", "polkadot-primitives", @@ -5570,7 +5572,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "log", @@ -5589,7 +5591,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "anyhow", "jsonrpsee", @@ -6088,7 +6090,7 @@ dependencies = [ [[package]] name = "pallet-alliance" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -6109,7 +6111,7 @@ dependencies = [ [[package]] name = "pallet-asset-tx-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6127,7 +6129,7 @@ dependencies = [ [[package]] name = "pallet-assets" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6142,7 +6144,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6158,7 +6160,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6174,7 +6176,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6188,7 +6190,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6212,7 +6214,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6232,7 +6234,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6247,7 +6249,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6266,7 +6268,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6290,7 +6292,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6308,7 +6310,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6352,7 +6354,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6369,7 +6371,7 @@ dependencies = [ [[package]] name = "pallet-contracts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "bitflags", "environmental", @@ -6399,7 +6401,7 @@ dependencies = [ [[package]] name = "pallet-contracts-primitives" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "bitflags", "parity-scale-codec", @@ -6412,7 +6414,7 @@ dependencies = [ [[package]] name = "pallet-contracts-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro2", "quote", @@ -6422,7 +6424,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6439,7 +6441,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6457,7 +6459,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6480,7 +6482,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6493,7 +6495,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6511,7 +6513,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6529,7 +6531,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6552,7 +6554,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6568,7 +6570,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6588,7 +6590,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6605,7 +6607,7 @@ dependencies = [ [[package]] name = "pallet-insecure-randomness-collective-flip" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6619,7 +6621,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6636,7 +6638,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6653,7 +6655,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6669,7 +6671,7 @@ dependencies = [ [[package]] name = "pallet-nfts" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6687,7 +6689,7 @@ dependencies = [ [[package]] name = "pallet-nfts-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "pallet-nfts", @@ -6698,7 +6700,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6714,7 +6716,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6731,7 +6733,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6751,7 +6753,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6762,7 +6764,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6779,7 +6781,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6803,7 +6805,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6820,7 +6822,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6835,7 +6837,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6853,7 +6855,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6868,7 +6870,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6887,7 +6889,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6904,7 +6906,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6925,7 +6927,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -6941,7 +6943,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -6955,7 +6957,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6978,7 +6980,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -6989,7 +6991,7 @@ dependencies = [ [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "log", "sp-arithmetic", @@ -6998,7 +7000,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "sp-api", @@ -7007,7 +7009,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -7024,7 +7026,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -7053,7 +7055,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -7071,7 +7073,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -7090,7 +7092,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-support", "frame-system", @@ -7106,7 +7108,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7122,7 +7124,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7134,7 +7136,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -7151,7 +7153,7 @@ dependencies = [ [[package]] name = "pallet-uniques" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -7166,7 +7168,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -7182,7 +7184,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -7197,7 +7199,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-benchmarking", "frame-support", @@ -7212,7 +7214,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7233,7 +7235,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "frame-benchmarking", "frame-support", @@ -7782,7 +7784,7 @@ dependencies = [ [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "polkadot-node-jaeger", @@ -7798,7 +7800,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7812,7 +7814,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "derive_more", "fatality", @@ -7835,7 +7837,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "fatality", "futures", @@ -7856,7 +7858,7 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "clap 4.1.14", "frame-benchmarking-cli", @@ -7884,7 +7886,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "frame-benchmarking", @@ -7927,7 +7929,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "always-assert", "bitvec", @@ -7949,7 +7951,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "parity-scale-codec", "scale-info", @@ -7961,7 +7963,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "derive_more", "fatality", @@ -7986,7 +7988,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -8000,7 +8002,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "futures-timer", @@ -8020,7 +8022,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "always-assert", "async-trait", @@ -8043,7 +8045,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "parity-scale-codec", @@ -8061,7 +8063,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "derive_more", @@ -8090,7 +8092,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "futures", @@ -8111,7 +8113,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "fatality", @@ -8130,7 +8132,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8145,7 +8147,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "futures", @@ -8165,7 +8167,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "polkadot-node-metrics", @@ -8180,7 +8182,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "futures-timer", @@ -8197,7 +8199,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "fatality", "futures", @@ -8216,7 +8218,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "futures", @@ -8233,7 +8235,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "fatality", @@ -8251,7 +8253,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "always-assert", "assert_matches", @@ -8288,7 +8290,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "polkadot-node-primitives", @@ -8304,7 +8306,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "futures", "lru 0.9.0", @@ -8319,7 +8321,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "lazy_static", "log", @@ -8337,7 +8339,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bs58", "futures", @@ -8356,7 +8358,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "derive_more", @@ -8378,7 +8380,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bounded-vec", "futures", @@ -8401,7 +8403,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8411,7 +8413,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-test-helpers" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "futures", @@ -8429,7 +8431,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "derive_more", @@ -8452,7 +8454,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "derive_more", @@ -8485,7 +8487,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "futures", @@ -8508,7 +8510,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bounded-collections", "derive_more", @@ -8606,7 +8608,7 @@ dependencies = [ [[package]] name = "polkadot-performance-test" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "env_logger 0.9.0", "kusama-runtime", @@ -8622,7 +8624,7 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "hex-literal 0.3.4", @@ -8648,7 +8650,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8680,7 +8682,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "frame-benchmarking", @@ -8774,7 +8776,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "frame-benchmarking", @@ -8820,7 +8822,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "frame-support", "polkadot-primitives", @@ -8834,7 +8836,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bs58", "parity-scale-codec", @@ -8846,7 +8848,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitflags", "bitvec", @@ -8890,7 +8892,7 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "async-trait", "frame-benchmarking-cli", @@ -9000,7 +9002,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -9021,7 +9023,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -9031,7 +9033,7 @@ dependencies = [ [[package]] name = "polkadot-test-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "parity-scale-codec", "polkadot-node-subsystem", @@ -9056,7 +9058,7 @@ dependencies = [ [[package]] name = "polkadot-test-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "frame-election-provider-support", @@ -9117,7 +9119,7 @@ dependencies = [ [[package]] name = "polkadot-test-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "frame-benchmarking", "frame-system", @@ -9873,7 +9875,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9959,7 +9961,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "frame-support", "polkadot-primitives", @@ -10206,7 +10208,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "log", "sp-core", @@ -10217,7 +10219,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "futures", @@ -10245,7 +10247,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "futures-timer", @@ -10268,7 +10270,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10283,7 +10285,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10302,7 +10304,7 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -10313,7 +10315,7 @@ dependencies = [ [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "chrono", @@ -10353,7 +10355,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "fnv", "futures", @@ -10379,7 +10381,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "hash-db", "kvdb", @@ -10405,7 +10407,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "futures", @@ -10430,7 +10432,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "futures", @@ -10459,7 +10461,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "fork-tree", @@ -10498,7 +10500,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "jsonrpsee", @@ -10520,7 +10522,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10555,7 +10557,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "jsonrpsee", @@ -10574,7 +10576,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10587,7 +10589,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "ahash 0.8.2", "array-bytes 4.2.0", @@ -10627,7 +10629,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "finality-grandpa", "futures", @@ -10647,7 +10649,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "futures", @@ -10670,7 +10672,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10694,7 +10696,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10707,7 +10709,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "log", "sc-allocator", @@ -10720,7 +10722,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "anyhow", "cfg-if", @@ -10738,7 +10740,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "ansi_term", "futures", @@ -10754,7 +10756,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10769,7 +10771,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10814,7 +10816,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "cid", "futures", @@ -10834,7 +10836,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10862,7 +10864,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "ahash 0.8.2", "futures", @@ -10881,7 +10883,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10903,7 +10905,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10937,7 +10939,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10957,7 +10959,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -10988,7 +10990,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "libp2p", @@ -11001,7 +11003,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -11010,7 +11012,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "jsonrpsee", @@ -11040,7 +11042,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11059,7 +11061,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "http", "jsonrpsee", @@ -11074,7 +11076,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "futures", @@ -11100,7 +11102,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "directories", @@ -11166,7 +11168,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "log", "parity-scale-codec", @@ -11177,7 +11179,7 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "clap 4.1.14", "fs4", @@ -11193,7 +11195,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11212,7 +11214,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "libc", @@ -11231,7 +11233,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "chrono", "futures", @@ -11250,7 +11252,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "ansi_term", "atty", @@ -11281,7 +11283,7 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -11292,7 +11294,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "futures", @@ -11319,7 +11321,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "futures", @@ -11333,7 +11335,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-channel", "futures", @@ -11814,7 +11816,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "enumn", "parity-scale-codec", @@ -11891,13 +11893,15 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "hash-db", "log", "parity-scale-codec", + "scale-info", "sp-api-proc-macro", "sp-core", + "sp-metadata-ir", "sp-runtime", "sp-state-machine", "sp-std", @@ -11909,7 +11913,7 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "Inflector", "blake2", @@ -11923,7 +11927,7 @@ dependencies = [ [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "scale-info", @@ -11936,7 +11940,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "integer-sqrt", "num-traits", @@ -11950,7 +11954,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "scale-info", @@ -11963,7 +11967,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "sp-api", @@ -11975,7 +11979,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "log", @@ -11993,7 +11997,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "futures", @@ -12008,7 +12012,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "parity-scale-codec", @@ -12026,7 +12030,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "merlin", @@ -12049,7 +12053,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "lazy_static", "parity-scale-codec", @@ -12068,7 +12072,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "finality-grandpa", "log", @@ -12086,7 +12090,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "scale-info", @@ -12098,7 +12102,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "scale-info", @@ -12111,7 +12115,7 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "bitflags", @@ -12154,7 +12158,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "blake2b_simd", "byteorder", @@ -12168,7 +12172,7 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro2", "quote", @@ -12179,7 +12183,7 @@ dependencies = [ [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12188,7 +12192,7 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro2", "quote", @@ -12198,7 +12202,7 @@ dependencies = [ [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "environmental", "parity-scale-codec", @@ -12209,7 +12213,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12224,7 +12228,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "bytes", "ed25519", @@ -12250,7 +12254,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "lazy_static", "sp-core", @@ -12261,7 +12265,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "merlin", @@ -12277,16 +12281,27 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "thiserror", "zstd", ] +[[package]] +name = "sp-metadata-ir" +version = "0.1.0" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-std", +] + [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "ckb-merkle-mountain-range", "log", @@ -12304,7 +12319,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "scale-info", @@ -12318,7 +12333,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "sp-api", "sp-core", @@ -12328,7 +12343,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "backtrace", "lazy_static", @@ -12338,7 +12353,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "rustc-hash", "serde", @@ -12348,7 +12363,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "either", "hash256-std-hasher", @@ -12370,7 +12385,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12388,7 +12403,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "Inflector", "proc-macro-crate", @@ -12400,7 +12415,7 @@ dependencies = [ [[package]] name = "sp-serializer" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "serde", "serde_json", @@ -12409,7 +12424,7 @@ dependencies = [ [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "scale-info", @@ -12423,7 +12438,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "scale-info", @@ -12435,7 +12450,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "hash-db", "log", @@ -12455,12 +12470,12 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12473,7 +12488,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "futures-timer", @@ -12488,7 +12503,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "sp-std", @@ -12500,7 +12515,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "sp-api", "sp-runtime", @@ -12509,7 +12524,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "log", @@ -12525,7 +12540,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "ahash 0.8.2", "hash-db", @@ -12548,7 +12563,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12565,7 +12580,7 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "proc-macro2", @@ -12576,7 +12591,7 @@ dependencies = [ [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12590,7 +12605,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "parity-scale-codec", "scale-info", @@ -12914,7 +12929,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "platforms 2.0.0", ] @@ -12922,7 +12937,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12941,7 +12956,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "hyper", "log", @@ -12953,7 +12968,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "jsonrpsee", @@ -12966,7 +12981,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "jsonrpsee", "log", @@ -12985,7 +13000,7 @@ dependencies = [ [[package]] name = "substrate-test-client" version = "2.0.1" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -13011,7 +13026,7 @@ dependencies = [ [[package]] name = "substrate-test-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "futures", "substrate-test-utils-derive", @@ -13021,7 +13036,7 @@ dependencies = [ [[package]] name = "substrate-test-utils-derive" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -13032,7 +13047,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "ansi_term", "build-helper", @@ -13159,7 +13174,7 @@ checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" [[package]] name = "test-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "frame-support", "polkadot-primitives", @@ -13549,7 +13564,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13560,7 +13575,7 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "expander 0.0.6", "proc-macro-crate", @@ -13690,7 +13705,7 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#7bbfe737a180e548ace7e819099dcb62cf48fa11" +source = "git+https://github.com/paritytech/substrate?branch=master#416b0f50bba519146ec7ea45a67980b45cd658e7" dependencies = [ "async-trait", "clap 4.1.14", @@ -14618,7 +14633,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bitvec", "frame-benchmarking", @@ -14710,7 +14725,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "frame-support", "polkadot-primitives", @@ -15146,7 +15161,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "bounded-collections", "derivative", @@ -15162,7 +15177,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "frame-support", "frame-system", @@ -15183,7 +15198,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "environmental", "frame-benchmarking", @@ -15203,7 +15218,7 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#dc230b323b5baeb9b4297430ed539b208d30bf6a" +source = "git+https://github.com/paritytech/polkadot?branch=master#dbae30efe080a1d41fe54ef4da8af47614c9ca93" dependencies = [ "Inflector", "proc-macro2", diff --git a/parachain-template/node/src/service.rs b/parachain-template/node/src/service.rs index 86d85f18faa..6fc04ef91d5 100644 --- a/parachain-template/node/src/service.rs +++ b/parachain-template/node/src/service.rs @@ -22,7 +22,9 @@ use cumulus_relay_chain_interface::RelayChainInterface; // Substrate Imports use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE; use sc_consensus::ImportQueue; -use sc_executor::NativeElseWasmExecutor; +use sc_executor::{ + HeapAllocStrategy, NativeElseWasmExecutor, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY, +}; use sc_network::NetworkBlock; use sc_network_sync::SyncingService; use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; @@ -81,12 +83,19 @@ pub fn new_partial( }) .transpose()?; - let executor = ParachainExecutor::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); + let heap_pages = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); + + let wasm = WasmExecutor::builder() + .with_execution_method(config.wasm_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .build(); + + let executor = ParachainExecutor::new_with_wasm_executor(wasm); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( diff --git a/parachains/runtimes/assets/common/Cargo.toml b/parachains/runtimes/assets/common/Cargo.toml index 7a795057cd5..69f56a2405e 100644 --- a/parachains/runtimes/assets/common/Cargo.toml +++ b/parachains/runtimes/assets/common/Cargo.toml @@ -7,6 +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.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } # Substrate diff --git a/parachains/runtimes/assets/common/src/runtime_api.rs b/parachains/runtimes/assets/common/src/runtime_api.rs index 6d060f22687..36a8df1271e 100644 --- a/parachains/runtimes/assets/common/src/runtime_api.rs +++ b/parachains/runtimes/assets/common/src/runtime_api.rs @@ -21,7 +21,7 @@ use sp_std::vec::Vec; use xcm::latest::MultiAsset; /// The possible errors that can happen querying the storage of assets. -#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug)] +#[derive(Eq, PartialEq, Encode, Decode, RuntimeDebug, scale_info::TypeInfo)] pub enum FungiblesAccessError { /// `MultiLocation` to `AssetId`/`ClassId` conversion failed. AssetIdConversionFailed, diff --git a/polkadot-parachain/src/service.rs b/polkadot-parachain/src/service.rs index ee5ae0572a8..000ebef80fd 100644 --- a/polkadot-parachain/src/service.rs +++ b/polkadot-parachain/src/service.rs @@ -42,7 +42,7 @@ use sc_consensus::{ import_queue::{BasicQueue, Verifier as VerifierT}, BlockImportParams, ImportQueue, }; -use sc_executor::WasmExecutor; +use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; use sc_network::NetworkBlock; use sc_network_sync::SyncingService; use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; @@ -257,13 +257,17 @@ where }) .transpose()?; - let executor = sc_executor::WasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - None, - config.runtime_cache_size, - ); + let heap_pages = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); + + let executor = sc_executor::WasmExecutor::::builder() + .with_execution_method(config.wasm_method) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .build(); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index bc00a655563..8429cd0d0d3 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive" ] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate sp-api = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" } @@ -23,6 +24,7 @@ xcm = { git = "https://github.com/paritytech/polkadot", default-features = false default = [ "std" ] std = [ "codec/std", + "scale-info/std", "sp-api/std", "sp-runtime/std", "sp-std/std", diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index d94224927dc..52770cdf716 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -20,6 +20,7 @@ use codec::{Decode, Encode}; use polkadot_parachain::primitives::HeadData; +use scale_info::TypeInfo; use sp_runtime::{traits::Block as BlockT, RuntimeDebug}; use sp_std::prelude::*; @@ -229,7 +230,7 @@ impl CollationInfoV1 { } /// Information about a collation. -#[derive(Clone, Debug, codec::Decode, codec::Encode, PartialEq)] +#[derive(Clone, Debug, codec::Decode, codec::Encode, PartialEq, TypeInfo)] pub struct CollationInfo { /// Messages destined to be interpreted by the Relay chain itself. pub upward_messages: Vec, diff --git a/test/client/src/lib.rs b/test/client/src/lib.rs index e50d4adf322..4008dca350d 100644 --- a/test/client/src/lib.rs +++ b/test/client/src/lib.rs @@ -22,7 +22,7 @@ use runtime::{ Balance, Block, BlockHashCount, GenesisConfig, Runtime, RuntimeCall, Signature, SignedExtra, SignedPayload, UncheckedExtrinsic, VERSION, }; -use sc_executor::{WasmExecutionMethod, WasmExecutor}; +use sc_executor::{HeapAllocStrategy, WasmExecutionMethod, WasmExecutor}; use sc_executor_common::runtime_blob::RuntimeBlob; use sc_service::client; use sp_blockchain::HeaderBackend; @@ -181,13 +181,14 @@ pub fn validate_block( let mut ext = TestExternalities::default(); let mut ext_ext = ext.ext(); - let executor = WasmExecutor::::new( - WasmExecutionMethod::Interpreted, - Some(1024), - 1, - None, - 2, - ); + let heap_pages = HeapAllocStrategy::Static { extra_pages: 1024 }; + let executor = WasmExecutor::::builder() + .with_execution_method(WasmExecutionMethod::Interpreted) + .with_max_runtime_instances(1) + .with_runtime_cache_size(2) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .build(); executor .uncached_call( diff --git a/test/service/src/lib.rs b/test/service/src/lib.rs index e34237d1017..5b38a53afb4 100644 --- a/test/service/src/lib.rs +++ b/test/service/src/lib.rs @@ -21,6 +21,7 @@ pub mod chain_spec; mod genesis; +use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; use std::{ future::Future, net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -184,12 +185,20 @@ pub fn new_partial( >, sc_service::Error, > { - let executor = sc_executor::NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); + let heap_pages = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); + + let wasm = WasmExecutor::builder() + .with_execution_method(config.wasm_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .build(); + + let executor = + sc_executor::NativeElseWasmExecutor::::new_with_wasm_executor(wasm); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::(config, None, executor)?; From b4a50e2775a62c91abc69ba9f8b868bc53c5a926 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Tue, 11 Apr 2023 12:47:06 +0200 Subject: [PATCH 38/57] use stable rust toolchain in ci --- .gitlab-ci.yml | 2 -- scripts/ci/gitlab/pipeline/build.yml | 2 +- scripts/ci/gitlab/pipeline/test.yml | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 449d32a993a..2e0f6330d70 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -109,8 +109,6 @@ variables: - !reference [.common-before-script, before_script] - rustup show - cargo --version - - rustup +nightly show - - cargo +nightly --version - bash --version tags: - linux-docker-vm-c2 diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index a60ef29c9a0..e512c9e7f74 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -40,7 +40,7 @@ build-test-parachain: artifacts: false script: - echo "___Building a binary, please refrain from using it in production since it goes with the debug assertions.___" - - time cargo +nightly build --release --locked --bin test-parachain + - time cargo build --release --locked --bin test-parachain - echo "___Packing the artifacts___" - mkdir -p ./artifacts - mv ./target/release/test-parachain ./artifacts/. diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 765a80b7b60..5bafe970fbc 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -84,7 +84,7 @@ check-rustdoc: SKIP_WASM_BUILD: 1 RUSTDOCFLAGS: "-Dwarnings" script: - - time cargo +nightly doc --workspace --all-features --verbose --no-deps + - time cargo doc --workspace --all-features --verbose --no-deps cargo-check-benches: stage: test From 4733416e083781b4069dddc95c1352cb3b636643 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 10:03:14 +0200 Subject: [PATCH 39/57] Bump syn from 2.0.13 to 2.0.14 (#2446) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.13 to 2.0.14. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.13...2.0.14) --- updated-dependencies: - dependency-name: syn 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 | 18 +++++++++--------- pallets/parachain-system/proc-macro/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e20de817a01..54c8dc44ffe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,7 +428,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -1224,7 +1224,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -2121,7 +2121,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -3771,7 +3771,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -11613,7 +11613,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -13089,9 +13089,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" dependencies = [ "proc-macro2", "quote", @@ -13208,7 +13208,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] @@ -13379,7 +13379,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.14", ] [[package]] diff --git a/pallets/parachain-system/proc-macro/Cargo.toml b/pallets/parachain-system/proc-macro/Cargo.toml index 170372eb2b1..9312575a05b 100644 --- a/pallets/parachain-system/proc-macro/Cargo.toml +++ b/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.13" +syn = "2.0.14" proc-macro2 = "1.0.54" quote = "1.0.26" proc-macro-crate = "1.3.1" From 5a0ebaddbcb48820d60bd198124448e1e044458d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 10:04:29 +0200 Subject: [PATCH 40/57] Bump serde from 1.0.159 to 1.0.160 (#2445) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.159 to 1.0.160. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.159...v1.0.160) --- updated-dependencies: - dependency-name: serde 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 | 8 ++++---- client/relay-chain-rpc-interface/Cargo.toml | 2 +- parachain-template/node/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 +- polkadot-parachain/Cargo.toml | 2 +- test/service/Cargo.toml | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54c8dc44ffe..85596ef1e8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11598,18 +11598,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", diff --git a/client/relay-chain-rpc-interface/Cargo.toml b/client/relay-chain-rpc-interface/Cargo.toml index 85f78b199e9..42984d71e8f 100644 --- a/client/relay-chain-rpc-interface/Cargo.toml +++ b/client/relay-chain-rpc-interface/Cargo.toml @@ -31,5 +31,5 @@ tracing = "0.1.37" async-trait = "0.1.68" url = "2.3.1" serde_json = "1.0.95" -serde = "1.0.159" +serde = "1.0.160" lru = "0.9.0" diff --git a/parachain-template/node/Cargo.toml b/parachain-template/node/Cargo.toml index 5bdeffa1541..90e522ee17e 100644 --- a/parachain-template/node/Cargo.toml +++ b/parachain-template/node/Cargo.toml @@ -13,7 +13,7 @@ build = "build.rs" clap = { version = "4.1.14", features = ["derive"] } log = "0.4.17" codec = { package = "parity-scale-codec", version = "3.0.0" } -serde = { version = "1.0.159", features = ["derive"] } +serde = { version = "1.0.160", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } # Local diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml index 7a08937cca9..00a9da0103c 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-kusama/Cargo.toml +++ b/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.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.159", optional = true, features = ["derive"] } +serde = { version = "1.0.160", optional = true, features = ["derive"] } smallvec = "1.8.1" # Substrate diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml index adda06b0b3e..86bb0780027 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-polkadot/Cargo.toml +++ b/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.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.159", optional = true, features = ["derive"] } +serde = { version = "1.0.160", optional = true, features = ["derive"] } smallvec = "1.8.1" # Substrate diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml index 04aefe39ea3..2efdcfd8263 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/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.17", default-features = false } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -serde = { version = "1.0.159", optional = true, features = ["derive"] } +serde = { version = "1.0.160", optional = true, features = ["derive"] } smallvec = "1.8.1" # Substrate diff --git a/polkadot-parachain/Cargo.toml b/polkadot-parachain/Cargo.toml index b4ced899f25..fb53c92b375 100644 --- a/polkadot-parachain/Cargo.toml +++ b/polkadot-parachain/Cargo.toml @@ -17,7 +17,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } futures = "0.3.28" hex-literal = "0.4.1" log = "0.4.17" -serde = { version = "1.0.159", features = ["derive"] } +serde = { version = "1.0.160", features = ["derive"] } # Local rococo-parachain-runtime = { path = "../parachains/runtimes/testing/rococo-parachain" } diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index 5388b83e23e..062dbc834c3 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -15,7 +15,7 @@ codec = { package = "parity-scale-codec", version = "3.0.0" } criterion = { version = "0.4.0", features = [ "async_tokio" ] } jsonrpsee = { version = "0.16.2", features = ["server"] } rand = "0.8.5" -serde = { version = "1.0.159", features = ["derive"] } +serde = { version = "1.0.160", features = ["derive"] } tokio = { version = "1.27.0", features = ["macros"] } tracing = "0.1.37" url = "2.3.1" From a9a6c30b82aeb9e8f00c527a2eb26b0172bab8c4 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 12 Apr 2023 10:55:29 +0200 Subject: [PATCH 41/57] Added `transfer-asset-from-statemine-rococo` --- parachains/runtimes/bridge-hubs/README.md | 2 +- scripts/bridges_rococo_wococo.sh | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/parachains/runtimes/bridge-hubs/README.md b/parachains/runtimes/bridge-hubs/README.md index 27df65c5ac5..de00813506d 100644 --- a/parachains/runtimes/bridge-hubs/README.md +++ b/parachains/runtimes/bridge-hubs/README.md @@ -187,7 +187,7 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ ``` - open explorers: (see zombienets) - - Statemine (see `polkadotXcm.Sent`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9910#/explorer + - Statemine (see events `xcmpQueue.XcmpMessageSent`, `bridgeTransfer.ReserveAssetsDeposited`, `bridgeTransfer.TransferInitiated`) 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`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8945#/explorer - Westmint (see `xcmpQueue.Success` for `transfer-asset` and `xcmpQueue.Fail` for `ping-via-bridge`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer diff --git a/scripts/bridges_rococo_wococo.sh b/scripts/bridges_rococo_wococo.sh index d707dcfb3f3..fb411603b1d 100755 --- a/scripts/bridges_rococo_wococo.sh +++ b/scripts/bridges_rococo_wococo.sh @@ -593,6 +593,12 @@ case "$1" in "ws://127.0.0.1:9910" \ "//Alice" ;; + transfer-asset-from-statemine-rococo) + ensure_polkadot_js_api + transfer_asset_via_bridge \ + "wss://ws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io" \ + "${ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO}" + ;; ping-via-bridge-from-statemine-local) ensure_polkadot_js_api ping_via_bridge \ @@ -616,5 +622,19 @@ case "$1" in pkill -f polkadot pkill -f parachain ;; - *) echo "A command is require. Supported commands: run-relay, allow-transfers-local/allow-transfer-on-statemine-local/remove-assets-transfer-from-statemine-local, allow-transfer-on-westmint-local, transfer-asset-from-statemine-local/TODO:, ping-via-bridge-from-statemine-local/ping-via-bridge-from-statemine-rococo"; exit 1;; + *) + echo "A command is require. Supported commands for: + Local (zombienet) run: + - run-relay + - allow-transfers-local + - allow-transfer-on-statemine-local + - allow-transfer-on-westmint-local + - remove-assets-transfer-from-statemine-local + - transfer-asset-from-statemine-local + - ping-via-bridge-from-statemine-local + Live Rococo/Wococo run: + - transfer-asset-from-statemine-rococo + - ping-via-bridge-from-statemine-rococo"; + exit 1 + ;; esac From 030db02f876461c19fc617dd7899536881b4ca26 Mon Sep 17 00:00:00 2001 From: Mira Ressel Date: Wed, 12 Apr 2023 12:06:05 +0200 Subject: [PATCH 42/57] Invoke cargo build commands with `--locked` (#2444) --- scripts/ci/gitlab/pipeline/build.yml | 2 +- scripts/ci/gitlab/pipeline/test.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/ci/gitlab/pipeline/build.yml b/scripts/ci/gitlab/pipeline/build.yml index e512c9e7f74..e4678727e9b 100644 --- a/scripts/ci/gitlab/pipeline/build.yml +++ b/scripts/ci/gitlab/pipeline/build.yml @@ -65,7 +65,7 @@ build-test-parachain: echo "_____Running cargo check for ${directory} ______"; cd ${directory}; pwd; - SKIP_WASM_BUILD=1 cargo check; + SKIP_WASM_BUILD=1 cargo check --locked; cd ..; done diff --git a/scripts/ci/gitlab/pipeline/test.yml b/scripts/ci/gitlab/pipeline/test.yml index 5bafe970fbc..0ef51ae2e6d 100644 --- a/scripts/ci/gitlab/pipeline/test.yml +++ b/scripts/ci/gitlab/pipeline/test.yml @@ -56,9 +56,9 @@ check-runtime-benchmarks: - .common-refs script: # Check that the node will compile with `runtime-benchmarks` feature flag. - - time cargo check --all --features runtime-benchmarks + - time cargo check --locked --all --features runtime-benchmarks # Check that parachain-template will compile with `runtime-benchmarks` feature flag. - - time cargo check -p parachain-template-node --features runtime-benchmarks + - time cargo check --locked -p parachain-template-node --features runtime-benchmarks cargo-check-try-runtime: stage: test @@ -71,9 +71,9 @@ cargo-check-try-runtime: artifacts: false script: # Check that the node will compile with `try-runtime` feature flag. - - time cargo check --all --features try-runtime + - time cargo check --locked --all --features try-runtime # Check that parachain-template will compile with `try-runtime` feature flag. - - time cargo check -p parachain-template-node --features try-runtime + - time cargo check --locked -p parachain-template-node --features try-runtime check-rustdoc: stage: test From 8252d87105ff32a253a6f34fe221696e121b2ef9 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 12 Apr 2023 16:22:05 +0200 Subject: [PATCH 43/57] Finished scripts --- parachains/runtimes/bridge-hubs/README.md | 12 ++-- scripts/bridges_rococo_wococo.sh | 71 +++++++++++++++++------ 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/parachains/runtimes/bridge-hubs/README.md b/parachains/runtimes/bridge-hubs/README.md index de00813506d..3c9f86295f0 100644 --- a/parachains/runtimes/bridge-hubs/README.md +++ b/parachains/runtimes/bridge-hubs/README.md @@ -169,7 +169,7 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ ### Send messages (Rococo, Wococo) -#### Transfer assets via bridge +#### Local (zombienet) run 1. allow bridge transfer on statemine/westmint (governance-like): ``` @@ -203,11 +203,11 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ ./scripts/bridges_rococo_wococo.sh ping-via-bridge-from-statemine-rococo ``` -- open explorers: (see https://github.com/paritytech/parity-bridges-common/issues/1671) - - Rockmine2 (see `polkadotXcm.Sent`) - - BridgeHubRococo (see `bridgeWococoMessages.MessageAccepted`) - - BridgeHubWococo (see `bridgeRococoMessages.MessagesReceived`) - - Wockmint (see `xcmpQueue.Success` for `transfer-asset` and `xcmpQueue.Fail` for `ping-via-bridge`) +- 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%2Fws-wococo-wockmint-collator-node-0.parity-testnet.parity.io#/explorer - BridgeHubRococo (see `bridgeWococoMessages.MessagesDelivered`) ## How to test local BridgeHubKusama diff --git a/scripts/bridges_rococo_wococo.sh b/scripts/bridges_rococo_wococo.sh index fb411603b1d..55edd8dee24 100755 --- a/scripts/bridges_rococo_wococo.sh +++ b/scripts/bridges_rococo_wococo.sh @@ -1,5 +1,34 @@ #!/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] +STATEMINE_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] +WOCKMINT_ACCOUNT_ADDRESS_FOR_LOCAL="5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" + +# Address: GegTpZJMyzkntLN7NJhRfHDk4GWukLbGSsag6PHrLSrCK4h +ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO="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] +WOCKMINT_ACCOUNT_ADDRESS_FOR_ROCOCO="5Ge7YcbctWCP1CccugzxWDn9hFnTxvTh3bL6PNy4ubNJmp7Y" +WOCKMINT_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 == "$WOCKMINT_ACCOUNT_ADDRESS_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 == "$WOCKMINT_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 +} + function ensure_binaries() { if [[ ! -f ~/local_bridge_testing/bin/polkadot ]]; then echo " Required polkadot binary '~/local_bridge_testing/bin/polkadot' does not exist!" @@ -160,10 +189,6 @@ function send_governance_transact() { "${message}" } -STATEMINE_ACCOUNT_SEED_FOR_LOCAL="//Alice" -# Address: GegTpZJMyzkntLN7NJhRfHDk4GWukLbGSsag6PHrLSrCK4h -ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO="scatter feed race company oxygen trip extra elbow slot bundle auto canoe" - function allow_assets_transfer_send() { local relay_url=$1 local relay_chain_seed=$2 @@ -351,12 +376,13 @@ function remove_assets_transfer_send() { function transfer_asset_via_bridge() { local url=$1 local seed=$2 + local target_account=$3 echo " calling transfer_asset_via_bridge:" echo " url: ${url}" echo " seed: ${seed}" + echo " target_account: ${target_account}" echo " params:" - local assets=$(jq --null-input \ ' { @@ -377,12 +403,12 @@ function transfer_asset_via_bridge() { ' ) - -## // TODO:check-parameter - find dynamic way to decode some account to bytes: "id": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" -## AccountId32::from_str("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY").unwrap().0` -> [u8; 32] -## [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] + 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 \ + --argjson hex_encoded_data "$hex_encoded_data" \ ' { "V3": { @@ -397,7 +423,7 @@ function transfer_asset_via_bridge() { }, { "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] + "id": $hex_encoded_data } } ] @@ -427,16 +453,19 @@ function transfer_asset_via_bridge() { function ping_via_bridge() { local url=$1 local seed=$2 - echo " calling transfer_asset_via_bridge:" + local target_account=$3 + echo " calling ping_via_bridge:" echo " url: ${url}" echo " seed: ${seed}" + echo " target_account: ${target_account}" echo " params:" -## // TODO:check-parameter - find dynamic way to decode some account to bytes: "id": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" -## AccountId32::from_str("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY").unwrap().0` -> [u8; 32] -## [212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] + 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 \ + --argjson hex_encoded_data "$hex_encoded_data" \ ' { "V3": { @@ -451,7 +480,7 @@ function ping_via_bridge() { }, { "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] + "id": $hex_encoded_data } } ] @@ -591,25 +620,29 @@ case "$1" in ensure_polkadot_js_api transfer_asset_via_bridge \ "ws://127.0.0.1:9910" \ - "//Alice" + "$STATEMINE_ACCOUNT_SEED_FOR_LOCAL" \ + "$WOCKMINT_ACCOUNT_ADDRESS_FOR_LOCAL" ;; transfer-asset-from-statemine-rococo) ensure_polkadot_js_api transfer_asset_via_bridge \ "wss://ws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io" \ - "${ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO}" + "$ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO" \ + "$WOCKMINT_ACCOUNT_ADDRESS_FOR_ROCOCO" ;; ping-via-bridge-from-statemine-local) ensure_polkadot_js_api ping_via_bridge \ "ws://127.0.0.1:9910" \ - "${STATEMINE_ACCOUNT_SEED_FOR_LOCAL}" + "$STATEMINE_ACCOUNT_SEED_FOR_LOCAL" \ + "$WOCKMINT_ACCOUNT_ADDRESS_FOR_LOCAL" ;; ping-via-bridge-from-statemine-rococo) ensure_polkadot_js_api ping_via_bridge \ "wss://ws-rococo-rockmine2-collator-node-0.parity-testnet.parity.io" \ - "${ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO}" + "${ROCKMINE2_ACCOUNT_SEED_FOR_ROCOCO}" \ + "$WOCKMINT_ACCOUNT_ADDRESS_FOR_ROCOCO" ;; drip) transfer_balance \ From c70f503eab10190013ff28975b8e80b3137d45e3 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Wed, 12 Apr 2023 16:59:01 +0200 Subject: [PATCH 44/57] README.md --- parachains/runtimes/bridge-hubs/README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/parachains/runtimes/bridge-hubs/README.md b/parachains/runtimes/bridge-hubs/README.md index 3c9f86295f0..a76fc7df519 100644 --- a/parachains/runtimes/bridge-hubs/README.md +++ b/parachains/runtimes/bridge-hubs/README.md @@ -5,11 +5,14 @@ + [Run relayers (Rococo, Wococo)](#run-relayers--rococo--wococo-) - [Run with script (alternative 1)](#run-with-script--alternative-1-) - [Run with binary (alternative 2)](#run-with-binary--alternative-2-) - + [Send messages (Rococo, Wococo)](#send-messages--rococo--wococo-) - - [Local Rococo:Statemine -> Wococo:Westmint](#local-rococo-statemine----wococo-westmint) - - [Live Rococo:Rockmine2 -> Wococo:Wockmint](#live-rococo-rockmine2----wococo-wockmint) + + [Send messages](#send-messages) + - [Local zombienet run](#local-zombienet-run) + - [Live Rockmine2 to Wockmint](#live-rockmine2-to-wockmint) * [How to test local BridgeHubKusama](#how-to-test-local-bridgehubkusama) + * [How to test local BridgeHubPolkadot](#how-to-test-local-bridgehubpolkadot) * [Git subtree `./bridges`](#git-subtree---bridges-) + + [How to update `bridges` subtree](#how-to-update--bridges--subtree) + + [How was first time initialized (dont need anymore)](#how-was-first-time-initialized--dont-need-anymore-) # Bridge-hub Parachains @@ -167,9 +170,9 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ - Pallet: **bridgeRococoParachain** - Keys: **bestParaHeads()** -### Send messages (Rococo, Wococo) +### Send messages -#### Local (zombienet) run +#### Local zombienet run 1. allow bridge transfer on statemine/westmint (governance-like): ``` @@ -193,7 +196,7 @@ RUST_LOG=runtime=trace,rpc=trace,bridge=trace \ - Westmint (see `xcmpQueue.Success` for `transfer-asset` and `xcmpQueue.Fail` for `ping-via-bridge`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:9010#/explorer - BridgeHubRococo (see `bridgeWococoMessages.MessagesDelivered`) https://polkadot.js.org/apps/?rpc=ws://127.0.0.1:8943#/explorer -#### Live Rococo:Rockmine2 -> Wococo:Wockmint +#### Live Rockmine2 to Wockmint - uses account seed on Live Rococo:Rockmine2 ``` cd From df9ed2455462e8c470a8a7ead44023b6eec79ed3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 00:24:16 +0200 Subject: [PATCH 45/57] Bump actions/checkout from 3.1.0 to 3.5.1 (#2448) * Bump actions/checkout from 3.1.0 to 3.5.1 Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.5.1. - [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.1.0...83b7061638ee4956cf7545a6f7efe594e5ad0247) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * align version with hash --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sergejs Kostjucenko --- .github/workflows/docs.yml | 2 +- .github/workflows/fmt-check.yml | 2 +- .github/workflows/release-01_branch-check.yml | 2 +- .github/workflows/release-10_rc-automation.yml | 2 +- .../release-20_extrinsic-ordering-check-from-bin.yml | 2 +- .../release-21_extrinsic-ordering-check-from-two.yml | 2 +- .github/workflows/release-30_create-draft.yml | 6 +++--- .github/workflows/release-50_docker-manual.yml | 2 +- .github/workflows/release-50_docker.yml | 2 +- .github/workflows/srtool.yml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 473684d2950..4af4ba06bdb 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -17,7 +17,7 @@ jobs: protoc --version - name: Checkout repository - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 - name: Rust versions run: rustup show diff --git a/.github/workflows/fmt-check.yml b/.github/workflows/fmt-check.yml index 9d2af9bb2cf..05c3cda3ad2 100644 --- a/.github/workflows/fmt-check.yml +++ b/.github/workflows/fmt-check.yml @@ -31,7 +31,7 @@ jobs: target key: ${{ runner.os }}-${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 - name: Cargo fmt uses: actions-rs/cargo@ae10961054e4aa8b4aa7dffede299aaf087aa33b # v1.0.3 diff --git a/.github/workflows/release-01_branch-check.yml b/.github/workflows/release-01_branch-check.yml index f65e45e47b1..8b8e1522435 100644 --- a/.github/workflows/release-01_branch-check.yml +++ b/.github/workflows/release-01_branch-check.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 with: fetch-depth: 0 diff --git a/.github/workflows/release-10_rc-automation.yml b/.github/workflows/release-10_rc-automation.yml index c6b70326bf5..ebb0770b987 100644 --- a/.github/workflows/release-10_rc-automation.yml +++ b/.github/workflows/release-10_rc-automation.yml @@ -17,7 +17,7 @@ jobs: pre-releases: true steps: - name: Checkout sources - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 with: fetch-depth: 0 - id: compute_tag diff --git a/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml b/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml index 16424ba03d0..2ecc87b2e20 100644 --- a/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml +++ b/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml @@ -29,7 +29,7 @@ jobs: REF_URL: ${{github.event.inputs.reference_url}} steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 - name: Fetch binary run: | diff --git a/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml b/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml index a8d9a3bcc39..91f8d56f344 100644 --- a/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml +++ b/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml @@ -42,7 +42,7 @@ jobs: relay: polkadot-local steps: - - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 - name: Create tmp dir run: | diff --git a/.github/workflows/release-30_create-draft.yml b/.github/workflows/release-30_create-draft.yml index fc5d9ac0622..9b8d6f813b8 100644 --- a/.github/workflows/release-30_create-draft.yml +++ b/.github/workflows/release-30_create-draft.yml @@ -68,7 +68,7 @@ jobs: runtime: rococo-parachain steps: - name: Checkout sources - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 with: ref: ${{ github.event.inputs.ref2 }} @@ -120,7 +120,7 @@ jobs: asset_upload_url: ${{ steps.create-release.outputs.upload_url }} steps: - name: Checkout sources - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 with: fetch-depth: 0 path: cumulus @@ -246,7 +246,7 @@ jobs: runtime: rococo-parachain steps: - name: Checkout sources - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 with: ref: ${{ github.event.inputs.ref2 }} diff --git a/.github/workflows/release-50_docker-manual.yml b/.github/workflows/release-50_docker-manual.yml index 487b104a1a1..4e4cfdaad8f 100644 --- a/.github/workflows/release-50_docker-manual.yml +++ b/.github/workflows/release-50_docker-manual.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 with: ref: ${{ github.event.release.tag_name }} diff --git a/.github/workflows/release-50_docker.yml b/.github/workflows/release-50_docker.yml index fce5e929d96..06fecdd964b 100644 --- a/.github/workflows/release-50_docker.yml +++ b/.github/workflows/release-50_docker.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 with: ref: ${{ github.event.release.tag_name }} diff --git a/.github/workflows/srtool.yml b/.github/workflows/srtool.yml index 390c7628439..d9013805c1b 100644 --- a/.github/workflows/srtool.yml +++ b/.github/workflows/srtool.yml @@ -54,7 +54,7 @@ jobs: - category: testing runtime: rococo-parachain steps: - - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 with: fetch-depth: 0 From 574f425fa2b9c822a1417af705169ab3a1835e24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Apr 2023 21:43:33 +0000 Subject: [PATCH 46/57] Bump serde_json from 1.0.95 to 1.0.96 (#2453) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.95 to 1.0.96. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.95...v1.0.96) --- updated-dependencies: - dependency-name: serde_json 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 | 4 ++-- client/relay-chain-rpc-interface/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85596ef1e8e..7369594afd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11618,9 +11618,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa 1.0.4", "ryu", diff --git a/client/relay-chain-rpc-interface/Cargo.toml b/client/relay-chain-rpc-interface/Cargo.toml index 42984d71e8f..655c7c8e74c 100644 --- a/client/relay-chain-rpc-interface/Cargo.toml +++ b/client/relay-chain-rpc-interface/Cargo.toml @@ -30,6 +30,6 @@ jsonrpsee = { version = "0.16.2", features = ["ws-client"] } tracing = "0.1.37" async-trait = "0.1.68" url = "2.3.1" -serde_json = "1.0.95" +serde_json = "1.0.96" serde = "1.0.160" lru = "0.9.0" From b42855d89256153acbdc226cdc0133bc7f5e61e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 11:25:54 +0000 Subject: [PATCH 47/57] Bump actions/checkout from 3.5.1 to 3.5.2 (#2452) Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.1 to 3.5.2. - [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/83b7061638ee4956cf7545a6f7efe594e5ad0247...8e5e7e5ab8b370d6c329ec480221332ada57f0ab) --- updated-dependencies: - dependency-name: actions/checkout 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/docs.yml | 2 +- .github/workflows/fmt-check.yml | 2 +- .github/workflows/release-01_branch-check.yml | 2 +- .github/workflows/release-10_rc-automation.yml | 2 +- .../release-20_extrinsic-ordering-check-from-bin.yml | 2 +- .../release-21_extrinsic-ordering-check-from-two.yml | 2 +- .github/workflows/release-30_create-draft.yml | 6 +++--- .github/workflows/release-50_docker-manual.yml | 2 +- .github/workflows/release-50_docker.yml | 2 +- .github/workflows/srtool.yml | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 4af4ba06bdb..81b94b0722f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -17,7 +17,7 @@ jobs: protoc --version - name: Checkout repository - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Rust versions run: rustup show diff --git a/.github/workflows/fmt-check.yml b/.github/workflows/fmt-check.yml index 05c3cda3ad2..cdde5c820cc 100644 --- a/.github/workflows/fmt-check.yml +++ b/.github/workflows/fmt-check.yml @@ -31,7 +31,7 @@ jobs: target key: ${{ runner.os }}-${{ matrix.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Cargo fmt uses: actions-rs/cargo@ae10961054e4aa8b4aa7dffede299aaf087aa33b # v1.0.3 diff --git a/.github/workflows/release-01_branch-check.yml b/.github/workflows/release-01_branch-check.yml index 8b8e1522435..c6237b40ceb 100644 --- a/.github/workflows/release-01_branch-check.yml +++ b/.github/workflows/release-01_branch-check.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout sources - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: fetch-depth: 0 diff --git a/.github/workflows/release-10_rc-automation.yml b/.github/workflows/release-10_rc-automation.yml index ebb0770b987..d0c669a5885 100644 --- a/.github/workflows/release-10_rc-automation.yml +++ b/.github/workflows/release-10_rc-automation.yml @@ -17,7 +17,7 @@ jobs: pre-releases: true steps: - name: Checkout sources - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: fetch-depth: 0 - id: compute_tag diff --git a/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml b/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml index 2ecc87b2e20..340f72420be 100644 --- a/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml +++ b/.github/workflows/release-20_extrinsic-ordering-check-from-bin.yml @@ -29,7 +29,7 @@ jobs: REF_URL: ${{github.event.inputs.reference_url}} steps: - - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Fetch binary run: | diff --git a/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml b/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml index 91f8d56f344..98b88de2ad4 100644 --- a/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml +++ b/.github/workflows/release-21_extrinsic-ordering-check-from-two.yml @@ -42,7 +42,7 @@ jobs: relay: polkadot-local steps: - - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Create tmp dir run: | diff --git a/.github/workflows/release-30_create-draft.yml b/.github/workflows/release-30_create-draft.yml index 9b8d6f813b8..e8ce688b71b 100644 --- a/.github/workflows/release-30_create-draft.yml +++ b/.github/workflows/release-30_create-draft.yml @@ -68,7 +68,7 @@ jobs: runtime: rococo-parachain steps: - name: Checkout sources - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: ref: ${{ github.event.inputs.ref2 }} @@ -120,7 +120,7 @@ jobs: asset_upload_url: ${{ steps.create-release.outputs.upload_url }} steps: - name: Checkout sources - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: fetch-depth: 0 path: cumulus @@ -246,7 +246,7 @@ jobs: runtime: rococo-parachain steps: - name: Checkout sources - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: ref: ${{ github.event.inputs.ref2 }} diff --git a/.github/workflows/release-50_docker-manual.yml b/.github/workflows/release-50_docker-manual.yml index 4e4cfdaad8f..b4b2964cbe9 100644 --- a/.github/workflows/release-50_docker-manual.yml +++ b/.github/workflows/release-50_docker-manual.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: ref: ${{ github.event.release.tag_name }} diff --git a/.github/workflows/release-50_docker.yml b/.github/workflows/release-50_docker.yml index 06fecdd964b..a2051071ffe 100644 --- a/.github/workflows/release-50_docker.yml +++ b/.github/workflows/release-50_docker.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: ref: ${{ github.event.release.tag_name }} diff --git a/.github/workflows/srtool.yml b/.github/workflows/srtool.yml index d9013805c1b..9b20be76611 100644 --- a/.github/workflows/srtool.yml +++ b/.github/workflows/srtool.yml @@ -54,7 +54,7 @@ jobs: - category: testing runtime: rococo-parachain steps: - - uses: actions/checkout@83b7061638ee4956cf7545a6f7efe594e5ad0247 # v3.5.1 + - uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 with: fetch-depth: 0 From 6a1272401b0cb7988438cdc2b605f13730620733 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 14 Apr 2023 15:44:06 +0200 Subject: [PATCH 48/57] Compile fix + log xcm trace all --- bridges/primitives/messages/src/lib.rs | 4 ++-- .../bridge-hubs/bridge_hub_rococo_local_network.toml | 10 +++++----- .../bridge-hubs/bridge_hub_wococo_local_network.toml | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 754349d634e..cb6fa36661a 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -194,7 +194,7 @@ impl InboundLaneData { } /// Outbound message details, returned by runtime APIs. -#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct OutboundMessageDetails { /// Nonce assigned to the message. pub nonce: MessageNonce, @@ -208,7 +208,7 @@ pub struct OutboundMessageDetails { } /// Inbound message details, returned by runtime APIs. -#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct InboundMessageDetails { /// Computed message dispatch weight. /// diff --git a/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml b/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml index 529fd638674..e5a8459a76a 100644 --- a/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml +++ b/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml @@ -3,7 +3,7 @@ node_spawn_timeout = 240 [relaychain] default_command = "{{POLKADOT_BINARY_PATH}}" -default_args = [ "-lparachain=debug,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,xcm::should_execute=trace" ] +default_args = [ "-lparachain=debug,xcm=trace" ] chain = "rococo-local" [[relaychain.nodes]] @@ -40,7 +40,7 @@ cumulus_based = true rpc_port = 8933 ws_port = 8943 args = [ - "-lparachain=debug,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,xcm::should_execute=trace", + "-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')}}", @@ -55,7 +55,7 @@ cumulus_based = true rpc_port = 8934 ws_port = 8944 args = [ - "-lparachain=trace,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,xcm::should_execute=trace", + "-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')}}", @@ -73,7 +73,7 @@ cumulus_based = true ws_port = 9910 command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ROCKMINE}}" args = [ - "-lparachain=debug,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,runtime::bridge-assets-transfer=trace,xcm::should_execute=trace", + "-lparachain=debug,xcm=trace", ] extra_args = [ "--no-mdns", "--bootnodes {{'rockmine-collator2'|zombie('multiAddress')}}", @@ -84,7 +84,7 @@ cumulus_based = true name = "rockmine-collator2" command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_ROCKMINE}}" args = [ - "-lparachain=debug,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,runtime::bridge-assets-transfer=trace,xcm::should_execute=trace", + "-lparachain=debug,xcm=trace", ] extra_args = [ "--no-mdns", "--bootnodes {{'rockmine-collator1'|zombie('multiAddress')}}", diff --git a/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml b/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml index cf8afd63ef5..55a95eb85f7 100644 --- a/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml +++ b/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml @@ -3,7 +3,7 @@ node_spawn_timeout = 240 [relaychain] default_command = "{{POLKADOT_BINARY_PATH}}" -default_args = [ "-lparachain=debug,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,xcm::should_execute=trace" ] +default_args = [ "-lparachain=debug,xcm=trace" ] chain = "wococo-local" [[relaychain.nodes]] @@ -40,7 +40,7 @@ cumulus_based = true rpc_port = 8935 ws_port = 8945 args = [ - "-lparachain=debug,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,xcm::should_execute=trace", + "-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')}}", @@ -55,7 +55,7 @@ cumulus_based = true rpc_port = 8936 ws_port = 8946 args = [ - "-lparachain=trace,runtime::mmr=info,substrate=info,runtime=info,runtime::bridge-hub=trace,runtime::bridge=trace,runtime::bridge-dispatch=trace,bridge=trace,runtime::bridge-messages=trace,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,xcm::should_execute=trace", + "-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')}}", @@ -73,7 +73,7 @@ cumulus_based = true ws_port = 9010 command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_WOCKMINT}}" args = [ - "-lparachain=debug,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,xcm::should_execute=trace", + "-lparachain=debug,xcm=trace", ] extra_args = [ "--no-mdns", "--bootnodes {{'wockmint-collator2'|zombie('multiAddress')}}", @@ -84,7 +84,7 @@ cumulus_based = true name = "wockmint-collator2" command = "{{POLKADOT_PARACHAIN_BINARY_PATH_FOR_WOCKMINT}}" args = [ - "-lparachain=debug,xcm::weight=trace,xcm::filter_asset_location=trace,xcm::send_xcm=trace,xcm::barriers=trace,xcm::barrier=trace,xcm::execute_xcm=trace,xcm::contains=trace,xcm::execute_xcm_in_credit,xcm::process_instruction=trace,xcm::currency_adapter=trace,xcm::origin_conversion=trace,xcm::fungibles_adapter=trace,xcm::process=trace,xcm::execute=trace,xcm::should_execute=trace", + "-lparachain=debug,xcm=trace", ] extra_args = [ "--no-mdns", "--bootnodes {{'wockmint-collator1'|zombie('multiAddress')}}", From a26ebb27cbde26f18bd6fba1544d8f690ae57fa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 23:13:45 +0000 Subject: [PATCH 49/57] Bump syn from 2.0.14 to 2.0.15 (#2454) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.14 to 2.0.15. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.14...2.0.15) --- updated-dependencies: - dependency-name: syn 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 | 18 +++++++++--------- pallets/parachain-system/proc-macro/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7369594afd4..d3a56703d50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -428,7 +428,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -1224,7 +1224,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -2121,7 +2121,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -3771,7 +3771,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -11613,7 +11613,7 @@ checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -13089,9 +13089,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.14" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" dependencies = [ "proc-macro2", "quote", @@ -13208,7 +13208,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] @@ -13379,7 +13379,7 @@ checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ "proc-macro2", "quote", - "syn 2.0.14", + "syn 2.0.15", ] [[package]] diff --git a/pallets/parachain-system/proc-macro/Cargo.toml b/pallets/parachain-system/proc-macro/Cargo.toml index 9312575a05b..2eb35fe4f0b 100644 --- a/pallets/parachain-system/proc-macro/Cargo.toml +++ b/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.14" +syn = "2.0.15" proc-macro2 = "1.0.54" quote = "1.0.26" proc-macro-crate = "1.3.1" From 863e94d8627bfd30c61cf2aeac3b8706f768bb8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 15 Apr 2023 21:45:04 +0000 Subject: [PATCH 50/57] Bump assert_cmd from 2.0.10 to 2.0.11 (#2457) Bumps [assert_cmd](https://github.com/assert-rs/assert_cmd) from 2.0.10 to 2.0.11. - [Release notes](https://github.com/assert-rs/assert_cmd/releases) - [Changelog](https://github.com/assert-rs/assert_cmd/blob/master/CHANGELOG.md) - [Commits](https://github.com/assert-rs/assert_cmd/compare/v2.0.10...v2.0.11) --- updated-dependencies: - dependency-name: assert_cmd 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 | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3a56703d50..7e72b09483d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,6 +185,12 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ba0b55c2201aa802adb684e7963ce2c3191675629e7df899774331e3ac747cf" +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + [[package]] name = "anyhow" version = "1.0.69" @@ -311,11 +317,11 @@ checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" [[package]] name = "assert_cmd" -version = "2.0.10" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0b2340f55d9661d76793b2bfc2eb0e62689bd79d067a95707ea762afd5e9dd" +checksum = "86d6b683edf8d1119fe420a94f8a7e389239666aa72e65495d91c00462510151" dependencies = [ - "anstyle", + "anstyle 1.0.0", "bstr 1.1.0", "doc-comment", "predicates 3.0.1", @@ -9251,7 +9257,7 @@ version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ba7d6ead3e3966038f68caa9fc1f860185d95a793180bbcfe0d0da47b3961ed" dependencies = [ - "anstyle", + "anstyle 0.3.4", "difflib", "itertools", "predicates-core", From 795fe4edd78ebef496fbb80880864eb61466566f Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Fri, 14 Apr 2023 16:05:02 +0200 Subject: [PATCH 51/57] Initial version of bridges pallet as subtree of https://github.com/paritytech/parity-bridges-common Added `Bridges subtree files` pr review rule --- .github/pr-custom-review.yml | 10 ++- Cargo.toml | 5 ++ parachains/runtimes/bridge-hubs/README.md | 38 ++++++++++ scripts/bridges_update_subtree.sh | 85 +++++++++++++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100755 scripts/bridges_update_subtree.sh diff --git a/.github/pr-custom-review.yml b/.github/pr-custom-review.yml index f8c887c5f4a..b833d3a01aa 100644 --- a/.github/pr-custom-review.yml +++ b/.github/pr-custom-review.yml @@ -19,12 +19,20 @@ rules: check_type: changed_files condition: include: .* - # excluding files from 'Runtime files' and 'CI files' rules + # excluding files from 'Runtime files' and 'CI files' rules and `Bridges subtree files` exclude: ^parachains/runtimes/assets/(statemine|statemint)/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: diff --git a/Cargo.toml b/Cargo.toml index cdcf4730f72..4ceb8d5c04a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,11 @@ resolver = "2" members = [ + "bridges/bin/runtime-common", + "bridges/modules/grandpa", + "bridges/modules/messages", + "bridges/modules/parachains", + "bridges/modules/relayers", "client/cli", "client/consensus/aura", "client/consensus/common", diff --git a/parachains/runtimes/bridge-hubs/README.md b/parachains/runtimes/bridge-hubs/README.md index 79e82f3497a..7a6cb35aaf7 100644 --- a/parachains/runtimes/bridge-hubs/README.md +++ b/parachains/runtimes/bridge-hubs/README.md @@ -35,3 +35,41 @@ or # BridgeHubPolkadot zombienet-linux --provider native spawn ./zombienet/examples/bridge_hub_polkadot_local_network.toml ``` + +---- +## Git subtree `./bridges` + +Add Bridges repo as a local remote and synchronize it with latest `master` from bridges repo: + +### How to update `bridges` subtree +``` +cd +# this will update new git branches from bridges repo +# there could be unresolved conflicts, but dont worry, +# lots of them are caused because of removed unneeded files with patch step :) +# so before solving conflicts just run patch +./scripts/bridges_update_subtree.sh fetch +# this will remove unneeded files and checks if subtree modules compiles +./scripts/bridges_update_subtree.sh patch +# if there are conflicts, this could help, removes locally deleted files at least +# (but you can also do this manually) +./scripts/bridges_update_subtree.sh merge +# when conflicts resolved, you can check build again - should pass +# also important: this updates global Cargo.lock +./scripts/bridges_update_subtree.sh patch +```` +We use `--squash` to avoid adding individual commits and rather squashing them +all into one. +Now we use `master` branch, but in future, it could change to some release branch/tag. + +### How was first time initialized (does not need anymore) +``` +cd +git remote add -f bridges git@github.com:paritytech/parity-bridges-common.git +# (ran just only first time, when subtree was initialized) +git subtree add --prefix=bridges bridges master --squash +# remove unnecessery files +./scripts/bridges_update_subtree.sh patch +./scripts/bridges_update_subtree.sh merge +git commit --amend +``` diff --git a/scripts/bridges_update_subtree.sh b/scripts/bridges_update_subtree.sh new file mode 100755 index 00000000000..bd9161b601f --- /dev/null +++ b/scripts/bridges_update_subtree.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# A script to udpate bridges repo as subtree to Cumulus +# Usage: +# ./scripts/bridges_update_subtree.sh fetch +# ./scripts/bridges_update_subtree.sh patch +# ./scripts/bridges_update_subtree.sh merge + +set -e + +BRIDGES_BRANCH="${BRANCH:-master}" +BRIDGES_TARGET_DIR="${TARGET_DIR:-bridges}" + +function fetch() { + # the script is able to work only on clean git copy + [[ -z "$(git status --porcelain)" ]] || { + echo >&2 "The git copy must be clean (stash all your changes):"; + git status --porcelain + exit 1; + } + + local bridges_remote=$(git remote -v | grep "parity-bridges-common.git (fetch)" | head -n1 | awk '{print $1;}') + if [ -z "$bridges_remote" ]; then + echo "" + echo "Adding new remote: 'bridges' repo..." + echo "" + echo "... check your YubiKey ..." + git remote add -f bridges git@github.com:paritytech/parity-bridges-common.git + bridges_remote="bridges" + else + echo "" + echo "Fetching remote: '${bridges_remote}' repo..." + echo "" + echo "... check your YubiKey ..." + git fetch ${bridges_remote} --prune + fi + + echo "" + echo "Syncing/updating subtree with remote branch '${bridges_remote}/$BRIDGES_BRANCH' to target directory: '$BRIDGES_TARGET_DIR'" + echo "" + echo "... check your YubiKey ..." + git subtree pull --prefix=$BRIDGES_TARGET_DIR ${bridges_remote} $BRIDGES_BRANCH --squash +} + +function patch() { + echo "" + echo "Patching/removing unneeded stuff from subtree in target directory: '$BRIDGES_TARGET_DIR'" + $BRIDGES_TARGET_DIR/scripts/verify-pallets-build.sh --ignore-git-state --no-revert +} + +function merge() { + echo "" + echo "Merging stuff from subtree in target directory: '$BRIDGES_TARGET_DIR'" + + # stage all removed by patch: DU, MD, D, AD - only from subtree directory + git status -s | awk '$1 == "DU" || $1 == "D" || $1 == "MD" || $1 == "AD" {print $2}' | grep "^$BRIDGES_TARGET_DIR/" | xargs git rm -q --ignore-unmatch + + echo "" + echo "When all conflicts are resolved, do 'git merge --continue'" +} + +function amend() { + echo "" + echo "Amend stuff from subtree in target directory: '$BRIDGES_TARGET_DIR'" + git commit --amend -S -m "updating bridges subtree + remove extra folders" +} + +case "$1" in + fetch) + fetch + ;; + patch) + patch + ;; + merge) + merge + ;; + amend) + amend + ;; + all) + fetch + patch + ;; +esac \ No newline at end of file From 3a8b6ea5290368cb0dbf39e76555d15d380fc194 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 17 Apr 2023 12:02:39 +0200 Subject: [PATCH 52/57] Squashed 'bridges/' changes from ecddd4a31..d30927c08 d30927c08 Revert dispatch-results (#2048) fa454c3b4 Remove unneeded files (#2044) 956a2c687 Bump clap from 4.2.1 to 4.2.2 91951583a Bump serde_json from 1.0.95 to 1.0.96 fcf462051 Bump h2 from 0.3.16 to 0.3.17 in /tools/runtime-codegen b751fb24f Bump h2 from 0.3.16 to 0.3.17 0bf31ab78 update refs (#2041) a490ecbd3 Fix CI build (#2039) 01139ebbc Define `RangeInclusiveExt` (#2037) 2db2f3fe3 Impl review suggestions from #2021 (#2036) 36292760f fix build step on CI (#2034) 3a2311b7a refund extra weight in receive_messages_delivery_proof call (#2031) 77f1641d1 Boost message delivery transaction priority (#2023) c23c4e441 Reject delivery transactions with at least one obsolete message (#2021) 68ba699b7 Reintroduce msg dispatch status reporting (#2027) d1e852cc3 Bump hex-literal from 0.4.0 to 0.4.1 16f25d613 Relay node down alert (#2002) 4bb1a6406 only refund if all bundled messages have been delivered (#2019) b9acf52bc fail with InsufficientDispatchWeight if dispatch_weight doesn't cover weight of all bundled messages (#2018) e10097fe2 Remove unneeded error debug strings (#2017) f5e38f057 enable metrics on all validator nodes (#2016) c35f1a187 Bump scale-info from 2.4.0 to 2.5.0 04c56977c Bump clap from 4.1.13 to 4.2.1 481371f3c Bump hex-literal from 0.3.4 to 0.4.0 6b9c1400d Bump serde from 1.0.158 to 1.0.159 e71877a2e Bump futures from 0.3.27 to 0.3.28 c019f4faa Bump tempfile from 3.4.0 to 3.5.0 2e6e79ef6 Bump serde_json from 1.0.94 to 1.0.95 0698b1ff9 Bump tokio from 1.26.0 to 1.27.0 35b149830 fix test step on CI (#2003) 0c3acc858 cleanup removed lane traces (#2001) 8bf81749e bump BridgeHubRococo/BridgeHubWococo versions (#2000) e53bb7f36 MaxRequests -> MaxFreeMandatoryHeadersPerBlock in pallet-bridge-grandpa (#1997) dfcc09043 Run tests for `runtime-benchmarks` feature only (#1998) efcc8db17 Run benchmarks for mock runtimes (#1996) git-subtree-dir: bridges git-subtree-split: d30927c089bd9e73092d1ec1a62895603cb277a3 --- .gitlab-ci.yml | 4 +- Cargo.lock | 1168 ++++++---- bin/millau/node/Cargo.toml | 4 +- bin/millau/node/src/service.rs | 17 +- bin/millau/runtime/Cargo.toml | 6 +- bin/millau/runtime/src/lib.rs | 10 +- .../runtime/src/rialto_parachain_messages.rs | 70 + bin/rialto-parachain/node/Cargo.toml | 2 +- bin/rialto-parachain/node/src/service.rs | 24 +- bin/rialto-parachain/runtime/Cargo.toml | 4 +- bin/rialto-parachain/runtime/src/lib.rs | 6 +- bin/rialto/node/Cargo.toml | 4 +- bin/rialto/node/src/command.rs | 4 +- bin/rialto/runtime/Cargo.toml | 2 +- bin/rialto/runtime/src/lib.rs | 6 +- bin/runtime-common/Cargo.toml | 2 +- bin/runtime-common/src/integrity.rs | 6 +- bin/runtime-common/src/lib.rs | 1 + bin/runtime-common/src/messages_call_ext.rs | 371 ++- .../src/messages_xcm_extension.rs | 16 +- bin/runtime-common/src/mock.rs | 10 +- bin/runtime-common/src/priority_calculator.rs | 201 ++ .../src/refund_relayer_extension.rs | 357 ++- .../dashboard/prometheus/targets.yml | 2 - .../dashboard/grafana/bridges-alerts.json | 1994 +++++++++++++++++ .../rococo-wococo-maintenance-dashboard.json | 1736 +++++++------- .../dashboard/grafana/beefy-dashboard.json | 347 ++- .../dashboard/prometheus/millau-targets.yml | 4 + .../dashboard/prometheus/rialto-targets.yml | 4 + deployments/networks/millau.yml | 16 +- deployments/networks/rialto.yml | 16 +- deployments/types-millau.json | 3 +- deployments/types-rialto.json | 3 +- deployments/types/common.json | 3 +- modules/beefy/Cargo.toml | 2 +- modules/beefy/src/lib.rs | 2 +- modules/grandpa/Cargo.toml | 2 +- modules/grandpa/src/benchmarking.rs | 2 + modules/grandpa/src/lib.rs | 200 +- modules/grandpa/src/mock.rs | 18 +- modules/messages/Cargo.toml | 6 +- modules/messages/src/benchmarking.rs | 4 +- modules/messages/src/lib.rs | 188 +- modules/messages/src/mock.rs | 60 +- modules/parachains/Cargo.toml | 2 +- modules/parachains/src/benchmarking.rs | 4 +- modules/parachains/src/lib.rs | 20 +- modules/parachains/src/mock.rs | 43 +- modules/relayers/Cargo.toml | 2 +- modules/relayers/src/benchmarking.rs | 2 + modules/relayers/src/mock.rs | 22 +- modules/relayers/src/payment_adapter.rs | 7 +- modules/shift-session-manager/Cargo.toml | 2 +- primitives/beefy/Cargo.toml | 2 +- primitives/chain-millau/Cargo.toml | 2 +- primitives/header-chain/Cargo.toml | 4 +- primitives/messages/Cargo.toml | 4 +- primitives/messages/src/lib.rs | 20 +- primitives/messages/src/source_chain.rs | 10 +- primitives/parachains/Cargo.toml | 2 +- primitives/polkadot-core/Cargo.toml | 2 +- primitives/relayers/Cargo.toml | 4 +- primitives/runtime/Cargo.toml | 4 +- primitives/runtime/src/lib.rs | 21 +- relays/bin-substrate/Cargo.toml | 6 +- relays/bin-substrate/src/chains/rococo.rs | 2 +- relays/bin-substrate/src/chains/wococo.rs | 2 +- relays/client-bridge-hub-kusama/Cargo.toml | 2 +- relays/client-bridge-hub-polkadot/Cargo.toml | 2 +- relays/client-bridge-hub-rococo/Cargo.toml | 2 +- relays/client-bridge-hub-wococo/Cargo.toml | 2 +- relays/client-rialto-parachain/Cargo.toml | 2 +- .../src/codegen_runtime.rs | 6 +- relays/client-substrate/Cargo.toml | 6 +- relays/finality/Cargo.toml | 2 +- relays/lib-substrate-relay/Cargo.toml | 2 +- relays/messages/Cargo.toml | 2 +- relays/parachains/Cargo.toml | 2 +- relays/utils/Cargo.toml | 4 +- scripts/dump-logs.sh | 2 - scripts/verify-pallets-build.sh | 2 + tools/runtime-codegen/Cargo.lock | 4 +- 82 files changed, 5270 insertions(+), 1868 deletions(-) create mode 100644 bin/runtime-common/src/priority_calculator.rs create mode 100644 deployments/bridges/rococo-wococo/dashboard/grafana/bridges-alerts.json diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f3ba2243c7f..eb88001b50c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -155,7 +155,7 @@ test: # Enable this, when you see: "`cargo metadata` can not fail on project `Cargo.toml`" #- time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"polkadot-runtime\").manifest_path"` #- time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"kusama-runtime\").manifest_path"` - - CARGO_NET_OFFLINE=true SKIP_POLKADOT_RUNTIME_WASM_BUILD=1 SKIP_KUSAMA_RUNTIME_WASM_BUILD=1 SKIP_POLKADOT_TEST_RUNTIME_WASM_BUILD=1 time cargo test --verbose --workspace + - CARGO_NET_OFFLINE=true SKIP_WASM_BUILD=1 time cargo test --verbose --workspace --features runtime-benchmarks test-nightly: stage: test @@ -238,7 +238,7 @@ build: # Enable this, when you see: "`cargo metadata` can not fail on project `Cargo.toml`" #- time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"polkadot-runtime\").manifest_path"` #- time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"kusama-runtime\").manifest_path"` - - CARGO_NET_OFFLINE=true SKIP_POLKADOT_RUNTIME_WASM_BUILD=1 SKIP_KUSAMA_RUNTIME_WASM_BUILD=1 SKIP_POLKADOT_TEST_RUNTIME_WASM_BUILD=1 time cargo build --release --verbose --workspace + - CARGO_NET_OFFLINE=true time cargo build --release --verbose --workspace after_script: # Prepare artifacts - mkdir -p ./artifacts diff --git a/Cargo.lock b/Cargo.lock index 20d18112ad1..f4b78e93bca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,6 +203,55 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstream" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "anyhow" version = "1.0.70" @@ -298,7 +347,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db8b7511298d5b7784b40b092d9e9dcd3a627a5707e4b5e507931ab0d44eeebf" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "synstructure", @@ -310,7 +359,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "synstructure", @@ -322,7 +371,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -457,9 +506,9 @@ version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 2.0.10", + "syn 2.0.14", ] [[package]] @@ -578,7 +627,7 @@ dependencies = [ [[package]] name = "binary-merkle-tree" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "hash-db", "log", @@ -605,7 +654,7 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "regex", "rustc-hash", @@ -854,7 +903,7 @@ dependencies = [ "finality-grandpa", "frame-support", "hex", - "hex-literal", + "hex-literal 0.4.1", "parity-scale-codec", "scale-info", "serde", @@ -882,7 +931,7 @@ dependencies = [ "bp-runtime", "frame-support", "hex", - "hex-literal", + "hex-literal 0.4.1", "parity-scale-codec", "scale-info", "serde", @@ -968,7 +1017,7 @@ dependencies = [ "bp-runtime", "frame-support", "hex", - "hex-literal", + "hex-literal 0.4.1", "parity-scale-codec", "scale-info", "sp-runtime", @@ -1024,7 +1073,7 @@ dependencies = [ "frame-support", "frame-system", "hash-db", - "hex-literal", + "hex-literal 0.4.1", "impl-trait-for-tuples", "num-traits", "parity-scale-codec", @@ -1406,39 +1455,45 @@ dependencies = [ [[package]] name = "clap" -version = "4.1.13" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c911b090850d79fc64fe9ea01e28e465f65e821e08813ced95bced72f7a8a9b" +checksum = "9b802d85aaf3a1cdb02b224ba472ebdea62014fccfcb269b95a4d76443b5ee5a" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", - "is-terminal", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14a1a858f532119338887a4b8e1af9c60de8249cd7bafd68036a489e261e37b6" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim 0.10.0", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.12" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a932373bab67b984c790ddf2c9ca295d8e3af3b7ef92de5a5bacdccdee4b09b" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 2.0.10", + "syn 2.0.14", ] [[package]] name = "clap_lex" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" -dependencies = [ - "os_str_bytes", -] +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" [[package]] name = "coarsetime" @@ -1462,6 +1517,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "comfy-table" version = "6.1.4" @@ -1821,9 +1882,9 @@ dependencies = [ [[package]] name = "cumulus-client-cli" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ - "clap 4.1.13", + "clap 4.2.2", "parity-scale-codec", "sc-chain-spec", "sc-cli", @@ -1836,7 +1897,7 @@ dependencies = [ [[package]] name = "cumulus-client-collator" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "cumulus-client-consensus-common", "cumulus-client-network", @@ -1859,7 +1920,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-aura" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "async-trait", "cumulus-client-consensus-common", @@ -1888,7 +1949,7 @@ dependencies = [ [[package]] name = "cumulus-client-consensus-common" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "async-trait", "cumulus-client-pov-recovery", @@ -1912,7 +1973,7 @@ dependencies = [ [[package]] name = "cumulus-client-network" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "async-trait", "cumulus-relay-chain-interface", @@ -1935,7 +1996,7 @@ dependencies = [ [[package]] name = "cumulus-client-pov-recovery" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -1959,7 +2020,7 @@ dependencies = [ [[package]] name = "cumulus-client-service" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "cumulus-client-cli", "cumulus-client-collator", @@ -1994,7 +2055,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-aura-ext" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "frame-support", "frame-system", @@ -2010,7 +2071,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-dmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -2027,7 +2088,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "bytes", "cumulus-pallet-parachain-system-proc-macro", @@ -2056,18 +2117,18 @@ dependencies = [ [[package]] name = "cumulus-pallet-parachain-system-proc-macro" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "cumulus-pallet-xcm" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -2083,7 +2144,7 @@ dependencies = [ [[package]] name = "cumulus-pallet-xcmp-queue" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -2103,12 +2164,13 @@ dependencies = [ [[package]] name = "cumulus-primitives-core" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", "polkadot-primitives", + "scale-info", "sp-api", "sp-runtime", "sp-std 5.0.0", @@ -2119,7 +2181,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-parachain-inherent" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -2142,7 +2204,7 @@ dependencies = [ [[package]] name = "cumulus-primitives-timestamp" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "cumulus-primitives-core", "futures", @@ -2155,7 +2217,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-inprocess-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -2180,7 +2242,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -2198,7 +2260,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-minimal-node" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "array-bytes 6.0.0", "async-trait", @@ -2207,19 +2269,23 @@ dependencies = [ "cumulus-relay-chain-rpc-interface", "futures", "lru 0.9.0", + "polkadot-availability-recovery", + "polkadot-collator-protocol", "polkadot-core-primitives", "polkadot-network-bridge", + "polkadot-node-collation-generation", + "polkadot-node-core-runtime-api", "polkadot-node-network-protocol", "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-primitives", - "polkadot-service", "sc-authority-discovery", "sc-client-api", "sc-network", "sc-network-common", "sc-service", "sc-tracing", + "sc-utils", "sp-api", "sp-blockchain", "sp-consensus", @@ -2232,7 +2298,7 @@ dependencies = [ [[package]] name = "cumulus-relay-chain-rpc-interface" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "async-trait", "cumulus-primitives-core", @@ -2262,7 +2328,7 @@ dependencies = [ [[package]] name = "cumulus-test-relay-sproof-builder" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "cumulus-primitives-core", "parity-scale-codec", @@ -2364,10 +2430,10 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "scratch", - "syn 2.0.10", + "syn 2.0.14", ] [[package]] @@ -2382,9 +2448,9 @@ version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 2.0.10", + "syn 2.0.14", ] [[package]] @@ -2405,7 +2471,7 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "strsim 0.10.0", "syn 1.0.109", @@ -2503,7 +2569,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -2514,7 +2580,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -2535,7 +2601,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" dependencies = [ "darling", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -2557,7 +2623,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "rustc_version", "syn 1.0.109", @@ -2645,7 +2711,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -2684,7 +2750,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -2819,7 +2885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -2839,7 +2905,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -2850,9 +2916,9 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 2.0.10", + "syn 2.0.14", ] [[package]] @@ -2956,7 +3022,7 @@ checksum = "a718c0675c555c5f976fff4ea9e2c150fa06cefa201cadef87cfbf9324075881" dependencies = [ "blake3", "fs-err", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", ] @@ -2968,9 +3034,8 @@ checksum = "3774182a5df13c3d1690311ad32fbe913feef26baba609fa2dd5f72042bd2ab6" dependencies = [ "blake2", "fs-err", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", ] [[package]] @@ -2981,11 +3046,24 @@ checksum = "f360349150728553f92e4c997a16af8915f418d3a0f21b440d34c5632f16ed84" dependencies = [ "blake2", "fs-err", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] +[[package]] +name = "expander" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -3026,7 +3104,7 @@ dependencies = [ "expander 0.0.4", "indexmap", "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "thiserror", @@ -3085,7 +3163,7 @@ checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "windows-sys 0.45.0", ] @@ -3167,7 +3245,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fork-tree" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", ] @@ -3190,7 +3268,7 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "frame-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-support-procedural", @@ -3215,12 +3293,12 @@ dependencies = [ [[package]] name = "frame-benchmarking-cli" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "Inflector", "array-bytes 4.2.0", "chrono", - "clap 4.1.13", + "clap 4.2.2", "comfy-table", "frame-benchmarking", "frame-support", @@ -3262,18 +3340,18 @@ dependencies = [ [[package]] name = "frame-election-provider-solution-type" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "frame-election-provider-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-election-provider-solution-type", "frame-support", @@ -3290,7 +3368,7 @@ dependencies = [ [[package]] name = "frame-executive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -3305,9 +3383,9 @@ dependencies = [ [[package]] name = "frame-metadata" -version = "15.0.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" +checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" dependencies = [ "cfg-if 1.0.0", "parity-scale-codec", @@ -3318,7 +3396,7 @@ dependencies = [ [[package]] name = "frame-remote-externalities" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "log", @@ -3334,7 +3412,7 @@ dependencies = [ [[package]] name = "frame-support" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "bitflags", "environmental", @@ -3367,44 +3445,45 @@ dependencies = [ [[package]] name = "frame-support-procedural" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "Inflector", "cfg-expr", "derive-syn-parse", "frame-support-procedural-tools", "itertools", - "proc-macro2 1.0.53", + "proc-macro-warning", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "frame-support-procedural-tools" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "frame-support-procedural-tools-derive" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "frame-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "log", @@ -3422,7 +3501,7 @@ dependencies = [ [[package]] name = "frame-system-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -3437,7 +3516,7 @@ dependencies = [ [[package]] name = "frame-system-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "sp-api", @@ -3446,7 +3525,7 @@ dependencies = [ [[package]] name = "frame-try-runtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "parity-scale-codec", @@ -3490,9 +3569,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -3505,9 +3584,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -3515,15 +3594,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -3533,9 +3612,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-lite" @@ -3554,13 +3633,13 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -3576,15 +3655,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-timer" @@ -3594,9 +3673,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -3765,9 +3844,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", @@ -3880,6 +3959,12 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hkdf" version = "0.12.3" @@ -4151,7 +4236,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -4435,7 +4520,7 @@ checksum = "baa6da1e4199c10d7b1d0a6e5e8bd8e55f351163b6f4b3cbb044672a69bd4c1c" dependencies = [ "heck 0.4.1", "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -4513,7 +4598,7 @@ dependencies = [ [[package]] name = "kusama-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", "frame-benchmarking", @@ -4524,7 +4609,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "kusama-runtime-constants", "log", "pallet-authority-discovery", @@ -4611,7 +4696,7 @@ dependencies = [ [[package]] name = "kusama-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "frame-support", "polkadot-primitives", @@ -5509,7 +5594,7 @@ dependencies = [ name = "millau-bridge-node" version = "0.1.0" dependencies = [ - "clap 4.1.13", + "clap 4.2.2", "frame-benchmarking", "frame-benchmarking-cli", "jsonrpsee", @@ -5564,7 +5649,7 @@ dependencies = [ "frame-support", "frame-system", "frame-system-rpc-runtime-api", - "hex-literal", + "hex-literal 0.4.1", "pallet-aura", "pallet-balances", "pallet-beefy", @@ -5641,7 +5726,7 @@ dependencies = [ [[package]] name = "mmr-gadget" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "log", @@ -5660,7 +5745,7 @@ dependencies = [ [[package]] name = "mmr-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "anyhow", "jsonrpsee", @@ -5695,7 +5780,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0" dependencies = [ "cfg-if 1.0.0", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -5786,7 +5871,7 @@ checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate", "proc-macro-error", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "synstructure", @@ -5834,7 +5919,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -5937,7 +6022,7 @@ name = "node-inspect" version = "0.9.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" dependencies = [ - "clap 4.1.13", + "clap 4.2.2", "parity-scale-codec", "sc-cli", "sc-client-api", @@ -6138,9 +6223,9 @@ dependencies = [ [[package]] name = "orchestra" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e7d5b6bb115db09390bed8842c94180893dd83df3dfce7354f2a2aa090a4ee" +checksum = "227585216d05ba65c7ab0a0450a3cf2cbd81a98862a54c4df8e14d5ac6adb015" dependencies = [ "async-trait", "dyn-clonable", @@ -6155,15 +6240,15 @@ dependencies = [ [[package]] name = "orchestra-proc-macro" -version = "0.0.4" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2af4dabb2286b0be0e9711d2d24e25f6217048b71210cffd3daddc3b5c84e1f" +checksum = "2871aadd82a2c216ee68a69837a526dfe788ecbe74c4c5038a6acdbff6653066" dependencies = [ "expander 0.0.6", "itertools", "petgraph", "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -6177,12 +6262,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - [[package]] name = "p256" version = "0.11.1" @@ -6218,7 +6297,7 @@ dependencies = [ [[package]] name = "pallet-aura" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -6234,7 +6313,7 @@ dependencies = [ [[package]] name = "pallet-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -6250,7 +6329,7 @@ dependencies = [ [[package]] name = "pallet-authorship" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -6264,7 +6343,7 @@ dependencies = [ [[package]] name = "pallet-babe" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6288,7 +6367,7 @@ dependencies = [ [[package]] name = "pallet-bags-list" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6308,7 +6387,7 @@ dependencies = [ [[package]] name = "pallet-balances" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6323,7 +6402,7 @@ dependencies = [ [[package]] name = "pallet-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -6342,7 +6421,7 @@ dependencies = [ [[package]] name = "pallet-beefy-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "binary-merkle-tree", @@ -6366,7 +6445,7 @@ dependencies = [ [[package]] name = "pallet-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6496,7 +6575,7 @@ dependencies = [ [[package]] name = "pallet-child-bounties" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6515,7 +6594,7 @@ dependencies = [ [[package]] name = "pallet-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6532,7 +6611,7 @@ dependencies = [ [[package]] name = "pallet-conviction-voting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6549,7 +6628,7 @@ dependencies = [ [[package]] name = "pallet-democracy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6567,7 +6646,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6590,7 +6669,7 @@ dependencies = [ [[package]] name = "pallet-election-provider-support-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6603,7 +6682,7 @@ dependencies = [ [[package]] name = "pallet-elections-phragmen" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6621,7 +6700,7 @@ dependencies = [ [[package]] name = "pallet-fast-unstake" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6639,7 +6718,7 @@ dependencies = [ [[package]] name = "pallet-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6662,7 +6741,7 @@ dependencies = [ [[package]] name = "pallet-identity" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "enumflags2", "frame-benchmarking", @@ -6678,7 +6757,7 @@ dependencies = [ [[package]] name = "pallet-im-online" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6698,7 +6777,7 @@ dependencies = [ [[package]] name = "pallet-indices" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6715,7 +6794,7 @@ dependencies = [ [[package]] name = "pallet-membership" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6732,7 +6811,7 @@ dependencies = [ [[package]] name = "pallet-mmr" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6749,7 +6828,7 @@ dependencies = [ [[package]] name = "pallet-multisig" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6765,7 +6844,7 @@ dependencies = [ [[package]] name = "pallet-nis" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#83c81985521b9f956890539d8b62371c40093c60" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6781,7 +6860,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -6798,7 +6877,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-benchmarking" version = "1.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#83c81985521b9f956890539d8b62371c40093c60" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6818,7 +6897,7 @@ dependencies = [ [[package]] name = "pallet-nomination-pools-runtime-api" version = "1.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", @@ -6829,7 +6908,7 @@ dependencies = [ [[package]] name = "pallet-offences" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -6846,7 +6925,7 @@ dependencies = [ [[package]] name = "pallet-offences-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#83c81985521b9f956890539d8b62371c40093c60" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -6870,7 +6949,7 @@ dependencies = [ [[package]] name = "pallet-preimage" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6887,7 +6966,7 @@ dependencies = [ [[package]] name = "pallet-proxy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6902,7 +6981,7 @@ dependencies = [ [[package]] name = "pallet-ranked-collective" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#83c81985521b9f956890539d8b62371c40093c60" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6920,7 +6999,7 @@ dependencies = [ [[package]] name = "pallet-recovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#83c81985521b9f956890539d8b62371c40093c60" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6935,7 +7014,7 @@ dependencies = [ [[package]] name = "pallet-referenda" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "assert_matches", "frame-benchmarking", @@ -6954,7 +7033,7 @@ dependencies = [ [[package]] name = "pallet-scheduler" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -6971,7 +7050,7 @@ dependencies = [ [[package]] name = "pallet-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -6992,7 +7071,7 @@ dependencies = [ [[package]] name = "pallet-session-benchmarking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#83c81985521b9f956890539d8b62371c40093c60" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -7023,7 +7102,7 @@ dependencies = [ [[package]] name = "pallet-society" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#83c81985521b9f956890539d8b62371c40093c60" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -7037,7 +7116,7 @@ dependencies = [ [[package]] name = "pallet-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-election-provider-support", @@ -7060,18 +7139,18 @@ dependencies = [ [[package]] name = "pallet-staking-reward-curve" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "pallet-staking-reward-fn" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "log", "sp-arithmetic", @@ -7080,7 +7159,7 @@ dependencies = [ [[package]] name = "pallet-staking-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "sp-api", @@ -7089,7 +7168,7 @@ dependencies = [ [[package]] name = "pallet-state-trie-migration" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#83c81985521b9f956890539d8b62371c40093c60" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -7106,7 +7185,7 @@ dependencies = [ [[package]] name = "pallet-sudo" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -7120,7 +7199,7 @@ dependencies = [ [[package]] name = "pallet-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -7138,7 +7217,7 @@ dependencies = [ [[package]] name = "pallet-tips" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -7157,7 +7236,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-support", "frame-system", @@ -7173,7 +7252,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "jsonrpsee", "pallet-transaction-payment-rpc-runtime-api", @@ -7189,7 +7268,7 @@ dependencies = [ [[package]] name = "pallet-transaction-payment-rpc-runtime-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", @@ -7201,7 +7280,7 @@ dependencies = [ [[package]] name = "pallet-treasury" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -7218,7 +7297,7 @@ dependencies = [ [[package]] name = "pallet-utility" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -7234,7 +7313,7 @@ dependencies = [ [[package]] name = "pallet-vesting" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -7249,7 +7328,7 @@ dependencies = [ [[package]] name = "pallet-whitelist" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-benchmarking", "frame-support", @@ -7264,7 +7343,7 @@ dependencies = [ [[package]] name = "pallet-xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bounded-collections", "frame-benchmarking", @@ -7285,7 +7364,7 @@ dependencies = [ [[package]] name = "pallet-xcm-benchmarks" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "frame-benchmarking", "frame-support", @@ -7304,7 +7383,7 @@ dependencies = [ [[package]] name = "parachain-info" version = "0.1.0" -source = "git+https://github.com/paritytech/cumulus?branch=master#020a024ab56a75812f6209842c369b631339609e" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" dependencies = [ "cumulus-primitives-core", "frame-support", @@ -7370,7 +7449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -7405,7 +7484,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "syn 1.0.109", "synstructure", ] @@ -7452,7 +7531,7 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] @@ -7465,7 +7544,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "windows-sys 0.45.0", ] @@ -7552,7 +7631,7 @@ checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -7593,7 +7672,7 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -7657,9 +7736,10 @@ checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" [[package]] name = "polkadot-approval-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", + "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -7672,7 +7752,7 @@ dependencies = [ [[package]] name = "polkadot-availability-bitfield-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", "polkadot-node-network-protocol", @@ -7686,7 +7766,7 @@ dependencies = [ [[package]] name = "polkadot-availability-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "derive_more", "fatality", @@ -7709,7 +7789,7 @@ dependencies = [ [[package]] name = "polkadot-availability-recovery" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "fatality", "futures", @@ -7730,9 +7810,9 @@ dependencies = [ [[package]] name = "polkadot-cli" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ - "clap 4.1.13", + "clap 4.2.2", "frame-benchmarking-cli", "futures", "log", @@ -7757,7 +7837,7 @@ dependencies = [ [[package]] name = "polkadot-client" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "async-trait", "frame-benchmarking", @@ -7799,7 +7879,7 @@ dependencies = [ [[package]] name = "polkadot-collator-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "always-assert", "bitvec", @@ -7821,7 +7901,7 @@ dependencies = [ [[package]] name = "polkadot-core-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "parity-scale-codec", "scale-info", @@ -7833,7 +7913,7 @@ dependencies = [ [[package]] name = "polkadot-dispute-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "derive_more", "fatality", @@ -7858,7 +7938,7 @@ dependencies = [ [[package]] name = "polkadot-erasure-coding" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "parity-scale-codec", "polkadot-node-primitives", @@ -7872,7 +7952,7 @@ dependencies = [ [[package]] name = "polkadot-gossip-support" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", "futures-timer", @@ -7892,7 +7972,7 @@ dependencies = [ [[package]] name = "polkadot-network-bridge" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "always-assert", "async-trait", @@ -7915,7 +7995,7 @@ dependencies = [ [[package]] name = "polkadot-node-collation-generation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", "parity-scale-codec", @@ -7933,7 +8013,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-approval-voting" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", "derive_more", @@ -7962,7 +8042,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-av-store" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", "futures", @@ -7983,7 +8063,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-backing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", "fatality", @@ -8002,7 +8082,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-bitfield-signing" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", "polkadot-node-subsystem", @@ -8017,7 +8097,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-candidate-validation" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "async-trait", "futures", @@ -8037,7 +8117,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", "polkadot-node-metrics", @@ -8052,7 +8132,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-chain-selection" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", "futures-timer", @@ -8069,7 +8149,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-dispute-coordinator" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "fatality", "futures", @@ -8088,7 +8168,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-parachains-inherent" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "async-trait", "futures", @@ -8105,7 +8185,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-provisioner" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", "fatality", @@ -8123,7 +8203,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "always-assert", "assert_matches", @@ -8150,6 +8230,7 @@ dependencies = [ "sp-maybe-compressed-blob", "sp-tracing", "sp-wasm-interface", + "substrate-build-script-utils", "tempfile", "tikv-jemalloc-ctl", "tokio", @@ -8159,7 +8240,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-pvf-checker" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", "polkadot-node-primitives", @@ -8175,7 +8256,7 @@ dependencies = [ [[package]] name = "polkadot-node-core-runtime-api" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "futures", "lru 0.9.0", @@ -8190,7 +8271,7 @@ dependencies = [ [[package]] name = "polkadot-node-jaeger" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "lazy_static", "log", @@ -8208,7 +8289,7 @@ dependencies = [ [[package]] name = "polkadot-node-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bs58", "futures", @@ -8227,7 +8308,7 @@ dependencies = [ [[package]] name = "polkadot-node-network-protocol" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "async-trait", "derive_more", @@ -8249,7 +8330,7 @@ dependencies = [ [[package]] name = "polkadot-node-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bounded-vec", "futures", @@ -8266,13 +8347,13 @@ dependencies = [ "sp-maybe-compressed-blob", "sp-runtime", "thiserror", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] name = "polkadot-node-subsystem" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "polkadot-node-jaeger", "polkadot-node-subsystem-types", @@ -8282,7 +8363,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-types" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "async-trait", "derive_more", @@ -8305,7 +8386,7 @@ dependencies = [ [[package]] name = "polkadot-node-subsystem-util" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "async-trait", "derive_more", @@ -8338,7 +8419,7 @@ dependencies = [ [[package]] name = "polkadot-overseer" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "async-trait", "futures", @@ -8361,7 +8442,7 @@ dependencies = [ [[package]] name = "polkadot-parachain" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bounded-collections", "derive_more", @@ -8378,10 +8459,10 @@ dependencies = [ [[package]] name = "polkadot-primitives" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", - "hex-literal", + "hex-literal 0.3.4", "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain", @@ -8404,7 +8485,7 @@ dependencies = [ [[package]] name = "polkadot-rpc" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "jsonrpsee", "mmr-rpc", @@ -8436,7 +8517,7 @@ dependencies = [ [[package]] name = "polkadot-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", "frame-benchmarking", @@ -8447,7 +8528,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", @@ -8530,7 +8611,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-common" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", "frame-benchmarking", @@ -8576,7 +8657,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "frame-support", "polkadot-primitives", @@ -8590,7 +8671,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-metrics" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bs58", "parity-scale-codec", @@ -8602,7 +8683,7 @@ dependencies = [ [[package]] name = "polkadot-runtime-parachains" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitflags", "bitvec", @@ -8646,14 +8727,14 @@ dependencies = [ [[package]] name = "polkadot-service" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "async-trait", "frame-benchmarking-cli", "frame-support", "frame-system-rpc-runtime-api", "futures", - "hex-literal", + "hex-literal 0.3.4", "kusama-runtime", "kvdb", "kvdb-rocksdb", @@ -8755,7 +8836,7 @@ dependencies = [ [[package]] name = "polkadot-statement-distribution" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "arrayvec 0.5.2", "fatality", @@ -8776,7 +8857,7 @@ dependencies = [ [[package]] name = "polkadot-statement-table" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "parity-scale-codec", "polkadot-primitives", @@ -8876,7 +8957,7 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "syn 1.0.109", ] @@ -8927,7 +9008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "version_check", @@ -8939,11 +9020,22 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "version_check", ] +[[package]] +name = "proc-macro-warning" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4f284d87b9cedc2ff57223cbc4e3937cd6063c01e92c8e2a8c080df0013933" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + [[package]] name = "proc-macro2" version = "0.4.30" @@ -8955,9 +9047,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.53" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -8994,7 +9086,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -9052,7 +9144,7 @@ checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" dependencies = [ "anyhow", "itertools", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -9134,7 +9226,7 @@ version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", ] [[package]] @@ -9305,6 +9397,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -9312,7 +9413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom 0.2.8", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -9344,9 +9445,9 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 2.0.10", + "syn 2.0.14", ] [[package]] @@ -9691,7 +9792,7 @@ dependencies = [ name = "rialto-bridge-node" version = "0.1.0" dependencies = [ - "clap 4.1.13", + "clap 4.2.2", "frame-benchmarking", "frame-benchmarking-cli", "frame-support", @@ -9718,7 +9819,7 @@ dependencies = [ name = "rialto-parachain-collator" version = "0.1.0" dependencies = [ - "clap 4.1.13", + "clap 4.2.2", "cumulus-client-cli", "cumulus-client-consensus-aura", "cumulus-client-consensus-common", @@ -9790,7 +9891,7 @@ dependencies = [ "frame-system", "frame-system-benchmarking", "frame-system-rpc-runtime-api", - "hex-literal", + "hex-literal 0.4.1", "pallet-aura", "pallet-balances", "pallet-bridge-grandpa", @@ -9921,7 +10022,7 @@ dependencies = [ [[package]] name = "rococo-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "binary-merkle-tree", "frame-benchmarking", @@ -9931,7 +10032,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", @@ -10007,7 +10108,7 @@ dependencies = [ [[package]] name = "rococo-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "frame-support", "polkadot-primitives", @@ -10247,7 +10348,7 @@ dependencies = [ [[package]] name = "sc-allocator" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "log", "sp-core", @@ -10258,7 +10359,7 @@ dependencies = [ [[package]] name = "sc-authority-discovery" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "futures", @@ -10286,7 +10387,7 @@ dependencies = [ [[package]] name = "sc-basic-authorship" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "futures-timer", @@ -10309,7 +10410,7 @@ dependencies = [ [[package]] name = "sc-block-builder" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "sc-client-api", @@ -10324,7 +10425,7 @@ dependencies = [ [[package]] name = "sc-chain-spec" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "memmap2", "sc-chain-spec-derive", @@ -10343,22 +10444,22 @@ dependencies = [ [[package]] name = "sc-chain-spec-derive" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "sc-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "chrono", - "clap 4.1.13", + "clap 4.2.2", "fdlimit", "futures", "libp2p", @@ -10394,7 +10495,7 @@ dependencies = [ [[package]] name = "sc-client-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "fnv", "futures", @@ -10420,7 +10521,7 @@ dependencies = [ [[package]] name = "sc-client-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "hash-db", "kvdb", @@ -10446,7 +10547,7 @@ dependencies = [ [[package]] name = "sc-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "futures", @@ -10471,7 +10572,7 @@ dependencies = [ [[package]] name = "sc-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "futures", @@ -10500,7 +10601,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "fork-tree", @@ -10539,7 +10640,7 @@ dependencies = [ [[package]] name = "sc-consensus-babe-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "jsonrpsee", @@ -10561,7 +10662,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10596,7 +10697,7 @@ dependencies = [ [[package]] name = "sc-consensus-beefy-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "jsonrpsee", @@ -10615,7 +10716,7 @@ dependencies = [ [[package]] name = "sc-consensus-epochs" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "fork-tree", "parity-scale-codec", @@ -10628,7 +10729,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "ahash 0.8.3", "array-bytes 4.2.0", @@ -10668,7 +10769,7 @@ dependencies = [ [[package]] name = "sc-consensus-grandpa-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "finality-grandpa", "futures", @@ -10688,7 +10789,7 @@ dependencies = [ [[package]] name = "sc-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "futures", @@ -10711,7 +10812,7 @@ dependencies = [ [[package]] name = "sc-executor" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "lru 0.8.1", "parity-scale-codec", @@ -10735,7 +10836,7 @@ dependencies = [ [[package]] name = "sc-executor-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "sc-allocator", "sp-maybe-compressed-blob", @@ -10748,7 +10849,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmi" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "log", "sc-allocator", @@ -10761,7 +10862,7 @@ dependencies = [ [[package]] name = "sc-executor-wasmtime" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -10779,7 +10880,7 @@ dependencies = [ [[package]] name = "sc-informant" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "ansi_term", "futures", @@ -10795,7 +10896,7 @@ dependencies = [ [[package]] name = "sc-keystore" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10810,7 +10911,7 @@ dependencies = [ [[package]] name = "sc-network" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "async-channel", @@ -10840,6 +10941,7 @@ dependencies = [ "serde", "serde_json", "smallvec", + "snow", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -10854,7 +10956,7 @@ dependencies = [ [[package]] name = "sc-network-bitswap" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "cid", "futures", @@ -10874,7 +10976,7 @@ dependencies = [ [[package]] name = "sc-network-common" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10902,7 +11004,7 @@ dependencies = [ [[package]] name = "sc-network-gossip" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "ahash 0.8.3", "futures", @@ -10921,7 +11023,7 @@ dependencies = [ [[package]] name = "sc-network-light" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10943,7 +11045,7 @@ dependencies = [ [[package]] name = "sc-network-sync" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "async-trait", @@ -10977,7 +11079,7 @@ dependencies = [ [[package]] name = "sc-network-transactions" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "futures", @@ -10997,7 +11099,7 @@ dependencies = [ [[package]] name = "sc-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "bytes", @@ -11028,7 +11130,7 @@ dependencies = [ [[package]] name = "sc-peerset" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "libp2p", @@ -11041,7 +11143,7 @@ dependencies = [ [[package]] name = "sc-proposer-metrics" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "log", "substrate-prometheus-endpoint", @@ -11050,7 +11152,7 @@ dependencies = [ [[package]] name = "sc-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "jsonrpsee", @@ -11080,7 +11182,7 @@ dependencies = [ [[package]] name = "sc-rpc-api" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11099,7 +11201,7 @@ dependencies = [ [[package]] name = "sc-rpc-server" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "http", "jsonrpsee", @@ -11114,7 +11216,7 @@ dependencies = [ [[package]] name = "sc-rpc-spec-v2" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", "futures", @@ -11140,7 +11242,7 @@ dependencies = [ [[package]] name = "sc-service" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "directories", @@ -11206,7 +11308,7 @@ dependencies = [ [[package]] name = "sc-state-db" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "log", "parity-scale-codec", @@ -11217,9 +11319,9 @@ dependencies = [ [[package]] name = "sc-storage-monitor" version = "0.1.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ - "clap 4.1.13", + "clap 4.2.2", "fs4", "futures", "log", @@ -11233,7 +11335,7 @@ dependencies = [ [[package]] name = "sc-sync-state-rpc" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "jsonrpsee", "parity-scale-codec", @@ -11252,7 +11354,7 @@ dependencies = [ [[package]] name = "sc-sysinfo" version = "6.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "libc", @@ -11271,7 +11373,7 @@ dependencies = [ [[package]] name = "sc-telemetry" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "chrono", "futures", @@ -11290,7 +11392,7 @@ dependencies = [ [[package]] name = "sc-tracing" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "ansi_term", "atty", @@ -11321,18 +11423,18 @@ dependencies = [ [[package]] name = "sc-tracing-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "sc-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "futures", @@ -11359,7 +11461,7 @@ dependencies = [ [[package]] name = "sc-transaction-pool-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "futures", @@ -11373,7 +11475,7 @@ dependencies = [ [[package]] name = "sc-utils" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-channel", "futures", @@ -11410,9 +11512,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61471dff9096de1d8b2319efed7162081e96793f5ebb147e50db10d50d648a4d" +checksum = "0cfdffd972d76b22f3d7f81c8be34b2296afd3a25e0a547bd9abe340a4dbbe97" dependencies = [ "bitvec", "cfg-if 1.0.0", @@ -11424,12 +11526,12 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219580e803a66b3f05761fd06f1f879a872444e49ce23f73694d26e5a954c7e6" +checksum = "61fa974aea2d63dd18a4ec3a49d59af9f34178c73a4f56d2f18205628d00681e" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -11637,29 +11739,29 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.158" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.158" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 2.0.10", + "syn 2.0.14", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "indexmap", "itoa", @@ -11667,6 +11769,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + [[package]] name = "sha-1" version = "0.9.8" @@ -11840,7 +11951,7 @@ checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" [[package]] name = "slot-range-helper" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "enumn", "parity-scale-codec", @@ -11928,13 +12039,15 @@ dependencies = [ [[package]] name = "sp-api" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "hash-db", "log", "parity-scale-codec", + "scale-info", "sp-api-proc-macro", "sp-core", + "sp-metadata-ir", "sp-runtime", "sp-state-machine", "sp-std 5.0.0", @@ -11946,21 +12059,21 @@ dependencies = [ [[package]] name = "sp-api-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "Inflector", "blake2", "expander 1.0.0", "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "sp-application-crypto" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "scale-info", @@ -11973,7 +12086,7 @@ dependencies = [ [[package]] name = "sp-arithmetic" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "integer-sqrt", "num-traits", @@ -11987,7 +12100,7 @@ dependencies = [ [[package]] name = "sp-authority-discovery" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "scale-info", @@ -12000,7 +12113,7 @@ dependencies = [ [[package]] name = "sp-block-builder" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "sp-api", @@ -12012,7 +12125,7 @@ dependencies = [ [[package]] name = "sp-blockchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "log", @@ -12030,7 +12143,7 @@ dependencies = [ [[package]] name = "sp-consensus" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "futures", @@ -12045,7 +12158,7 @@ dependencies = [ [[package]] name = "sp-consensus-aura" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "parity-scale-codec", @@ -12063,7 +12176,7 @@ dependencies = [ [[package]] name = "sp-consensus-babe" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "merlin", @@ -12086,7 +12199,7 @@ dependencies = [ [[package]] name = "sp-consensus-beefy" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "lazy_static", "parity-scale-codec", @@ -12105,7 +12218,7 @@ dependencies = [ [[package]] name = "sp-consensus-grandpa" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "finality-grandpa", "log", @@ -12123,7 +12236,7 @@ dependencies = [ [[package]] name = "sp-consensus-slots" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "scale-info", @@ -12135,7 +12248,7 @@ dependencies = [ [[package]] name = "sp-consensus-vrf" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "scale-info", @@ -12148,13 +12261,13 @@ dependencies = [ [[package]] name = "sp-core" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "array-bytes 4.2.0", - "base58", "bitflags", "blake2", "bounded-collections", + "bs58", "dyn-clonable", "ed25519-zebra", "futures", @@ -12191,7 +12304,7 @@ dependencies = [ [[package]] name = "sp-core-hashing" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "blake2b_simd", "byteorder", @@ -12220,18 +12333,18 @@ dependencies = [ [[package]] name = "sp-core-hashing-proc-macro" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "sp-core-hashing 5.0.0", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "sp-database" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "kvdb", "parking_lot 0.12.1", @@ -12240,17 +12353,17 @@ dependencies = [ [[package]] name = "sp-debug-derive" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "sp-externalities" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "environmental", "parity-scale-codec", @@ -12261,7 +12374,7 @@ dependencies = [ [[package]] name = "sp-inherents" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "impl-trait-for-tuples", @@ -12276,7 +12389,7 @@ dependencies = [ [[package]] name = "sp-io" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "bytes", "ed25519", @@ -12285,6 +12398,7 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", + "rustversion", "secp256k1", "sp-core", "sp-externalities", @@ -12301,7 +12415,7 @@ dependencies = [ [[package]] name = "sp-keyring" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "lazy_static", "sp-core", @@ -12312,7 +12426,7 @@ dependencies = [ [[package]] name = "sp-keystore" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "futures", "merlin", @@ -12328,16 +12442,27 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "4.1.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "thiserror", - "zstd", + "zstd 0.12.3+zstd.1.5.2", +] + +[[package]] +name = "sp-metadata-ir" +version = "0.1.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-std 5.0.0", ] [[package]] name = "sp-mmr-primitives" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "ckb-merkle-mountain-range 0.5.2", "log", @@ -12355,7 +12480,7 @@ dependencies = [ [[package]] name = "sp-npos-elections" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "scale-info", @@ -12369,7 +12494,7 @@ dependencies = [ [[package]] name = "sp-offchain" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "sp-api", "sp-core", @@ -12379,7 +12504,7 @@ dependencies = [ [[package]] name = "sp-panic-handler" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "backtrace", "lazy_static", @@ -12389,7 +12514,7 @@ dependencies = [ [[package]] name = "sp-rpc" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "rustc-hash", "serde", @@ -12399,7 +12524,7 @@ dependencies = [ [[package]] name = "sp-runtime" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "either", "hash256-std-hasher", @@ -12421,7 +12546,7 @@ dependencies = [ [[package]] name = "sp-runtime-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "bytes", "impl-trait-for-tuples", @@ -12439,19 +12564,19 @@ dependencies = [ [[package]] name = "sp-runtime-interface-proc-macro" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "Inflector", "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "sp-session" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "scale-info", @@ -12465,7 +12590,7 @@ dependencies = [ [[package]] name = "sp-staking" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "scale-info", @@ -12477,7 +12602,7 @@ dependencies = [ [[package]] name = "sp-state-machine" version = "0.13.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "hash-db", "log", @@ -12497,7 +12622,7 @@ dependencies = [ [[package]] name = "sp-std" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" [[package]] name = "sp-std" @@ -12508,7 +12633,7 @@ checksum = "af0ee286f98455272f64ac5bb1384ff21ac029fbb669afbaf48477faff12760e" [[package]] name = "sp-storage" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12521,7 +12646,7 @@ dependencies = [ [[package]] name = "sp-timestamp" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "futures-timer", @@ -12536,7 +12661,7 @@ dependencies = [ [[package]] name = "sp-tracing" version = "6.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "sp-std 5.0.0", @@ -12548,7 +12673,7 @@ dependencies = [ [[package]] name = "sp-transaction-pool" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "sp-api", "sp-runtime", @@ -12557,7 +12682,7 @@ dependencies = [ [[package]] name = "sp-transaction-storage-proof" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "log", @@ -12573,7 +12698,7 @@ dependencies = [ [[package]] name = "sp-trie" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "ahash 0.8.3", "hash-db", @@ -12596,7 +12721,7 @@ dependencies = [ [[package]] name = "sp-version" version = "5.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "impl-serde", "parity-scale-codec", @@ -12613,18 +12738,18 @@ dependencies = [ [[package]] name = "sp-version-proc-macro" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] name = "sp-wasm-interface" version = "7.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "anyhow", "impl-trait-for-tuples", @@ -12638,7 +12763,7 @@ dependencies = [ [[package]] name = "sp-weights" version = "4.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "parity-scale-codec", "scale-info", @@ -12684,7 +12809,7 @@ checksum = "ecf0bd63593ef78eca595a7fc25e9a443ca46fe69fd472f8f09f5245cdcd769d" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "serde", "serde_json", @@ -12738,7 +12863,7 @@ checksum = "f2261c91034a1edc3fc4d1b80e89d82714faede0515c14a75da10cb941546bbf" dependencies = [ "cfg_aliases", "memchr", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -12751,7 +12876,7 @@ checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ "cfg_aliases", "memchr", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -12802,7 +12927,7 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -12823,7 +12948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "rustversion", "syn 1.0.109", @@ -12864,7 +12989,7 @@ dependencies = [ [[package]] name = "substrate-build-script-utils" version = "3.0.0" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "platforms 2.0.0", ] @@ -12872,7 +12997,7 @@ dependencies = [ [[package]] name = "substrate-frame-rpc-system" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "frame-system-rpc-runtime-api", "futures", @@ -12891,7 +13016,7 @@ dependencies = [ [[package]] name = "substrate-prometheus-endpoint" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "hyper", "log", @@ -12921,7 +13046,7 @@ dependencies = [ "frame-support", "futures", "hex", - "hex-literal", + "hex-literal 0.4.1", "log", "millau-runtime", "num-format", @@ -13010,7 +13135,7 @@ dependencies = [ [[package]] name = "substrate-rpc-client" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", "jsonrpsee", @@ -13023,7 +13148,7 @@ dependencies = [ [[package]] name = "substrate-state-trie-migration-rpc" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "jsonrpsee", "log", @@ -13042,7 +13167,7 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" version = "5.0.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "ansi_term", "build-helper", @@ -13051,7 +13176,7 @@ dependencies = [ "sp-maybe-compressed-blob", "strum", "tempfile", - "toml", + "toml 0.7.3", "walkdir", "wasm-opt", ] @@ -13114,7 +13239,7 @@ dependencies = [ "jsonrpsee", "parity-scale-codec", "proc-macro-error", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "scale-info", "subxt-metadata", @@ -13163,18 +13288,18 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.10" +version = "2.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "unicode-ident", ] @@ -13185,7 +13310,7 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "unicode-xid 0.2.4", @@ -13241,15 +13366,15 @@ checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if 1.0.0", "fastrand", - "redox_syscall", - "rustix 0.36.11", - "windows-sys 0.42.0", + "redox_syscall 0.3.5", + "rustix 0.37.3", + "windows-sys 0.45.0", ] [[package]] @@ -13291,9 +13416,9 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 2.0.10", + "syn 2.0.14", ] [[package]] @@ -13450,14 +13575,13 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.26.0" +version = "1.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "num_cpus", "parking_lot 0.12.1", @@ -13470,13 +13594,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -13526,11 +13650,26 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + [[package]] name = "toml_datetime" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -13539,6 +13678,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ "indexmap", + "serde", + "serde_spanned", "toml_datetime", "winnow", ] @@ -13603,7 +13744,7 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", ] @@ -13631,7 +13772,7 @@ dependencies = [ [[package]] name = "tracing-gum" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "polkadot-node-jaeger", "polkadot-primitives", @@ -13642,13 +13783,13 @@ dependencies = [ [[package]] name = "tracing-gum-proc-macro" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ - "expander 0.0.6", + "expander 2.0.0", "proc-macro-crate", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -13772,10 +13913,10 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "try-runtime-cli" version = "0.10.0-dev" -source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" dependencies = [ "async-trait", - "clap 4.1.13", + "clap 4.2.2", "frame-remote-externalities", "hex", "log", @@ -13802,7 +13943,7 @@ dependencies = [ "sp-version", "sp-weights", "substrate-rpc-client", - "zstd", + "zstd 0.12.3+zstd.1.5.2", ] [[package]] @@ -13960,6 +14101,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" version = "1.3.0" @@ -14081,7 +14228,7 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "wasm-bindgen-shared", @@ -14115,7 +14262,7 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "wasm-bindgen-backend", @@ -14289,9 +14436,9 @@ dependencies = [ "rustix 0.36.11", "serde", "sha2 0.10.6", - "toml", + "toml 0.5.11", "windows-sys 0.42.0", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -14670,7 +14817,7 @@ dependencies = [ [[package]] name = "westend-runtime" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bitvec", "frame-benchmarking", @@ -14681,7 +14828,7 @@ dependencies = [ "frame-system-benchmarking", "frame-system-rpc-runtime-api", "frame-try-runtime", - "hex-literal", + "hex-literal 0.3.4", "log", "pallet-authority-discovery", "pallet-authorship", @@ -14762,7 +14909,7 @@ dependencies = [ [[package]] name = "westend-runtime-constants" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "frame-support", "polkadot-primitives", @@ -14850,7 +14997,7 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", ] [[package]] @@ -14859,12 +15006,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.2", "windows_aarch64_msvc 0.42.2", "windows_i686_gnu 0.42.2", "windows_i686_msvc 0.42.2", "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.2", "windows_x86_64_msvc 0.42.2", ] @@ -14874,7 +15021,16 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", ] [[package]] @@ -14883,21 +15039,42 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.42.2", "windows_aarch64_msvc 0.42.2", "windows_i686_gnu 0.42.2", "windows_i686_msvc 0.42.2", "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.42.2", "windows_x86_64_msvc 0.42.2", ] +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + [[package]] name = "windows_aarch64_msvc" version = "0.34.0" @@ -14910,6 +15087,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + [[package]] name = "windows_i686_gnu" version = "0.34.0" @@ -14922,6 +15105,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + [[package]] name = "windows_i686_msvc" version = "0.34.0" @@ -14934,6 +15123,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + [[package]] name = "windows_x86_64_gnu" version = "0.34.0" @@ -14946,12 +15141,24 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + [[package]] name = "windows_x86_64_msvc" version = "0.34.0" @@ -14964,6 +15171,12 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + [[package]] name = "winnow" version = "0.4.0" @@ -15053,7 +15266,7 @@ dependencies = [ [[package]] name = "xcm" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "bounded-collections", "derivative", @@ -15069,7 +15282,7 @@ dependencies = [ [[package]] name = "xcm-builder" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "frame-support", "frame-system", @@ -15090,7 +15303,7 @@ dependencies = [ [[package]] name = "xcm-executor" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "environmental", "frame-benchmarking", @@ -15110,12 +15323,12 @@ dependencies = [ [[package]] name = "xcm-procedural" version = "0.9.39" -source = "git+https://github.com/paritytech/polkadot?branch=master#2bbef460d24f44aeba9d4014062bb8c631327496" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" dependencies = [ "Inflector", - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", - "syn 1.0.109", + "syn 2.0.14", ] [[package]] @@ -15162,7 +15375,7 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ - "proc-macro2 1.0.53", + "proc-macro2 1.0.56", "quote 1.0.26", "syn 1.0.109", "synstructure", @@ -15174,7 +15387,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.12.3+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +dependencies = [ + "zstd-safe 6.0.5+zstd.1.5.4", ] [[package]] @@ -15187,6 +15409,16 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "6.0.5+zstd.1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +dependencies = [ + "libc", + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.7+zstd.1.5.4" diff --git a/bin/millau/node/Cargo.toml b/bin/millau/node/Cargo.toml index cfe6e921f4b..21b5cd02559 100644 --- a/bin/millau/node/Cargo.toml +++ b/bin/millau/node/Cargo.toml @@ -9,9 +9,9 @@ repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -clap = { version = "4.1.13", features = ["derive"] } +clap = { version = "4.2.2", features = ["derive"] } jsonrpsee = { version = "0.16.2", features = ["server"] } -serde_json = "1.0.94" +serde_json = "1.0.96" # Bridge dependencies diff --git a/bin/millau/node/src/service.rs b/bin/millau/node/src/service.rs index 7230accef8e..07cd29a0d6d 100644 --- a/bin/millau/node/src/service.rs +++ b/bin/millau/node/src/service.rs @@ -22,6 +22,7 @@ use sc_client_api::BlockBackend; use sc_consensus_aura::{CompatibilityMode, ImportQueueParams, SlotProportion, StartAuraParams}; use sc_consensus_grandpa::SharedVoterState; pub use sc_executor::NativeElseWasmExecutor; +use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; use sc_telemetry::{Telemetry, TelemetryWorker}; use sp_consensus_aura::sr25519::AuthorityPair as AuraPair; @@ -88,11 +89,17 @@ pub fn new_partial( }) .transpose()?; - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, + let heap_pages = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); + let executor = NativeElseWasmExecutor::::new_with_wasm_executor( + WasmExecutor::builder() + .with_execution_method(config.wasm_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .build(), ); let (client, backend, keystore_container, task_manager) = diff --git a/bin/millau/runtime/Cargo.toml b/bin/millau/runtime/Cargo.toml index 2f828393336..e1a55ea6f24 100644 --- a/bin/millau/runtime/Cargo.toml +++ b/bin/millau/runtime/Cargo.toml @@ -7,9 +7,9 @@ repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -hex-literal = "0.3" +hex-literal = "0.4" codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Bridge dependencies @@ -69,7 +69,7 @@ xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } [dev-dependencies] -bridge-runtime-common = { path = "../../runtime-common", features = ["integrity-test"] } +bridge-runtime-common = { path = "../../runtime-common", features = ["integrity-test", "std"] } env_logger = "0.10" static_assertions = "1.1" diff --git a/bin/millau/runtime/src/lib.rs b/bin/millau/runtime/src/lib.rs index b0c6b2875fe..4e6f1e43e8c 100644 --- a/bin/millau/runtime/src/lib.rs +++ b/bin/millau/runtime/src/lib.rs @@ -399,11 +399,7 @@ pub type RialtoGrandpaInstance = (); impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_rialto::Rialto; - // This is a pretty unscientific cap. - // - // Note that once this is hit the pallet will essentially throttle incoming requests down to one - // call per block. - type MaxRequests = ConstU32<50>; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; type HeadersToKeep = ConstU32<{ bp_rialto::DAYS }>; type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; } @@ -412,7 +408,7 @@ pub type WestendGrandpaInstance = pallet_bridge_grandpa::Instance1; impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_westend::Westend; - type MaxRequests = ConstU32<50>; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; type HeadersToKeep = ConstU32<{ bp_westend::DAYS }>; type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; } @@ -593,11 +589,13 @@ generate_bridge_reject_obsolete_headers_and_messages! { bp_runtime::generate_static_str_provider!(BridgeRefundRialtoPara2000Lane0Msgs); /// Signed extension that refunds relayers that are delivering messages from the Rialto parachain. +pub type PriorityBoostPerMessage = ConstU64<921_900_294>; pub type BridgeRefundRialtoParachainMessages = RefundBridgedParachainMessages< Runtime, RefundableParachain, RefundableMessagesLane, ActualFeeRefund, + PriorityBoostPerMessage, StrBridgeRefundRialtoPara2000Lane0Msgs, >; diff --git a/bin/millau/runtime/src/rialto_parachain_messages.rs b/bin/millau/runtime/src/rialto_parachain_messages.rs index b3d33c1cefd..bef8a281188 100644 --- a/bin/millau/runtime/src/rialto_parachain_messages.rs +++ b/bin/millau/runtime/src/rialto_parachain_messages.rs @@ -137,3 +137,73 @@ impl XcmBlobHauler for ToRialtoParachainXcmBlobHauler { XCM_LANE } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + PriorityBoostPerMessage, RialtoGrandpaInstance, Runtime, + WithRialtoParachainMessagesInstance, + }; + + use bridge_runtime_common::{ + assert_complete_bridge_types, + integrity::{ + assert_complete_bridge_constants, check_message_lane_weights, + AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, + AssertCompleteBridgeConstants, + }, + }; + + #[test] + fn ensure_millau_message_lane_weights_are_correct() { + check_message_lane_weights::( + bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE, + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + ); + } + + #[test] + fn ensure_bridge_integrity() { + assert_complete_bridge_types!( + runtime: Runtime, + with_bridged_chain_grandpa_instance: RialtoGrandpaInstance, + with_bridged_chain_messages_instance: WithRialtoParachainMessagesInstance, + bridge: WithRialtoParachainMessageBridge, + this_chain: bp_millau::Millau, + bridged_chain: bp_rialto::Rialto, + ); + + assert_complete_bridge_constants::< + Runtime, + RialtoGrandpaInstance, + WithRialtoParachainMessagesInstance, + WithRialtoParachainMessageBridge, + >(AssertCompleteBridgeConstants { + this_chain_constants: AssertChainConstants { + block_length: bp_millau::BlockLength::get(), + block_weights: bp_millau::BlockWeights::get(), + }, + messages_pallet_constants: AssertBridgeMessagesPalletConstants { + max_unrewarded_relayers_in_bridged_confirmation_tx: + bp_rialto_parachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + max_unconfirmed_messages_in_bridged_confirmation_tx: + bp_rialto_parachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + bridged_chain_id: bp_runtime::RIALTO_PARACHAIN_CHAIN_ID, + }, + pallet_names: AssertBridgePalletNames { + with_this_chain_messages_pallet_name: bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME, + with_bridged_chain_grandpa_pallet_name: bp_rialto::WITH_RIALTO_GRANDPA_PALLET_NAME, + with_bridged_chain_messages_pallet_name: + bp_rialto_parachain::WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME, + }, + }); + + bridge_runtime_common::priority_calculator::ensure_priority_boost_is_sane::< + Runtime, + WithRialtoParachainMessagesInstance, + PriorityBoostPerMessage, + >(1_000_000); + } +} diff --git a/bin/rialto-parachain/node/Cargo.toml b/bin/rialto-parachain/node/Cargo.toml index c60bad8386a..2315eb94a11 100644 --- a/bin/rialto-parachain/node/Cargo.toml +++ b/bin/rialto-parachain/node/Cargo.toml @@ -17,7 +17,7 @@ default = [] runtime-benchmarks = ['rialto-parachain-runtime/runtime-benchmarks'] [dependencies] -clap = { version = "4.1.13", features = ["derive"] } +clap = { version = "4.2.2", features = ["derive"] } log = '0.4.17' codec = { package = 'parity-scale-codec', version = '3.1.5' } serde = { version = '1.0', features = ['derive'] } diff --git a/bin/rialto-parachain/node/src/service.rs b/bin/rialto-parachain/node/src/service.rs index 6662b2e9625..24eb94e655d 100644 --- a/bin/rialto-parachain/node/src/service.rs +++ b/bin/rialto-parachain/node/src/service.rs @@ -41,7 +41,10 @@ use cumulus_primitives_core::ParaId; use cumulus_relay_chain_interface::RelayChainInterface; use sc_consensus::ImportQueue; // Substrate Imports -use sc_executor::{NativeElseWasmExecutor, NativeExecutionDispatch}; +use sc_executor::{ + HeapAllocStrategy, NativeElseWasmExecutor, NativeExecutionDispatch, WasmExecutor, + DEFAULT_HEAP_ALLOC_STRATEGY, +}; use sc_network::NetworkBlock; use sc_network_sync::SyncingService; use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; @@ -131,12 +134,19 @@ where }) .transpose()?; - let executor = sc_executor::NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - config.runtime_cache_size, - ); + let heap_pages = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); + let executor = + sc_executor::NativeElseWasmExecutor::::new_with_wasm_executor( + WasmExecutor::builder() + .with_execution_method(config.wasm_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .build(), + ); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( diff --git a/bin/rialto-parachain/runtime/Cargo.toml b/bin/rialto-parachain/runtime/Cargo.toml index 0018c8f3905..53f57e02619 100644 --- a/bin/rialto-parachain/runtime/Cargo.toml +++ b/bin/rialto-parachain/runtime/Cargo.toml @@ -11,8 +11,8 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran [dependencies] codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false, features = ['derive']} -hex-literal = "0.3" -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +hex-literal = "0.4" +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Bridge depedencies diff --git a/bin/rialto-parachain/runtime/src/lib.rs b/bin/rialto-parachain/runtime/src/lib.rs index b5419e2c25e..cd4e256f420 100644 --- a/bin/rialto-parachain/runtime/src/lib.rs +++ b/bin/rialto-parachain/runtime/src/lib.rs @@ -540,11 +540,7 @@ pub type MillauGrandpaInstance = (); impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_millau::Millau; - /// This is a pretty unscientific cap. - /// - /// Note that once this is hit the pallet will essentially throttle incoming requests down to - /// one call per block. - type MaxRequests = ConstU32<50>; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; type HeadersToKeep = ConstU32<{ bp_millau::DAYS as u32 }>; type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; } diff --git a/bin/rialto/node/Cargo.toml b/bin/rialto/node/Cargo.toml index bc8841c4f87..23c7d3315e7 100644 --- a/bin/rialto/node/Cargo.toml +++ b/bin/rialto/node/Cargo.toml @@ -9,8 +9,8 @@ repository = "https://github.com/paritytech/parity-bridges-common/" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] -clap = { version = "4.1.13", features = ["derive"] } -serde_json = "1.0.94" +clap = { version = "4.2.2", features = ["derive"] } +serde_json = "1.0.96" # Bridge dependencies diff --git a/bin/rialto/node/src/command.rs b/bin/rialto/node/src/command.rs index 8286444d3ea..0bff2e523b4 100644 --- a/bin/rialto/node/src/command.rs +++ b/bin/rialto/node/src/command.rs @@ -164,7 +164,7 @@ pub fn run() -> sc_cli::Result<()> { builder.with_colors(false); let _ = builder.init(); - polkadot_node_core_pvf::prepare_worker_entrypoint(&cmd.socket_path); + polkadot_node_core_pvf::prepare_worker_entrypoint(&cmd.socket_path, None); Ok(()) }, Some(crate::cli::Subcommand::PvfExecuteWorker(cmd)) => { @@ -172,7 +172,7 @@ pub fn run() -> sc_cli::Result<()> { builder.with_colors(false); let _ = builder.init(); - polkadot_node_core_pvf::execute_worker_entrypoint(&cmd.socket_path); + polkadot_node_core_pvf::execute_worker_entrypoint(&cmd.socket_path, None); Ok(()) }, None => { diff --git a/bin/rialto/runtime/Cargo.toml b/bin/rialto/runtime/Cargo.toml index 4f0f64cbc95..2b68e72d6f8 100644 --- a/bin/rialto/runtime/Cargo.toml +++ b/bin/rialto/runtime/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.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/bin/rialto/runtime/src/lib.rs b/bin/rialto/runtime/src/lib.rs index 1a6f0f1e540..aeb0a3a7c57 100644 --- a/bin/rialto/runtime/src/lib.rs +++ b/bin/rialto/runtime/src/lib.rs @@ -396,11 +396,7 @@ pub type MillauGrandpaInstance = (); impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_millau::Millau; - /// This is a pretty unscientific cap. - /// - /// Note that once this is hit the pallet will essentially throttle incoming requests down to - /// one call per block. - type MaxRequests = ConstU32<50>; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; type HeadersToKeep = ConstU32<{ bp_millau::DAYS as u32 }>; type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; } diff --git a/bin/runtime-common/Cargo.toml b/bin/runtime-common/Cargo.toml index e4a5d7ccce1..3db4ae9abca 100644 --- a/bin/runtime-common/Cargo.toml +++ b/bin/runtime-common/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, features = ["derive"] } hash-db = { version = "0.16.0", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } static_assertions = { version = "1.1", optional = true } # Bridge dependencies diff --git a/bin/runtime-common/src/integrity.rs b/bin/runtime-common/src/integrity.rs index 96716fe851c..5820dd99b91 100644 --- a/bin/runtime-common/src/integrity.rs +++ b/bin/runtime-common/src/integrity.rs @@ -178,9 +178,9 @@ where GI: 'static, { assert!( - R::MaxRequests::get() > 0, - "MaxRequests ({}) must be larger than zero", - R::MaxRequests::get(), + R::HeadersToKeep::get() > 0, + "HeadersToKeep ({}) must be larger than zero", + R::HeadersToKeep::get(), ); } diff --git a/bin/runtime-common/src/lib.rs b/bin/runtime-common/src/lib.rs index ed486c04abc..e8a2d2470fa 100644 --- a/bin/runtime-common/src/lib.rs +++ b/bin/runtime-common/src/lib.rs @@ -30,6 +30,7 @@ pub mod messages_benchmarking; pub mod messages_call_ext; pub mod messages_xcm_extension; pub mod parachains_benchmarking; +pub mod priority_calculator; pub mod refund_relayer_extension; mod messages_generation; diff --git a/bin/runtime-common/src/messages_call_ext.rs b/bin/runtime-common/src/messages_call_ext.rs index 588afad106d..f3665a8d93b 100644 --- a/bin/runtime-common/src/messages_call_ext.rs +++ b/bin/runtime-common/src/messages_call_ext.rs @@ -17,33 +17,96 @@ use crate::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; -use bp_messages::{LaneId, MessageNonce}; -use frame_support::{dispatch::CallableCallFor, traits::IsSubType, RuntimeDebug}; +use bp_messages::{InboundLaneData, LaneId, MessageNonce}; +use frame_support::{ + dispatch::CallableCallFor, + traits::{Get, IsSubType}, + RuntimeDebug, +}; use pallet_bridge_messages::{Config, Pallet}; use sp_runtime::transaction_validity::TransactionValidity; +use sp_std::ops::RangeInclusive; /// Generic info about a messages delivery/confirmation proof. #[derive(PartialEq, RuntimeDebug)] pub struct BaseMessagesProofInfo { + /// Message lane, used by the call. pub lane_id: LaneId, - pub best_bundled_nonce: MessageNonce, + /// Nonces of messages, included in the call. + /// + /// For delivery transaction, it is nonces of bundled messages. For confirmation + /// transaction, it is nonces that are to be confirmed during the call. + pub bundled_range: RangeInclusive, + /// Nonce of the best message, stored by this chain before the call is dispatched. + /// + /// For delivery transaction, it is the nonce of best delivered message before the call. + /// For confirmation transaction, it is the nonce of best confirmed message before the call. pub best_stored_nonce: MessageNonce, } impl BaseMessagesProofInfo { - fn is_obsolete(&self) -> bool { - self.best_bundled_nonce <= self.best_stored_nonce + /// Returns true if `bundled_range` continues the `0..=best_stored_nonce` range. + fn appends_to_stored_nonce(&self) -> bool { + *self.bundled_range.start() == self.best_stored_nonce + 1 } } +/// Occupation state of the unrewarded relayers vector. +#[derive(PartialEq, RuntimeDebug)] +#[cfg_attr(test, derive(Default))] +pub struct UnrewardedRelayerOccupation { + /// The number of remaining unoccupied entries for new relayers. + pub free_relayer_slots: MessageNonce, + /// The number of messages that we are ready to accept. + pub free_message_slots: MessageNonce, +} + /// Info about a `ReceiveMessagesProof` call which tries to update a single lane. #[derive(PartialEq, RuntimeDebug)] -pub struct ReceiveMessagesProofInfo(pub BaseMessagesProofInfo); +pub struct ReceiveMessagesProofInfo { + /// Base messages proof info + pub base: BaseMessagesProofInfo, + /// State of unrewarded relayers vector. + pub unrewarded_relayers: UnrewardedRelayerOccupation, +} + +impl ReceiveMessagesProofInfo { + /// Returns true if: + /// + /// - either inbound lane is ready to accept bundled messages; + /// + /// - or there are no bundled messages, but the inbound lane is blocked by too many unconfirmed + /// messages and/or unrewarded relayers. + fn is_obsolete(&self) -> bool { + // transactions with zero bundled nonces are not allowed, unless they're message + // delivery transactions, which brings reward confirmations required to unblock + // the lane + if self.base.bundled_range.is_empty() { + let empty_transactions_allowed = + // we allow empty transactions when we can't accept delivery from new relayers + self.unrewarded_relayers.free_relayer_slots == 0 || + // or if we can't accept new messages at all + self.unrewarded_relayers.free_message_slots == 0; + + return !empty_transactions_allowed + } + + // otherwise we require bundled messages to continue stored range + !self.base.appends_to_stored_nonce() + } +} /// Info about a `ReceiveMessagesDeliveryProof` call which tries to update a single lane. #[derive(PartialEq, RuntimeDebug)] pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); +impl ReceiveMessagesDeliveryProofInfo { + /// Returns true if outbound lane is ready to accept confirmations of bundled messages. + fn is_obsolete(&self) -> bool { + self.0.bundled_range.is_empty() || !self.0.appends_to_stored_nonce() + } +} + /// Info about a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call /// which tries to update a single lane. #[derive(PartialEq, RuntimeDebug)] @@ -58,19 +121,34 @@ pub struct CallHelper, I: 'static> { } impl, I: 'static> CallHelper { - /// Check if a call delivered proof/confirmation for at least some of the messages that it - /// contained. - pub fn was_partially_successful(info: &CallInfo) -> bool { + /// Returns true if: + /// + /// - call is `receive_messages_proof` and all messages have been delivered; + /// + /// - call is `receive_messages_delivery_proof` and all messages confirmations have been + /// received. + pub fn was_successful(info: &CallInfo) -> bool { match info { CallInfo::ReceiveMessagesProof(info) => { let inbound_lane_data = - pallet_bridge_messages::InboundLanes::::get(info.0.lane_id); - inbound_lane_data.last_delivered_nonce() > info.0.best_stored_nonce + pallet_bridge_messages::InboundLanes::::get(info.base.lane_id); + if info.base.bundled_range.is_empty() { + let post_occupation = + unrewarded_relayers_occupation::(&inbound_lane_data); + // we don't care about `free_relayer_slots` here - it is checked in + // `is_obsolete` and every relayer has delivered at least one message, + // so if relayer slots are released, then message slots are also + // released + return post_occupation.free_message_slots > + info.unrewarded_relayers.free_message_slots + } + + inbound_lane_data.last_delivered_nonce() == *info.base.bundled_range.end() }, CallInfo::ReceiveMessagesDeliveryProof(info) => { let outbound_lane_data = pallet_bridge_messages::OutboundLanes::::get(info.0.lane_id); - outbound_lane_data.latest_received_nonce > info.0.best_stored_nonce + outbound_lane_data.latest_received_nonce == *info.0.bundled_range.end() }, } } @@ -124,11 +202,16 @@ impl< { let inbound_lane_data = pallet_bridge_messages::InboundLanes::::get(proof.lane); - return Some(ReceiveMessagesProofInfo(BaseMessagesProofInfo { - lane_id: proof.lane, - best_bundled_nonce: proof.nonces_end, - best_stored_nonce: inbound_lane_data.last_delivered_nonce(), - })) + return Some(ReceiveMessagesProofInfo { + base: BaseMessagesProofInfo { + lane_id: proof.lane, + // we want all messages in this range to be new for us. Otherwise transaction + // will be considered obsolete. + bundled_range: proof.nonces_start..=proof.nonces_end, + best_stored_nonce: inbound_lane_data.last_delivered_nonce(), + }, + unrewarded_relayers: unrewarded_relayers_occupation::(&inbound_lane_data), + }) } None @@ -145,7 +228,12 @@ impl< return Some(ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { lane_id: proof.lane, - best_bundled_nonce: relayers_state.last_delivered_nonce, + // there's a time frame between message delivery, message confirmation and reward + // confirmation. Because of that, we can't assume that our state has been confirmed + // to the bridged chain. So we are accepting any proof that brings new + // confirmations. + bundled_range: outbound_lane_data.latest_received_nonce + 1..= + relayers_state.last_delivered_nonce, best_stored_nonce: outbound_lane_data.latest_received_nonce, })) } @@ -168,7 +256,7 @@ impl< fn call_info_for(&self, lane_id: LaneId) -> Option { self.call_info().filter(|info| { let actual_lane_id = match info { - CallInfo::ReceiveMessagesProof(info) => info.0.lane_id, + CallInfo::ReceiveMessagesProof(info) => info.base.lane_id, CallInfo::ReceiveMessagesDeliveryProof(info) => info.0.lane_id, }; actual_lane_id == lane_id @@ -177,7 +265,7 @@ impl< fn check_obsolete_call(&self) -> TransactionValidity { match self.call_info() { - Some(CallInfo::ReceiveMessagesProof(proof_info)) if proof_info.0.is_obsolete() => { + Some(CallInfo::ReceiveMessagesProof(proof_info)) if proof_info.is_obsolete() => { log::trace!( target: pallet_bridge_messages::LOG_TARGET, "Rejecting obsolete messages delivery transaction: {:?}", @@ -187,7 +275,7 @@ impl< return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() }, Some(CallInfo::ReceiveMessagesDeliveryProof(proof_info)) - if proof_info.0.is_obsolete() => + if proof_info.is_obsolete() => { log::trace!( target: pallet_bridge_messages::LOG_TARGET, @@ -204,20 +292,72 @@ impl< } } +/// Returns occupation state of unrewarded relayers vector. +fn unrewarded_relayers_occupation, I: 'static>( + inbound_lane_data: &InboundLaneData, +) -> UnrewardedRelayerOccupation { + UnrewardedRelayerOccupation { + free_relayer_slots: T::MaxUnrewardedRelayerEntriesAtInboundLane::get() + .saturating_sub(inbound_lane_data.relayers.len() as MessageNonce), + free_message_slots: { + let unconfirmed_messages = inbound_lane_data + .last_delivered_nonce() + .saturating_sub(inbound_lane_data.last_confirmed_nonce); + T::MaxUnconfirmedMessagesAtInboundLane::get().saturating_sub(unconfirmed_messages) + }, + } +} + #[cfg(test)] mod tests { + use super::*; use crate::{ messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }, messages_call_ext::MessagesCallSubType, - mock::{TestRuntime, ThisChainRuntimeCall}, + mock::{ + MaxUnconfirmedMessagesAtInboundLane, MaxUnrewardedRelayerEntriesAtInboundLane, + TestRuntime, ThisChainRuntimeCall, + }, }; - use bp_messages::UnrewardedRelayersState; + use bp_messages::{DeliveredMessages, UnrewardedRelayer, UnrewardedRelayersState}; + use sp_std::ops::RangeInclusive; + + fn fill_unrewarded_relayers() { + let mut inbound_lane_state = + pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); + for n in 0..MaxUnrewardedRelayerEntriesAtInboundLane::get() { + inbound_lane_state.relayers.push_back(UnrewardedRelayer { + relayer: Default::default(), + messages: DeliveredMessages { begin: n + 1, end: n + 1 }, + }); + } + pallet_bridge_messages::InboundLanes::::insert( + LaneId([0, 0, 0, 0]), + inbound_lane_state, + ); + } + + fn fill_unrewarded_messages() { + let mut inbound_lane_state = + pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); + inbound_lane_state.relayers.push_back(UnrewardedRelayer { + relayer: Default::default(), + messages: DeliveredMessages { + begin: 1, + end: MaxUnconfirmedMessagesAtInboundLane::get(), + }, + }); + pallet_bridge_messages::InboundLanes::::insert( + LaneId([0, 0, 0, 0]), + inbound_lane_state, + ); + } fn deliver_message_10() { pallet_bridge_messages::InboundLanes::::insert( - bp_messages::LaneId([0, 0, 0, 0]), + LaneId([0, 0, 0, 0]), bp_messages::InboundLaneData { relayers: Default::default(), last_confirmed_nonce: 10 }, ); } @@ -229,12 +369,13 @@ mod tests { ThisChainRuntimeCall::BridgeMessages( pallet_bridge_messages::Call::::receive_messages_proof { relayer_id_at_bridged_chain: 42, - messages_count: (nonces_end - nonces_start + 1) as u32, + messages_count: nonces_end.checked_sub(nonces_start).map(|x| x + 1).unwrap_or(0) + as u32, dispatch_weight: frame_support::weights::Weight::zero(), proof: FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: vec![], - lane: bp_messages::LaneId([0, 0, 0, 0]), + lane: LaneId([0, 0, 0, 0]), nonces_start, nonces_end, }, @@ -247,8 +388,8 @@ mod tests { #[test] fn extension_rejects_obsolete_messages() { sp_io::TestExternalities::new(Default::default()).execute_with(|| { - // when current best delivered is message#10 and we're trying to deliver message#5 => tx - // is rejected + // when current best delivered is message#10 and we're trying to deliver messages 8..=9 + // => tx is rejected deliver_message_10(); assert!(!validate_message_delivery(8, 9)); }); @@ -257,26 +398,77 @@ mod tests { #[test] fn extension_rejects_same_message() { sp_io::TestExternalities::new(Default::default()).execute_with(|| { - // when current best delivered is message#10 and we're trying to import message#10 => tx - // is rejected + // when current best delivered is message#10 and we're trying to import messages 10..=10 + // => tx is rejected deliver_message_10(); assert!(!validate_message_delivery(8, 10)); }); } #[test] - fn extension_accepts_new_message() { + fn extension_rejects_call_with_some_obsolete_messages() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver messages + // 10..=15 => tx is rejected + deliver_message_10(); + assert!(!validate_message_delivery(10, 15)); + }); + } + + #[test] + fn extension_rejects_call_with_future_messages() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver messages + // 13..=15 => tx is rejected + deliver_message_10(); + assert!(!validate_message_delivery(13, 15)); + }); + } + + #[test] + fn extension_rejects_empty_delivery_with_rewards_confirmations_if_there_are_free_relayer_and_message_slots( + ) { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + assert!(!validate_message_delivery(10, 9)); + }); + } + + #[test] + fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_relayer_slots( + ) { sp_io::TestExternalities::new(Default::default()).execute_with(|| { - // when current best delivered is message#10 and we're trying to deliver message#15 => - // tx is accepted deliver_message_10(); - assert!(validate_message_delivery(10, 15)); + fill_unrewarded_relayers(); + assert!(validate_message_delivery(10, 9)); + }); + } + + #[test] + fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_message_slots( + ) { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + fill_unrewarded_messages(); + assert!(validate_message_delivery( + MaxUnconfirmedMessagesAtInboundLane::get(), + MaxUnconfirmedMessagesAtInboundLane::get() - 1 + )); + }); + } + + #[test] + fn extension_accepts_new_messages() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver message 11..=15 + // => tx is accepted + deliver_message_10(); + assert!(validate_message_delivery(11, 15)); }); } fn confirm_message_10() { pallet_bridge_messages::OutboundLanes::::insert( - bp_messages::LaneId([0, 0, 0, 0]), + LaneId([0, 0, 0, 0]), bp_messages::OutboundLaneData { oldest_unpruned_nonce: 0, latest_received_nonce: 10, @@ -291,7 +483,7 @@ mod tests { proof: FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), storage_proof: Vec::new(), - lane: bp_messages::LaneId([0, 0, 0, 0]), + lane: LaneId([0, 0, 0, 0]), }, relayers_state: UnrewardedRelayersState { last_delivered_nonce, @@ -323,6 +515,15 @@ mod tests { }); } + #[test] + fn extension_rejects_empty_confirmation_even_if_there_are_no_free_unrewarded_entries() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + confirm_message_10(); + fill_unrewarded_relayers(); + assert!(!validate_message_confirmation(10)); + }); + } + #[test] fn extension_accepts_new_confirmation() { sp_io::TestExternalities::new(Default::default()).execute_with(|| { @@ -332,4 +533,102 @@ mod tests { assert!(validate_message_confirmation(15)); }); } + + fn was_message_delivery_successful( + bundled_range: RangeInclusive, + is_empty: bool, + ) -> bool { + CallHelper::::was_successful(&CallInfo::ReceiveMessagesProof( + ReceiveMessagesProofInfo { + base: BaseMessagesProofInfo { + lane_id: LaneId([0, 0, 0, 0]), + bundled_range, + best_stored_nonce: 0, // doesn't matter for `was_successful` + }, + unrewarded_relayers: UnrewardedRelayerOccupation { + free_relayer_slots: 0, // doesn't matter for `was_successful` + free_message_slots: if is_empty { + 0 + } else { + MaxUnconfirmedMessagesAtInboundLane::get() + }, + }, + }, + )) + } + + #[test] + #[allow(clippy::reversed_empty_ranges)] + fn was_successful_returns_false_for_failed_reward_confirmation_transaction() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + fill_unrewarded_messages(); + assert!(!was_message_delivery_successful(10..=9, true)); + }); + } + + #[test] + #[allow(clippy::reversed_empty_ranges)] + fn was_successful_returns_true_for_successful_reward_confirmation_transaction() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + assert!(was_message_delivery_successful(10..=9, true)); + }); + } + + #[test] + fn was_successful_returns_false_for_failed_delivery() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + assert!(!was_message_delivery_successful(10..=12, false)); + }); + } + + #[test] + fn was_successful_returns_false_for_partially_successful_delivery() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + assert!(!was_message_delivery_successful(9..=12, false)); + }); + } + + #[test] + fn was_successful_returns_true_for_successful_delivery() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + assert!(was_message_delivery_successful(9..=10, false)); + }); + } + + fn was_message_confirmation_successful(bundled_range: RangeInclusive) -> bool { + CallHelper::::was_successful(&CallInfo::ReceiveMessagesDeliveryProof( + ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { + lane_id: LaneId([0, 0, 0, 0]), + bundled_range, + best_stored_nonce: 0, // doesn't matter for `was_successful` + }), + )) + } + + #[test] + fn was_successful_returns_false_for_failed_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + confirm_message_10(); + assert!(!was_message_confirmation_successful(10..=12)); + }); + } + + #[test] + fn was_successful_returns_false_for_partially_successful_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + confirm_message_10(); + assert!(!was_message_confirmation_successful(9..=12)); + }); + } + + #[test] + fn was_successful_returns_true_for_successful_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + confirm_message_10(); + assert!(was_message_confirmation_successful(9..=10)); + }); + } } diff --git a/bin/runtime-common/src/messages_xcm_extension.rs b/bin/runtime-common/src/messages_xcm_extension.rs index 3d802d12fad..4ccdd7a4b4d 100644 --- a/bin/runtime-common/src/messages_xcm_extension.rs +++ b/bin/runtime-common/src/messages_xcm_extension.rs @@ -42,7 +42,7 @@ pub type XcmAsPlainPayload = sp_std::prelude::Vec; pub enum XcmBlobMessageDispatchResult { InvalidPayload, Dispatched, - NotDispatched(#[codec(skip)] &'static str), + NotDispatched(#[codec(skip)] Option), } /// [`XcmBlobMessageDispatch`] is responsible for dispatching received messages @@ -106,24 +106,12 @@ impl< XcmBlobMessageDispatchResult::Dispatched }, Err(e) => { - let e = match e { - DispatchBlobError::Unbridgable => "DispatchBlobError::Unbridgable", - DispatchBlobError::InvalidEncoding => "DispatchBlobError::InvalidEncoding", - DispatchBlobError::UnsupportedLocationVersion => - "DispatchBlobError::UnsupportedLocationVersion", - DispatchBlobError::UnsupportedXcmVersion => - "DispatchBlobError::UnsupportedXcmVersion", - DispatchBlobError::RoutingError => "DispatchBlobError::RoutingError", - DispatchBlobError::NonUniversalDestination => - "DispatchBlobError::NonUniversalDestination", - DispatchBlobError::WrongGlobal => "DispatchBlobError::WrongGlobal", - }; log::error!( target: crate::LOG_TARGET_BRIDGE_DISPATCH, "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob failed, error: {:?} - message_nonce: {:?}", e, message.key.nonce ); - XcmBlobMessageDispatchResult::NotDispatched(e) + XcmBlobMessageDispatchResult::NotDispatched(Some(e)) }, }; MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result } diff --git a/bin/runtime-common/src/mock.rs b/bin/runtime-common/src/mock.rs index ac6cf122b0f..036813f6fd5 100644 --- a/bin/runtime-common/src/mock.rs +++ b/bin/runtime-common/src/mock.rs @@ -33,7 +33,7 @@ use crate::messages::{ }; use bp_header_chain::{ChainWithGrandpa, HeaderChain}; -use bp_messages::{target_chain::ForbidInboundMessages, LaneId}; +use bp_messages::{target_chain::ForbidInboundMessages, LaneId, MessageNonce}; use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_runtime::{Chain, ChainId, Parachain, UnderlyingChainProvider}; use codec::{Decode, Encode}; @@ -126,6 +126,8 @@ parameter_types! { pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); pub MaximumMultiplier: Multiplier = sp_runtime::traits::Bounded::max_value(); + pub const MaxUnrewardedRelayerEntriesAtInboundLane: MessageNonce = 16; + pub const MaxUnconfirmedMessagesAtInboundLane: MessageNonce = 1_000; } impl frame_system::Config for TestRuntime { @@ -196,7 +198,7 @@ impl pallet_transaction_payment::Config for TestRuntime { impl pallet_bridge_grandpa::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgedChain = BridgedUnderlyingChain; - type MaxRequests = ConstU32<50>; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; type HeadersToKeep = ConstU32<8>; type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; } @@ -216,8 +218,8 @@ impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; type ActiveOutboundLanes = ActiveOutboundLanes; - type MaxUnrewardedRelayerEntriesAtInboundLane = ConstU64<16>; - type MaxUnconfirmedMessagesAtInboundLane = ConstU64<16>; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; type MaximalOutboundPayloadSize = FromThisChainMaximalOutboundPayloadSize; type OutboundPayload = FromThisChainMessagePayload; diff --git a/bin/runtime-common/src/priority_calculator.rs b/bin/runtime-common/src/priority_calculator.rs new file mode 100644 index 00000000000..590de05fb1c --- /dev/null +++ b/bin/runtime-common/src/priority_calculator.rs @@ -0,0 +1,201 @@ +// Copyright 2021 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 . + +//! Bridge transaction priority calculator. +//! +//! We want to prioritize message delivery transactions with more messages over +//! transactions with less messages. That's because we reject delivery transactions +//! if it contains already delivered message. And if some transaction delivers +//! single message with nonce `N`, then the transaction with nonces `N..=N+100` will +//! be rejected. This can lower bridge throughput down to one message per block. + +use bp_messages::MessageNonce; +use frame_support::traits::Get; +use sp_runtime::transaction_validity::TransactionPriority; + +// reexport everything from `integrity_tests` module +pub use integrity_tests::*; + +/// Compute priority boost for message delivery transaction that delivers +/// given number of messages. +pub fn compute_priority_boost( + messages: MessageNonce, +) -> TransactionPriority +where + PriorityBoostPerMessage: Get, +{ + // we don't want any boost for transaction with single message => minus one + PriorityBoostPerMessage::get().saturating_mul(messages - 1) +} + +#[cfg(not(feature = "integrity-test"))] +mod integrity_tests {} + +#[cfg(feature = "integrity-test")] +mod integrity_tests { + use super::compute_priority_boost; + + use bp_messages::MessageNonce; + use bp_runtime::PreComputedSize; + use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, Dispatchable, Pays, PostDispatchInfo}, + traits::Get, + }; + use pallet_bridge_messages::WeightInfoExt; + use pallet_transaction_payment::OnChargeTransaction; + use sp_runtime::{ + traits::{UniqueSaturatedInto, Zero}, + transaction_validity::TransactionPriority, + FixedPointOperand, SaturatedConversion, Saturating, + }; + + type BalanceOf = + <::OnChargeTransaction as OnChargeTransaction< + T, + >>::Balance; + + /// Ensures that the value of `PriorityBoostPerMessage` matches the value of + /// `tip_boost_per_message`. + /// + /// We want two transactions, `TX1` with `N` messages and `TX2` with `N+1` messages, have almost + /// the same priority if we'll add `tip_boost_per_message` tip to the `TX1`. We want to be sure + /// that if we add plain `PriorityBoostPerMessage` priority to `TX1`, the priority will be close + /// to `TX2` as well. + pub fn ensure_priority_boost_is_sane( + tip_boost_per_message: BalanceOf, + ) where + Runtime: + pallet_transaction_payment::Config + pallet_bridge_messages::Config, + MessagesInstance: 'static, + PriorityBoostPerMessage: Get, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + let priority_boost_per_message = PriorityBoostPerMessage::get(); + let maximal_messages_in_delivery_transaction = + Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); + for messages in 1..=maximal_messages_in_delivery_transaction { + let base_priority = estimate_message_delivery_transaction_priority::< + Runtime, + MessagesInstance, + >(messages, Zero::zero()); + let priority_boost = compute_priority_boost::(messages); + let priority_with_boost = base_priority + priority_boost; + + let tip = tip_boost_per_message.saturating_mul((messages - 1).unique_saturated_into()); + let priority_with_tip = + estimate_message_delivery_transaction_priority::(1, tip); + + const ERROR_MARGIN: TransactionPriority = 5; // 5% + if priority_with_boost.abs_diff(priority_with_tip).saturating_mul(100) / + priority_with_tip > + ERROR_MARGIN + { + panic!( + "The PriorityBoostPerMessage value ({}) must be fixed to: {}", + priority_boost_per_message, + compute_priority_boost_per_message::( + tip_boost_per_message + ), + ); + } + } + } + + /// Compute priority boost that we give to message delivery transaction for additional message. + #[cfg(feature = "integrity-test")] + fn compute_priority_boost_per_message( + tip_boost_per_message: BalanceOf, + ) -> TransactionPriority + where + Runtime: + pallet_transaction_payment::Config + pallet_bridge_messages::Config, + MessagesInstance: 'static, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // esimate priority of transaction that delivers one message and has large tip + let maximal_messages_in_delivery_transaction = + Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); + let small_with_tip_priority = + estimate_message_delivery_transaction_priority::( + 1, + tip_boost_per_message + .saturating_mul(maximal_messages_in_delivery_transaction.saturated_into()), + ); + // estimate priority of transaction that delivers maximal number of messages, but has no tip + let large_without_tip_priority = estimate_message_delivery_transaction_priority::< + Runtime, + MessagesInstance, + >(maximal_messages_in_delivery_transaction, Zero::zero()); + + small_with_tip_priority + .saturating_sub(large_without_tip_priority) + .saturating_div(maximal_messages_in_delivery_transaction - 1) + } + + /// Estimate message delivery transaction priority. + #[cfg(feature = "integrity-test")] + fn estimate_message_delivery_transaction_priority( + messages: MessageNonce, + tip: BalanceOf, + ) -> TransactionPriority + where + Runtime: + pallet_transaction_payment::Config + pallet_bridge_messages::Config, + MessagesInstance: 'static, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // just an estimation of extra transaction bytes that are added to every transaction + // (including signature, signed extensions extra and etc + in our case it includes + // all call arguments extept the proof itself) + let base_tx_size = 512; + // let's say we are relaying similar small messages and for every message we add more trie + // nodes to the proof (x0.5 because we expect some nodes to be reused) + let estimated_message_size = 512; + // let's say all our messages have the same dispatch weight + let estimated_message_dispatch_weight = + Runtime::WeightInfo::message_dispatch_weight(estimated_message_size); + // messages proof argument size is (for every message) messages size + some additional + // trie nodes. Some of them are reused by different messages, so let's take 2/3 of default + // "overhead" constant + let messages_proof_size = Runtime::WeightInfo::expected_extra_storage_proof_size() + .saturating_mul(2) + .saturating_div(3) + .saturating_add(estimated_message_size) + .saturating_mul(messages as _); + + // finally we are able to estimate transaction size and weight + let transaction_size = base_tx_size.saturating_add(messages_proof_size); + let transaction_weight = Runtime::WeightInfo::receive_messages_proof_weight( + &PreComputedSize(transaction_size as _), + messages as _, + estimated_message_dispatch_weight.saturating_mul(messages), + ); + + pallet_transaction_payment::ChargeTransactionPayment::::get_priority( + &DispatchInfo { + weight: transaction_weight, + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }, + transaction_size as _, + tip, + Zero::zero(), + ) + } +} diff --git a/bin/runtime-common/src/refund_relayer_extension.rs b/bin/runtime-common/src/refund_relayer_extension.rs index 7be97f19ad2..925fea2a743 100644 --- a/bin/runtime-common/src/refund_relayer_extension.rs +++ b/bin/runtime-common/src/refund_relayer_extension.rs @@ -24,7 +24,7 @@ use crate::messages_call_ext::{ }; use bp_messages::LaneId; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::StaticStrProvider; +use bp_runtime::{RangeInclusiveExt, StaticStrProvider}; use codec::{Decode, Encode}; use frame_support::{ dispatch::{CallableCallFor, DispatchInfo, Dispatchable, PostDispatchInfo}, @@ -46,7 +46,9 @@ use pallet_utility::{Call as UtilityCall, Config as UtilityConfig, Pallet as Uti use scale_info::TypeInfo; use sp_runtime::{ traits::{DispatchInfoOf, Get, PostDispatchInfoOf, SignedExtension, Zero}, - transaction_validity::{TransactionValidity, TransactionValidityError, ValidTransaction}, + transaction_validity::{ + TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, + }, DispatchResult, FixedPointOperand, }; use sp_std::{marker::PhantomData, vec, vec::Vec}; @@ -58,7 +60,7 @@ type CallOf = ::RuntimeCall; /// Trait identifying a bridged parachain. A relayer might be refunded for delivering messages /// coming from this parachain. -trait RefundableParachainId { +pub trait RefundableParachainId { /// The instance of the bridge parachains pallet. type Instance; /// The parachain Id. @@ -78,7 +80,7 @@ where /// Trait identifying a bridged messages lane. A relayer might be refunded for delivering messages /// coming from this lane. -trait RefundableMessagesLaneId { +pub trait RefundableMessagesLaneId { /// The instance of the bridge messages pallet. type Instance; /// The messages lane id. @@ -201,36 +203,75 @@ impl CallInfo { RuntimeDebugNoBound, TypeInfo, )] -#[scale_info(skip_type_params(Runtime, Para, Msgs, Refund, Id))] -pub struct RefundBridgedParachainMessages( - PhantomData<(Runtime, Para, Msgs, Refund, Id)>, +#[scale_info(skip_type_params(Runtime, Para, Msgs, Refund, Priority, Id))] +pub struct RefundBridgedParachainMessages( + PhantomData<(Runtime, Para, Msgs, Refund, Priority, Id)>, ); -impl - RefundBridgedParachainMessages +impl + RefundBridgedParachainMessages where - Runtime: UtilityConfig>, - CallOf: IsSubType, Runtime>>, + Self: 'static + Send + Sync, + Runtime: UtilityConfig> + + BoundedBridgeGrandpaConfig + + ParachainsConfig + + MessagesConfig, + Para: RefundableParachainId, + Msgs: RefundableMessagesLaneId, + CallOf: Dispatchable + + IsSubType, Runtime>> + + GrandpaCallSubType + + ParachainsCallSubType + + MessagesCallSubType, { - fn expand_call<'a>(&self, call: &'a CallOf) -> Option>> { - let calls = match call.is_sub_type() { - Some(UtilityCall::::batch_all { ref calls }) => { - if calls.len() > 3 { - return None - } - - calls.iter().collect() - }, - Some(_) => return None, + 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], - }; + } + } + + fn parse_and_check_for_obsolete_call( + &self, + call: &CallOf, + ) -> Result, TransactionValidityError> { + let calls = self.expand_call(call); + let total_calls = calls.len(); + let mut calls = calls.into_iter().map(Self::check_obsolete_call).rev(); + + let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); + let para_finality_call = calls + .next() + .transpose()? + .and_then(|c| c.submit_parachain_heads_info_for(Para::Id::get())); + let relay_finality_call = + calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + + 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, + }) + } - Some(calls) + 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) } } -impl SignedExtension - for RefundBridgedParachainMessages +impl SignedExtension + for RefundBridgedParachainMessages where Self: 'static + Send + Sync, Runtime: UtilityConfig> @@ -241,6 +282,7 @@ where Para: RefundableParachainId, Msgs: RefundableMessagesLaneId, Refund: RefundCalculator, + Priority: Get, Id: StaticStrProvider, CallOf: Dispatchable + IsSubType, Runtime>> @@ -265,46 +307,46 @@ where _info: &DispatchInfoOf, _len: usize, ) -> TransactionValidity { - if let Some(calls) = self.expand_call(call) { - for nested_call in calls { - nested_call.check_obsolete_submit_finality_proof()?; - nested_call.check_obsolete_submit_parachain_heads()?; - nested_call.check_obsolete_call()?; + // this is the only relevant line of code for the `pre_dispatch` + // + // we're not calling `validato` 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)?; + + // the following code just plays with transaction priority and never returns an error + let mut valid_transaction = ValidTransactionBuilder::default(); + if let Some(parsed_call) = parsed_call { + // we give delivery transactions some boost, that depends on number of messages inside + let messages_call_info = parsed_call.messages_call_info(); + if let MessagesCallInfo::ReceiveMessagesProof(info) = messages_call_info { + // compute total number of messages in transaction + let bundled_messages = info.base.bundled_range.checked_len().unwrap_or(0); + + // a quick check to avoid invalid high-priority transactions + if bundled_messages <= Runtime::MaxUnconfirmedMessagesAtInboundLane::get() { + let priority_boost = crate::priority_calculator::compute_priority_boost::< + Priority, + >(bundled_messages); + valid_transaction = valid_transaction.priority(priority_boost); + } } } - Ok(ValidTransaction::default()) + valid_transaction.build() } fn pre_dispatch( self, who: &Self::AccountId, call: &Self::Call, - info: &DispatchInfoOf, - len: usize, + _info: &DispatchInfoOf, + _len: usize, ) -> Result { - // reject batch transactions with obsolete headers - self.validate(who, call, info, len).map(drop)?; - - // Try to check if the tx matches one of types we support. - let parse_call = || { - let mut calls = self.expand_call(call)?.into_iter(); - match calls.len() { - 3 => Some(CallInfo::AllFinalityAndMsgs( - calls.next()?.submit_finality_proof_info()?, - calls.next()?.submit_parachain_heads_info_for(Para::Id::get())?, - calls.next()?.call_info_for(Msgs::Id::get())?, - )), - 2 => Some(CallInfo::ParachainFinalityAndMsgs( - calls.next()?.submit_parachain_heads_info_for(Para::Id::get())?, - calls.next()?.call_info_for(Msgs::Id::get())?, - )), - 1 => Some(CallInfo::Msgs(calls.next()?.call_info_for(Msgs::Id::get())?)), - _ => None, - } - }; + // 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)?; - Ok(parse_call().map(|call_info| { + Ok(parsed_call.map(|call_info| { log::trace!( target: "runtime::bridge", "{} from parachain {} via {:?} parsed bridge transaction in pre-dispatch: {:?}", @@ -344,6 +386,16 @@ where finality_proof_info.block_number, ) { // we only refund relayer if all calls have updated chain state + log::trace!( + target: "runtime::bridge", + "{} from parachain {} via {:?}: failed to refund relayer {:?}, because \ + relay chain finality proof has not been accepted", + Self::IDENTIFIER, + Para::Id::get(), + Msgs::Id::get(), + relayer, + ); + return Ok(()) } @@ -366,15 +418,34 @@ where para_proof_info, ) { // we only refund relayer if all calls have updated chain state + log::trace!( + target: "runtime::bridge", + "{} from parachain {} via {:?}: failed to refund relayer {:?}, because \ + parachain finality proof has not been accepted", + Self::IDENTIFIER, + Para::Id::get(), + Msgs::Id::get(), + relayer, + ); + return Ok(()) } } - // Check if the `ReceiveMessagesProof` call delivered at least some of the messages that + // Check if the `ReceiveMessagesProof` call delivered all 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_partially_successful(msgs_call_info) - { + if !MessagesCallHelper::::was_successful(msgs_call_info) { + log::trace!( + target: "runtime::bridge", + "{} from parachain {} via {:?}: failed to refund relayer {:?}, because \ + some of messages have not been accepted", + Self::IDENTIFIER, + Para::Id::get(), + Msgs::Id::get(), + relayer, + ); + return Ok(()) } @@ -432,6 +503,7 @@ mod tests { }, messages_call_ext::{ BaseMessagesProofInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, + UnrewardedRelayerOccupation, }, mock::*, }; @@ -445,14 +517,24 @@ mod tests { use pallet_bridge_messages::Call as MessagesCall; use pallet_bridge_parachains::{Call as ParachainsCall, RelayBlockHash}; use sp_runtime::{ - traits::Header as HeaderT, transaction_validity::InvalidTransaction, DispatchError, + traits::{ConstU64, Header as HeaderT}, + transaction_validity::{InvalidTransaction, ValidTransaction}, + DispatchError, }; parameter_types! { TestParachain: u32 = 1000; pub TestLaneId: LaneId = TEST_LANE_ID; - pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new(TEST_LANE_ID, TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::ThisChain); - pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new(TEST_LANE_ID, TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::BridgedChain); + pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + TEST_LANE_ID, + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::ThisChain, + ); + pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + TEST_LANE_ID, + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::BridgedChain, + ); } bp_runtime::generate_static_str_provider!(TestExtension); @@ -461,6 +543,7 @@ mod tests { RefundableParachain<(), TestParachain>, RefundableMessagesLane<(), TestLaneId>, ActualFeeRefund, + ConstU64<1>, StrTestExtension, >; @@ -538,7 +621,11 @@ mod tests { bridged_header_hash: Default::default(), storage_proof: vec![], lane: TestLaneId::get(), - nonces_start: best_message, + nonces_start: pallet_bridge_messages::InboundLanes::::get( + TEST_LANE_ID, + ) + .last_delivered_nonce() + + 1, nonces_end: best_message, }, messages_count: 1, @@ -626,13 +713,17 @@ mod tests { para_id: ParaId(TestParachain::get()), para_head_hash: [1u8; 32].into(), }, - MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo( - BaseMessagesProofInfo { + MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { + base: BaseMessagesProofInfo { lane_id: TEST_LANE_ID, - best_bundled_nonce: 200, + bundled_range: 101..=200, best_stored_nonce: 100, }, - )), + unrewarded_relayers: UnrewardedRelayerOccupation { + free_relayer_slots: MaxUnrewardedRelayerEntriesAtInboundLane::get(), + free_message_slots: MaxUnconfirmedMessagesAtInboundLane::get(), + }, + }), ), } } @@ -654,7 +745,7 @@ mod tests { MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { lane_id: TEST_LANE_ID, - best_bundled_nonce: 200, + bundled_range: 101..=200, best_stored_nonce: 100, }, )), @@ -671,13 +762,17 @@ mod tests { para_id: ParaId(TestParachain::get()), para_head_hash: [1u8; 32].into(), }, - MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo( - BaseMessagesProofInfo { + MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { + base: BaseMessagesProofInfo { lane_id: TEST_LANE_ID, - best_bundled_nonce: 200, + bundled_range: 101..=200, best_stored_nonce: 100, }, - )), + unrewarded_relayers: UnrewardedRelayerOccupation { + free_relayer_slots: MaxUnrewardedRelayerEntriesAtInboundLane::get(), + free_message_slots: MaxUnconfirmedMessagesAtInboundLane::get(), + }, + }), ), } } @@ -694,7 +789,7 @@ mod tests { MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { lane_id: TEST_LANE_ID, - best_bundled_nonce: 200, + bundled_range: 101..=200, best_stored_nonce: 100, }, )), @@ -706,11 +801,17 @@ mod tests { PreDispatchData { relayer: relayer_account_at_this_chain(), call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( - ReceiveMessagesProofInfo(BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, - best_bundled_nonce: 200, - best_stored_nonce: 100, - }), + 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(), + }, + }, )), } } @@ -721,7 +822,7 @@ mod tests { call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { lane_id: TEST_LANE_ID, - best_bundled_nonce: 200, + bundled_range: 101..=200, best_stored_nonce: 100, }), )), @@ -782,32 +883,98 @@ mod tests { ) } + #[test] + fn validate_boosts_priority_of_message_delivery_transactons() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + let priority_of_100_messages_delivery = + run_validate(message_delivery_call(200)).unwrap().priority; + let priority_of_200_messages_delivery = + run_validate(message_delivery_call(300)).unwrap().priority; + assert!( + priority_of_200_messages_delivery > priority_of_100_messages_delivery, + "Invalid priorities: {} for 200 messages vs {} for 100 messages", + priority_of_200_messages_delivery, + priority_of_100_messages_delivery, + ); + + let priority_of_100_messages_confirmation = + run_validate(message_confirmation_call(200)).unwrap().priority; + let priority_of_200_messages_confirmation = + run_validate(message_confirmation_call(300)).unwrap().priority; + assert_eq!( + priority_of_100_messages_confirmation, + priority_of_200_messages_confirmation + ); + }); + } + + #[test] + fn validate_does_not_boost_priority_of_message_delivery_transactons_with_too_many_messages() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + let priority_of_max_messages_delivery = run_validate(message_delivery_call( + 100 + MaxUnconfirmedMessagesAtInboundLane::get(), + )) + .unwrap() + .priority; + let priority_of_more_than_max_messages_delivery = run_validate(message_delivery_call( + 100 + MaxUnconfirmedMessagesAtInboundLane::get() + 1, + )) + .unwrap() + .priority; + + assert!( + priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, + "Invalid priorities: {} for MAX messages vs {} for MAX+1 messages", + priority_of_max_messages_delivery, + priority_of_more_than_max_messages_delivery, + ); + }); + } + #[test] fn validate_allows_non_obsolete_transactions() { run_test(|| { initialize_environment(100, 100, Default::default(), 100); - assert_eq!(run_validate(message_delivery_call(200)), Ok(ValidTransaction::default()),); + fn run_validate_ignore_priority(call: RuntimeCall) -> TransactionValidity { + run_validate(call).map(|mut tx| { + tx.priority = 0; + tx + }) + } + assert_eq!( - run_validate(message_confirmation_call(200)), + run_validate_ignore_priority(message_delivery_call(200)), + Ok(ValidTransaction::default()), + ); + assert_eq!( + run_validate_ignore_priority(message_confirmation_call(200)), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate(parachain_finality_and_delivery_batch_call(200, 200)), + run_validate_ignore_priority(parachain_finality_and_delivery_batch_call(200, 200)), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate(parachain_finality_and_confirmation_batch_call(200, 200)), + run_validate_ignore_priority(parachain_finality_and_confirmation_batch_call( + 200, 200 + )), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate(all_finality_and_delivery_batch_call(200, 200, 200)), + run_validate_ignore_priority(all_finality_and_delivery_batch_call(200, 200, 200)), Ok(ValidTransaction::default()), ); assert_eq!( - run_validate(all_finality_and_confirmation_batch_call(200, 200, 200)), + run_validate_ignore_priority(all_finality_and_confirmation_batch_call( + 200, 200, 200 + )), Ok(ValidTransaction::default()), ); }); @@ -1032,6 +1199,30 @@ mod tests { }); } + #[test] + fn post_dispatch_ignores_transaction_that_has_not_delivered_all_messages() { + run_test(|| { + initialize_environment(200, 200, Default::default(), 150); + + assert_storage_noop!(run_post_dispatch(Some(all_finality_pre_dispatch_data()), Ok(()))); + assert_storage_noop!(run_post_dispatch( + Some(parachain_finality_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch(Some(delivery_pre_dispatch_data()), Ok(()))); + + assert_storage_noop!(run_post_dispatch( + Some(all_finality_confirmation_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch( + Some(parachain_finality_confirmation_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch(Some(confirmation_pre_dispatch_data()), Ok(()))); + }); + } + #[test] fn post_dispatch_refunds_relayer_in_all_finality_batch_with_extra_weight() { run_test(|| { diff --git a/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml b/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml index 16b798b5a25..75c3e0c2aa9 100644 --- a/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml +++ b/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml @@ -1,4 +1,2 @@ - targets: - relay-millau-rialto:9616 - - relay-messages-millau-to-rialto-lane-00000001:9616 - - relay-messages-rialto-to-millau-lane-00000001:9616 diff --git a/deployments/bridges/rococo-wococo/dashboard/grafana/bridges-alerts.json b/deployments/bridges/rococo-wococo/dashboard/grafana/bridges-alerts.json new file mode 100644 index 00000000000..6432f79deaf --- /dev/null +++ b/deployments/bridges/rococo-wococo/dashboard/grafana/bridges-alerts.json @@ -0,0 +1,1994 @@ +{ + "Bridges": [ + { + "name": "Bridges", + "interval": "1m", + "rules": [ + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "12", + "summary": "Messages from RococoBridgeHub to WococoBridgeHub (00000001) are either not delivered, or are delivered with lags" + }, + "grafana_alert": { + "id": 51, + "orgId": 1, + "title": "RococoBridgeHub -> WococoBridgeHub delivery lags (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_generated\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Undelivered messages", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 90, + "uid": "r41otJp4k", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "zqjpgXxnk", + "__panelId__": "14", + "summary": "Messages from WococoBridgeHub to RococoBridgeHub (00000001) are either not delivered, or are delivered with lags" + }, + "grafana_alert": { + "id": 55, + "orgId": 1, + "title": "WococoBridgeHub -> RococoBridgeHub delivery lags (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_generated\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Undelivered messages", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 88, + "uid": "wqmPtJpVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "14", + "summary": "Messages from RococoBridgeHub to WococoBridgeHub (00000001) are either not confirmed, or are confirmed with lags" + }, + "grafana_alert": { + "id": 56, + "orgId": 1, + "title": "RococoBridgeHub -> WococoBridgeHub confirmation lags (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(RococoBridgeHub_to_WococoBridgeHub_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(RococoBridgeHub_to_WococoBridgeHub_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Unconfirmed messages", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 84, + "uid": "z4h3pJtVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "zqjpgXxnk", + "__panelId__": "16", + "summary": "Messages from WococoBridgeHub to RococoBridgeHub (00000001) are either not confirmed, or are confirmed with lags" + }, + "grafana_alert": { + "id": 57, + "orgId": 1, + "title": "WococoBridgeHub -> RococoBridgeHub confirmation lags (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Unconfirmed messages", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 83, + "uid": "Kj_z21t4k", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "zqjpgXxnk", + "__panelId__": "18", + "summary": "Rewards for messages from WococoBridgeHub to RococoBridgeHub (00000001) are either not confirmed, or are confirmed with lags" + }, + "grafana_alert": { + "id": 58, + "orgId": 1, + "title": "WococoBridgeHub -> RococoBridgeHub reward lags (00000001)", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Unconfirmed rewards", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "(scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0) > bool min_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "hide": true, + "interval": "", + "intervalMs": 30000, + "legendFormat": "__auto", + "maxDataPoints": 43200, + "range": true, + "refId": "B" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 78, + "uid": "hw_a21pVk", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "15", + "summary": "Rewards for messages from RococoBridgeHub to WococoBridgeHub (00000001) are either not confirmed, or are confirmed with lags" + }, + "grafana_alert": { + "id": 59, + "orgId": 1, + "title": "RococoBridgeHub -> WococoBridgeHub reward lags (00000001)", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Unconfirmed rewards", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "(scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0) > bool min_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "hide": true, + "interval": "", + "intervalMs": 30000, + "legendFormat": "__auto", + "maxDataPoints": 43200, + "range": true, + "refId": "B" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 77, + "uid": "daN62Jt4z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "2", + "summary": "Best BridgeHubRococo header at BridgeHubWococo (00000001) doesn't match the same header at BridgeHubRococo" + }, + "grafana_alert": { + "id": 60, + "orgId": 1, + "title": "BridgeHubRococo header mismatch (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 74, + "uid": "BzBDb1pVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "3", + "summary": "Best BridgeHubWococo header at BridgeHubRococo (00000001) doesn't match the same header at BridgeHubWococo" + }, + "grafana_alert": { + "id": 61, + "orgId": 1, + "title": "BridgeHubWococo header mismatch (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 73, + "uid": "1W6lb1p4z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "5", + "summary": "With-WococoBridgeHub messages relay balance at RococoBridgeHub (00000001) is too low" + }, + "grafana_alert": { + "id": 62, + "orgId": 1, + "title": "With-WococoBridgeHub messages relay balance at RococoBridgeHub (00000001) is too low", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "last_over_time(at_BridgeHubRococo_relay_BridgeHubWococoMessages_balance{domain=\"parity-testnet\"}[1h])", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Messages Relay Balance", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 72, + "uid": "Y5Dm-1tVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "6", + "summary": "With-RococoBridgeHub messages relay balance at WococoBridgeHub (00000001) is too low" + }, + "grafana_alert": { + "id": 63, + "orgId": 1, + "title": "With-RococoBridgeHub messages relay balance at WococoBridgeHub (00000001) is too low", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "last_over_time(at_BridgeHubWococo_relay_BridgeHubRococoMessages_balance{domain=\"parity-testnet\"}[1h])", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Messages Relay Balance", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 71, + "uid": "yUl4a1tVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "5m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "6", + "summary": "Less than 500 Rococo headers have been synced to WococoBridgeHub in last 120 minutes. Relay is not running?" + }, + "grafana_alert": { + "id": 65, + "orgId": 1, + "title": "Rococo -> WococoBridgeHub finality sync lags (00000001)", + "condition": "D", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "max(increase(Rococo_to_BridgeHubWococo_Sync_best_source_at_target_block_number{domain=\"parity-testnet\"}[120m]))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "At Rococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "last", + "refId": "C", + "type": "reduce" + } + }, + { + "refId": "D", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 500 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "D" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "C", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "D", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 40, + "uid": "R6GKwNA4z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "5m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "zqjpgXxnk", + "__panelId__": "2", + "summary": "Less than 500 Wococo headers have been synced to RococoBridgeHub in last 120 minutes. Relay is not running?" + }, + "grafana_alert": { + "id": 66, + "orgId": 1, + "title": "Wococo -> RococoBridgeHub finality sync lags (00000001)", + "condition": "D", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "max(increase(Wococo_to_BridgeHubRococo_Sync_best_source_at_target_block_number{domain=\"parity-testnet\"}[120m]))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "At Wococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "last", + "refId": "C", + "type": "reduce" + } + }, + { + "refId": "D", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 500 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "D" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "C", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "D", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 38, + "uid": "rAM1QHAVk", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "0s", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "11", + "summary": "The RococoBridgeHub <> WococoBridgeHub relay (00000001) has been aborted by version guard - i.e. one of chains has been upgraded and relay wasn't redeployed" + }, + "grafana_alert": { + "id": 67, + "orgId": 1, + "title": "Version guard has aborted RococoBridgeHub <> WococoBridgeHub relay (00000001)", + "condition": "B", + "data": [ + { + "refId": "B", + "queryType": "range", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "P03E52D76DFE188C3", + "model": { + "datasource": { + "type": "loki", + "uid": "P03E52D76DFE188C3" + }, + "editorMode": "code", + "expr": "count_over_time({container=\"bridges-common-relay\"} |= `Aborting relay` [1m])", + "hide": false, + "intervalMs": 1000, + "legendFormat": "Aborts per minute", + "maxDataPoints": 43200, + "queryType": "range", + "refId": "B" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "max", + "refId": "C", + "type": "reduce" + } + }, + { + "refId": "D", + "queryType": "", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "D" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "C", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "D", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 37, + "uid": "TwWPeN04z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "12", + "summary": "Best Rococo header at BridgeHubWococo (00000001) doesn't match the same header at Rococo" + }, + "grafana_alert": { + "id": 69, + "orgId": 1, + "title": "Rococo headers mismatch", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Rococo_to_BridgeHubWococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "last", + "refId": "B", + "type": "reduce" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 32, + "uid": "08-5gv04k", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "13", + "summary": "Best Wococo header at BridgeHubRococo (00000001) doesn't match the same header at Wococo" + }, + "grafana_alert": { + "id": 70, + "orgId": 1, + "title": "Wococo headers mismatch", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Wococo_to_BridgeHubRococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "last", + "refId": "B", + "type": "reduce" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 31, + "uid": "Esj2gD0Vk", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "5m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "9", + "summary": "Test messages from RococoBridgeHub to WococoBridgeHub are not generated. Our cronjob has died?" + }, + "grafana_alert": { + "id": 73, + "orgId": 1, + "title": "Test messages from RococoBridgeHub to WococoBridgeHub are not generated.", + "condition": "D", + "data": [ + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "increase(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\", type=~\"source_latest_generated\"}[24h])", + "hide": true, + "interval": "", + "intervalMs": 30000, + "legendFormat": "Messages generated in last 24h", + "maxDataPoints": 43200, + "range": true, + "refId": "B" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "max", + "refId": "C", + "type": "reduce" + } + }, + { + "refId": "D", + "queryType": "", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "D" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "C", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "D", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 3, + "uid": "ry1K5SB4k", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "5m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "16", + "summary": "RococoBridgeHub <> WococoBridgeHub relay (00000001) node is down" + }, + "grafana_alert": { + "id": 74, + "orgId": 1, + "title": "RococoBridgeHub <> WococoBridgeHub relay (00000001) node is down", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 900, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "up{domain=\"parity-testnet\",container=\"bridges-common-relay\"}", + "instant": false, + "interval": "", + "intervalMs": 30000, + "legendFormat": "Is relay running", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "max", + "refId": "B", + "type": "reduce" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 1, + "uid": "9YAdEUB4z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + } + ] + } + ] + } diff --git a/deployments/bridges/rococo-wococo/dashboard/grafana/rococo-wococo-maintenance-dashboard.json b/deployments/bridges/rococo-wococo/dashboard/grafana/rococo-wococo-maintenance-dashboard.json index 46dc6c43c49..6158c3e73a9 100644 --- a/deployments/bridges/rococo-wococo/dashboard/grafana/rococo-wococo-maintenance-dashboard.json +++ b/deployments/bridges/rococo-wococo/dashboard/grafana/rococo-wococo-maintenance-dashboard.json @@ -1,853 +1,1031 @@ { - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "target": { - "limit": 100, - "matchAny": false, - "tags": [], - "type": "dashboard" - }, - "type": "dashboard" - } - ] - }, - "editable": true, - "fiscalYearStartMonth": 0, - "graphTooltip": 0, - "id": 284, - "links": [], - "liveNow": false, - "panels": [ + "annotations": { + "list": [ { + "builtIn": 1, "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "type": "grafana", + "uid": "-- Grafana --" }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" }, - "gridPos": { - "h": 5, - "w": 5, - "x": 0, - "y": 0 + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 284, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } }, - "id": 8, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "", - "values": false - }, - "text": {}, - "textMode": "name" + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 5, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "pluginVersion": "9.3.1", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" - }, - "editorMode": "code", - "exemplar": false, - "expr": "substrate_relay_build_info{domain=\"parity-testnet\"}", - "instant": true, - "legendFormat": "{{commit}}", - "range": false, - "refId": "A" + "text": {}, + "textMode": "name" + }, + "pluginVersion": "9.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "substrate_relay_build_info{domain=\"parity-testnet\"}", + "instant": true, + "legendFormat": "{{commit}}", + "range": false, + "refId": "A" + } + ], + "title": "Relay build commit", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } - ], - "title": "Relay build commit", - "type": "stat" + }, + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "gridPos": { + "h": 5, + "w": 4, + "x": 5, + "y": 0 + }, + "id": 9, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^1\\.0\\.1$/", + "values": false }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { + "text": {}, + "textMode": "name" + }, + "pluginVersion": "9.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "substrate_relay_build_info{domain=\"parity-testnet\"}", + "instant": true, + "legendFormat": "{{version}}", + "range": false, + "refId": "A" + } + ], + "title": "Relay build version", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { "color": "red", - "value": 80 + "index": 1, + "text": "No" + }, + "1": { + "color": "green", + "index": 0, + "text": "Yes" } - ] + }, + "type": "value" } - }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 5, - "x": 5, - "y": 0 - }, - "id": 9, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "fields": "/^1\\.0\\.1$/", - "values": false - }, - "text": {}, - "textMode": "name" - }, - "pluginVersion": "9.3.1", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" - }, - "editorMode": "code", - "exemplar": false, - "expr": "substrate_relay_build_info{domain=\"parity-testnet\"}", - "instant": true, - "legendFormat": "{{version}}", - "range": false, - "refId": "A" + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } - ], - "title": "Relay build version", - "type": "stat" + }, + "overrides": [] }, - { - "datasource": { - "type": "loki", - "uid": "P03E52D76DFE188C3" + "gridPos": { + "h": 5, + "w": 4, + "x": 9, + "y": 0 + }, + "id": 15, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "textMode": "auto" + }, + "pluginVersion": "9.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "up{domain=\"parity-testnet\",container=\"bridges-common-relay\"}", + "instant": false, + "legendFormat": "Is relay running", + "range": true, + "refId": "A" + } + ], + "title": "Is relay running?", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] - }, - "gridPos": { - "h": 5, - "w": 8, - "x": 10, - "y": 0 - }, - "id": 11, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } }, - "targets": [ - { - "datasource": { - "type": "loki", - "uid": "P03E52D76DFE188C3" - }, - "editorMode": "code", - "expr": "count_over_time({container=\"bridges-common-relay\"} |~ `(?i)(warn|error|fail)` [1m])", - "legendFormat": "Errors per minute", - "queryType": "range", - "refId": "A" - } - ], - "title": "Relay errors/warnings per minute", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "gridPos": { + "h": 5, + "w": 5, + "x": 13, + "y": 0 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "up{domain=\"parity-testnet\",container=\"bridges-common-relay\"}", + "instant": false, + "legendFormat": "Is relay running", + "range": true, + "refId": "A" + } + ], + "title": "Is relay running? (for alert)", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "P03E52D76DFE188C3" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 9, - "x": 0, - "y": 5 - }, - "id": 12, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" - }, - "editorMode": "code", - "expr": "Rococo_to_BridgeHubWococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", - "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", - "range": true, - "refId": "A" - } - ], - "title": "Rococo headers mismatch", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "gridPos": { + "h": 9, + "w": 18, + "x": 0, + "y": 5 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "P03E52D76DFE188C3" + }, + "editorMode": "code", + "expr": "count_over_time({container=\"bridges-common-relay\"} |~ `(?i)(warn|error|fail)` [1m])", + "legendFormat": "Errors per minute", + "queryType": "range", + "refId": "A" + } + ], + "title": "Relay errors/warnings per minute", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 9, - "x": 9, - "y": 5 - }, - "id": 13, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" - }, - "editorMode": "code", - "expr": "Wococo_to_BridgeHubRococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", - "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", - "range": true, - "refId": "A" - } - ], - "title": "Wococo headers mismatch", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "gridPos": { + "h": 7, + "w": 9, + "x": 0, + "y": 14 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Rococo_to_BridgeHubWococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "range": true, + "refId": "A" + } + ], + "title": "Rococo headers mismatch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 9, - "x": 0, - "y": 12 - }, - "id": 2, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" - }, - "editorMode": "code", - "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", - "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", - "range": true, - "refId": "A" - } - ], - "title": "BridgeHubRococo headers mismatch", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "gridPos": { + "h": 7, + "w": 9, + "x": 9, + "y": 14 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Wococo_to_BridgeHubRococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "range": true, + "refId": "A" + } + ], + "title": "Wococo headers mismatch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] - }, - "gridPos": { - "h": 7, - "w": 9, - "x": 9, - "y": 12 - }, - "id": 3, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" - }, - "editorMode": "code", - "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", - "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", - "range": true, - "refId": "A" - } - ], - "title": "BridgeHubWococo headers mismatch", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "gridPos": { + "h": 7, + "w": 9, + "x": 0, + "y": 21 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "range": true, + "refId": "A" + } + ], + "title": "BridgeHubRococo headers mismatch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 9, - "x": 0, - "y": 19 - }, - "id": 5, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" - }, - "editorMode": "code", - "expr": "at_BridgeHubRococo_relay_BridgeHubWococoMessages_balance{domain=\"parity-testnet\"}", - "legendFormat": "Messages Relay Balance", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" - }, - "editorMode": "code", - "expr": "at_BridgeHubRococo_relay_WococoHeaders_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"} + at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"}", - "hide": false, - "legendFormat": "Pending reward", - "range": true, - "refId": "B" - } - ], - "title": "Relay balances at RococoBridgeHub", - "type": "timeseries" + "overrides": [] }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "gridPos": { + "h": 7, + "w": 9, + "x": 9, + "y": 21 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "range": true, + "refId": "A" + } + ], + "title": "BridgeHubWococo headers mismatch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" } }, - "overrides": [] + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } }, - "gridPos": { - "h": 8, - "w": 9, - "x": 9, - "y": 19 + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 0, + "y": 28 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - "id": 6, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "at_BridgeHubRococo_relay_BridgeHubWococoMessages_balance{domain=\"parity-testnet\"}", + "legendFormat": "Messages Relay Balance", + "range": true, + "refId": "A" }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "at_BridgeHubRococo_relay_WococoHeaders_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"} + at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "Pending reward", + "range": true, + "refId": "B" + } + ], + "title": "Relay balances at RococoBridgeHub", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" }, - "editorMode": "code", - "expr": "at_BridgeHubWococo_relay_BridgeHubRococoMessages_balance{domain=\"parity-testnet\"}", - "legendFormat": "Messages Relay Balance", - "range": true, - "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PC96415006F908B67" + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" }, - "editorMode": "code", - "expr": "at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_from_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"} + at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"}", - "hide": false, - "legendFormat": "Pending reward", - "range": true, - "refId": "B" + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] } - ], - "title": "Relay balances at WococoBridgeHub", - "type": "timeseries" - } - ], - "refresh": "5s", - "schemaVersion": 37, - "style": "dark", - "tags": [], - "templating": { - "list": [] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timepicker": {}, - "timezone": "", - "title": "BridgeHubRococo <> BridgeHubWococo maintenance (00000001)", - "uid": "UFsgbJtVz", - "version": 23, - "weekStart": "" - } \ No newline at end of file + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 9, + "y": 28 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "at_BridgeHubWococo_relay_BridgeHubRococoMessages_balance{domain=\"parity-testnet\"}", + "legendFormat": "Messages Relay Balance", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_from_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"} + at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "Pending reward", + "range": true, + "refId": "B" + } + ], + "title": "Relay balances at WococoBridgeHub", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "BridgeHubRococo <> BridgeHubWococo maintenance (00000001)", + "uid": "UFsgbJtVz", + "version": 26, + "weekStart": "" +} diff --git a/deployments/networks/dashboard/grafana/beefy-dashboard.json b/deployments/networks/dashboard/grafana/beefy-dashboard.json index a5df3449e67..2e1e177641a 100644 --- a/deployments/networks/dashboard/grafana/beefy-dashboard.json +++ b/deployments/networks/dashboard/grafana/beefy-dashboard.json @@ -8,14 +8,22 @@ "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, "type": "dashboard" } ] }, "editable": true, + "fiscalYearStartMonth": 0, "gnetId": null, "graphTooltip": 0, "links": [], + "liveNow": false, "panels": [ { "alert": { @@ -81,28 +89,6 @@ "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": { - "align": null - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "green", - "value": null - } - ] - } - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -125,8 +111,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -136,24 +125,33 @@ "steppedLine": false, "targets": [ { + "exemplar": true, "expr": "substrate_beefy_best_block{chain=\"rialto_local\"}", - "legendFormat": "Rialto(Charlie)", + "interval": "", + "legendFormat": "", "refId": "A" }, { + "exemplar": true, "expr": "substrate_beefy_best_block{chain=\"millau_local\"}", - "legendFormat": "Millau(Charlie)", + "hide": false, + "interval": "", + "legendFormat": "", "refId": "B" }, { - "expr": "max_over_time(substrate_beefy_best_block{chain=\"millau_local\"}[5m]) - min_over_time(substrate_beefy_best_block{chain=\"millau_local\"}[5m])", + "exemplar": true, + "expr": "increase(substrate_beefy_best_block{chain=\"millau_local\"}[5m])", "hide": true, + "interval": "", "legendFormat": "Millau Best Beefy blocks count in last 5 minutes", "refId": "C" }, { - "expr": "max_over_time(substrate_beefy_best_block{chain=\"rialto_local\"}[5m]) - min_over_time(substrate_beefy_best_block{chain=\"rialto_local\"}[5m])", + "exemplar": true, + "expr": "increase(substrate_beefy_best_block{chain=\"rialto_local\"}[5m])", "hide": true, + "interval": "", "legendFormat": "Rialto Best Beefy blocks count in last 5 minutes", "refId": "D" } @@ -164,7 +162,8 @@ "fill": true, "line": true, "op": "lt", - "value": 1 + "value": 1, + "visible": true } ], "timeFrom": null, @@ -208,98 +207,79 @@ } }, { - "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {}, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "yellow", - "value": null - }, - { - "color": "yellow", - "value": null - } - ] + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" } - }, - "overrides": [] - }, - "gridPos": { - "h": 14, - "w": 11, - "x": 12, - "y": 0 - }, - "id": 4, - "options": { - "colorMode": "value", - "graphMode": "area", - "justifyMode": "auto", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "mean" - ], - "fields": "", - "values": false - }, - "textMode": "auto" + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Beefy Lagging Sessions alert", + "noDataState": "no_data", + "notifications": [] }, - "pluginVersion": "7.1.3", - "targets": [ - { - "expr": "substrate_beefy_should_vote_on{chain=\"rialto_local\"}", - "legendFormat": "Rialto(Charlie) Should-Vote-On", - "refId": "C" - }, - { - "expr": "substrate_beefy_round_concluded{chain=\"rialto_local\"}", - "legendFormat": "Rialto(Charlie) Round-Concluded", - "refId": "A" - }, - { - "expr": "substrate_beefy_should_vote_on{chain=\"millau_local\"}", - "legendFormat": "Millau(Charlie) Should-Vote-On", - "refId": "D" - }, - { - "expr": "substrate_beefy_round_concluded{chain=\"millau_local\"}", - "legendFormat": "Millau(Charlie) Round-Concluded", - "refId": "B" - } - ], - "timeFrom": null, - "timeShift": null, - "title": "Beefy Voting Rounds", - "type": "stat" - }, - { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": {} - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { - "h": 8, - "w": 18, - "x": 0, - "y": 14 + "h": 14, + "w": 6, + "x": 12, + "y": 0 }, "hiddenSeries": false, - "id": 6, + "id": 8, "legend": { "avg": false, "current": false, @@ -312,8 +292,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -323,21 +306,34 @@ "steppedLine": false, "targets": [ { - "expr": "substrate_beefy_votes_sent{chain=\"rialto_local\"}", - "legendFormat": "Rialto (node Charlie)", + "exemplar": true, + "expr": "substrate_beefy_lagging_sessions{chain=\"rialto_local\"}", + "interval": "", + "legendFormat": "", "refId": "A" }, { - "expr": "substrate_beefy_votes_sent{chain=\"millau_local\"}", - "legendFormat": "Millau (node Charlie)", + "exemplar": true, + "expr": "substrate_beefy_lagging_sessions{chain=\"millau_local\"}", + "interval": "", + "legendFormat": "", "refId": "B" } ], - "thresholds": [], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0, + "visible": true + } + ], "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Beefy Votes Sent", + "title": "Beefy Lagging Sessions", "tooltip": { "shared": true, "sort": 0, @@ -375,101 +371,21 @@ } }, { - "alert": { - "alertRuleTags": {}, - "conditions": [ - { - "evaluator": { - "params": [ - 0 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "max" - }, - "type": "query" - }, - { - "evaluator": { - "params": [ - 0 - ], - "type": "gt" - }, - "operator": { - "type": "or" - }, - "query": { - "params": [ - "B", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "max" - }, - "type": "query" - } - ], - "executionErrorState": "alerting", - "for": "5m", - "frequency": "1m", - "handler": 1, - "name": "Beefy Lagging Sessions alert", - "noDataState": "no_data", - "notifications": [] - }, "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "Prometheus", - "fieldConfig": { - "defaults": { - "custom": { - "align": null - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 1 - } - ] - } - }, - "overrides": [] - }, "fill": 1, "fillGradient": 0, "gridPos": { - "h": 8, - "w": 5, - "x": 18, + "h": 12, + "w": 18, + "x": 0, "y": 14 }, "hiddenSeries": false, - "id": 8, + "id": 6, "legend": { "avg": false, "current": false, @@ -482,8 +398,11 @@ "lines": true, "linewidth": 1, "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "percentage": false, - "pluginVersion": "7.1.3", + "pluginVersion": "8.2.6", "pointradius": 2, "points": false, "renderer": "flot", @@ -493,29 +412,25 @@ "steppedLine": false, "targets": [ { - "expr": "substrate_beefy_lagging_sessions{chain=\"rialto_local\"}", - "legendFormat": "Rialto(Charlie)", + "exemplar": true, + "expr": "substrate_beefy_votes_sent{chain=\"rialto_local\"}", + "interval": "", + "legendFormat": "", "refId": "A" }, { - "expr": "substrate_beefy_lagging_sessions{chain=\"millau_local\"}", - "legendFormat": "Millau(Charlie)", + "exemplar": true, + "expr": "substrate_beefy_votes_sent{chain=\"millau_local\"}", + "interval": "", + "legendFormat": "", "refId": "B" } ], - "thresholds": [ - { - "colorMode": "critical", - "fill": true, - "line": true, - "op": "gt", - "value": 0 - } - ], + "thresholds": [], "timeFrom": null, "timeRegions": [], "timeShift": null, - "title": "Beefy Lagging Sessions", + "title": "Beefy Votes Sent", "tooltip": { "shared": true, "sort": 0, @@ -554,14 +469,14 @@ } ], "refresh": "5s", - "schemaVersion": 26, + "schemaVersion": 32, "style": "dark", "tags": [], "templating": { "list": [] }, "time": { - "from": "now-5m", + "from": "now-30m", "to": "now" }, "timepicker": { diff --git a/deployments/networks/dashboard/prometheus/millau-targets.yml b/deployments/networks/dashboard/prometheus/millau-targets.yml index c7a06509276..5890c8fb3fd 100644 --- a/deployments/networks/dashboard/prometheus/millau-targets.yml +++ b/deployments/networks/dashboard/prometheus/millau-targets.yml @@ -1,2 +1,6 @@ - targets: + - millau-node-alice:9615 + - millau-node-bob:9615 - millau-node-charlie:9615 + - millau-node-dave:9615 + - millau-node-eve:9615 diff --git a/deployments/networks/dashboard/prometheus/rialto-targets.yml b/deployments/networks/dashboard/prometheus/rialto-targets.yml index 9de26b9a2d7..0c89926e8c3 100644 --- a/deployments/networks/dashboard/prometheus/rialto-targets.yml +++ b/deployments/networks/dashboard/prometheus/rialto-targets.yml @@ -1,2 +1,6 @@ - targets: + - rialto-node-alice:9615 + - rialto-node-bob:9615 - rialto-node-charlie:9615 + - rialto-node-dave:9615 + - rialto-node-eve:9615 diff --git a/deployments/networks/millau.yml b/deployments/networks/millau.yml index 0f5846571aa..d91c5d83286 100644 --- a/deployments/networks/millau.yml +++ b/deployments/networks/millau.yml @@ -20,11 +20,13 @@ services: - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external environment: - RUST_LOG: runtime=trace,rpc=debug,txpool=trace,runtime::bridge=trace,sc_basic_authorship=trace,beefy=debug,xcm=trace + RUST_LOG: runtime=trace,rpc=debug,txpool=trace,runtime::bridge=trace,sc_basic_authorship=trace,beefy=trace,xcm=trace ports: - "19933:9933" - "19944:9944" + - "19615:9615" millau-node-bob: <<: *millau-bridge-node @@ -39,9 +41,11 @@ services: - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external ports: - "20033:9933" - "20044:9944" + - "20015:9615" millau-node-charlie: <<: *millau-bridge-node @@ -59,7 +63,7 @@ services: ports: - "20133:9933" - "20144:9944" - - "20615:9615" + - "20115:9615" millau-node-dave: <<: *millau-bridge-node @@ -73,9 +77,11 @@ services: - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external ports: - "20233:9933" - "20244:9944" + - "20215:9615" millau-node-eve: <<: *millau-bridge-node @@ -89,13 +95,19 @@ services: - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external ports: - "20333:9933" - "20344:9944" + - "20315:9615" # Note: These are being overridden from the top level `monitoring` compose file. prometheus-metrics: volumes: - ./networks/dashboard/prometheus/millau-targets.yml:/etc/prometheus/targets-millau-nodes.yml depends_on: + - millau-node-alice + - millau-node-bob - millau-node-charlie + - millau-node-dave + - millau-node-eve diff --git a/deployments/networks/rialto.yml b/deployments/networks/rialto.yml index 5a8ed64e067..fab85b89c04 100644 --- a/deployments/networks/rialto.yml +++ b/deployments/networks/rialto.yml @@ -20,11 +20,13 @@ services: - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external environment: - RUST_LOG: runtime=trace,rpc=debug,txpool=trace,runtime::bridge=trace,beefy=debug,xcm=trace + RUST_LOG: runtime=trace,rpc=debug,txpool=trace,runtime::bridge=trace,beefy=trace,xcm=trace ports: - "9933:9933" - "9944:9944" + - "9915:9615" rialto-node-bob: <<: *rialto-bridge-node @@ -39,9 +41,11 @@ services: - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external ports: - "10033:9933" - "10044:9944" + - "10015:9615" rialto-node-charlie: <<: *rialto-bridge-node @@ -59,7 +63,7 @@ services: ports: - "10133:9933" - "10144:9944" - - "10615:9615" + - "10115:9615" rialto-node-dave: <<: *rialto-bridge-node @@ -73,9 +77,11 @@ services: - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external ports: - "10233:9933" - "10244:9944" + - "10215:9615" rialto-node-eve: <<: *rialto-bridge-node @@ -89,9 +95,11 @@ services: - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external ports: - "10333:9933" - "10344:9944" + - "10315:9615" rialto-chainspec-exporter: image: ${RIALTO_BRIDGE_NODE_IMAGE:-paritytech/rialto-bridge-node} @@ -105,7 +113,11 @@ services: volumes: - ./networks/dashboard/prometheus/rialto-targets.yml:/etc/prometheus/targets-rialto-nodes.yml depends_on: + - rialto-node-alice + - rialto-node-bob - rialto-node-charlie + - rialto-node-dave + - rialto-node-eve # we're using `/rialto-share` to expose Rialto chain spec to those who are interested. Right # now it is Rialto Parachain collator nodes. Local + tmpfs combination allows sharing writable diff --git a/deployments/types-millau.json b/deployments/types-millau.json index 6d651b4c7cf..88b67f70b05 100644 --- a/deployments/types-millau.json +++ b/deployments/types-millau.json @@ -88,8 +88,7 @@ }, "DeliveredMessages": { "begin": "MessageNonce", - "end": "MessageNonce", - "dispatch_results": "BitVec" + "end": "MessageNonce" }, "OutboundLaneData": { "oldest_unpruned_nonce": "MessageNonce", diff --git a/deployments/types-rialto.json b/deployments/types-rialto.json index a574e117893..02ceaf676d6 100644 --- a/deployments/types-rialto.json +++ b/deployments/types-rialto.json @@ -88,8 +88,7 @@ }, "DeliveredMessages": { "begin": "MessageNonce", - "end": "MessageNonce", - "dispatch_results": "BitVec" + "end": "MessageNonce" }, "OutboundLaneData": { "oldest_unpruned_nonce": "MessageNonce", diff --git a/deployments/types/common.json b/deployments/types/common.json index 4e129f7132b..7247e546bec 100644 --- a/deployments/types/common.json +++ b/deployments/types/common.json @@ -34,8 +34,7 @@ }, "DeliveredMessages": { "begin": "MessageNonce", - "end": "MessageNonce", - "dispatch_results": "BitVec" + "end": "MessageNonce" }, "OutboundLaneData": { "oldest_unpruned_nonce": "MessageNonce", diff --git a/modules/beefy/Cargo.toml b/modules/beefy/Cargo.toml index b50ac723db2..8aff2c169b4 100644 --- a/modules/beefy/Cargo.toml +++ b/modules/beefy/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.0.0", default-features = false } log = { version = "0.4.14", default-features = false } -scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true } # Bridge Dependencies diff --git a/modules/beefy/src/lib.rs b/modules/beefy/src/lib.rs index a3a68928bc5..79795dd0770 100644 --- a/modules/beefy/src/lib.rs +++ b/modules/beefy/src/lib.rs @@ -94,7 +94,7 @@ pub struct ImportedCommitmentsInfoData { next_block_number_index: u32, } -#[frame_support::pallet] +#[frame_support::pallet(dev_mode)] pub mod pallet { use super::*; use bp_runtime::{BasicOperatingMode, OwnedBridgeModule}; diff --git a/modules/grandpa/Cargo.toml b/modules/grandpa/Cargo.toml index 0a737ef633a..07d2593b914 100644 --- a/modules/grandpa/Cargo.toml +++ b/modules/grandpa/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 } finality-grandpa = { version = "0.16.2", default-features = false } log = { version = "0.4.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/modules/grandpa/src/benchmarking.rs b/modules/grandpa/src/benchmarking.rs index 78c7fc362a2..aa222d6e4de 100644 --- a/modules/grandpa/src/benchmarking.rs +++ b/modules/grandpa/src/benchmarking.rs @@ -136,4 +136,6 @@ benchmarks_instance_pallet! { // check that the header#0 has been pruned assert!(!>::contains_key(genesis_header.hash())); } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) } diff --git a/modules/grandpa/src/lib.rs b/modules/grandpa/src/lib.rs index 2d81f3106fc..9d38c9723d7 100644 --- a/modules/grandpa/src/lib.rs +++ b/modules/grandpa/src/lib.rs @@ -103,14 +103,17 @@ pub mod pallet { /// The chain we are bridging to here. type BridgedChain: ChainWithGrandpa; - /// The upper bound on the number of requests allowed by the pallet. + /// Maximal number of "free" mandatory header transactions per block. /// - /// A request refers to an action which writes a header to storage. - /// - /// Once this bound is reached the pallet will not allow any dispatchables to be called - /// until the request count has decreased. + /// To be able to track the bridged chain, the pallet requires all headers that are + /// changing GRANDPA authorities set at the bridged chain (we call them mandatory). + /// So it is a common good deed to submit mandatory headers to the pallet. However, if the + /// bridged chain gets compromised, its validators may generate as many mandatory headers + /// as they want. And they may fill the whole block (at this chain) for free. This constants + /// limits number of calls that we may refund in a single block. All calls above this + /// limit are accepted, but are not refunded. #[pallet::constant] - type MaxRequests: Get; + type MaxFreeMandatoryHeadersPerBlock: Get; /// Maximal number of finalized headers to keep in the storage. /// @@ -131,10 +134,13 @@ pub mod pallet { #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { - fn on_initialize(_n: T::BlockNumber) -> frame_support::weights::Weight { - >::mutate(|count| *count = count.saturating_sub(1)); + fn on_initialize(_n: BlockNumberFor) -> Weight { + FreeMandatoryHeadersRemaining::::put(T::MaxFreeMandatoryHeadersPerBlock::get()); + Weight::zero() + } - T::DbWeight::get().reads_writes(1, 1) + fn on_finalize(_n: BlockNumberFor) { + FreeMandatoryHeadersRemaining::::kill(); } } @@ -154,6 +160,16 @@ pub mod pallet { /// /// If successful in verification, it will write the target header to the underlying storage /// pallet. + /// + /// The call fails if: + /// + /// - the pallet is halted; + /// + /// - the pallet knows better header than the `finality_target`; + /// + /// - verification is not optimized or invalid; + /// + /// - header contains forced authorities set change or change with non-zero delay. #[pallet::call_index(0)] #[pallet::weight(::submit_finality_proof( justification.commit.precommits.len().saturated_into(), @@ -166,8 +182,6 @@ pub mod pallet { ) -> DispatchResultWithPostInfo { Self::ensure_not_halted().map_err(Error::::BridgeModule)?; - ensure!(Self::request_count() < T::MaxRequests::get(), >::TooManyRequests); - let (hash, number) = (finality_target.hash(), *finality_target.number()); log::trace!( target: LOG_TARGET, @@ -185,9 +199,16 @@ pub mod pallet { let is_authorities_change_enacted = try_enact_authority_change::(&finality_target, set_id)?; let may_refund_call_fee = is_authorities_change_enacted && + // if we have seen too many mandatory headers in this block, we don't want to refund + Self::free_mandatory_headers_remaining() > 0 && + // if arguments out of expected bounds, we don't want to refund submit_finality_proof_info_from_args::(&finality_target, &justification) .fits_limits(); - >::mutate(|count| *count += 1); + if may_refund_call_fee { + FreeMandatoryHeadersRemaining::::mutate(|count| { + *count = count.saturating_sub(1) + }); + } insert_header::(*finality_target, hash); log::info!( target: LOG_TARGET, @@ -273,16 +294,20 @@ pub mod pallet { } } - /// The current number of requests which have written to storage. + /// Number mandatory headers that we may accept in the current block for free (returning + /// `Pays::No`). /// - /// If the `RequestCount` hits `MaxRequests`, no more calls will be allowed to the pallet until - /// the request capacity is increased. + /// If the `FreeMandatoryHeadersRemaining` hits zero, all following mandatory headers in the + /// current block are accepted with fee (`Pays::Yes` is returned). /// - /// The `RequestCount` is decreased by one at the beginning of every block. This is to ensure - /// that the pallet can always make progress. + /// The `FreeMandatoryHeadersRemaining` is an ephemeral value that is set to + /// `MaxFreeMandatoryHeadersPerBlock` at each block initialization and is killed on block + /// finalization. So it never ends up in the storage trie. #[pallet::storage] - #[pallet::getter(fn request_count)] - pub(super) type RequestCount, I: 'static = ()> = StorageValue<_, u32, ValueQuery>; + #[pallet::whitelist_storage] + #[pallet::getter(fn free_mandatory_headers_remaining)] + pub(super) type FreeMandatoryHeadersRemaining, I: 'static = ()> = + StorageValue<_, u32, ValueQuery>; /// Hash of the header used to bootstrap the pallet. #[pallet::storage] @@ -392,8 +417,6 @@ pub mod pallet { InvalidJustification, /// The authority set from the underlying header chain is invalid. InvalidAuthoritySet, - /// There are too many requests for the current window to handle. - TooManyRequests, /// The header being imported is older than the best finalized header known to the pallet. OldHeader, /// The scheduled authority set change found in the header is unsupported by the pallet. @@ -662,7 +685,8 @@ mod tests { }; use codec::Encode; use frame_support::{ - assert_err, assert_noop, assert_ok, dispatch::PostDispatchInfo, + assert_err, assert_noop, assert_ok, + dispatch::{Pays, PostDispatchInfo}, storage::generator::StorageValue, }; use frame_system::{EventRecord, Phase}; @@ -705,6 +729,51 @@ mod tests { ) } + fn submit_finality_proof_with_set_id( + header: u8, + set_id: u64, + ) -> frame_support::dispatch::DispatchResultWithPostInfo { + let header = test_header(header.into()); + let justification = make_justification_for_header(JustificationGeneratorParams { + header: header.clone(), + set_id, + ..Default::default() + }); + + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ) + } + + fn submit_mandatory_finality_proof( + number: u8, + set_id: u64, + ) -> frame_support::dispatch::DispatchResultWithPostInfo { + let mut header = test_header(number.into()); + // to ease tests that are using `submit_mandatory_finality_proof`, we'll be using the + // same set for all sessions + let consensus_log = + ConsensusLog::::ScheduledChange(sp_consensus_grandpa::ScheduledChange { + next_authorities: authority_list(), + delay: 0, + }); + header.digest = + Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] }; + let justification = make_justification_for_header(JustificationGeneratorParams { + header: header.clone(), + set_id, + ..Default::default() + }); + + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ) + } + fn next_block() { use frame_support::traits::OnInitialize; @@ -1169,13 +1238,18 @@ mod tests { } #[test] - fn rate_limiter_disallows_imports_once_limit_is_hit_in_single_block() { + fn rate_limiter_disallows_free_imports_once_limit_is_hit_in_single_block() { run_test(|| { initialize_substrate_bridge(); - assert_ok!(submit_finality_proof(1)); - assert_ok!(submit_finality_proof(2)); - assert_err!(submit_finality_proof(3), >::TooManyRequests); + let result = submit_mandatory_finality_proof(1, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(2, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(3, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); }) } @@ -1183,7 +1257,8 @@ mod tests { fn rate_limiter_invalid_requests_do_not_count_towards_request_count() { run_test(|| { let submit_invalid_request = || { - let header = test_header(1); + let mut header = test_header(1); + header.digest = change_log(0); let mut invalid_justification = make_default_justification(&header); invalid_justification.round = 42; @@ -1196,15 +1271,19 @@ mod tests { initialize_substrate_bridge(); - for _ in 0..::MaxRequests::get() + 1 { - // Notice that the error here *isn't* `TooManyRequests` + for _ in 0..::MaxFreeMandatoryHeadersPerBlock::get() + 1 { assert_err!(submit_invalid_request(), >::InvalidJustification); } - // Can still submit `MaxRequests` requests afterwards - assert_ok!(submit_finality_proof(1)); - assert_ok!(submit_finality_proof(2)); - assert_err!(submit_finality_proof(3), >::TooManyRequests); + // Can still submit free mandatory headers afterwards + let result = submit_mandatory_finality_proof(1, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(2, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(3, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); }) } @@ -1212,40 +1291,51 @@ mod tests { fn rate_limiter_allows_request_after_new_block_has_started() { run_test(|| { initialize_substrate_bridge(); - assert_ok!(submit_finality_proof(1)); - assert_ok!(submit_finality_proof(2)); - next_block(); - assert_ok!(submit_finality_proof(3)); - }) - } + let result = submit_mandatory_finality_proof(1, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); - #[test] - fn rate_limiter_disallows_imports_once_limit_is_hit_across_different_blocks() { - run_test(|| { - initialize_substrate_bridge(); - assert_ok!(submit_finality_proof(1)); - assert_ok!(submit_finality_proof(2)); + let result = submit_mandatory_finality_proof(2, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(3, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); next_block(); - assert_ok!(submit_finality_proof(3)); - assert_err!(submit_finality_proof(4), >::TooManyRequests); + + let result = submit_mandatory_finality_proof(4, 4); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(5, 5); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(6, 6); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); }) } #[test] - fn rate_limiter_allows_max_requests_after_long_time_with_no_activity() { + fn rate_limiter_ignores_non_mandatory_headers() { run_test(|| { initialize_substrate_bridge(); - assert_ok!(submit_finality_proof(1)); - assert_ok!(submit_finality_proof(2)); - next_block(); - next_block(); + let result = submit_finality_proof(1); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); - next_block(); - assert_ok!(submit_finality_proof(5)); - assert_ok!(submit_finality_proof(7)); + let result = submit_mandatory_finality_proof(2, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_finality_proof_with_set_id(3, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + + let result = submit_mandatory_finality_proof(4, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_finality_proof_with_set_id(5, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + + let result = submit_mandatory_finality_proof(6, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); }) } diff --git a/modules/grandpa/src/mock.rs b/modules/grandpa/src/mock.rs index b10f5d86c3d..0ebbc0bccbb 100644 --- a/modules/grandpa/src/mock.rs +++ b/modules/grandpa/src/mock.rs @@ -21,7 +21,7 @@ use bp_header_chain::ChainWithGrandpa; use bp_runtime::Chain; use frame_support::{ construct_runtime, parameter_types, - traits::{ConstU32, ConstU64}, + traits::{ConstU32, ConstU64, Hooks}, weights::Weight, }; use sp_core::sr25519::Signature; @@ -87,7 +87,7 @@ impl frame_system::Config for TestRuntime { } parameter_types! { - pub const MaxRequests: u32 = 2; + pub const MaxFreeMandatoryHeadersPerBlock: u32 = 2; pub const HeadersToKeep: u32 = 5; pub const SessionLength: u64 = 5; pub const NumValidators: u32 = 5; @@ -96,7 +96,7 @@ parameter_types! { impl grandpa::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgedChain = TestBridgedChain; - type MaxRequests = MaxRequests; + type MaxFreeMandatoryHeadersPerBlock = MaxFreeMandatoryHeadersPerBlock; type HeadersToKeep = HeadersToKeep; type WeightInfo = (); } @@ -131,10 +131,20 @@ impl ChainWithGrandpa for TestBridgedChain { const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; } +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new(Default::default()) +} + +/// Return test within default test externalities context. pub fn run_test(test: impl FnOnce() -> T) -> T { - sp_io::TestExternalities::new(Default::default()).execute_with(test) + new_test_ext().execute_with(|| { + let _ = Grandpa::on_initialize(0); + test() + }) } +/// Return test header with given number. pub fn test_header(num: TestNumber) -> TestHeader { // We wrap the call to avoid explicit type annotations in our tests bp_test_utils::test_header(num) diff --git a/modules/messages/Cargo.toml b/modules/messages/Cargo.toml index afa8b92b228..f733d62bf64 100644 --- a/modules/messages/Cargo.toml +++ b/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.17", default-features = false } num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Bridge dependencies @@ -27,9 +27,9 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } [dev-dependencies] -sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } bp-test-utils = { path = "../../primitives/test-utils" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } [features] default = ["std"] diff --git a/modules/messages/src/benchmarking.rs b/modules/messages/src/benchmarking.rs index bc9c1f75257..aab8855a729 100644 --- a/modules/messages/src/benchmarking.rs +++ b/modules/messages/src/benchmarking.rs @@ -37,7 +37,7 @@ use sp_std::{ops::RangeInclusive, prelude::*}; const SEED: u32 = 0; /// Pallet we're benchmarking here. -pub struct Pallet, I: 'static>(crate::Pallet); +pub struct Pallet, I: 'static = ()>(crate::Pallet); /// Benchmark-specific message proof parameters. #[derive(Debug)] @@ -437,6 +437,8 @@ benchmarks_instance_pallet! { ); assert!(T::is_message_successfully_dispatched(21)); } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) } fn send_regular_message, I: 'static>() { diff --git a/modules/messages/src/lib.rs b/modules/messages/src/lib.rs index 3faf00b9e75..c94f5ffa752 100644 --- a/modules/messages/src/lib.rs +++ b/modules/messages/src/lib.rs @@ -63,7 +63,7 @@ use bp_messages::{ MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayersState, }; -use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, Size}; +use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, PreComputedSize, Size}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get}; use sp_runtime::traits::UniqueSaturatedFrom; @@ -90,6 +90,7 @@ pub const LOG_TARGET: &str = "runtime::bridge-messages"; pub mod pallet { use super::*; use bp_messages::{ReceivalResult, ReceivedMessages}; + use bp_runtime::RangeInclusiveExt; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -249,6 +250,22 @@ pub mod pallet { /// The weight of the call assumes that the transaction always brings outbound lane /// state update. Because of that, the submitter (relayer) has no benefit of not including /// this data in the transaction, so reward confirmations lags should be minimal. + /// + /// The call fails if: + /// + /// - the pallet is halted; + /// + /// - the call origin is not `Signed(_)`; + /// + /// - there are too many messages in the proof; + /// + /// - the proof verification procedure returns an error - e.g. because header used to craft + /// proof is not imported by the associated finality pallet; + /// + /// - the `dispatch_weight` argument is not sufficient to dispatch all bundled messages. + /// + /// The call may succeed, but some messages may not be delivered e.g. if they are not fit + /// into the unrewarded relayers vector. #[pallet::call_index(2)] #[pallet::weight(T::WeightInfo::receive_messages_proof_weight(proof, *messages_count, *dispatch_weight))] pub fn receive_messages_proof( @@ -324,18 +341,10 @@ pub mod pallet { let mut lane_messages_received_status = ReceivedMessages::new(lane_id, Vec::with_capacity(lane_data.messages.len())); - let mut is_lane_processing_stopped_no_weight_left = false; - for mut message in lane_data.messages { debug_assert_eq!(message.key.lane_id, lane_id); total_messages += 1; - if is_lane_processing_stopped_no_weight_left { - lane_messages_received_status - .push_skipped_for_not_enough_weight(message.key.nonce); - continue - } - // ensure that relayer has declared enough weight for dispatching next message // on this lane. We can't dispatch lane messages out-of-order, so if declared // weight is not enough, let's move to next lane @@ -348,10 +357,8 @@ pub mod pallet { message_dispatch_weight, dispatch_weight_left, ); - lane_messages_received_status - .push_skipped_for_not_enough_weight(message.key.nonce); - is_lane_processing_stopped_no_weight_left = true; - continue + + fail!(Error::::InsufficientDispatchWeight); } let receival_result = lane.receive_message::( @@ -417,10 +424,11 @@ pub mod pallet { pub fn receive_messages_delivery_proof( origin: OriginFor, proof: MessagesDeliveryProofOf, - relayers_state: UnrewardedRelayersState, - ) -> DispatchResult { + mut relayers_state: UnrewardedRelayersState, + ) -> DispatchResultWithPostInfo { Self::ensure_not_halted().map_err(Error::::BridgeModule)?; + let proof_size = proof.size(); let confirmation_relayer = ensure_signed(origin)?; let (lane_id, lane_data) = T::TargetHeaderChain::verify_messages_delivery_proof(proof) .map_err(|err| { @@ -493,13 +501,23 @@ pub mod pallet { }); // if some new messages have been confirmed, reward relayers - T::DeliveryConfirmationPayments::pay_reward( + let actually_rewarded_relayers = T::DeliveryConfirmationPayments::pay_reward( lane_id, lane_data.relayers, &confirmation_relayer, &received_range, ); - } + + // update relayers state with actual numbers to compute actual weight below + relayers_state.unrewarded_relayer_entries = sp_std::cmp::min( + relayers_state.unrewarded_relayer_entries, + actually_rewarded_relayers, + ); + relayers_state.total_messages = sp_std::cmp::min( + relayers_state.total_messages, + received_range.checked_len().unwrap_or(MessageNonce::MAX), + ); + }; log::trace!( target: LOG_TARGET, @@ -508,7 +526,15 @@ pub mod pallet { lane_id, ); - Ok(()) + // because of lags, the inbound lane state (`lane_data`) may have entries for + // already rewarded relayers and messages (if all entries are duplicated, then + // this transaction must be filtered out by our signed extension) + let actual_weight = T::WeightInfo::receive_messages_delivery_proof_weight( + &PreComputedSize(proof_size as usize), + &relayers_state, + ); + + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee: Pays::Yes }) } } @@ -554,8 +580,9 @@ pub mod pallet { /// The relayer has declared invalid unrewarded relayers state in the /// `receive_messages_delivery_proof` call. InvalidUnrewardedRelayersState, - /// The message someone is trying to work with (i.e. increase fee) is already-delivered. - MessageIsAlreadyDelivered, + /// The cumulative dispatch weight, passed by relayer is not enough to cover dispatch + /// of all bundled messages. + InsufficientDispatchWeight, /// The message someone is trying to work with (i.e. increase fee) is not yet sent. MessageIsNotYetSent, /// The number of actually confirmed messages is going to be larger than the number of @@ -925,8 +952,9 @@ mod tests { message, message_payload, run_test, unrewarded_relayer, AccountId, DbWeight, RuntimeEvent as TestEvent, RuntimeOrigin, TestDeliveryConfirmationPayments, TestDeliveryPayments, TestMessagesDeliveryProof, TestMessagesProof, TestRelayer, - TestRuntime, MAX_OUTBOUND_PAYLOAD_SIZE, PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, - TEST_LANE_ID, TEST_LANE_ID_2, TEST_LANE_ID_3, TEST_RELAYER_A, TEST_RELAYER_B, + TestRuntime, TestWeightInfo, MAX_OUTBOUND_PAYLOAD_SIZE, PAYLOAD_REJECTED_BY_TARGET_CHAIN, + REGULAR_PAYLOAD, TEST_LANE_ID, TEST_LANE_ID_2, TEST_LANE_ID_3, TEST_RELAYER_A, + TEST_RELAYER_B, }; use bp_messages::{BridgeMessagesCall, UnrewardedRelayer, UnrewardedRelayersState}; use bp_test_utils::generate_owned_bridge_module_tests; @@ -1277,13 +1305,16 @@ mod tests { run_test(|| { let mut declared_weight = REGULAR_PAYLOAD.declared_weight; *declared_weight.ref_time_mut() -= 1; - assert_ok!(Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), - 1, - declared_weight, - )); + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), + 1, + declared_weight, + ), + Error::::InsufficientDispatchWeight + ); assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); }); } @@ -1348,50 +1379,78 @@ mod tests { )); // this reports delivery of message 1 => reward is paid to TEST_RELAYER_A - assert_ok!(Pallet::::receive_messages_delivery_proof( + let single_message_delivery_proof = TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into_iter().collect(), + ..Default::default() + }, + ))); + let single_message_delivery_proof_size = single_message_delivery_proof.size(); + let result = Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)] - .into_iter() - .collect(), - ..Default::default() - } - ))), + single_message_delivery_proof, UnrewardedRelayersState { unrewarded_relayer_entries: 1, total_messages: 1, last_delivered_nonce: 1, ..Default::default() }, - )); + ); + assert_ok!(result); + assert_eq!( + result.unwrap().actual_weight.unwrap(), + TestWeightInfo::receive_messages_delivery_proof_weight( + &PreComputedSize(single_message_delivery_proof_size as _), + &UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }, + ) + ); assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); // this reports delivery of both message 1 and message 2 => reward is paid only to // TEST_RELAYER_B - assert_ok!(Pallet::::receive_messages_delivery_proof( + let two_messages_delivery_proof = TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B), + ] + .into_iter() + .collect(), + ..Default::default() + }, + ))); + let two_messages_delivery_proof_size = two_messages_delivery_proof.size(); + let result = Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), - TestMessagesDeliveryProof(Ok(( - TEST_LANE_ID, - InboundLaneData { - relayers: vec![ - unrewarded_relayer(1, 1, TEST_RELAYER_A), - unrewarded_relayer(2, 2, TEST_RELAYER_B) - ] - .into_iter() - .collect(), - ..Default::default() - } - ))), + two_messages_delivery_proof, UnrewardedRelayersState { unrewarded_relayer_entries: 2, total_messages: 2, last_delivered_nonce: 2, ..Default::default() }, - )); + ); + assert_ok!(result); + // even though the pre-dispatch weight was for two messages, the actual weight is + // for single message only + assert_eq!( + result.unwrap().actual_weight.unwrap(), + TestWeightInfo::receive_messages_delivery_proof_weight( + &PreComputedSize(two_messages_delivery_proof_size as _), + &UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }, + ) + ); assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); }); @@ -1541,15 +1600,18 @@ mod tests { let message2 = message(2, message_payload(0, u64::MAX / 2)); let message3 = message(3, message_payload(0, u64::MAX / 2)); - assert_ok!(Pallet::::receive_messages_proof( - RuntimeOrigin::signed(1), - TEST_RELAYER_A, - // this may cause overflow if source chain storage is invalid - Ok(vec![message1, message2, message3]).into(), - 3, - Weight::MAX, - )); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 2); + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + // this may cause overflow if source chain storage is invalid + Ok(vec![message1, message2, message3]).into(), + 3, + Weight::MAX, + ), + Error::::InsufficientDispatchWeight + ); + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); }); } diff --git a/modules/messages/src/mock.rs b/modules/messages/src/mock.rs index 807721ba866..75f05b4820a 100644 --- a/modules/messages/src/mock.rs +++ b/modules/messages/src/mock.rs @@ -147,9 +147,12 @@ parameter_types! { pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID, TEST_LANE_ID_2]; } +/// weights of messages pallet calls we use in tests. +pub type TestWeightInfo = (); + impl Config for TestRuntime { type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); + type WeightInfo = TestWeightInfo; type ActiveOutboundLanes = ActiveOutboundLanes; type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; @@ -170,6 +173,44 @@ impl Config for TestRuntime { type BridgedChainId = TestBridgedChainId; } +#[cfg(feature = "runtime-benchmarks")] +impl crate::benchmarking::Config<()> for TestRuntime { + fn bench_lane_id() -> LaneId { + TEST_LANE_ID + } + + fn prepare_message_proof( + params: crate::benchmarking::MessageProofParams, + ) -> (TestMessagesProof, Weight) { + // in mock run we only care about benchmarks correctness, not the benchmark results + // => ignore size related arguments + let (messages, total_dispatch_weight) = + params.message_nonces.into_iter().map(|n| message(n, REGULAR_PAYLOAD)).fold( + (Vec::new(), Weight::zero()), + |(mut messages, total_dispatch_weight), message| { + let weight = REGULAR_PAYLOAD.declared_weight; + messages.push(message); + (messages, total_dispatch_weight.saturating_add(weight)) + }, + ); + let mut proof: TestMessagesProof = Ok(messages).into(); + proof.result.as_mut().unwrap().get_mut(0).unwrap().1.lane_state = params.outbound_lane_data; + (proof, total_dispatch_weight) + } + + fn prepare_message_delivery_proof( + params: crate::benchmarking::MessageDeliveryProofParams, + ) -> TestMessagesDeliveryProof { + // in mock run we only care about benchmarks correctness, not the benchmark results + // => ignore size related arguments + TestMessagesDeliveryProof(Ok((params.lane, params.inbound_lane_data))) + } + + fn is_relayer_rewarded(_relayer: &AccountId) -> bool { + true + } +} + impl Size for TestPayload { fn size(&self) -> u32 { 16 + self.extra.len() as u32 @@ -342,12 +383,15 @@ impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayment messages_relayers: VecDeque>, _confirmation_relayer: &AccountId, received_range: &RangeInclusive, - ) { + ) -> MessageNonce { let relayers_rewards = calc_relayers_rewards(messages_relayers, received_range); + let rewarded_relayers = relayers_rewards.len(); for (relayer, reward) in &relayers_rewards { let key = (b":relayer-reward:", relayer, reward).encode(); frame_support::storage::unhashed::put(&key, &true); } + + rewarded_relayers as _ } } @@ -439,12 +483,16 @@ pub fn unrewarded_relayer( UnrewardedRelayer { relayer, messages: DeliveredMessages { begin, end } } } -/// Run pallet test. -pub fn run_test(test: impl FnOnce() -> T) -> T { +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); pallet_balances::GenesisConfig:: { balances: vec![(ENDOWED_ACCOUNT, 1_000_000)] } .assimilate_storage(&mut t) .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(test) + sp_io::TestExternalities::new(t) +} + +/// Run pallet test. +pub fn run_test(test: impl FnOnce() -> T) -> T { + new_test_ext().execute_with(test) } diff --git a/modules/parachains/Cargo.toml b/modules/parachains/Cargo.toml index c25956248d0..39c3ba626aa 100644 --- a/modules/parachains/Cargo.toml +++ b/modules/parachains/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.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Bridge Dependencies diff --git a/modules/parachains/src/benchmarking.rs b/modules/parachains/src/benchmarking.rs index 83cfba0b8c6..59c4642cde9 100644 --- a/modules/parachains/src/benchmarking.rs +++ b/modules/parachains/src/benchmarking.rs @@ -28,7 +28,7 @@ use frame_system::RawOrigin; use sp_std::prelude::*; /// Pallet we're benchmarking here. -pub struct Pallet, I: 'static>(crate::Pallet); +pub struct Pallet, I: 'static = ()>(crate::Pallet); /// Trait that must be implemented by runtime to benchmark the parachains finality pallet. pub trait Config: crate::Config { @@ -111,4 +111,6 @@ benchmarks_instance_pallet! { assert!(crate::Pallet::::best_parachain_head(parachain).is_some()); } } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) } diff --git a/modules/parachains/src/lib.rs b/modules/parachains/src/lib.rs index e72e2aec8c2..6c89b09513c 100644 --- a/modules/parachains/src/lib.rs +++ b/modules/parachains/src/lib.rs @@ -294,6 +294,16 @@ pub mod pallet { /// `polkadot-runtime-parachains::paras` pallet instance, deployed at the bridged chain. /// The proof is supposed to be crafted at the `relay_header_hash` that must already be /// imported by corresponding GRANDPA pallet at this chain. + /// + /// The call fails if: + /// + /// - the pallet is halted; + /// + /// - the relay chain block `at_relay_block` is not imported by the associated bridge + /// GRANDPA pallet. + /// + /// The call may succeed, but some heads may not be updated e.g. because pallet knows + /// better head or it isn't tracked by the pallet. #[pallet::call_index(0)] #[pallet::weight(WeightInfoOf::::submit_parachain_heads_weight( T::DbWeight::get(), @@ -689,7 +699,7 @@ pub fn initialize_for_benchmarks, I: 'static, PC: Parachain::WeightInfo; type DbWeight = ::DbWeight; - fn initialize(state_root: RelayBlockHash) { + pub(crate) fn initialize(state_root: RelayBlockHash) -> RelayBlockHash { pallet_bridge_grandpa::Pallet::::initialize( RuntimeOrigin::root(), bp_header_chain::InitializationData { @@ -738,6 +748,8 @@ mod tests { System::::set_block_number(1); System::::reset_events(); + + test_relay_header(0, state_root).hash() } fn proceed(num: RelayBlockNumber, state_root: RelayBlockHash) -> ParaHash { @@ -759,7 +771,7 @@ mod tests { hash } - fn prepare_parachain_heads_proof( + pub(crate) fn prepare_parachain_heads_proof( heads: Vec<(u32, ParaHead)>, ) -> (RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) { let mut parachains = Vec::with_capacity(heads.len()); @@ -795,7 +807,7 @@ mod tests { } } - fn head_data(parachain: u32, head_number: u32) -> ParaHead { + pub(crate) fn head_data(parachain: u32, head_number: u32) -> ParaHead { ParaHead( RegularParachainHeader::new( head_number as _, diff --git a/modules/parachains/src/mock.rs b/modules/parachains/src/mock.rs index c19ce98eba2..3086adc1cc2 100644 --- a/modules/parachains/src/mock.rs +++ b/modules/parachains/src/mock.rs @@ -199,7 +199,7 @@ parameter_types! { impl pallet_bridge_grandpa::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgedChain = TestBridgedChain; - type MaxRequests = ConstU32<2>; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<2>; type HeadersToKeep = HeadersToKeep; type WeightInfo = (); } @@ -207,7 +207,7 @@ impl pallet_bridge_grandpa::Config for TestRun impl pallet_bridge_grandpa::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type BridgedChain = TestBridgedChain; - type MaxRequests = ConstU32<2>; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<2>; type HeadersToKeep = HeadersToKeep; type WeightInfo = (); } @@ -228,6 +228,36 @@ impl pallet_bridge_parachains::Config for TestRuntime { type MaxParaHeadDataSize = ConstU32; } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_bridge_parachains::benchmarking::Config<()> for TestRuntime { + fn parachains() -> Vec { + vec![ + ParaId(Parachain1::PARACHAIN_ID), + ParaId(Parachain2::PARACHAIN_ID), + ParaId(Parachain3::PARACHAIN_ID), + ] + } + + fn prepare_parachain_heads_proof( + parachains: &[ParaId], + _parachain_head_size: u32, + _proof_size: bp_runtime::StorageProofSize, + ) -> ( + crate::RelayBlockNumber, + crate::RelayBlockHash, + bp_polkadot_core::parachains::ParaHeadsProof, + Vec<(ParaId, bp_polkadot_core::parachains::ParaHash)>, + ) { + // in mock run we only care about benchmarks correctness, not the benchmark results + // => ignore size related arguments + let (state_root, proof, parachains) = crate::tests::prepare_parachain_heads_proof( + parachains.iter().map(|p| (p.0, crate::tests::head_data(p.0, 1))).collect(), + ); + let relay_genesis_hash = crate::tests::initialize(state_root); + (0, relay_genesis_hash, proof, parachains) + } +} + #[derive(Debug)] pub struct TestBridgedChain; @@ -290,14 +320,21 @@ impl ChainWithGrandpa for OtherBridgedChain { const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; } +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new(Default::default()) +} + +/// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + new_test_ext().execute_with(|| { System::set_block_number(1); System::reset_events(); test() }) } +/// Return test relay chain header with given number. pub fn test_relay_header( num: crate::RelayBlockNumber, state_root: crate::RelayBlockHash, diff --git a/modules/relayers/Cargo.toml b/modules/relayers/Cargo.toml index 200fbbca309..c654c60d02b 100644 --- a/modules/relayers/Cargo.toml +++ b/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.17", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/modules/relayers/src/benchmarking.rs b/modules/relayers/src/benchmarking.rs index 7dcf77eb958..a762a5693c2 100644 --- a/modules/relayers/src/benchmarking.rs +++ b/modules/relayers/src/benchmarking.rs @@ -54,4 +54,6 @@ benchmarks! { // payment logic, so we assume that if call has succeeded, the procedure has // also completed successfully } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) } diff --git a/modules/relayers/src/mock.rs b/modules/relayers/src/mock.rs index 5e97e81ae33..fe8c586eecc 100644 --- a/modules/relayers/src/mock.rs +++ b/modules/relayers/src/mock.rs @@ -99,6 +99,18 @@ impl pallet_bridge_relayers::Config for TestRuntime { type WeightInfo = (); } +#[cfg(feature = "runtime-benchmarks")] +impl pallet_bridge_relayers::benchmarking::Config for TestRuntime { + fn prepare_environment(account_params: RewardsAccountParams, reward: Balance) { + use frame_support::traits::fungible::Mutate; + let rewards_account = + bp_relayers::PayRewardFromAccount::::rewards_account( + account_params, + ); + Balances::mint_into(&rewards_account, reward).unwrap(); + } +} + /// Message lane that we're using in tests. pub const TEST_REWARDS_ACCOUNT_PARAMS: RewardsAccountParams = RewardsAccountParams::new(LaneId([0, 0, 0, 0]), *b"test", RewardsAccountOwner::ThisChain); @@ -127,9 +139,13 @@ impl PaymentProcedure for TestPaymentProcedure { } } +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + sp_io::TestExternalities::new(t) +} + /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { - let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(test) + new_test_ext().execute_with(test) } diff --git a/modules/relayers/src/payment_adapter.rs b/modules/relayers/src/payment_adapter.rs index 2752044958b..a9536cfc027 100644 --- a/modules/relayers/src/payment_adapter.rs +++ b/modules/relayers/src/payment_adapter.rs @@ -20,7 +20,7 @@ use crate::{Config, Pallet}; use bp_messages::{ source_chain::{DeliveryConfirmationPayments, RelayersRewards}, - LaneId, + LaneId, MessageNonce, }; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; @@ -47,9 +47,10 @@ where messages_relayers: VecDeque>, confirmation_relayer: &T::AccountId, received_range: &RangeInclusive, - ) { + ) -> MessageNonce { let relayers_rewards = bp_messages::calc_relayers_rewards::(messages_relayers, received_range); + let rewarded_relayers = relayers_rewards.len(); register_relayers_rewards::( confirmation_relayer, @@ -61,6 +62,8 @@ where ), DeliveryReward::get(), ); + + rewarded_relayers as _ } } diff --git a/modules/shift-session-manager/Cargo.toml b/modules/shift-session-manager/Cargo.toml index 504adfae416..2d7dc272a6f 100644 --- a/modules/shift-session-manager/Cargo.toml +++ b/modules/shift-session-manager/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.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Substrate Dependencies diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml index 4b4044252ca..9039064fbf4 100644 --- a/primitives/beefy/Cargo.toml +++ b/primitives/beefy/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.0.0", default-features = false, features = ["derive", "bit-vec"] } -scale-info = { version = "2.0.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["bit-vec", "derive"] } serde = { version = "1.0", optional = true } # Bridge Dependencies diff --git a/primitives/chain-millau/Cargo.toml b/primitives/chain-millau/Cargo.toml index 00d5a02d47c..d1e2e0edd96 100644 --- a/primitives/chain-millau/Cargo.toml +++ b/primitives/chain-millau/Cargo.toml @@ -13,7 +13,7 @@ hash256-std-hasher = { version = "0.15.2", default-features = false } impl-codec = { version = "0.6", default-features = false } impl-serde = { version = "0.4.0", optional = true } parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Bridge Dependencies diff --git a/primitives/header-chain/Cargo.toml b/primitives/header-chain/Cargo.toml index ca2f4ad88d3..5b9f87614a8 100644 --- a/primitives/header-chain/Cargo.toml +++ b/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.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true } # Bridge dependencies @@ -27,7 +27,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", d [dev-dependencies] bp-test-utils = { path = "../test-utils" } hex = "0.4" -hex-literal = "0.3" +hex-literal = "0.4" [features] default = ["std"] diff --git a/primitives/messages/Cargo.toml b/primitives/messages/Cargo.toml index f54090893a6..32d7c65ebcb 100644 --- a/primitives/messages/Cargo.toml +++ b/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.1.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["bit-vec", "derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Bridge dependencies @@ -23,7 +23,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", d [dev-dependencies] hex = "0.4" -hex-literal = "0.3" +hex-literal = "0.4" [features] default = ["std"] diff --git a/primitives/messages/src/lib.rs b/primitives/messages/src/lib.rs index 754349d634e..3910837a442 100644 --- a/primitives/messages/src/lib.rs +++ b/primitives/messages/src/lib.rs @@ -20,7 +20,7 @@ // RuntimeApi generated functions #![allow(clippy::too_many_arguments)] -use bp_runtime::{BasicOperatingMode, OperatingMode}; +use bp_runtime::{BasicOperatingMode, OperatingMode, RangeInclusiveExt}; use codec::{Decode, Encode, MaxEncodedLen}; use frame_support::RuntimeDebug; use scale_info::TypeInfo; @@ -194,7 +194,7 @@ impl InboundLaneData { } /// Outbound message details, returned by runtime APIs. -#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct OutboundMessageDetails { /// Nonce assigned to the message. pub nonce: MessageNonce, @@ -208,7 +208,7 @@ pub struct OutboundMessageDetails { } /// Inbound message details, returned by runtime APIs. -#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq)] +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] pub struct InboundMessageDetails { /// Computed message dispatch weight. /// @@ -238,8 +238,6 @@ pub struct ReceivedMessages { pub lane: LaneId, /// Result of messages which we tried to dispatch pub receive_results: Vec<(MessageNonce, ReceivalResult)>, - /// Messages which were skipped and never dispatched - pub skipped_for_not_enough_weight: Vec, } impl ReceivedMessages { @@ -247,16 +245,12 @@ impl ReceivedMessages { lane: LaneId, receive_results: Vec<(MessageNonce, ReceivalResult)>, ) -> Self { - ReceivedMessages { lane, receive_results, skipped_for_not_enough_weight: Vec::new() } + ReceivedMessages { lane, receive_results } } pub fn push(&mut self, message: MessageNonce, result: ReceivalResult) { self.receive_results.push((message, result)); } - - pub fn push_skipped_for_not_enough_weight(&mut self, message: MessageNonce) { - self.skipped_for_not_enough_weight.push(message); - } } /// Result of single message receival. @@ -293,11 +287,7 @@ impl DeliveredMessages { /// Return total count of delivered messages. pub fn total_messages(&self) -> MessageNonce { - if self.end >= self.begin { - self.end - self.begin + 1 - } else { - 0 - } + (self.begin..=self.end).checked_len().unwrap_or(0) } /// Note new dispatched message. diff --git a/primitives/messages/src/source_chain.rs b/primitives/messages/src/source_chain.rs index 83f27843d63..394a934171f 100644 --- a/primitives/messages/src/source_chain.rs +++ b/primitives/messages/src/source_chain.rs @@ -98,12 +98,14 @@ pub trait DeliveryConfirmationPayments { /// /// The implementation may also choose to pay reward to the `confirmation_relayer`, which is /// a relayer that has submitted delivery confirmation transaction. + /// + /// Returns number of actually rewarded relayers. fn pay_reward( lane_id: LaneId, messages_relayers: VecDeque>, confirmation_relayer: &AccountId, received_range: &RangeInclusive, - ); + ) -> MessageNonce; } impl DeliveryConfirmationPayments for () { @@ -114,8 +116,9 @@ impl DeliveryConfirmationPayments for () { _messages_relayers: VecDeque>, _confirmation_relayer: &AccountId, _received_range: &RangeInclusive, - ) { + ) -> MessageNonce { // this implementation is not rewarding relayers at all + 0 } } @@ -202,6 +205,7 @@ impl DeliveryConfirmationPayments for ForbidOutboundMessag _messages_relayers: VecDeque>, _confirmation_relayer: &AccountId, _received_range: &RangeInclusive, - ) { + ) -> MessageNonce { + 0 } } diff --git a/primitives/parachains/Cargo.toml b/primitives/parachains/Cargo.toml index 333f7ad647a..e47b8c5e68c 100644 --- a/primitives/parachains/Cargo.toml +++ b/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.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } # Bridge dependencies diff --git a/primitives/polkadot-core/Cargo.toml b/primitives/polkadot-core/Cargo.toml index a9db53a8bf0..daae99ec71c 100644 --- a/primitives/polkadot-core/Cargo.toml +++ b/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.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Bridge Dependencies diff --git a/primitives/relayers/Cargo.toml b/primitives/relayers/Cargo.toml index ee91361a4e2..8ac31258488 100644 --- a/primitives/relayers/Cargo.toml +++ b/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.1.1", default-features = false, features = ["bit-vec", "derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["bit-vec", "derive"] } # Bridge Dependencies @@ -23,7 +23,7 @@ sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", d [dev-dependencies] hex = "0.4" -hex-literal = "0.3" +hex-literal = "0.4" [features] default = ["std"] diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml index 802e58e1af1..4d48ad61894 100644 --- a/primitives/runtime/Cargo.toml +++ b/primitives/runtime/Cargo.toml @@ -11,7 +11,7 @@ codec = { package = "parity-scale-codec", version = "3.1.5", default-features = hash-db = { version = "0.16.0", default-features = false } impl-trait-for-tuples = "0.2.2" num-traits = { version = "0.2", default-features = false } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] } # Substrate Dependencies @@ -27,7 +27,7 @@ sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", trie-db = { version = "0.27.1", default-features = false } [dev-dependencies] -hex-literal = "0.3" +hex-literal = "0.4" [features] default = ["std"] diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index d4f551ce57a..df77745bc02 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -27,7 +27,7 @@ use frame_system::RawOrigin; use scale_info::TypeInfo; use sp_core::storage::StorageKey; use sp_runtime::traits::{BadOrigin, Header as HeaderT, UniqueSaturatedInto}; -use sp_std::{convert::TryFrom, fmt::Debug, vec, vec::Vec}; +use sp_std::{convert::TryFrom, fmt::Debug, ops::RangeInclusive, vec, vec::Vec}; pub use chain::{ AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf, @@ -35,7 +35,7 @@ pub use chain::{ UnderlyingChainProvider, }; pub use frame_support::storage::storage_prefix as storage_value_final_key; -use num_traits::{CheckedSub, One}; +use num_traits::{CheckedAdd, CheckedSub, One}; pub use storage_proof::{ record_all_keys as record_all_trie_keys, Error as StorageProofError, ProofSize as StorageProofSize, RawStorageProof, StorageProofChecker, @@ -523,6 +523,23 @@ impl Debug for StrippableError { } } +/// A trait defining helper methods for `RangeInclusive` (start..=end) +pub trait RangeInclusiveExt { + /// Computes the length of the `RangeInclusive`, checking for underflow and overflow. + fn checked_len(&self) -> Option; +} + +impl RangeInclusiveExt for RangeInclusive +where + Idx: CheckedSub + CheckedAdd + One, +{ + fn checked_len(&self) -> Option { + self.end() + .checked_sub(self.start()) + .and_then(|len| len.checked_add(&Idx::one())) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/relays/bin-substrate/Cargo.toml b/relays/bin-substrate/Cargo.toml index 6984cfed00c..7853b9cb599 100644 --- a/relays/bin-substrate/Cargo.toml +++ b/relays/bin-substrate/Cargo.toml @@ -10,7 +10,7 @@ anyhow = "1.0" async-std = "1.9.0" async-trait = "0.1" codec = { package = "parity-scale-codec", version = "3.1.5" } -futures = "0.3.27" +futures = "0.3.28" hex = "0.4" log = "0.4.17" num-format = "0.4" @@ -67,7 +67,7 @@ xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", defau [dev-dependencies] bp-test-utils = { path = "../../primitives/test-utils" } -hex-literal = "0.3" +hex-literal = "0.4" sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } -tempfile = "3.4" +tempfile = "3.5" finality-grandpa = { version = "0.16.2" } diff --git a/relays/bin-substrate/src/chains/rococo.rs b/relays/bin-substrate/src/chains/rococo.rs index 166e6edbad3..c0041c53ddb 100644 --- a/relays/bin-substrate/src/chains/rococo.rs +++ b/relays/bin-substrate/src/chains/rococo.rs @@ -27,5 +27,5 @@ impl CliChain for Rococo { impl CliChain for BridgeHubRococo { const RUNTIME_VERSION: Option = - Some(SimpleRuntimeVersion { spec_version: 9372, transaction_version: 1 }); + Some(SimpleRuntimeVersion { spec_version: 9381, transaction_version: 2 }); } diff --git a/relays/bin-substrate/src/chains/wococo.rs b/relays/bin-substrate/src/chains/wococo.rs index b6eceb8614e..73b3884c289 100644 --- a/relays/bin-substrate/src/chains/wococo.rs +++ b/relays/bin-substrate/src/chains/wococo.rs @@ -27,5 +27,5 @@ impl CliChain for Wococo { impl CliChain for BridgeHubWococo { const RUNTIME_VERSION: Option = - Some(SimpleRuntimeVersion { spec_version: 9372, transaction_version: 1 }); + Some(SimpleRuntimeVersion { spec_version: 9381, transaction_version: 2 }); } diff --git a/relays/client-bridge-hub-kusama/Cargo.toml b/relays/client-bridge-hub-kusama/Cargo.toml index 3485323ca6c..96650710f67 100644 --- a/relays/client-bridge-hub-kusama/Cargo.toml +++ b/relays/client-bridge-hub-kusama/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } relay-substrate-client = { path = "../client-substrate" } # Bridge dependencies diff --git a/relays/client-bridge-hub-polkadot/Cargo.toml b/relays/client-bridge-hub-polkadot/Cargo.toml index dee3147eb35..6126a8f2b3f 100644 --- a/relays/client-bridge-hub-polkadot/Cargo.toml +++ b/relays/client-bridge-hub-polkadot/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } relay-substrate-client = { path = "../client-substrate" } # Bridge dependencies diff --git a/relays/client-bridge-hub-rococo/Cargo.toml b/relays/client-bridge-hub-rococo/Cargo.toml index 78c3533971c..48df2e56cf0 100644 --- a/relays/client-bridge-hub-rococo/Cargo.toml +++ b/relays/client-bridge-hub-rococo/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } relay-substrate-client = { path = "../client-substrate" } # Bridge dependencies diff --git a/relays/client-bridge-hub-wococo/Cargo.toml b/relays/client-bridge-hub-wococo/Cargo.toml index 8164ae5afed..d4578fcd488 100644 --- a/relays/client-bridge-hub-wococo/Cargo.toml +++ b/relays/client-bridge-hub-wococo/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5", features = ["derive"] } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } relay-substrate-client = { path = "../client-substrate" } # Bridge dependencies diff --git a/relays/client-rialto-parachain/Cargo.toml b/relays/client-rialto-parachain/Cargo.toml index 987ac532ca6..4450dee3711 100644 --- a/relays/client-rialto-parachain/Cargo.toml +++ b/relays/client-rialto-parachain/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] codec = { package = "parity-scale-codec", version = "3.1.5" } -scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } subxt = { version = "0.27.1", default-features = false, features = [] } # Bridge dependencies diff --git a/relays/client-rialto-parachain/src/codegen_runtime.rs b/relays/client-rialto-parachain/src/codegen_runtime.rs index 893bca1e27e..3ea4a0ac2b5 100644 --- a/relays/client-rialto-parachain/src/codegen_runtime.rs +++ b/relays/client-rialto-parachain/src/codegen_runtime.rs @@ -6043,7 +6043,6 @@ pub mod api { ::core::primitive::u64, runtime_types::bp_messages::ReceivalResult<_0>, )>, - pub skipped_for_not_enough_weight: ::std::vec::Vec<::core::primitive::u64>, } #[derive( :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, @@ -7508,8 +7507,9 @@ pub mod api { #[doc = "`receive_messages_delivery_proof` call."] InvalidUnrewardedRelayersState, #[codec(index = 11)] - #[doc = "The message someone is trying to work with (i.e. increase fee) is already-delivered."] - MessageIsAlreadyDelivered, + #[doc = "The cumulative dispatch weight, passed by relayer is not enough to cover dispatch"] + #[doc = "of all bundled messages."] + InsufficientDispatchWeight, #[codec(index = 12)] #[doc = "The message someone is trying to work with (i.e. increase fee) is not yet sent."] MessageIsNotYetSent, diff --git a/relays/client-substrate/Cargo.toml b/relays/client-substrate/Cargo.toml index ce83817a995..2a79832bf9d 100644 --- a/relays/client-substrate/Cargo.toml +++ b/relays/client-substrate/Cargo.toml @@ -9,13 +9,13 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" async-std = { version = "1.6.5", features = ["attributes"] } async-trait = "0.1" codec = { package = "parity-scale-codec", version = "3.1.5" } -futures = "0.3.27" +futures = "0.3.28" jsonrpsee = { version = "0.16", features = ["macros", "ws-client"] } log = "0.4.17" num-traits = "0.2" rand = "0.8" -scale-info = { version = "2.1.1", features = ["derive"] } -tokio = { version = "1.26", features = ["rt-multi-thread"] } +scale-info = { version = "2.5.0", features = ["derive"] } +tokio = { version = "1.27", features = ["rt-multi-thread"] } thiserror = "1.0.40" # Bridge dependencies diff --git a/relays/finality/Cargo.toml b/relays/finality/Cargo.toml index 287798431fe..ab75533b023 100644 --- a/relays/finality/Cargo.toml +++ b/relays/finality/Cargo.toml @@ -11,7 +11,7 @@ async-std = "1.6.5" async-trait = "0.1" backoff = "0.4" bp-header-chain = { path = "../../primitives/header-chain" } -futures = "0.3.27" +futures = "0.3.28" log = "0.4.17" num-traits = "0.2" relay-utils = { path = "../utils" } diff --git a/relays/lib-substrate-relay/Cargo.toml b/relays/lib-substrate-relay/Cargo.toml index 17c75220f6d..d07aa936b57 100644 --- a/relays/lib-substrate-relay/Cargo.toml +++ b/relays/lib-substrate-relay/Cargo.toml @@ -11,7 +11,7 @@ thiserror = "1.0.40" async-std = "1.9.0" async-trait = "0.1" codec = { package = "parity-scale-codec", version = "3.1.5" } -futures = "0.3.27" +futures = "0.3.28" hex = "0.4" num-traits = "0.2" log = "0.4.17" diff --git a/relays/messages/Cargo.toml b/relays/messages/Cargo.toml index efb6c6c8585..8c4b8257d5a 100644 --- a/relays/messages/Cargo.toml +++ b/relays/messages/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-std = { version = "1.6.5", features = ["attributes"] } async-trait = "0.1" -futures = "0.3.27" +futures = "0.3.28" hex = "0.4" log = "0.4.17" num-traits = "0.2" diff --git a/relays/parachains/Cargo.toml b/relays/parachains/Cargo.toml index 80df2311bc9..0cecf063922 100644 --- a/relays/parachains/Cargo.toml +++ b/relays/parachains/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [dependencies] async-std = "1.6.5" async-trait = "0.1.68" -futures = "0.3.27" +futures = "0.3.28" log = "0.4.17" relay-utils = { path = "../utils" } diff --git a/relays/utils/Cargo.toml b/relays/utils/Cargo.toml index 91bd9e20d65..aa14e2ae2e3 100644 --- a/relays/utils/Cargo.toml +++ b/relays/utils/Cargo.toml @@ -13,14 +13,14 @@ async-trait = "0.1" backoff = "0.4" isahc = "1.2" env_logger = "0.10.0" -futures = "0.3.27" +futures = "0.3.28" jsonpath_lib = "0.3" log = "0.4.17" num-traits = "0.2" serde_json = "1.0" sysinfo = "0.28" time = { version = "0.3", features = ["formatting", "local-offset", "std"] } -tokio = { version = "1.26", features = ["rt"] } +tokio = { version = "1.27", features = ["rt"] } thiserror = "1.0.40" # Bridge dependencies diff --git a/scripts/dump-logs.sh b/scripts/dump-logs.sh index 51e8518872a..709a5065887 100755 --- a/scripts/dump-logs.sh +++ b/scripts/dump-logs.sh @@ -15,8 +15,6 @@ cd $LOGS_DIR SERVICES=(\ deployments_relay-messages-millau-to-rialto-generator_1 \ deployments_relay-messages-rialto-to-millau-generator_1 \ - deployments_relay-messages-millau-to-rialto-lane-00000001_1 \ - deployments_relay-messages-rialto-to-millau-lane-00000001_1 \ deployments_relay-millau-rialto_1 \ deployments_relay-headers-westend-to-millau-1_1 \ deployments_relay-headers-westend-to-millau-2_1 \ diff --git a/scripts/verify-pallets-build.sh b/scripts/verify-pallets-build.sh index 98dbe02b4b0..ad69c5df008 100755 --- a/scripts/verify-pallets-build.sh +++ b/scripts/verify-pallets-build.sh @@ -88,7 +88,9 @@ 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/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/Dockerfile diff --git a/tools/runtime-codegen/Cargo.lock b/tools/runtime-codegen/Cargo.lock index 85777e90283..46093b70727 100644 --- a/tools/runtime-codegen/Cargo.lock +++ b/tools/runtime-codegen/Cargo.lock @@ -1199,9 +1199,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" dependencies = [ "bytes", "fnv", From 20f7a557a2e30e695b56881512152419d6347e0a Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 17 Apr 2023 12:29:29 +0200 Subject: [PATCH 53/57] Fixes --- .../bridge-hub-rococo/src/bridge_hub_rococo_config.rs | 2 ++ .../bridge-hub-rococo/src/bridge_hub_wococo_config.rs | 2 ++ parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs | 4 ++-- .../runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs | 5 +++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs index 1dd47bdb17f..b2f4a7af81b 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_rococo_config.rs @@ -50,6 +50,7 @@ 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; } /// Proof of messages, coming from Wococo. @@ -137,6 +138,7 @@ pub type BridgeRefundBridgeHubWococoMessages = RefundBridgedParachainMessages< RefundableParachain, RefundableMessagesLane, ActualFeeRefund, + PriorityBoostPerMessage, StrBridgeRefundBridgeHubWococoMessages, >; bp_runtime::generate_static_str_provider!(BridgeRefundBridgeHubWococoMessages); diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs index 7f756abee99..02d95c0646a 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_hub_wococo_config.rs @@ -50,6 +50,7 @@ parameter_types! { pub BridgeHubWococoUniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(Wococo), Parachain(ParachainInfo::parachain_id().into())); pub RococoGlobalConsensusNetwork: NetworkId = NetworkId::Rococo; pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[DEFAULT_XCM_LANE_TO_BRIDGE_HUB_ROCOCO]; + pub PriorityBoostPerMessage: u64 = 921_900_294; } /// Proof of messages, coming from Rococo. @@ -137,6 +138,7 @@ pub type BridgeRefundBridgeHubRococoMessages = RefundBridgedParachainMessages< RefundableParachain, RefundableMessagesLane, ActualFeeRefund, + PriorityBoostPerMessage, StrBridgeRefundBridgeHubRococoMessages, >; bp_runtime::generate_static_str_provider!(BridgeRefundBridgeHubRococoMessages); diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs index 22b6b7d13e0..ee0c7a660d6 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs @@ -402,7 +402,7 @@ pub type BridgeGrandpaWococoInstance = pallet_bridge_grandpa::Instance1; impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_wococo::Wococo; - type MaxRequests = MaxRequests; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; type HeadersToKeep = RelayChainHeadersToKeep; type WeightInfo = weights::pallet_bridge_grandpa_bridge_wococo_grandpa::WeightInfo; } @@ -412,7 +412,7 @@ pub type BridgeGrandpaRococoInstance = pallet_bridge_grandpa::Instance2; impl pallet_bridge_grandpa::Config for Runtime { type RuntimeEvent = RuntimeEvent; type BridgedChain = bp_rococo::Rococo; - type MaxRequests = MaxRequests; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; type HeadersToKeep = RelayChainHeadersToKeep; type WeightInfo = weights::pallet_bridge_grandpa_bridge_rococo_grandpa::WeightInfo; } diff --git a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs index e0b1f47fba6..84cdb3ecb4c 100644 --- a/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs +++ b/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs @@ -26,6 +26,7 @@ use xcm::latest::prelude::*; use bridge_hub_test_utils::*; use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; use frame_support::weights::Weight; +use xcm_builder::DispatchBlobError; use xcm_executor::XcmExecutor; fn execute_on_runtime( @@ -95,7 +96,7 @@ fn dispatch_blob_and_xcm_routing_works_on_bridge_hub_wococo() { ); assert_eq!( result.dispatch_level_result, - XcmBlobMessageDispatchResult::NotDispatched("DispatchBlobError::RoutingError") + XcmBlobMessageDispatchResult::NotDispatched(Some(DispatchBlobError::RoutingError)) ); // 2.1. WITH hrmp channel -> Ok @@ -164,7 +165,7 @@ fn dispatch_blob_and_xcm_routing_works_on_bridge_hub_rococo() { ); assert_eq!( result.dispatch_level_result, - XcmBlobMessageDispatchResult::NotDispatched("DispatchBlobError::RoutingError") + XcmBlobMessageDispatchResult::NotDispatched(Some(DispatchBlobError::RoutingError)) ); // 2.1. WITH hrmp channel -> Ok From a9e27730296e3269b82cd315aed9d635610f076c Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 17 Apr 2023 12:31:10 +0200 Subject: [PATCH 54/57] Squashed 'bridges/' content from commit d30927c08 git-subtree-dir: bridges git-subtree-split: d30927c089bd9e73092d1ec1a62895603cb277a3 --- .config/lingua.dic | 244 + .config/spellcheck.toml | 13 + .dockerignore | 1 + .editorconfig | 19 + .github/dependabot.yml | 62 + .gitignore | 26 + .gitlab-ci.yml | 412 + .maintain/millau-weight-template.hbs | 138 + CODEOWNERS | 21 + CODE_OF_CONDUCT.md | 80 + Cargo.lock | 15431 ++++++++++++++++ Cargo.toml | 59 + Dockerfile | 72 + LICENSE | 675 + README.md | 259 + SECURITY.md | 14 + bin/.keep | 0 bin/millau/node/Cargo.toml | 59 + bin/millau/node/build.rs | 23 + bin/millau/node/src/chain_spec.rs | 235 + bin/millau/node/src/cli.rs | 73 + bin/millau/node/src/command.rs | 159 + bin/millau/node/src/lib.rs | 32 + bin/millau/node/src/main.rs | 30 + bin/millau/node/src/service.rs | 453 + bin/millau/runtime/Cargo.toml | 144 + bin/millau/runtime/build.rs | 25 + bin/millau/runtime/src/lib.rs | 1159 ++ bin/millau/runtime/src/rialto_messages.rs | 199 + .../runtime/src/rialto_parachain_messages.rs | 209 + bin/millau/runtime/src/xcm_config.rs | 373 + bin/rialto-parachain/node/Cargo.toml | 81 + bin/rialto-parachain/node/build.rs | 22 + bin/rialto-parachain/node/src/chain_spec.rs | 198 + bin/rialto-parachain/node/src/cli.rs | 142 + bin/rialto-parachain/node/src/command.rs | 445 + bin/rialto-parachain/node/src/lib.rs | 18 + bin/rialto-parachain/node/src/main.rs | 29 + bin/rialto-parachain/node/src/service.rs | 510 + bin/rialto-parachain/runtime/Cargo.toml | 139 + bin/rialto-parachain/runtime/build.rs | 25 + bin/rialto-parachain/runtime/src/lib.rs | 959 + .../runtime/src/millau_messages.rs | 138 + bin/rialto/node/Cargo.toml | 50 + bin/rialto/node/build.rs | 23 + bin/rialto/node/src/chain_spec.rs | 289 + bin/rialto/node/src/cli.rs | 88 + bin/rialto/node/src/command.rs | 222 + bin/rialto/node/src/main.rs | 28 + bin/rialto/runtime/Cargo.toml | 142 + bin/rialto/runtime/build.rs | 25 + bin/rialto/runtime/src/lib.rs | 986 + bin/rialto/runtime/src/millau_messages.rs | 198 + bin/rialto/runtime/src/parachains.rs | 165 + bin/rialto/runtime/src/xcm_config.rs | 276 + bin/runtime-common/Cargo.toml | 92 + bin/runtime-common/src/integrity.rs | 331 + bin/runtime-common/src/lib.rs | 245 + bin/runtime-common/src/messages.rs | 787 + bin/runtime-common/src/messages_api.rs | 66 + .../src/messages_benchmarking.rs | 293 + bin/runtime-common/src/messages_call_ext.rs | 634 + bin/runtime-common/src/messages_generation.rs | 119 + .../src/messages_xcm_extension.rs | 164 + bin/runtime-common/src/mock.rs | 402 + .../src/parachains_benchmarking.rs | 88 + bin/runtime-common/src/priority_calculator.rs | 201 + .../src/refund_relayer_extension.rs | 1349 ++ ci.Dockerfile | 53 + deny.toml | 202 + deployments/README.md | 270 + .../bridges/common/generate_messages.sh | 65 + ...y-millau-to-rialto-messages-dashboard.json | 1153 ++ ...y-rialto-to-millau-messages-dashboard.json | 1145 ++ .../rialto-millau-maintenance-dashboard.json | 635 + .../dashboard/prometheus/targets.yml | 2 + .../bridges/rialto-millau/docker-compose.yml | 88 + ...ay-messages-millau-to-rialto-entrypoint.sh | 16 + ...ay-messages-rialto-to-millau-entrypoint.sh | 16 + ...messages-to-millau-generator-entrypoint.sh | 27 + ...messages-to-rialto-generator-entrypoint.sh | 27 + ...ssages-to-rialto-resubmitter-entrypoint.sh | 25 + .../relay-millau-rialto-entrypoint.sh | 37 + ...o-rialto-parachain-messages-dashboard.json | 910 + ...arachain-to-millau-messages-dashboard.json | 908 + ...arachain-millau-maintenance-dashboard.json | 627 + .../dashboard/prometheus/targets.yml | 3 + .../docker-compose.yml | 90 + ...messages-to-millau-generator-entrypoint.sh | 28 + ...o-rialto-parachain-generator-entrypoint.sh | 27 + ...rialto-parachain-resubmitter-entrypoint.sh | 25 + ...elay-millau-rialto-parachain-entrypoint.sh | 39 + deployments/bridges/rococo-wococo/README.md | 10 + .../dashboard/grafana/bridges-alerts.json | 1994 ++ ...y-rococo-to-wococo-messages-dashboard.json | 941 + ...y-wococo-to-rococo-messages-dashboard.json | 941 + .../rococo-wococo-maintenance-dashboard.json | 1031 ++ ...y-westend-to-millau-headers-dashboard.json | 781 + ...estend-to-millau-parachains-dashboard.json | 200 + .../dashboard/prometheus/targets.yml | 3 + .../bridges/westend-millau/docker-compose.yml | 72 + ...ay-headers-westend-to-millau-entrypoint.sh | 26 + ...parachains-westend-to-millau-entrypoint.sh | 16 + .../local-scripts/bridge-entrypoint.sh | 7 + .../relay-messages-millau-to-rialto.sh | 20 + .../relay-messages-rialto-to-millau.sh | 20 + .../local-scripts/relay-millau-to-rialto.sh | 29 + .../local-scripts/relay-rialto-to-millau.sh | 27 + deployments/local-scripts/run-millau-node.sh | 11 + deployments/local-scripts/run-rialto-node.sh | 11 + deployments/local-scripts/run-westend-node.sh | 14 + .../monitoring/GrafanaMatrix.Dockerfile | 15 + deployments/monitoring/disabled.yml | 15 + deployments/monitoring/docker-compose.yml | 36 + .../monitoring/grafana-matrix/config.yml | 47 + .../monitoring/grafana/dashboards/nodes.json | 200 + .../dashboards/grafana-dashboard.yaml | 6 + .../datasources/grafana-datasource.yaml | 16 + .../notifiers/grafana-notifier.yaml | 15 + .../monitoring/prometheus/prometheus.yml | 7 + .../dashboard/grafana/beefy-dashboard.json | 500 + .../dashboard/prometheus/millau-targets.yml | 6 + .../dashboard/prometheus/rialto-targets.yml | 6 + .../rialto-chainspec-exporter-entrypoint.sh | 16 + .../rialto-parachain-registrar-entrypoint.sh | 11 + deployments/networks/millau.yml | 113 + deployments/networks/rialto-parachain.yml | 90 + deployments/networks/rialto.yml | 130 + deployments/reverse-proxy/README.md | 15 + deployments/reverse-proxy/docker-compose.yml | 45 + deployments/run.sh | 217 + deployments/types-millau.json | 191 + deployments/types-rialto.json | 191 + deployments/types/build.sh | 20 + deployments/types/common.json | 123 + deployments/types/millau.json | 17 + deployments/types/rialto-millau.json | 56 + deployments/types/rialto.json | 17 + deployments/ui/README.md | 23 + deployments/ui/docker-compose.yml | 14 + docs/complex-relay.html | 85 + docs/dockerhub-bridges-common-relay.README.md | 1 + docs/dockerhub-millau-bridge-node.README.md | 1 + docs/dockerhub-rialto-bridge-node.README.md | 1 + ...kerhub-rialto-parachain-collator.README.md | 1 + docs/dockerhub-substrate-relay.README.md | 1 + docs/grandpa-finality-relay.html | 47 + docs/high-level-overview.md | 181 + docs/messages-relay.html | 78 + docs/parachains-finality-relay.html | 55 + docs/polkadot-kusama-bridge-overview.md | 132 + docs/polkadot-kusama-bridge.html | 67 + fuzz/storage-proof/Cargo.lock | 2796 +++ fuzz/storage-proof/Cargo.toml | 25 + fuzz/storage-proof/README.md | 34 + fuzz/storage-proof/src/main.rs | 78 + modules/beefy/Cargo.toml | 54 + modules/beefy/src/lib.rs | 648 + modules/beefy/src/mock.rs | 224 + modules/beefy/src/mock_chain.rs | 299 + modules/beefy/src/utils.rs | 361 + modules/grandpa/Cargo.toml | 63 + modules/grandpa/README.md | 101 + modules/grandpa/src/benchmarking.rs | 141 + modules/grandpa/src/call_ext.rs | 311 + modules/grandpa/src/lib.rs | 1423 ++ modules/grandpa/src/mock.rs | 151 + modules/grandpa/src/storage_types.rs | 136 + modules/grandpa/src/weights.rs | 167 + modules/messages/Cargo.toml | 56 + modules/messages/README.md | 242 + modules/messages/src/benchmarking.rs | 460 + modules/messages/src/inbound_lane.rs | 550 + modules/messages/src/lib.rs | 2176 +++ modules/messages/src/mock.rs | 498 + modules/messages/src/outbound_lane.rs | 436 + modules/messages/src/weights.rs | 525 + modules/messages/src/weights_ext.rs | 444 + modules/parachains/Cargo.toml | 60 + modules/parachains/README.md | 90 + modules/parachains/src/benchmarking.rs | 116 + modules/parachains/src/call_ext.rs | 243 + modules/parachains/src/lib.rs | 1609 ++ modules/parachains/src/mock.rs | 349 + modules/parachains/src/weights.rs | 273 + modules/parachains/src/weights_ext.rs | 107 + modules/relayers/Cargo.toml | 59 + modules/relayers/README.md | 14 + modules/relayers/src/benchmarking.rs | 59 + modules/relayers/src/lib.rs | 309 + modules/relayers/src/mock.rs | 151 + modules/relayers/src/payment_adapter.rs | 158 + modules/relayers/src/weights.rs | 101 + modules/shift-session-manager/Cargo.toml | 39 + modules/shift-session-manager/README.md | 10 + modules/shift-session-manager/src/lib.rs | 266 + primitives/beefy/Cargo.toml | 41 + primitives/beefy/src/lib.rs | 149 + .../chain-bridge-hub-cumulus/Cargo.toml | 37 + .../chain-bridge-hub-cumulus/src/lib.rs | 216 + primitives/chain-bridge-hub-kusama/Cargo.toml | 31 + primitives/chain-bridge-hub-kusama/src/lib.rs | 84 + .../chain-bridge-hub-polkadot/Cargo.toml | 32 + .../chain-bridge-hub-polkadot/src/lib.rs | 75 + primitives/chain-bridge-hub-rococo/Cargo.toml | 31 + primitives/chain-bridge-hub-rococo/src/lib.rs | 82 + primitives/chain-bridge-hub-wococo/Cargo.toml | 32 + primitives/chain-bridge-hub-wococo/src/lib.rs | 72 + primitives/chain-kusama/Cargo.toml | 30 + primitives/chain-kusama/src/lib.rs | 65 + primitives/chain-millau/Cargo.toml | 59 + primitives/chain-millau/src/lib.rs | 249 + primitives/chain-millau/src/millau_hash.rs | 58 + primitives/chain-polkadot/Cargo.toml | 30 + primitives/chain-polkadot/src/lib.rs | 65 + primitives/chain-rialto-parachain/Cargo.toml | 39 + primitives/chain-rialto-parachain/src/lib.rs | 152 + primitives/chain-rialto/Cargo.toml | 38 + primitives/chain-rialto/src/lib.rs | 214 + primitives/chain-rococo/Cargo.toml | 30 + primitives/chain-rococo/src/lib.rs | 76 + primitives/chain-westend/Cargo.toml | 30 + primitives/chain-westend/src/lib.rs | 108 + primitives/chain-wococo/Cargo.toml | 32 + primitives/chain-wococo/src/lib.rs | 65 + primitives/header-chain/Cargo.toml | 45 + primitives/header-chain/src/justification.rs | 390 + primitives/header-chain/src/lib.rs | 227 + primitives/header-chain/src/storage_keys.rs | 104 + .../tests/implementation_match.rs | 418 + .../header-chain/tests/justification.rs | 280 + primitives/messages/Cargo.toml | 38 + primitives/messages/src/lib.rs | 471 + primitives/messages/src/source_chain.rs | 211 + primitives/messages/src/storage_keys.rs | 128 + primitives/messages/src/target_chain.rs | 205 + primitives/parachains/Cargo.toml | 39 + primitives/parachains/src/lib.rs | 180 + primitives/polkadot-core/Cargo.toml | 45 + primitives/polkadot-core/src/lib.rs | 292 + primitives/polkadot-core/src/parachains.rs | 98 + primitives/relayers/Cargo.toml | 36 + primitives/relayers/src/lib.rs | 202 + primitives/runtime/Cargo.toml | 49 + primitives/runtime/src/chain.rs | 375 + primitives/runtime/src/extensions.rs | 144 + primitives/runtime/src/lib.rs | 573 + primitives/runtime/src/messages.rs | 35 + primitives/runtime/src/storage_proof.rs | 272 + primitives/runtime/src/storage_types.rs | 90 + primitives/test-utils/Cargo.toml | 29 + primitives/test-utils/src/keyring.rs | 94 + primitives/test-utils/src/lib.rs | 302 + relays/bin-substrate/Cargo.toml | 73 + ..._kusama_messages_to_bridge_hub_polkadot.rs | 65 + ..._polkadot_messages_to_bridge_hub_kusama.rs | 65 + .../kusama_headers_to_bridge_hub_polkadot.rs | 72 + ...usama_parachains_to_bridge_hub_polkadot.rs | 75 + .../src/bridges/kusama_polkadot/mod.rs | 24 + .../polkadot_headers_to_bridge_hub_kusama.rs | 72 + ...olkadot_parachains_to_bridge_hub_kusama.rs | 75 + relays/bin-substrate/src/bridges/mod.rs | 23 + .../rialto_millau/millau_headers_to_rialto.rs | 56 + .../millau_messages_to_rialto.rs | 47 + .../src/bridges/rialto_millau/mod.rs | 22 + .../rialto_millau/rialto_headers_to_millau.rs | 56 + .../rialto_messages_to_millau.rs | 47 + .../millau_headers_to_rialto_parachain.rs | 76 + .../millau_messages_to_rialto_parachain.rs | 51 + .../bridges/rialto_parachain_millau/mod.rs | 22 + .../rialto_parachain_messages_to_millau.rs | 51 + .../rialto_parachains_to_millau.rs | 65 + ...ub_rococo_messages_to_bridge_hub_wococo.rs | 64 + ...ub_wococo_messages_to_bridge_hub_rococo.rs | 64 + .../src/bridges/rococo_wococo/mod.rs | 24 + .../rococo_headers_to_bridge_hub_wococo.rs | 72 + .../rococo_parachains_to_bridge_hub_wococo.rs | 75 + .../wococo_headers_to_bridge_hub_rococo.rs | 72 + .../wococo_parachains_to_bridge_hub_rococo.rs | 75 + .../src/bridges/westend_millau/mod.rs | 20 + .../westend_headers_to_millau.rs | 51 + .../westend_parachains_to_millau.rs | 59 + relays/bin-substrate/src/chains/kusama.rs | 32 + relays/bin-substrate/src/chains/millau.rs | 39 + relays/bin-substrate/src/chains/mod.rs | 110 + relays/bin-substrate/src/chains/polkadot.rs | 32 + relays/bin-substrate/src/chains/rialto.rs | 39 + .../src/chains/rialto_parachain.rs | 42 + relays/bin-substrate/src/chains/rococo.rs | 31 + relays/bin-substrate/src/chains/westend.rs | 29 + relays/bin-substrate/src/chains/wococo.rs | 31 + relays/bin-substrate/src/cli/bridge.rs | 87 + relays/bin-substrate/src/cli/chain_schema.rs | 370 + .../bin-substrate/src/cli/encode_message.rs | 151 + relays/bin-substrate/src/cli/init_bridge.rs | 221 + relays/bin-substrate/src/cli/mod.rs | 355 + .../src/cli/register_parachain.rs | 324 + relays/bin-substrate/src/cli/relay_headers.rs | 145 + .../src/cli/relay_headers_and_messages/mod.rs | 715 + .../parachain_to_parachain.rs | 275 + .../relay_to_parachain.rs | 248 + .../relay_to_relay.rs | 189 + .../bin-substrate/src/cli/relay_messages.rs | 133 + .../bin-substrate/src/cli/relay_parachains.rs | 143 + .../src/cli/resubmit_transactions.rs | 560 + relays/bin-substrate/src/cli/send_message.rs | 187 + relays/bin-substrate/src/main.rs | 29 + relays/client-bridge-hub-kusama/Cargo.toml | 28 + relays/client-bridge-hub-kusama/src/lib.rs | 162 + .../src/runtime_wrapper.rs | 74 + relays/client-bridge-hub-polkadot/Cargo.toml | 32 + relays/client-bridge-hub-polkadot/src/lib.rs | 160 + .../src/runtime_wrapper.rs | 119 + relays/client-bridge-hub-rococo/Cargo.toml | 28 + relays/client-bridge-hub-rococo/src/lib.rs | 162 + .../src/runtime_wrapper.rs | 69 + relays/client-bridge-hub-wococo/Cargo.toml | 32 + relays/client-bridge-hub-wococo/src/lib.rs | 160 + .../src/runtime_wrapper.rs | 115 + relays/client-kusama/Cargo.toml | 19 + relays/client-kusama/src/lib.rs | 60 + relays/client-millau/Cargo.toml | 26 + relays/client-millau/src/lib.rs | 188 + relays/client-polkadot/Cargo.toml | 19 + relays/client-polkadot/src/lib.rs | 60 + relays/client-rialto-parachain/Cargo.toml | 30 + .../src/codegen_runtime.rs | 10210 ++++++++++ relays/client-rialto-parachain/src/lib.rs | 138 + relays/client-rialto/Cargo.toml | 26 + relays/client-rialto/src/lib.rs | 184 + relays/client-rococo/Cargo.toml | 19 + relays/client-rococo/src/lib.rs | 58 + relays/client-substrate/Cargo.toml | 55 + relays/client-substrate/src/calls.rs | 59 + relays/client-substrate/src/chain.rs | 294 + relays/client-substrate/src/client.rs | 813 + relays/client-substrate/src/error.rs | 155 + relays/client-substrate/src/guard.rs | 373 + relays/client-substrate/src/lib.rs | 94 + .../src/metrics/float_storage_value.rs | 133 + relays/client-substrate/src/metrics/mod.rs | 21 + relays/client-substrate/src/rpc.rs | 170 + relays/client-substrate/src/sync_header.rs | 61 + relays/client-substrate/src/test_chain.rs | 117 + .../src/transaction_tracker.rs | 447 + relays/client-westend/Cargo.toml | 19 + relays/client-westend/src/lib.rs | 80 + relays/client-wococo/Cargo.toml | 18 + relays/client-wococo/src/lib.rs | 58 + relays/finality/Cargo.toml | 20 + relays/finality/README.md | 58 + relays/finality/src/finality_loop.rs | 761 + relays/finality/src/finality_loop_tests.rs | 598 + relays/finality/src/lib.rs | 61 + relays/finality/src/sync_loop_metrics.rs | 95 + relays/lib-substrate-relay/Cargo.toml | 59 + relays/lib-substrate-relay/src/error.rs | 63 + .../src/finality/engine.rs | 308 + .../src/finality/guards.rs | 48 + .../src/finality/initialize.rs | 163 + .../lib-substrate-relay/src/finality/mod.rs | 209 + .../src/finality/source.rs | 298 + .../src/finality/target.rs | 131 + relays/lib-substrate-relay/src/lib.rs | 145 + .../lib-substrate-relay/src/messages_lane.rs | 572 + .../src/messages_metrics.rs | 190 + .../src/messages_source.rs | 721 + .../src/messages_target.rs | 311 + .../src/on_demand/headers.rs | 511 + .../lib-substrate-relay/src/on_demand/mod.rs | 48 + .../src/on_demand/parachains.rs | 1033 ++ .../lib-substrate-relay/src/parachains/mod.rs | 108 + .../src/parachains/source.rs | 169 + .../src/parachains/target.rs | 148 + relays/messages/Cargo.toml | 23 + relays/messages/src/lib.rs | 37 + relays/messages/src/message_lane.rs | 71 + relays/messages/src/message_lane_loop.rs | 1261 ++ relays/messages/src/message_race_delivery.rs | 1162 ++ relays/messages/src/message_race_limits.rs | 206 + relays/messages/src/message_race_loop.rs | 816 + relays/messages/src/message_race_receiving.rs | 235 + relays/messages/src/message_race_strategy.rs | 596 + relays/messages/src/metrics.rs | 148 + relays/parachains/Cargo.toml | 23 + relays/parachains/README.md | 49 + relays/parachains/src/lib.rs | 32 + relays/parachains/src/parachains_loop.rs | 953 + .../parachains/src/parachains_loop_metrics.rs | 86 + relays/utils/Cargo.toml | 33 + relays/utils/src/error.rs | 46 + relays/utils/src/initialize.rs | 136 + relays/utils/src/lib.rs | 313 + relays/utils/src/metrics.rs | 192 + relays/utils/src/metrics/float_json_value.rs | 147 + relays/utils/src/metrics/global.rs | 118 + relays/utils/src/relay_loop.rs | 269 + rustfmt.toml | 24 + scripts/add_license.sh | 22 + scripts/build-containers.sh | 7 + scripts/ci-cache.sh | 19 + scripts/dump-logs.sh | 44 + scripts/license_header | 16 + scripts/send-message-from-millau-rialto.sh | 18 + scripts/send-message-from-rialto-millau.sh | 18 + scripts/update-weights-setup.sh | 33 + scripts/update-weights.sh | 55 + scripts/update_substrate.sh | 10 + scripts/verify-pallets-build.sh | 133 + tools/runtime-codegen/Cargo.lock | 4508 +++++ tools/runtime-codegen/Cargo.toml | 20 + tools/runtime-codegen/README.md | 11 + tools/runtime-codegen/src/main.rs | 173 + 413 files changed, 110220 insertions(+) create mode 100644 .config/lingua.dic create mode 100644 .config/spellcheck.toml create mode 100644 .dockerignore create mode 100644 .editorconfig create mode 100644 .github/dependabot.yml create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .maintain/millau-weight-template.hbs create mode 100644 CODEOWNERS create mode 100644 CODE_OF_CONDUCT.md create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 SECURITY.md create mode 100644 bin/.keep create mode 100644 bin/millau/node/Cargo.toml create mode 100644 bin/millau/node/build.rs create mode 100644 bin/millau/node/src/chain_spec.rs create mode 100644 bin/millau/node/src/cli.rs create mode 100644 bin/millau/node/src/command.rs create mode 100644 bin/millau/node/src/lib.rs create mode 100644 bin/millau/node/src/main.rs create mode 100644 bin/millau/node/src/service.rs create mode 100644 bin/millau/runtime/Cargo.toml create mode 100644 bin/millau/runtime/build.rs create mode 100644 bin/millau/runtime/src/lib.rs create mode 100644 bin/millau/runtime/src/rialto_messages.rs create mode 100644 bin/millau/runtime/src/rialto_parachain_messages.rs create mode 100644 bin/millau/runtime/src/xcm_config.rs create mode 100644 bin/rialto-parachain/node/Cargo.toml create mode 100644 bin/rialto-parachain/node/build.rs create mode 100644 bin/rialto-parachain/node/src/chain_spec.rs create mode 100644 bin/rialto-parachain/node/src/cli.rs create mode 100644 bin/rialto-parachain/node/src/command.rs create mode 100644 bin/rialto-parachain/node/src/lib.rs create mode 100644 bin/rialto-parachain/node/src/main.rs create mode 100644 bin/rialto-parachain/node/src/service.rs create mode 100644 bin/rialto-parachain/runtime/Cargo.toml create mode 100644 bin/rialto-parachain/runtime/build.rs create mode 100644 bin/rialto-parachain/runtime/src/lib.rs create mode 100644 bin/rialto-parachain/runtime/src/millau_messages.rs create mode 100644 bin/rialto/node/Cargo.toml create mode 100644 bin/rialto/node/build.rs create mode 100644 bin/rialto/node/src/chain_spec.rs create mode 100644 bin/rialto/node/src/cli.rs create mode 100644 bin/rialto/node/src/command.rs create mode 100644 bin/rialto/node/src/main.rs create mode 100644 bin/rialto/runtime/Cargo.toml create mode 100644 bin/rialto/runtime/build.rs create mode 100644 bin/rialto/runtime/src/lib.rs create mode 100644 bin/rialto/runtime/src/millau_messages.rs create mode 100644 bin/rialto/runtime/src/parachains.rs create mode 100644 bin/rialto/runtime/src/xcm_config.rs create mode 100644 bin/runtime-common/Cargo.toml create mode 100644 bin/runtime-common/src/integrity.rs create mode 100644 bin/runtime-common/src/lib.rs create mode 100644 bin/runtime-common/src/messages.rs create mode 100644 bin/runtime-common/src/messages_api.rs create mode 100644 bin/runtime-common/src/messages_benchmarking.rs create mode 100644 bin/runtime-common/src/messages_call_ext.rs create mode 100644 bin/runtime-common/src/messages_generation.rs create mode 100644 bin/runtime-common/src/messages_xcm_extension.rs create mode 100644 bin/runtime-common/src/mock.rs create mode 100644 bin/runtime-common/src/parachains_benchmarking.rs create mode 100644 bin/runtime-common/src/priority_calculator.rs create mode 100644 bin/runtime-common/src/refund_relayer_extension.rs create mode 100644 ci.Dockerfile create mode 100644 deny.toml create mode 100644 deployments/README.md create mode 100755 deployments/bridges/common/generate_messages.sh create mode 100644 deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-messages-dashboard.json create mode 100644 deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-messages-dashboard.json create mode 100644 deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json create mode 100644 deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml create mode 100644 deployments/bridges/rialto-millau/docker-compose.yml create mode 100755 deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh create mode 100755 deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh create mode 100755 deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh create mode 100755 deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh create mode 100755 deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh create mode 100755 deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh create mode 100644 deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-millau-to-rialto-parachain-messages-dashboard.json create mode 100644 deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-rialto-parachain-to-millau-messages-dashboard.json create mode 100644 deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json create mode 100644 deployments/bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml create mode 100644 deployments/bridges/rialto-parachain-millau/docker-compose.yml create mode 100755 deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh create mode 100755 deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh create mode 100755 deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh create mode 100755 deployments/bridges/rialto-parachain-millau/entrypoints/relay-millau-rialto-parachain-entrypoint.sh create mode 100644 deployments/bridges/rococo-wococo/README.md create mode 100644 deployments/bridges/rococo-wococo/dashboard/grafana/bridges-alerts.json create mode 100644 deployments/bridges/rococo-wococo/dashboard/grafana/relay-rococo-to-wococo-messages-dashboard.json create mode 100644 deployments/bridges/rococo-wococo/dashboard/grafana/relay-wococo-to-rococo-messages-dashboard.json create mode 100644 deployments/bridges/rococo-wococo/dashboard/grafana/rococo-wococo-maintenance-dashboard.json create mode 100644 deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-headers-dashboard.json create mode 100644 deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-parachains-dashboard.json create mode 100644 deployments/bridges/westend-millau/dashboard/prometheus/targets.yml create mode 100644 deployments/bridges/westend-millau/docker-compose.yml create mode 100755 deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh create mode 100755 deployments/bridges/westend-millau/entrypoints/relay-parachains-westend-to-millau-entrypoint.sh create mode 100755 deployments/local-scripts/bridge-entrypoint.sh create mode 100755 deployments/local-scripts/relay-messages-millau-to-rialto.sh create mode 100755 deployments/local-scripts/relay-messages-rialto-to-millau.sh create mode 100755 deployments/local-scripts/relay-millau-to-rialto.sh create mode 100755 deployments/local-scripts/relay-rialto-to-millau.sh create mode 100755 deployments/local-scripts/run-millau-node.sh create mode 100755 deployments/local-scripts/run-rialto-node.sh create mode 100755 deployments/local-scripts/run-westend-node.sh create mode 100644 deployments/monitoring/GrafanaMatrix.Dockerfile create mode 100644 deployments/monitoring/disabled.yml create mode 100644 deployments/monitoring/docker-compose.yml create mode 100644 deployments/monitoring/grafana-matrix/config.yml create mode 100644 deployments/monitoring/grafana/dashboards/nodes.json create mode 100644 deployments/monitoring/grafana/provisioning/dashboards/grafana-dashboard.yaml create mode 100644 deployments/monitoring/grafana/provisioning/datasources/grafana-datasource.yaml create mode 100644 deployments/monitoring/grafana/provisioning/notifiers/grafana-notifier.yaml create mode 100644 deployments/monitoring/prometheus/prometheus.yml create mode 100644 deployments/networks/dashboard/grafana/beefy-dashboard.json create mode 100644 deployments/networks/dashboard/prometheus/millau-targets.yml create mode 100644 deployments/networks/dashboard/prometheus/rialto-targets.yml create mode 100755 deployments/networks/entrypoints/rialto-chainspec-exporter-entrypoint.sh create mode 100755 deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh create mode 100644 deployments/networks/millau.yml create mode 100644 deployments/networks/rialto-parachain.yml create mode 100644 deployments/networks/rialto.yml create mode 100644 deployments/reverse-proxy/README.md create mode 100644 deployments/reverse-proxy/docker-compose.yml create mode 100755 deployments/run.sh create mode 100644 deployments/types-millau.json create mode 100644 deployments/types-rialto.json create mode 100755 deployments/types/build.sh create mode 100644 deployments/types/common.json create mode 100644 deployments/types/millau.json create mode 100644 deployments/types/rialto-millau.json create mode 100644 deployments/types/rialto.json create mode 100644 deployments/ui/README.md create mode 100644 deployments/ui/docker-compose.yml create mode 100644 docs/complex-relay.html create mode 100644 docs/dockerhub-bridges-common-relay.README.md create mode 100644 docs/dockerhub-millau-bridge-node.README.md create mode 100644 docs/dockerhub-rialto-bridge-node.README.md create mode 100644 docs/dockerhub-rialto-parachain-collator.README.md create mode 100644 docs/dockerhub-substrate-relay.README.md create mode 100644 docs/grandpa-finality-relay.html create mode 100644 docs/high-level-overview.md create mode 100644 docs/messages-relay.html create mode 100644 docs/parachains-finality-relay.html create mode 100644 docs/polkadot-kusama-bridge-overview.md create mode 100644 docs/polkadot-kusama-bridge.html create mode 100644 fuzz/storage-proof/Cargo.lock create mode 100644 fuzz/storage-proof/Cargo.toml create mode 100644 fuzz/storage-proof/README.md create mode 100644 fuzz/storage-proof/src/main.rs create mode 100644 modules/beefy/Cargo.toml create mode 100644 modules/beefy/src/lib.rs create mode 100644 modules/beefy/src/mock.rs create mode 100644 modules/beefy/src/mock_chain.rs create mode 100644 modules/beefy/src/utils.rs create mode 100644 modules/grandpa/Cargo.toml create mode 100644 modules/grandpa/README.md create mode 100644 modules/grandpa/src/benchmarking.rs create mode 100644 modules/grandpa/src/call_ext.rs create mode 100644 modules/grandpa/src/lib.rs create mode 100644 modules/grandpa/src/mock.rs create mode 100644 modules/grandpa/src/storage_types.rs create mode 100644 modules/grandpa/src/weights.rs create mode 100644 modules/messages/Cargo.toml create mode 100644 modules/messages/README.md create mode 100644 modules/messages/src/benchmarking.rs create mode 100644 modules/messages/src/inbound_lane.rs create mode 100644 modules/messages/src/lib.rs create mode 100644 modules/messages/src/mock.rs create mode 100644 modules/messages/src/outbound_lane.rs create mode 100644 modules/messages/src/weights.rs create mode 100644 modules/messages/src/weights_ext.rs create mode 100644 modules/parachains/Cargo.toml create mode 100644 modules/parachains/README.md create mode 100644 modules/parachains/src/benchmarking.rs create mode 100644 modules/parachains/src/call_ext.rs create mode 100644 modules/parachains/src/lib.rs create mode 100644 modules/parachains/src/mock.rs create mode 100644 modules/parachains/src/weights.rs create mode 100644 modules/parachains/src/weights_ext.rs create mode 100644 modules/relayers/Cargo.toml create mode 100644 modules/relayers/README.md create mode 100644 modules/relayers/src/benchmarking.rs create mode 100644 modules/relayers/src/lib.rs create mode 100644 modules/relayers/src/mock.rs create mode 100644 modules/relayers/src/payment_adapter.rs create mode 100644 modules/relayers/src/weights.rs create mode 100644 modules/shift-session-manager/Cargo.toml create mode 100644 modules/shift-session-manager/README.md create mode 100644 modules/shift-session-manager/src/lib.rs create mode 100644 primitives/beefy/Cargo.toml create mode 100644 primitives/beefy/src/lib.rs create mode 100644 primitives/chain-bridge-hub-cumulus/Cargo.toml create mode 100644 primitives/chain-bridge-hub-cumulus/src/lib.rs create mode 100644 primitives/chain-bridge-hub-kusama/Cargo.toml create mode 100644 primitives/chain-bridge-hub-kusama/src/lib.rs create mode 100644 primitives/chain-bridge-hub-polkadot/Cargo.toml create mode 100644 primitives/chain-bridge-hub-polkadot/src/lib.rs create mode 100644 primitives/chain-bridge-hub-rococo/Cargo.toml create mode 100644 primitives/chain-bridge-hub-rococo/src/lib.rs create mode 100644 primitives/chain-bridge-hub-wococo/Cargo.toml create mode 100644 primitives/chain-bridge-hub-wococo/src/lib.rs create mode 100644 primitives/chain-kusama/Cargo.toml create mode 100644 primitives/chain-kusama/src/lib.rs create mode 100644 primitives/chain-millau/Cargo.toml create mode 100644 primitives/chain-millau/src/lib.rs create mode 100644 primitives/chain-millau/src/millau_hash.rs create mode 100644 primitives/chain-polkadot/Cargo.toml create mode 100644 primitives/chain-polkadot/src/lib.rs create mode 100644 primitives/chain-rialto-parachain/Cargo.toml create mode 100644 primitives/chain-rialto-parachain/src/lib.rs create mode 100644 primitives/chain-rialto/Cargo.toml create mode 100644 primitives/chain-rialto/src/lib.rs create mode 100644 primitives/chain-rococo/Cargo.toml create mode 100644 primitives/chain-rococo/src/lib.rs create mode 100644 primitives/chain-westend/Cargo.toml create mode 100644 primitives/chain-westend/src/lib.rs create mode 100644 primitives/chain-wococo/Cargo.toml create mode 100644 primitives/chain-wococo/src/lib.rs create mode 100644 primitives/header-chain/Cargo.toml create mode 100644 primitives/header-chain/src/justification.rs create mode 100644 primitives/header-chain/src/lib.rs create mode 100644 primitives/header-chain/src/storage_keys.rs create mode 100644 primitives/header-chain/tests/implementation_match.rs create mode 100644 primitives/header-chain/tests/justification.rs create mode 100644 primitives/messages/Cargo.toml create mode 100644 primitives/messages/src/lib.rs create mode 100644 primitives/messages/src/source_chain.rs create mode 100644 primitives/messages/src/storage_keys.rs create mode 100644 primitives/messages/src/target_chain.rs create mode 100644 primitives/parachains/Cargo.toml create mode 100644 primitives/parachains/src/lib.rs create mode 100644 primitives/polkadot-core/Cargo.toml create mode 100644 primitives/polkadot-core/src/lib.rs create mode 100644 primitives/polkadot-core/src/parachains.rs create mode 100644 primitives/relayers/Cargo.toml create mode 100644 primitives/relayers/src/lib.rs create mode 100644 primitives/runtime/Cargo.toml create mode 100644 primitives/runtime/src/chain.rs create mode 100644 primitives/runtime/src/extensions.rs create mode 100644 primitives/runtime/src/lib.rs create mode 100644 primitives/runtime/src/messages.rs create mode 100644 primitives/runtime/src/storage_proof.rs create mode 100644 primitives/runtime/src/storage_types.rs create mode 100644 primitives/test-utils/Cargo.toml create mode 100644 primitives/test-utils/src/keyring.rs create mode 100644 primitives/test-utils/src/lib.rs create mode 100644 relays/bin-substrate/Cargo.toml create mode 100644 relays/bin-substrate/src/bridges/kusama_polkadot/bridge_hub_kusama_messages_to_bridge_hub_polkadot.rs create mode 100644 relays/bin-substrate/src/bridges/kusama_polkadot/bridge_hub_polkadot_messages_to_bridge_hub_kusama.rs create mode 100644 relays/bin-substrate/src/bridges/kusama_polkadot/kusama_headers_to_bridge_hub_polkadot.rs create mode 100644 relays/bin-substrate/src/bridges/kusama_polkadot/kusama_parachains_to_bridge_hub_polkadot.rs create mode 100644 relays/bin-substrate/src/bridges/kusama_polkadot/mod.rs create mode 100644 relays/bin-substrate/src/bridges/kusama_polkadot/polkadot_headers_to_bridge_hub_kusama.rs create mode 100644 relays/bin-substrate/src/bridges/kusama_polkadot/polkadot_parachains_to_bridge_hub_kusama.rs create mode 100644 relays/bin-substrate/src/bridges/mod.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_millau/millau_headers_to_rialto.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_millau/millau_messages_to_rialto.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_millau/mod.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_millau/rialto_headers_to_millau.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_millau/rialto_messages_to_millau.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_parachain_millau/millau_headers_to_rialto_parachain.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_parachain_millau/millau_messages_to_rialto_parachain.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_parachain_millau/mod.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_parachain_millau/rialto_parachain_messages_to_millau.rs create mode 100644 relays/bin-substrate/src/bridges/rialto_parachain_millau/rialto_parachains_to_millau.rs create mode 100644 relays/bin-substrate/src/bridges/rococo_wococo/bridge_hub_rococo_messages_to_bridge_hub_wococo.rs create mode 100644 relays/bin-substrate/src/bridges/rococo_wococo/bridge_hub_wococo_messages_to_bridge_hub_rococo.rs create mode 100644 relays/bin-substrate/src/bridges/rococo_wococo/mod.rs create mode 100644 relays/bin-substrate/src/bridges/rococo_wococo/rococo_headers_to_bridge_hub_wococo.rs create mode 100644 relays/bin-substrate/src/bridges/rococo_wococo/rococo_parachains_to_bridge_hub_wococo.rs create mode 100644 relays/bin-substrate/src/bridges/rococo_wococo/wococo_headers_to_bridge_hub_rococo.rs create mode 100644 relays/bin-substrate/src/bridges/rococo_wococo/wococo_parachains_to_bridge_hub_rococo.rs create mode 100644 relays/bin-substrate/src/bridges/westend_millau/mod.rs create mode 100644 relays/bin-substrate/src/bridges/westend_millau/westend_headers_to_millau.rs create mode 100644 relays/bin-substrate/src/bridges/westend_millau/westend_parachains_to_millau.rs create mode 100644 relays/bin-substrate/src/chains/kusama.rs create mode 100644 relays/bin-substrate/src/chains/millau.rs create mode 100644 relays/bin-substrate/src/chains/mod.rs create mode 100644 relays/bin-substrate/src/chains/polkadot.rs create mode 100644 relays/bin-substrate/src/chains/rialto.rs create mode 100644 relays/bin-substrate/src/chains/rialto_parachain.rs create mode 100644 relays/bin-substrate/src/chains/rococo.rs create mode 100644 relays/bin-substrate/src/chains/westend.rs create mode 100644 relays/bin-substrate/src/chains/wococo.rs create mode 100644 relays/bin-substrate/src/cli/bridge.rs create mode 100644 relays/bin-substrate/src/cli/chain_schema.rs create mode 100644 relays/bin-substrate/src/cli/encode_message.rs create mode 100644 relays/bin-substrate/src/cli/init_bridge.rs create mode 100644 relays/bin-substrate/src/cli/mod.rs create mode 100644 relays/bin-substrate/src/cli/register_parachain.rs create mode 100644 relays/bin-substrate/src/cli/relay_headers.rs create mode 100644 relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs create mode 100644 relays/bin-substrate/src/cli/relay_headers_and_messages/parachain_to_parachain.rs create mode 100644 relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs create mode 100644 relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs create mode 100644 relays/bin-substrate/src/cli/relay_messages.rs create mode 100644 relays/bin-substrate/src/cli/relay_parachains.rs create mode 100644 relays/bin-substrate/src/cli/resubmit_transactions.rs create mode 100644 relays/bin-substrate/src/cli/send_message.rs create mode 100644 relays/bin-substrate/src/main.rs create mode 100644 relays/client-bridge-hub-kusama/Cargo.toml create mode 100644 relays/client-bridge-hub-kusama/src/lib.rs create mode 100644 relays/client-bridge-hub-kusama/src/runtime_wrapper.rs create mode 100644 relays/client-bridge-hub-polkadot/Cargo.toml create mode 100644 relays/client-bridge-hub-polkadot/src/lib.rs create mode 100644 relays/client-bridge-hub-polkadot/src/runtime_wrapper.rs create mode 100644 relays/client-bridge-hub-rococo/Cargo.toml create mode 100644 relays/client-bridge-hub-rococo/src/lib.rs create mode 100644 relays/client-bridge-hub-rococo/src/runtime_wrapper.rs create mode 100644 relays/client-bridge-hub-wococo/Cargo.toml create mode 100644 relays/client-bridge-hub-wococo/src/lib.rs create mode 100644 relays/client-bridge-hub-wococo/src/runtime_wrapper.rs create mode 100644 relays/client-kusama/Cargo.toml create mode 100644 relays/client-kusama/src/lib.rs create mode 100644 relays/client-millau/Cargo.toml create mode 100644 relays/client-millau/src/lib.rs create mode 100644 relays/client-polkadot/Cargo.toml create mode 100644 relays/client-polkadot/src/lib.rs create mode 100644 relays/client-rialto-parachain/Cargo.toml create mode 100644 relays/client-rialto-parachain/src/codegen_runtime.rs create mode 100644 relays/client-rialto-parachain/src/lib.rs create mode 100644 relays/client-rialto/Cargo.toml create mode 100644 relays/client-rialto/src/lib.rs create mode 100644 relays/client-rococo/Cargo.toml create mode 100644 relays/client-rococo/src/lib.rs create mode 100644 relays/client-substrate/Cargo.toml create mode 100644 relays/client-substrate/src/calls.rs create mode 100644 relays/client-substrate/src/chain.rs create mode 100644 relays/client-substrate/src/client.rs create mode 100644 relays/client-substrate/src/error.rs create mode 100644 relays/client-substrate/src/guard.rs create mode 100644 relays/client-substrate/src/lib.rs create mode 100644 relays/client-substrate/src/metrics/float_storage_value.rs create mode 100644 relays/client-substrate/src/metrics/mod.rs create mode 100644 relays/client-substrate/src/rpc.rs create mode 100644 relays/client-substrate/src/sync_header.rs create mode 100644 relays/client-substrate/src/test_chain.rs create mode 100644 relays/client-substrate/src/transaction_tracker.rs create mode 100644 relays/client-westend/Cargo.toml create mode 100644 relays/client-westend/src/lib.rs create mode 100644 relays/client-wococo/Cargo.toml create mode 100644 relays/client-wococo/src/lib.rs create mode 100644 relays/finality/Cargo.toml create mode 100644 relays/finality/README.md create mode 100644 relays/finality/src/finality_loop.rs create mode 100644 relays/finality/src/finality_loop_tests.rs create mode 100644 relays/finality/src/lib.rs create mode 100644 relays/finality/src/sync_loop_metrics.rs create mode 100644 relays/lib-substrate-relay/Cargo.toml create mode 100644 relays/lib-substrate-relay/src/error.rs create mode 100644 relays/lib-substrate-relay/src/finality/engine.rs create mode 100644 relays/lib-substrate-relay/src/finality/guards.rs create mode 100644 relays/lib-substrate-relay/src/finality/initialize.rs create mode 100644 relays/lib-substrate-relay/src/finality/mod.rs create mode 100644 relays/lib-substrate-relay/src/finality/source.rs create mode 100644 relays/lib-substrate-relay/src/finality/target.rs create mode 100644 relays/lib-substrate-relay/src/lib.rs create mode 100644 relays/lib-substrate-relay/src/messages_lane.rs create mode 100644 relays/lib-substrate-relay/src/messages_metrics.rs create mode 100644 relays/lib-substrate-relay/src/messages_source.rs create mode 100644 relays/lib-substrate-relay/src/messages_target.rs create mode 100644 relays/lib-substrate-relay/src/on_demand/headers.rs create mode 100644 relays/lib-substrate-relay/src/on_demand/mod.rs create mode 100644 relays/lib-substrate-relay/src/on_demand/parachains.rs create mode 100644 relays/lib-substrate-relay/src/parachains/mod.rs create mode 100644 relays/lib-substrate-relay/src/parachains/source.rs create mode 100644 relays/lib-substrate-relay/src/parachains/target.rs create mode 100644 relays/messages/Cargo.toml create mode 100644 relays/messages/src/lib.rs create mode 100644 relays/messages/src/message_lane.rs create mode 100644 relays/messages/src/message_lane_loop.rs create mode 100644 relays/messages/src/message_race_delivery.rs create mode 100644 relays/messages/src/message_race_limits.rs create mode 100644 relays/messages/src/message_race_loop.rs create mode 100644 relays/messages/src/message_race_receiving.rs create mode 100644 relays/messages/src/message_race_strategy.rs create mode 100644 relays/messages/src/metrics.rs create mode 100644 relays/parachains/Cargo.toml create mode 100644 relays/parachains/README.md create mode 100644 relays/parachains/src/lib.rs create mode 100644 relays/parachains/src/parachains_loop.rs create mode 100644 relays/parachains/src/parachains_loop_metrics.rs create mode 100644 relays/utils/Cargo.toml create mode 100644 relays/utils/src/error.rs create mode 100644 relays/utils/src/initialize.rs create mode 100644 relays/utils/src/lib.rs create mode 100644 relays/utils/src/metrics.rs create mode 100644 relays/utils/src/metrics/float_json_value.rs create mode 100644 relays/utils/src/metrics/global.rs create mode 100644 relays/utils/src/relay_loop.rs create mode 100644 rustfmt.toml create mode 100755 scripts/add_license.sh create mode 100755 scripts/build-containers.sh create mode 100755 scripts/ci-cache.sh create mode 100755 scripts/dump-logs.sh create mode 100644 scripts/license_header create mode 100755 scripts/send-message-from-millau-rialto.sh create mode 100755 scripts/send-message-from-rialto-millau.sh create mode 100644 scripts/update-weights-setup.sh create mode 100755 scripts/update-weights.sh create mode 100755 scripts/update_substrate.sh create mode 100755 scripts/verify-pallets-build.sh create mode 100644 tools/runtime-codegen/Cargo.lock create mode 100644 tools/runtime-codegen/Cargo.toml create mode 100644 tools/runtime-codegen/README.md create mode 100644 tools/runtime-codegen/src/main.rs diff --git a/.config/lingua.dic b/.config/lingua.dic new file mode 100644 index 00000000000..9b622aad77d --- /dev/null +++ b/.config/lingua.dic @@ -0,0 +1,244 @@ +90 + +&& +1KB +1MB +5MB += +API/SM +APIs +AccountId/MS +Apache-2.0/M +Autogenerated +BFT/M +BTC/S +Best/MS +BlockId +BlockNumber +BridgeStorage +BridgeHub +BridgeHubRococo +BridgeHubWococo +BridgeHubKusama +BridgeHubPolkadot +CLI/MS +Chain1 +Chain2 +ChainSpec +ChainTime +DOT/S +ERC-20 +Ethereum +FN +FinalizationError +GPL/M +GPLv3/M +GiB/S +Handler/MS +Hasher +HeaderA +HeaderId +InitiateChange +Instance1 +Instance2 +Instance42 +KSM/S +KYC/M +KeyPair +Kovan +Lane1 +Lane2 +Lane3 +LaneId +MIN_SIZE +MIT/M +MMR +MaxUnrewardedRelayerEntriesAtInboundLane +MaybeExtra +MaybeOrphan +Merklized +MessageNonce +MessageNonces +MessagePayload +MetricsParams +Millau/MS +OldHeader +OutboundMessages +PoA +PoV/MS +Pre +RLP +RPC/MS +Rialto/MS +RialtoParachain/MS +Relayer/MS +Runtime1 +Runtime2 +SIZE_FACTOR +SS58 +SS58Prefix +STALL_SYNC_TIMEOUT +SURI +ServiceFactory/MS +SignedExtension +Stringified +Submitter1 +S|N +TCP +ThisChain +TODO +U256 +Unparsed +Vec +WND/S +Westend/MS +Wococo/MS +XCM/S +XCMP/M +annualised/MS +api/SM +aren +arg +args +async +auth +auths/SM +backoff +benchmarking/MS +best_substrate_header +bitfield/MS +blake2/MS +blockchain/MS +borked +chain_getBlock +choosen +config/MS +crypto/MS +customizable/B +debian/M +decodable/MS +delivery_and_dispatch_fee +dev +dispatchable +dispatchables +doesn +ed25519 +enum/MS +entrypoint/MS +ethereum/MS +externality/MS +extrinsic/MS +extrinsics +fedora/M +functor +fuzzer +hasher +hardcoded +https +implementers +include/BG +inherent/MS +initialize/RG +instantiate/B +intrinsic/MS +invariant/MS +invariants +io +isn +isolate/BG +js +jsonrpsee +keccak +keccak256/M +keyring +keystore/MS +kusama/S +lane +malus +max_value +merkle/MS +metadata +millau +misbehavior/SM +misbehaviors +multivalidator/SM +natively +no_std +nonces +number +ok +oneshot/MS +others' +pallet_bridge_grandpa +pallet_bridge_messages +pallet_message_lane +parablock/MS +parachain/MS +param/MS +parameterize/D +plancks +polkadot/MS +pov-block/MS +precommit +promethius +promethius' +provisioner/MS +probabilistically +prune_depth +prune_end +receival +reconnection +redhat/M +repo/MS +runtime/MS +rustc/MS +relayer/MS +shouldn +source_at_target +source_latest_confirmed +source_latest_generated +sp_consensus_grandpa +spawner +sr25519 +src +stringified +struct/MS +submitters/MS +subsystem/MS +subsystems' +subcommand/MS +synchronizer +target_at_source +target_latest_confirmed +target_latest_received +taskmanager/MS +teleport/RG +teleportation/SM +teleporter/SM +teleporters +testnet/MS +timeframe +tokio +timestamp +trie/MS +trustless/Y +tuple +u32 +ubuntu/M +undeliverable +unfinalized +union/MSG +unpruned +unservable/B +unsynced +updatable +validator/SM +ve +vec +verifier +w3f/MS +wakeup +wasm/M +websocket +x2 +~ diff --git a/.config/spellcheck.toml b/.config/spellcheck.toml new file mode 100644 index 00000000000..e061c29ac22 --- /dev/null +++ b/.config/spellcheck.toml @@ -0,0 +1,13 @@ +[hunspell] +lang = "en_US" +search_dirs = ["."] +extra_dictionaries = ["lingua.dic"] +skip_os_lookups = true +use_builtin = true + +[hunspell.quirks] +# `Type`'s +# 5x +transform_regex = ["^'([^\\s])'$", "^[0-9]+(?:\\.[0-9]*)?x$", "^'s$", "^\\+$", "[><+-]"] +allow_concatenation = true +allow_dashes = true diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000000..f4ceea78560 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +**/target/ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..e2375881ea0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +root = true +[*] +indent_style=tab +indent_size=tab +tab_width=4 +end_of_line=lf +charset=utf-8 +trim_trailing_whitespace=true +max_line_length=100 +insert_final_newline=true + +[*.{yml,md,yaml,sh}] +indent_style=space +indent_size=2 +tab_width=8 +end_of_line=lf + +[*.md] +max_line_length=80 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000000..c0c8ea64802 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,62 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: weekly + time: "03:00" + timezone: Europe/Berlin + open-pull-requests-limit: 20 + ignore: + # Substrate (+ Polkadot/Cumulus pallets) dependencies + - dependency-name: beefy-* + versions: + - ">= 0" + - dependency-name: frame-* + versions: + - ">= 0" + - dependency-name: fork-tree + versions: + - ">= 0" + - dependency-name: mmr-* + versions: + - ">= 0" + - dependency-name: node-inspect + versions: + - ">= 0" + - dependency-name: pallet-* + versions: + - ">= 0" + - dependency-name: sc-* + versions: + - ">= 0" + - dependency-name: sp-* + versions: + - ">= 0" + - dependency-name: substrate-* + versions: + - ">= 0" + - dependency-name: try-runtime-cli + versions: + - ">= 0" + - dependency-name: binary-merkle-tree + versions: + - ">= 0" + # Polkadot dependencies + - dependency-name: kusama-* + versions: + - ">= 0" + - dependency-name: polkadot-* + versions: + - ">= 0" + - dependency-name: xcm* + versions: + - ">= 0" + # Cumulus dependencies + - dependency-name: cumulus-* + versions: + - ">= 0" + - dependency-name: parachain-info + versions: + - ">= 0" + rebase-strategy: disabled diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..5d10cfa41a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +**/target/ +**/.env +**/.env2 +**/rust-toolchain +hfuzz_target +hfuzz_workspace +**/Cargo.lock + +**/*.rs.bk + +*.o +*.so +*.rlib +*.dll +.gdb_history + +*.exe + +.DS_Store + +.cargo +.idea +.vscode +*.iml +*.swp +*.swo diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000000..eb88001b50c --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,412 @@ +stages: + - lint + - check + - test + - build + - publish + - publish-docker-description + - deploy + +variables: + GIT_STRATEGY: fetch + GIT_DEPTH: 100 + CARGO_INCREMENTAL: 0 + ARCH: "x86_64" + CI_IMAGE: "paritytech/bridges-ci:production" + BUILDAH_IMAGE: "quay.io/buildah/stable:v1.27" + RUST_BACKTRACE: full + +default: + cache: {} + interruptible: true + retry: + max: 2 + when: + - runner_system_failure + - unknown_failure + - api_failure + +.collect-artifacts: &collect-artifacts + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: on_success + expire_in: 7 days + paths: + - artifacts/ + +.kubernetes-build: &kubernetes-build + tags: + - kubernetes-parity-build + +.docker-env: &docker-env + image: "${CI_IMAGE}" + before_script: + - rustup show + - cargo --version + - rustup +nightly show + - cargo +nightly --version + tags: + - linux-docker-vm-c2 + +.test-refs: &test-refs + rules: + # FIXME: This is the cause why pipelines wouldn't start. The problem might be in our custom + # mirroring. This should be investigated further, but for now let's have the working + # pipeline. + # - if: $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH + # changes: + # - '**.md' + # - diagrams/* + # - docs/* + # when: never + - if: $CI_PIPELINE_SOURCE == "pipeline" + - 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 + +.build-refs: &build-refs + rules: + # won't run on the CI image update pipeline + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]{4}-[0-9]{2}-[0-9]{2}.*$/ # i.e. v2021-09-27, v2021-09-27-1 + # there are two types of nightly pipelines: + # 1. this one is triggered by the schedule with $PIPELINE == "nightly", it's for releasing. + # this job runs only on nightly pipeline with the mentioned variable, against `master` branch + - if: $CI_PIPELINE_SOURCE == "schedule" && $PIPELINE == "nightly" + +.deploy-refs: &deploy-refs + rules: + - if: $CI_PIPELINE_SOURCE == "pipeline" + when: never + - if: $SCHEDULED_JOB + when: never + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]+\.[0-9]+.*$/ # i.e. v1.0, v2.1rc1 + when: manual + - if: $CI_COMMIT_REF_NAME =~ /^v[0-9]{4}-[0-9]{2}-[0-9]{2}.*$/ # i.e. v2021-09-27, v2021-09-27-1 + when: manual + +.nightly-test: &nightly-test + rules: + # 2. another is triggered by scripts repo $CI_PIPELINE_SOURCE == "pipeline" it's for the CI image + # update, it also runs all the nightly checks. + - if: $CI_PIPELINE_SOURCE == "pipeline" + +#### stage: lint + +clippy-nightly: + stage: lint + <<: *docker-env + <<: *test-refs + variables: + RUSTFLAGS: "-D warnings" + script: + # clippy currently is raising `derive-partial-eq-without-eq` warning even if `Eq` is actually derived + - SKIP_WASM_BUILD=1 cargo +nightly clippy --all-targets -- -A clippy::redundant_closure -A clippy::derive-partial-eq-without-eq -A clippy::or_fun_call + +fmt: + stage: lint + <<: *docker-env + <<: *test-refs + script: + - cargo +nightly fmt --all -- --check + +spellcheck: + stage: lint + <<: *docker-env + <<: *test-refs + script: + - cargo spellcheck check --cfg=.config/spellcheck.toml --checkers hunspell -m 1 $(find . -type f -name '*.rs' ! -path "./target/*" ! -name 'codegen_runtime.rs' ! -name 'weights.rs') + +#### stage: check + +check: + stage: check + <<: *docker-env + <<: *test-refs + script: &check-script + - SKIP_WASM_BUILD=1 time cargo check --locked --verbose --workspace + # Check Rialto benchmarks runtime + - SKIP_WASM_BUILD=1 time cargo check -p rialto-runtime --locked --features runtime-benchmarks --verbose + # Check Millau benchmarks runtime + - SKIP_WASM_BUILD=1 time cargo check -p millau-runtime --locked --features runtime-benchmarks --verbose + +check-nightly: + stage: check + <<: *docker-env + <<: *nightly-test + script: + - rustup default nightly + - *check-script + +#### stage: test + +test: + stage: test + <<: *docker-env + <<: *test-refs +# variables: +# RUSTFLAGS: "-D warnings" + script: &test-script + - time cargo fetch + # Enable this, when you see: "`cargo metadata` can not fail on project `Cargo.toml`" + #- time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"polkadot-runtime\").manifest_path"` + #- time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"kusama-runtime\").manifest_path"` + - CARGO_NET_OFFLINE=true SKIP_WASM_BUILD=1 time cargo test --verbose --workspace --features runtime-benchmarks + +test-nightly: + stage: test + <<: *docker-env + <<: *nightly-test + script: + - rustup default nightly + - *test-script + +deny: + stage: test + <<: *docker-env + <<: *nightly-test + <<: *collect-artifacts + script: + - cargo deny check advisories --hide-inclusion-graph + - cargo deny check bans sources --hide-inclusion-graph + after_script: + - mkdir -p ./artifacts + - echo "___Complete logs can be found in the artifacts___" + - cargo deny check advisories 2> advisories.log + - cargo deny check bans sources 2> bans_sources.log + # this job is allowed to fail, only licenses check is important + allow_failure: true + +deny-licenses: + stage: test + <<: *docker-env + <<: *test-refs + <<: *collect-artifacts + script: + - cargo deny check licenses --hide-inclusion-graph + after_script: + - mkdir -p ./artifacts + - echo "___Complete logs can be found in the artifacts___" + - cargo deny check licenses 2> licenses.log + +benchmarks-test: + stage: test + <<: *docker-env + <<: *nightly-test + script: + - time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet --chain=dev --steps=2 --repeat=1 --pallet=RialtoMessages --extrinsic=* --execution=wasm --wasm-execution=Compiled --heap-pages=4096 + - time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet --chain=dev --steps=2 --repeat=1 --pallet=RialtoParachainMessages --extrinsic=* --execution=wasm --wasm-execution=Compiled --heap-pages=4096 + - time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet --chain=dev --steps=2 --repeat=1 --pallet=pallet_bridge_grandpa --extrinsic=* --execution=wasm --wasm-execution=Compiled --heap-pages=4096 + - time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet --chain=dev --steps=2 --repeat=1 --pallet=pallet_bridge_parachains --extrinsic=* --execution=wasm --wasm-execution=Compiled --heap-pages=4096 + - time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet --chain=dev --steps=2 --repeat=1 --pallet=pallet_bridge_relayers --extrinsic=* --execution=wasm --wasm-execution=Compiled --heap-pages=4096 + # we may live with failing benchmarks, it is just a signal for us + allow_failure: true + +check-rustdoc: + stage: test + <<: *docker-env + <<: *test-refs + variables: + SKIP_WASM_BUILD: 1 + RUSTDOCFLAGS: "-Dwarnings" + script: + - time cargo +nightly doc --workspace --verbose --no-deps --all-features --exclude relay-rialto-parachain-client + +partial-repo-pallets-build-test: + stage: test + <<: *docker-env + <<: *nightly-test + script: + - ./scripts/verify-pallets-build.sh --no-revert + # we may live with failing partial repo build, it is just a signal for us + allow_failure: true + +#### stage: build + +build: + stage: build + <<: *docker-env + <<: *build-refs + <<: *collect-artifacts + # master + script: &build-script + - time cargo fetch + # Enable this, when you see: "`cargo metadata` can not fail on project `Cargo.toml`" + #- time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"polkadot-runtime\").manifest_path"` + #- time cargo fetch --manifest-path=`cargo metadata --format-version=1 | jq --compact-output --raw-output ".packages[] | select(.name == \"kusama-runtime\").manifest_path"` + - CARGO_NET_OFFLINE=true time cargo build --release --verbose --workspace + after_script: + # Prepare artifacts + - mkdir -p ./artifacts + - strip ./target/release/rialto-bridge-node + - mv -v ./target/release/rialto-bridge-node ./artifacts/ + - strip ./target/release/rialto-parachain-collator + - mv -v ./target/release/rialto-parachain-collator ./artifacts/ + - strip ./target/release/millau-bridge-node + - mv -v ./target/release/millau-bridge-node ./artifacts/ + - strip ./target/release/substrate-relay + - mv -v ./target/release/substrate-relay ./artifacts/ + - mv -v ./deployments/local-scripts/bridge-entrypoint.sh ./artifacts/ + - mv -v ./ci.Dockerfile ./artifacts/ + +build-nightly: + stage: build + <<: *docker-env + <<: *collect-artifacts + <<: *nightly-test + script: + - rustup default nightly + - *build-script + +#### stage: publish + +.build-push-image: &build-push-image + <<: *kubernetes-build + image: $BUILDAH_IMAGE + <<: *build-refs + variables: &image-variables + GIT_STRATEGY: none + DOCKERFILE: ci.Dockerfile + BRIDGES_PROJECT: "${CI_JOB_NAME}" + DOCKER_IMAGE_NAME: "${CI_JOB_NAME}" + IMAGE_NAME: docker.io/paritytech/$DOCKER_IMAGE_NAME + needs: + - job: build + artifacts: true + before_script: + - echo "Starting docker image build/push with name '${IMAGE_NAME}' for '${BRIDGES_PROJECT}' with Dockerfile = '${DOCKERFILE}'" + - if [[ "${CI_COMMIT_TAG}" ]]; then + VERSION=${CI_COMMIT_TAG}; + elif [[ "${CI_COMMIT_REF_NAME}" ]]; then + VERSION=$(echo ${CI_COMMIT_REF_NAME} | sed -r 's#/+#-#g'); + fi + # When building from version tags (v1.0, v2.1rc1, ...) we'll use "production" to tag + # docker image. In all other cases, it'll be "latest". + - if [[ $CI_COMMIT_REF_NAME =~ ^v[0-9]+\.[0-9]+.*$ ]]; then + FLOATING_TAG="production"; + else + FLOATING_TAG="latest"; + fi + - echo "Effective tags = ${VERSION} sha-${CI_COMMIT_SHORT_SHA} ${FLOATING_TAG}" + - echo "Full docker image name = ${IMAGE_NAME}" + script: + - test "${Docker_Hub_User_Parity}" -a "${Docker_Hub_Pass_Parity}" || + ( echo "no docker credentials provided"; exit 1 ) + - cd ./artifacts + - buildah bud + --format=docker + --build-arg VCS_REF="${CI_COMMIT_SHORT_SHA}" + --build-arg BUILD_DATE="$(date +%d-%m-%Y)" + --build-arg PROJECT="${BRIDGES_PROJECT}" + --build-arg VERSION="${VERSION}" + --tag "${IMAGE_NAME}:${VERSION}" + --tag "${IMAGE_NAME}:sha-${CI_COMMIT_SHORT_SHA}" + --tag "${IMAGE_NAME}:${FLOATING_TAG}" + --file "${DOCKERFILE}" . + # The job will success only on the protected branch + - echo "${Docker_Hub_Pass_Parity}" | + buildah login --username "${Docker_Hub_User_Parity}" --password-stdin docker.io + - buildah info + - buildah push --format=v2s2 "${IMAGE_NAME}:${VERSION}" + - buildah push --format=v2s2 "${IMAGE_NAME}:sha-${CI_COMMIT_SHORT_SHA}" + - buildah push --format=v2s2 "${IMAGE_NAME}:${FLOATING_TAG}" + after_script: + - env REGISTRY_AUTH_FILE= buildah logout --all + +rialto-bridge-node: + stage: publish + <<: *build-push-image + +rialto-parachain-collator: + stage: publish + <<: *build-push-image + +millau-bridge-node: + stage: publish + <<: *build-push-image + +substrate-relay: + stage: publish + <<: *build-push-image + +bridges-common-relay: + stage: publish + <<: *build-push-image + variables: + <<: *image-variables + BRIDGES_PROJECT: substrate-relay + DOCKER_IMAGE_NAME: bridges-common-relay + +# Publish Docker images description to hub.docker.com + +.publish-docker-image-description: &publish-docker-image-description + stage: publish-docker-description + image: paritytech/dockerhub-description + variables: + DOCKER_USERNAME: $Docker_Hub_User_Parity + DOCKER_PASSWORD: $Docker_Hub_Pass_Parity + README_FILEPATH: $CI_PROJECT_DIR/docs/${CI_JOB_NAME}.README.md + rules: + - if: $CI_COMMIT_REF_NAME == "master" + changes: + - docs/${CI_JOB_NAME}.README.md + script: + - export DOCKERHUB_REPOSITORY="paritytech/${CI_JOB_NAME:10}" + - cd / && sh entrypoint.sh + tags: + - kubernetes-parity-build + +dockerhub-rialto-bridge-node: + extends: .publish-docker-image-description + variables: + SHORT_DESCRIPTION: "rialto-bridge-node" + +dockerhub-rialto-parachain-collator: + extends: .publish-docker-image-description + variables: + SHORT_DESCRIPTION: "rialto-parachain-collator" + +dockerhub-millau-bridge-node: + extends: .publish-docker-image-description + variables: + SHORT_DESCRIPTION: "millau-bridge-node" + +dockerhub-substrate-relay: + extends: .publish-docker-image-description + variables: + SHORT_DESCRIPTION: "substrate-relay" + +dockerhub-bridges-common-relay: + extends: .publish-docker-image-description + variables: + SHORT_DESCRIPTION: "bridges-common-relay" + +# FIXME: publish binaries + +deploy-bridges-common-relay-testnet: + <<: *deploy-refs + <<: *kubernetes-build + needs: + - job: bridges-common-relay + stage: deploy + image: argoproj/argocd:v2.5.5 + environment: parity-testnet + variables: + ARGOCD_OPTS: --grpc-web --grpc-web-root-path /parity-testnet + APP: bridges-common-relay + before_script: + - if [[ "${CI_COMMIT_TAG}" ]]; then + VERSION=${CI_COMMIT_TAG}; + elif [[ "${CI_COMMIT_REF_NAME}" ]]; then + VERSION=$(echo ${CI_COMMIT_REF_NAME} | sed -r 's#/+#-#g'); + fi + script: + - echo "Starting deploy version=${VERSION}" + - argocd app list + - argocd app set $APP --helm-set bridges-common-relay.image.tag=$VERSION + - argocd app sync $APP + - argocd app wait $APP --timeout 120 diff --git a/.maintain/millau-weight-template.hbs b/.maintain/millau-weight-template.hbs new file mode 100644 index 00000000000..ff70b55aa2c --- /dev/null +++ b/.maintain/millau-weight-template.hbs @@ -0,0 +1,138 @@ +// Copyright 2019-2021 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 . + +//! Autogenerated weights for {{pallet}} +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} +//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}` +//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` +//! EXECUTION: {{cmd.execution}}, WASM-EXECUTION: {{cmd.wasm_execution}}, CHAIN: {{cmd.chain}}, DB CACHE: {{cmd.db_cache}} + +// Executed Command: +{{#each args as |arg|}} +// {{arg}} +{{/each}} + +#![allow(clippy::all)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for {{pallet}}. +pub trait WeightInfo { + {{#each benchmarks as |benchmark|}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{c.name}}: u32, {{/each~}} + ) -> Weight; + {{/each}} +} + +/// Weights for `{{pallet}}` 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 { + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + /// {{comment}} + /// + {{/each}} + {{#each benchmark.component_ranges as |range|}} + /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. + /// + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}}_u64)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(T::DbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}}_u64)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} + } + {{/each}} +} + +// For backwards compatibility and tests +impl WeightInfo for () { + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + /// {{comment}} + /// + {{/each}} + {{#each benchmark.component_ranges as |range|}} + /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. + /// + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}} nanoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}}_u64)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(RocksDbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}}_u64)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} + } + {{/each}} +} diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 00000000000..3941ba8451a --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,21 @@ +# 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_org/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 +/.gitlab-ci.yml @paritytech/ci diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..70541fb72fa --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,80 @@ +# 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, sex characteristics, gender identity +and expression, level of experience, education, socio-economic status, 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 admin@parity.io. All complaints will be reviewed and investigated and will +result in a response that is deemed necessary and 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://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000000..f4b78e93bca --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,15431 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli 0.26.2", +] + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli 0.27.2", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array 0.14.6", + "rand_core 0.6.4", +] + +[[package]] +name = "aead" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8" +dependencies = [ + "crypto-common", + "generic-array 0.14.6", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher 0.2.5", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.3.0", + "cpufeatures", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aes" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.4.4", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" +dependencies = [ + "aead 0.4.3", + "aes 0.7.5", + "cipher 0.3.0", + "ctr 0.8.0", + "ghash 0.4.4", + "subtle", +] + +[[package]] +name = "aes-gcm" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e1366e0c69c9f927b1fa5ce2c7bf9eafc8f9268c0b9800729e8b267612447c" +dependencies = [ + "aead 0.5.1", + "aes 0.8.2", + "cipher 0.4.4", + "ctr 0.9.2", + "ghash 0.5.0", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher 0.2.5", + "opaque-debug 0.3.0", +] + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.8", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if 1.0.0", + "getrandom 0.2.8", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "always-assert" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf688625d06217d5b1bb0ea9d9c44a1635fd0ee3534466388d18203174f4d11" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anstream" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arbitrary" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" + +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + +[[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.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22f72e9d6fac4bc80778ea470b20197b88d28c292bb7d60c3fb099280003cd19" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "asn1-rs" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ff05a702273012438132f449575dbc804e27b2f3cbe3069aa237d26c98fa33" +dependencies = [ + "asn1-rs-derive 0.1.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive 0.4.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8b7511298d5b7784b40b092d9e9dcd3a627a5707e4b5e507931ab0d44eeebf" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "asn1_der" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22d1f4b888c298a027c99dc9048015fac177587de20fc30232a057dfbe24a21" + +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if 1.0.0", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix 0.37.3", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite 0.2.9", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" + +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "asynchronous-codec" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06a0daa378f5fd10634e44b0a29b2a87b890657658e072a30d6f26e57ddee182" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite 0.2.9", +] + +[[package]] +name = "atomic-waker" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debc29dde2e69f9e47506b525f639ed42300fc014a3e007832592448fa8e4599" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "getrandom 0.2.8", + "instant", + "rand 0.8.5", +] + +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line 0.19.0", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object 0.30.3", + "rustc-demangle", +] + +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +dependencies = [ + "serde", +] + +[[package]] +name = "binary-merkle-tree" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "hash-db", + "log", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.64.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2 1.0.56", + "quote 1.0.26", + "regex", + "rustc-hash", + "shlex", + "syn 1.0.109", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec 0.7.2", + "constant_time_eq", +] + +[[package]] +name = "blake2s_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637f448b9e61dfadbdcbae9a885fadee1f3eaffb1f8d3c1965d3ade8bdfd44f" +dependencies = [ + "arrayref", + "arrayvec 0.7.2", + "constant_time_eq", +] + +[[package]] +name = "blake3" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" +dependencies = [ + "arrayref", + "arrayvec 0.7.2", + "cc", + "cfg-if 1.0.0", + "constant_time_eq", + "digest 0.10.6", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "block-modes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" +dependencies = [ + "block-padding 0.2.1", + "cipher 0.2.5", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "blocking" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c67b173a56acffd6d2326fb7ab938ba0b00a71480e14902b2591c87bc5741e8" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", +] + +[[package]] +name = "bounded-collections" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370" +dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "bounded-vec" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68534a48cbf63a4b1323c433cf21238c9ec23711e0df13b08c33e5c2082663ce" +dependencies = [ + "thiserror", +] + +[[package]] +name = "bp-beefy" +version = "0.1.0" +dependencies = [ + "binary-merkle-tree", + "bp-runtime", + "frame-support", + "pallet-beefy-mmr", + "pallet-mmr", + "parity-scale-codec", + "scale-info", + "serde", + "sp-consensus-beefy", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-bridge-hub-cumulus" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "frame-system", + "polkadot-primitives", + "sp-api", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-bridge-hub-kusama" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-cumulus", + "bp-messages", + "bp-runtime", + "frame-support", + "sp-api", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-bridge-hub-polkadot" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-cumulus", + "bp-messages", + "bp-runtime", + "frame-support", + "sp-api", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-bridge-hub-rococo" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-cumulus", + "bp-messages", + "bp-runtime", + "frame-support", + "sp-api", + "sp-std 5.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-std 5.0.0", +] + +[[package]] +name = "bp-header-chain" +version = "0.1.0" +dependencies = [ + "bp-runtime", + "bp-test-utils", + "finality-grandpa", + "frame-support", + "hex", + "hex-literal 0.4.1", + "parity-scale-codec", + "scale-info", + "serde", + "sp-consensus-grandpa", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-kusama" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "sp-api", +] + +[[package]] +name = "bp-messages" +version = "0.1.0" +dependencies = [ + "bp-runtime", + "frame-support", + "hex", + "hex-literal 0.4.1", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-millau" +version = "0.1.0" +dependencies = [ + "bp-beefy", + "bp-header-chain", + "bp-messages", + "bp-runtime", + "fixed-hash", + "frame-support", + "frame-system", + "hash256-std-hasher", + "impl-codec", + "impl-serde", + "parity-util-mem", + "scale-info", + "serde", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-trie", +] + +[[package]] +name = "bp-parachains" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-polkadot" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "sp-api", +] + +[[package]] +name = "bp-polkadot-core" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-runtime", + "frame-support", + "frame-system", + "hex", + "parity-scale-codec", + "parity-util-mem", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-relayers" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-runtime", + "frame-support", + "hex", + "hex-literal 0.4.1", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-rialto" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-messages", + "bp-runtime", + "frame-support", + "frame-system", + "sp-api", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-rialto-parachain" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-cumulus", + "bp-messages", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "frame-system", + "sp-api", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-rococo" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "sp-api", +] + +[[package]] +name = "bp-runtime" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "hash-db", + "hex-literal 0.4.1", + "impl-trait-for-tuples", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std 5.0.0", + "sp-trie", + "trie-db", +] + +[[package]] +name = "bp-test-utils" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "ed25519-dalek", + "finality-grandpa", + "parity-scale-codec", + "sp-application-crypto", + "sp-consensus-grandpa", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "bp-westend" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-polkadot-core", + "bp-runtime", + "frame-support", + "sp-api", +] + +[[package]] +name = "bp-wococo" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-polkadot-core", + "bp-rococo", + "bp-runtime", + "frame-support", + "sp-api", +] + +[[package]] +name = "bridge-runtime-common" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-messages", + "bp-parachains", + "bp-polkadot-core", + "bp-relayers", + "bp-runtime", + "bp-test-utils", + "frame-support", + "frame-system", + "hash-db", + "log", + "pallet-balances", + "pallet-bridge-grandpa", + "pallet-bridge-messages", + "pallet-bridge-parachains", + "pallet-bridge-relayers", + "pallet-transaction-payment", + "pallet-utility", + "pallet-xcm", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-trie", + "static_assertions", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bstr" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "build-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdce191bf3fa4995ce948c8c83b4640a1745457a149e73c6db75b4ffe36aad5f" +dependencies = [ + "semver 0.6.0", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "camino" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.17", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "castaway" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "ccm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aca1a8fbc20b50ac9673ff014abfb2b5f4085ee1a850d408f14a159c5853ac7" +dependencies = [ + "aead 0.3.2", + "cipher 0.2.5", + "subtle", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-expr" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aacacf4d96c24b2ad6eb8ee6df040e4f27b0d0b39a5710c30091baa830485db" +dependencies = [ + "smallvec", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "chacha20" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.3.0", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "chacha20poly1305" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" +dependencies = [ + "aead 0.4.3", + "chacha20", + "cipher 0.3.0", + "poly1305", + "zeroize", +] + +[[package]] +name = "chrono" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time 0.1.45", + "wasm-bindgen", + "winapi", +] + +[[package]] +name = "cid" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ed9c8b2d17acb8110c46f1da5bf4a696d745e1474a16db0cd2b49cd0249bf2" +dependencies = [ + "core2", + "multibase", + "multihash 0.16.3", + "serde", + "unsigned-varint", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "ckb-merkle-mountain-range" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f061f97d64fd1822664bdfb722f7ae5469a97b77567390f7442be5b5dc82a5b" +dependencies = [ + "cfg-if 0.1.10", +] + +[[package]] +name = "ckb-merkle-mountain-range" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ccb671c5921be8a84686e6212ca184cb1d7c51cadcdbfcbd1cc3f042f5dfb8" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "clang-sys" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim 0.8.0", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clap" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b802d85aaf3a1cdb02b224ba472ebdea62014fccfcb269b95a4d76443b5ee5a" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14a1a858f532119338887a4b8e1af9c60de8249cd7bafd68036a489e261e37b6" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", + "strsim 0.10.0", +] + +[[package]] +name = "clap_derive" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +dependencies = [ + "heck 0.4.1", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "clap_lex" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" + +[[package]] +name = "coarsetime" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90d114103adbc625300f346d4d09dfb4ab1c4a8df6868435dd903392ecf4354" +dependencies = [ + "libc", + "once_cell", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "comfy-table" +version = "6.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d" +dependencies = [ + "strum", + "strum_macros", + "unicode-width", +] + +[[package]] +name = "concurrent-queue" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c278839b831783b70278b14df4d45e1beb1aad306c07bb796637de9a0e323e8e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + +[[package]] +name = "constant_time_eq" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "cpu-time" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e393a7668fe1fad3075085b86c781883000b4ede868f43627b34a87c8b7ded" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7379abaacee0f14abf3204a7606118f0465785252169d186337bcb75030815a" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9489fa336927df749631f1008007ced2871068544f40a202ce6d93fbf2366a7b" +dependencies = [ + "arrayvec 0.7.2", + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "cranelift-isle", + "gimli 0.26.2", + "hashbrown 0.12.3", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05bbb67da91ec721ed57cef2f7c5ef7728e1cd9bde9ffd3ef8601022e73e3239" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418ecb2f36032f6665dc1a5e2060a143dbab41d83b784882e97710e890a7a16d" + +[[package]] +name = "cranelift-entity" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b66bf9e916f57fbbd0f7703ec6286f4624866bf45000111627c70d272c8dda1" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649782a39ce99798dd6b4029e2bb318a2fbeaade1b4fa25330763c10c65bc358" + +[[package]] +name = "cranelift-native" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "937e021e089c51f9749d09e7ad1c4f255c2f8686cb8c3df63a34b3ec9921bc41" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d850cf6775477747c9dfda9ae23355dd70512ffebc70cf82b85a5b111ae668b5" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "crossbeam-utils", + "memoffset 0.8.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array 0.14.6", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" +dependencies = [ + "generic-array 0.14.6", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.6", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher 0.3.0", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + +[[package]] +name = "cumulus-client-cli" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "clap 4.2.2", + "parity-scale-codec", + "sc-chain-spec", + "sc-cli", + "sc-service", + "sp-core", + "sp-runtime", + "url", +] + +[[package]] +name = "cumulus-client-collator" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "cumulus-client-consensus-common", + "cumulus-client-network", + "cumulus-primitives-core", + "futures", + "parity-scale-codec", + "parking_lot 0.12.1", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-overseer", + "polkadot-primitives", + "sc-client-api", + "sp-api", + "sp-consensus", + "sp-core", + "sp-runtime", + "tracing", +] + +[[package]] +name = "cumulus-client-consensus-aura" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "async-trait", + "cumulus-client-consensus-common", + "cumulus-primitives-core", + "futures", + "parity-scale-codec", + "sc-client-api", + "sc-consensus", + "sc-consensus-aura", + "sc-consensus-slots", + "sc-telemetry", + "sp-api", + "sp-application-crypto", + "sp-block-builder", + "sp-blockchain", + "sp-consensus", + "sp-consensus-aura", + "sp-core", + "sp-inherents", + "sp-keystore", + "sp-runtime", + "substrate-prometheus-endpoint", + "tracing", +] + +[[package]] +name = "cumulus-client-consensus-common" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "async-trait", + "cumulus-client-pov-recovery", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "dyn-clone", + "futures", + "log", + "parity-scale-codec", + "polkadot-primitives", + "sc-client-api", + "sc-consensus", + "schnellru", + "sp-blockchain", + "sp-consensus", + "sp-runtime", + "sp-trie", + "tracing", +] + +[[package]] +name = "cumulus-client-network" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "async-trait", + "cumulus-relay-chain-interface", + "futures", + "futures-timer", + "parity-scale-codec", + "parking_lot 0.12.1", + "polkadot-node-primitives", + "polkadot-parachain", + "polkadot-primitives", + "sc-client-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "sp-state-machine", + "tracing", +] + +[[package]] +name = "cumulus-client-pov-recovery" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "futures", + "futures-timer", + "parity-scale-codec", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-overseer", + "polkadot-primitives", + "rand 0.8.5", + "sc-client-api", + "sc-consensus", + "sp-consensus", + "sp-maybe-compressed-blob", + "sp-runtime", + "tracing", +] + +[[package]] +name = "cumulus-client-service" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "cumulus-client-cli", + "cumulus-client-collator", + "cumulus-client-consensus-common", + "cumulus-client-network", + "cumulus-client-pov-recovery", + "cumulus-primitives-core", + "cumulus-relay-chain-inprocess-interface", + "cumulus-relay-chain-interface", + "cumulus-relay-chain-minimal-node", + "futures", + "polkadot-primitives", + "sc-client-api", + "sc-consensus", + "sc-network", + "sc-network-sync", + "sc-network-transactions", + "sc-rpc", + "sc-service", + "sc-sysinfo", + "sc-telemetry", + "sc-transaction-pool", + "sc-utils", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "sp-transaction-pool", +] + +[[package]] +name = "cumulus-pallet-aura-ext" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "frame-support", + "frame-system", + "pallet-aura", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-consensus-aura", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "cumulus-pallet-dmp-queue" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "xcm", +] + +[[package]] +name = "cumulus-pallet-parachain-system" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "bytes", + "cumulus-pallet-parachain-system-proc-macro", + "cumulus-primitives-core", + "cumulus-primitives-parachain-inherent", + "environmental", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "polkadot-parachain", + "scale-info", + "sp-core", + "sp-externalities", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std 5.0.0", + "sp-trie", + "sp-version", + "xcm", +] + +[[package]] +name = "cumulus-pallet-parachain-system-proc-macro" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "cumulus-pallet-xcm" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "xcm", +] + +[[package]] +name = "cumulus-pallet-xcmp-queue" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "polkadot-runtime-common", + "rand_chacha 0.3.1", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "xcm", + "xcm-executor", +] + +[[package]] +name = "cumulus-primitives-core" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain", + "polkadot-primitives", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std 5.0.0", + "sp-trie", + "xcm", +] + +[[package]] +name = "cumulus-primitives-parachain-inherent" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "cumulus-test-relay-sproof-builder", + "parity-scale-codec", + "sc-client-api", + "scale-info", + "sp-api", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-state-machine", + "sp-std 5.0.0", + "sp-storage", + "sp-trie", + "tracing", +] + +[[package]] +name = "cumulus-primitives-timestamp" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "cumulus-primitives-core", + "futures", + "parity-scale-codec", + "sp-inherents", + "sp-std 5.0.0", + "sp-timestamp", +] + +[[package]] +name = "cumulus-relay-chain-inprocess-interface" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "futures", + "futures-timer", + "polkadot-cli", + "polkadot-client", + "polkadot-service", + "sc-cli", + "sc-client-api", + "sc-sysinfo", + "sc-telemetry", + "sc-tracing", + "sp-api", + "sp-consensus", + "sp-core", + "sp-runtime", + "sp-state-machine", +] + +[[package]] +name = "cumulus-relay-chain-interface" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "futures", + "jsonrpsee-core", + "parity-scale-codec", + "polkadot-overseer", + "sc-client-api", + "sp-api", + "sp-blockchain", + "sp-state-machine", + "thiserror", +] + +[[package]] +name = "cumulus-relay-chain-minimal-node" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "array-bytes 6.0.0", + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "cumulus-relay-chain-rpc-interface", + "futures", + "lru 0.9.0", + "polkadot-availability-recovery", + "polkadot-collator-protocol", + "polkadot-core-primitives", + "polkadot-network-bridge", + "polkadot-node-collation-generation", + "polkadot-node-core-runtime-api", + "polkadot-node-network-protocol", + "polkadot-node-subsystem-util", + "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", + "tokio", + "tracing", +] + +[[package]] +name = "cumulus-relay-chain-rpc-interface" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "futures", + "futures-timer", + "jsonrpsee", + "lru 0.9.0", + "parity-scale-codec", + "polkadot-overseer", + "sc-client-api", + "sc-rpc-api", + "sc-service", + "serde", + "serde_json", + "sp-api", + "sp-authority-discovery", + "sp-consensus-babe", + "sp-core", + "sp-state-machine", + "sp-storage", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "cumulus-test-relay-sproof-builder" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "cumulus-primitives-core", + "parity-scale-codec", + "polkadot-primitives", + "sp-runtime", + "sp-state-machine", + "sp-std 5.0.0", +] + +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "winapi", +] + +[[package]] +name = "curl-sys" +version = "0.4.61+curl-8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d05c10f541ae6f3bc5b3d923c20001f47db7d5f0b2bc6ad16490133842db79" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "winapi", +] + +[[package]] +name = "curve25519-dalek" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" +dependencies = [ + "byteorder", + "digest 0.8.1", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +dependencies = [ + "cfg-if 1.0.0", + "fiat-crypto", + "packed_simd_2", + "platforms 3.0.2", + "subtle", + "zeroize", +] + +[[package]] +name = "cxx" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c00419335c41018365ddf7e4d5f1c12ee3659ddcf3e01974650ba1de73d038" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8307ad413a98fff033c8545ecf133e3257747b3bae935e7602aab8aa92d4ca" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2 1.0.56", + "quote 1.0.26", + "scratch", + "syn 2.0.14", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc52e2eb08915cb12596d29d55f0b5384f00d697a646dbd269b6ecb0fbd9d31" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.56", + "quote 1.0.26", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "data-encoding" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" + +[[package]] +name = "data-encoding-macro" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86927b7cd2fe88fa698b87404b287ab98d1a0063a34071d92e575b72d3029aca" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db" +dependencies = [ + "data-encoding", + "syn 1.0.109", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc906908ea6458456e5eaa160a9c08543ec3d1e6f71e2235cedd660cb65f9df0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe398ac75057914d7d07307bf67dc7f3f574a26783b4fc7805a20ffa9f506e82" +dependencies = [ + "asn1-rs 0.3.1", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs 0.5.2", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "derive-syn-parse" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79116f119dd1dba1abf1f3405f03b9b0e79a27a3883864bfebded8a3dc768cd" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +dependencies = [ + "darling", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2 1.0.56", + "quote 1.0.26", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "directories" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51c5d4ddabd36886dd3e1438cb358cdcb0d7c499cb99cb4ac2e38e18b5cb210" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dtoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d09067bfacaa79114679b279d7f5885b53295b1e2cfb4e79c8e4bd3d633169" + +[[package]] +name = "dyn-clonable" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +dependencies = [ + "dyn-clonable-impl", + "dyn-clone", +] + +[[package]] +name = "dyn-clonable-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1b0a1222f8072619e8a6b667a854020a03d363738303203c09468b3424a420a" +dependencies = [ + "der 0.7.1", + "elliptic-curve 0.13.2", + "rfc6979 0.4.0", + "signature 2.0.0", +] + +[[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-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", + "digest 0.10.6", + "ff 0.12.1", + "generic-array 0.14.6", + "group 0.12.1", + "hkdf", + "pem-rfc7468", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea5a92946e8614bb585254898bb7dd1ddad241ace60c52149e3765e34cc039d" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.1", + "digest 0.10.6", + "ff 0.13.0", + "generic-array 0.14.6", + "group 0.13.0", + "pkcs8 0.10.1", + "rand_core 0.6.4", + "sec1 0.7.1", + "subtle", + "zeroize", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "enum-as-inner" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" +dependencies = [ + "heck 0.4.1", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "enumflags2" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "enumn" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48016319042fb7c87b78d2993084a831793a897a5cd1a2a67cab9d1eeb4b7d76" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "environmental" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d6a0976c999d473fe89ad888d5a284e55366d9dc9038b1ba2aa15128c4afa0" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "exit-future" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e43f2f1833d64e33f15592464d6fdd70f349dda7b1a53088eb83cd94014008c5" +dependencies = [ + "futures", +] + +[[package]] +name = "expander" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a718c0675c555c5f976fff4ea9e2c150fa06cefa201cadef87cfbf9324075881" +dependencies = [ + "blake3", + "fs-err", + "proc-macro2 1.0.56", + "quote 1.0.26", +] + +[[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 1.0.56", + "quote 1.0.26", +] + +[[package]] +name = "expander" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f360349150728553f92e4c997a16af8915f418d3a0f21b440d34c5632f16ed84" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "expander" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" +dependencies = [ + "blake2", + "fs-err", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fatality" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad875162843b0d046276327afe0136e9ed3a23d5a754210fb6f1f33610d39ab" +dependencies = [ + "fatality-proc-macro", + "thiserror", +] + +[[package]] +name = "fatality-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5aa1e3ae159e592ad222dc90c5acbad632b527779ba88486abe92782ab268bd" +dependencies = [ + "expander 0.0.4", + "indexmap", + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "fdlimit" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4c9e43643f5a3be4ca5b67d26b98031ff9db6806c3440ae32e02e3ceac3f1b" +dependencies = [ + "libc", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" + +[[package]] +name = "file-per-thread-logger" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "filetime" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.16", + "windows-sys 0.45.0", +] + +[[package]] +name = "finality-grandpa" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36530797b9bf31cd4ff126dcfee8170f86b00cfdcea3269d73133cc0415945c3" +dependencies = [ + "either", + "futures", + "futures-timer", + "log", + "num-traits", + "parity-scale-codec", + "parking_lot 0.12.1", + "scale-info", +] + +[[package]] +name = "finality-relay" +version = "0.1.0" +dependencies = [ + "async-std", + "async-trait", + "backoff", + "bp-header-chain", + "futures", + "log", + "num-traits", + "parking_lot 0.12.1", + "relay-utils", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fork-tree" +version = "3.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + +[[package]] +name = "frame-benchmarking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-support-procedural", + "frame-system", + "linregress", + "log", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", + "sp-runtime-interface", + "sp-std 5.0.0", + "sp-storage", + "static_assertions", +] + +[[package]] +name = "frame-benchmarking-cli" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "Inflector", + "array-bytes 4.2.0", + "chrono", + "clap 4.2.2", + "comfy-table", + "frame-benchmarking", + "frame-support", + "frame-system", + "gethostname", + "handlebars", + "itertools", + "lazy_static", + "linked-hash-map", + "log", + "parity-scale-codec", + "rand 0.8.5", + "rand_pcg", + "sc-block-builder", + "sc-cli", + "sc-client-api", + "sc-client-db", + "sc-executor", + "sc-service", + "sc-sysinfo", + "serde", + "serde_json", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-database", + "sp-externalities", + "sp-inherents", + "sp-keystore", + "sp-runtime", + "sp-state-machine", + "sp-std 5.0.0", + "sp-storage", + "sp-trie", + "thiserror", + "thousands", +] + +[[package]] +name = "frame-election-provider-solution-type" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "frame-election-provider-support" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-election-provider-solution-type", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-npos-elections", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "frame-executive" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-tracing", +] + +[[package]] +name = "frame-metadata" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" +dependencies = [ + "cfg-if 1.0.0", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "frame-remote-externalities" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "log", + "parity-scale-codec", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "substrate-rpc-client", + "tokio", +] + +[[package]] +name = "frame-support" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "bitflags", + "environmental", + "frame-metadata", + "frame-support-procedural", + "impl-trait-for-tuples", + "k256", + "log", + "once_cell", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "smallvec", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-core-hashing-proc-macro", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-state-machine", + "sp-std 5.0.0", + "sp-tracing", + "sp-weights", + "tt-call", +] + +[[package]] +name = "frame-support-procedural" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "Inflector", + "cfg-expr", + "derive-syn-parse", + "frame-support-procedural-tools", + "itertools", + "proc-macro-warning", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support-procedural-tools-derive", + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "frame-support-procedural-tools-derive" +version = "3.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "frame-system" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-version", + "sp-weights", +] + +[[package]] +name = "frame-system-benchmarking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "frame-system-rpc-runtime-api" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "sp-api", +] + +[[package]] +name = "frame-try-runtime" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "parity-scale-codec", + "sp-api", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "fs-err" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0845fa252299212f0389d64ba26f34fa32cfe41588355f21ed507c59a0f64541" + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fs4" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea55201cc351fdb478217c0fb641b59813da9b4efe4c414a9d8f989a657d149" +dependencies = [ + "libc", + "rustix 0.35.13", + "winapi", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-lite" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite 0.2.9", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "futures-rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd" +dependencies = [ + "futures-io", + "rustls 0.20.8", + "webpki 0.22.0", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite 0.2.9", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug 0.3.0", + "polyval 0.5.3", +] + +[[package]] +name = "ghash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930750de5717d2dd0b8c0d42c076c0e884c81a73e6cab859bbd2339c71e3e40" +dependencies = [ + "opaque-debug 0.3.0", + "polyval 0.6.0", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "handlebars" +version = "4.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "hash-db" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7d7786361d7425ae2fe4f9e407eb0efaa0840f5212d109cc018c40c35c6ab4" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.6", + "hmac 0.8.1", +] + +[[package]] +name = "honggfuzz" +version = "0.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" +dependencies = [ + "arbitrary", + "lazy_static", + "memmap2", + "rustc_version", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite 0.2.9", +] + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite 0.2.9", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +dependencies = [ + "http", + "hyper", + "log", + "rustls 0.20.8", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "webpki-roots", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows 0.46.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if-addrs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc0fa01ffc752e9dbc72818cdb072cd028b86be5e09dd04c5a643704fe101a9" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "if-watch" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba7abdbb86e485125dad06c2691e1e393bf3b08c7b743b43aa162a00fd39062e" +dependencies = [ + "async-io", + "core-foundation", + "fnv", + "futures", + "if-addrs", + "ipnet", + "log", + "rtnetlink", + "system-configuration", + "tokio", + "windows 0.34.0", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "integer-encoding" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + +[[package]] +name = "interceptor" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e8a11ae2da61704edada656798b61c94b35ecac2c58eb955156987d5e6be90b" +dependencies = [ + "async-trait", + "bytes", + "log", + "rand 0.8.5", + "rtcp", + "rtp", + "thiserror", + "tokio", + "waitgroup", + "webrtc-srtp", + "webrtc-util", +] + +[[package]] +name = "io-lifetimes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ce5ef949d49ee85593fc4d3f3f95ad61657076395cbbce23e2121fc5542074" + +[[package]] +name = "io-lifetimes" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "ip_network" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1" + +[[package]] +name = "ipconfig" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be" +dependencies = [ + "socket2", + "widestring", + "winapi", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" + +[[package]] +name = "is-terminal" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes 1.0.9", + "rustix 0.36.11", + "windows-sys 0.45.0", +] + +[[package]] +name = "isahc" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9" +dependencies = [ + "async-channel", + "castaway", + "crossbeam-utils", + "curl", + "curl-sys", + "encoding_rs", + "event-listener", + "futures-lite", + "http", + "log", + "mime", + "once_cell", + "polling", + "slab", + "sluice", + "tracing", + "tracing-futures", + "url", + "waker-fn", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonpath_lib" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" +dependencies = [ + "log", + "serde", + "serde_json", +] + +[[package]] +name = "jsonrpsee" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" +dependencies = [ + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-proc-macros", + "jsonrpsee-server", + "jsonrpsee-types", + "jsonrpsee-ws-client", + "tracing", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965de52763f2004bc91ac5bcec504192440f0b568a5d621c59d9dbd6f886c3fb" +dependencies = [ + "futures-util", + "http", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "rustls-native-certs", + "soketto", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "webpki-roots", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" +dependencies = [ + "anyhow", + "arrayvec 0.7.2", + "async-lock", + "async-trait", + "beef", + "futures-channel", + "futures-timer", + "futures-util", + "globset", + "hyper", + "jsonrpsee-types", + "parking_lot 0.12.1", + "rand 0.8.5", + "rustc-hash", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core", + "jsonrpsee-types", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa6da1e4199c10d7b1d0a6e5e8bd8e55f351163b6f4b3cbb044672a69bd4c1c" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb69dad85df79527c019659a992498d03f8495390496da2f07e6c24c2b356fc" +dependencies = [ + "futures-channel", + "futures-util", + "http", + "hyper", + "jsonrpsee-core", + "jsonrpsee-types", + "serde", + "serde_json", + "soketto", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd522fe1ce3702fd94812965d7bb7a3364b1c9aba743944c5a00529aae80f8c" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b83daeecfc6517cfe210df24e570fb06213533dfb990318fae781f4c7119dd9" +dependencies = [ + "http", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", +] + +[[package]] +name = "k256" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955890845095ccf31ef83ad41a05aabb4d8cc23dc3cac5a9f5c89cf26dd0da75" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa 0.16.1", + "elliptic-curve 0.13.2", + "once_cell", + "sha2 0.10.6", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "kusama-runtime" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "frame-benchmarking", + "frame-election-provider-support", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal 0.3.4", + "kusama-runtime-constants", + "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-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-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", + "serde", + "serde_derive", + "smallvec", + "sp-api", + "sp-arithmetic", + "sp-authority-discovery", + "sp-block-builder", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-inherents", + "sp-io", + "sp-mmr-primitives", + "sp-npos-elections", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", + "sp-transaction-pool", + "sp-version", + "static_assertions", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "kusama-runtime-constants" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-core", + "sp-runtime", + "sp-weights", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "kvdb" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7d770dcb02bf6835887c3a979b5107a04ff4bbde97a5f0928d27404a155add9" +dependencies = [ + "smallvec", +] + +[[package]] +name = "kvdb-memorydb" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7a85fe66f9ff9cd74e169fdd2c94c6e1e74c412c99a73b4df3200b5d3760b2" +dependencies = [ + "kvdb", + "parking_lot 0.12.1", +] + +[[package]] +name = "kvdb-rocksdb" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2182b8219fee6bd83aacaab7344e840179ae079d5216aa4e249b4d704646a844" +dependencies = [ + "kvdb", + "num_cpus", + "parking_lot 0.12.1", + "regex", + "rocksdb", + "smallvec", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "libnghttp2-sys" +version = "0.1.7+1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libp2p" +version = "0.50.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7b0104790be871edcf97db9bd2356604984e623a08d825c3f27852290266b8" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "getrandom 0.2.8", + "instant", + "libp2p-core 0.38.0", + "libp2p-dns", + "libp2p-identify", + "libp2p-kad", + "libp2p-mdns", + "libp2p-metrics", + "libp2p-mplex", + "libp2p-noise", + "libp2p-ping", + "libp2p-quic", + "libp2p-request-response", + "libp2p-swarm", + "libp2p-tcp", + "libp2p-wasm-ext", + "libp2p-webrtc", + "libp2p-websocket", + "libp2p-yamux", + "multiaddr 0.16.0", + "parking_lot 0.12.1", + "pin-project", + "smallvec", +] + +[[package]] +name = "libp2p-core" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a8fcd392ff67af6cc3f03b1426c41f7f26b6b9aff2dc632c1c56dd649e571f" +dependencies = [ + "asn1_der", + "bs58", + "ed25519-dalek", + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "log", + "multiaddr 0.16.0", + "multihash 0.16.3", + "multistream-select", + "once_cell", + "parking_lot 0.12.1", + "pin-project", + "prost", + "prost-build", + "rand 0.8.5", + "rw-stream-sink", + "sec1 0.3.0", + "sha2 0.10.6", + "smallvec", + "thiserror", + "unsigned-varint", + "void", + "zeroize", +] + +[[package]] +name = "libp2p-core" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7f8b7d65c070a5a1b5f8f0510648189da08f787b8963f8e21219e0710733af" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-identity", + "log", + "multiaddr 0.17.1", + "multihash 0.17.0", + "multistream-select", + "once_cell", + "parking_lot 0.12.1", + "pin-project", + "quick-protobuf", + "rand 0.8.5", + "rw-stream-sink", + "smallvec", + "thiserror", + "unsigned-varint", + "void", +] + +[[package]] +name = "libp2p-dns" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e42a271c1b49f789b92f7fc87749fa79ce5c7bdc88cbdfacb818a4bca47fec5" +dependencies = [ + "futures", + "libp2p-core 0.38.0", + "log", + "parking_lot 0.12.1", + "smallvec", + "trust-dns-resolver", +] + +[[package]] +name = "libp2p-identify" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c052d0026f4817b44869bfb6810f4e1112f43aec8553f2cb38881c524b563abf" +dependencies = [ + "asynchronous-codec", + "futures", + "futures-timer", + "libp2p-core 0.38.0", + "libp2p-swarm", + "log", + "lru 0.8.1", + "prost", + "prost-build", + "prost-codec", + "smallvec", + "thiserror", + "void", +] + +[[package]] +name = "libp2p-identity" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a8ea433ae0cea7e3315354305237b9897afe45278b2118a7a57ca744e70fd27" +dependencies = [ + "bs58", + "ed25519-dalek", + "log", + "multiaddr 0.17.1", + "multihash 0.17.0", + "prost", + "quick-protobuf", + "rand 0.8.5", + "thiserror", + "zeroize", +] + +[[package]] +name = "libp2p-kad" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2766dcd2be8c87d5e1f35487deb22d765f49c6ae1251b3633efe3b25698bd3d2" +dependencies = [ + "arrayvec 0.7.2", + "asynchronous-codec", + "bytes", + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-core 0.38.0", + "libp2p-swarm", + "log", + "prost", + "prost-build", + "rand 0.8.5", + "sha2 0.10.6", + "smallvec", + "thiserror", + "uint", + "unsigned-varint", + "void", +] + +[[package]] +name = "libp2p-mdns" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f378264aade9872d6ccd315c0accc18be3a35d15fc1b9c36e5b6f983b62b5b" +dependencies = [ + "data-encoding", + "futures", + "if-watch", + "libp2p-core 0.38.0", + "libp2p-swarm", + "log", + "rand 0.8.5", + "smallvec", + "socket2", + "tokio", + "trust-dns-proto", + "void", +] + +[[package]] +name = "libp2p-metrics" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad8a64f29da86005c86a4d2728b8a0719e9b192f4092b609fd8790acb9dec55" +dependencies = [ + "libp2p-core 0.38.0", + "libp2p-identify", + "libp2p-kad", + "libp2p-ping", + "libp2p-swarm", + "prometheus-client", +] + +[[package]] +name = "libp2p-mplex" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03805b44107aa013e7cbbfa5627b31c36cbedfdfb00603c0311998882bc4bace" +dependencies = [ + "asynchronous-codec", + "bytes", + "futures", + "libp2p-core 0.38.0", + "log", + "nohash-hasher", + "parking_lot 0.12.1", + "rand 0.8.5", + "smallvec", + "unsigned-varint", +] + +[[package]] +name = "libp2p-noise" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978cb57efe82e892ec6f348a536bfbd9fee677adbe5689d7a93ad3a9bffbf2e" +dependencies = [ + "bytes", + "curve25519-dalek 3.2.0", + "futures", + "libp2p-core 0.38.0", + "log", + "once_cell", + "prost", + "prost-build", + "rand 0.8.5", + "sha2 0.10.6", + "snow", + "static_assertions", + "thiserror", + "x25519-dalek 1.1.1", + "zeroize", +] + +[[package]] +name = "libp2p-ping" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "929fcace45a112536e22b3dcfd4db538723ef9c3cb79f672b98be2cc8e25f37f" +dependencies = [ + "futures", + "futures-timer", + "instant", + "libp2p-core 0.38.0", + "libp2p-swarm", + "log", + "rand 0.8.5", + "void", +] + +[[package]] +name = "libp2p-quic" +version = "0.7.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e7c867e95c8130667b24409d236d37598270e6da69b3baf54213ba31ffca59" +dependencies = [ + "bytes", + "futures", + "futures-timer", + "if-watch", + "libp2p-core 0.38.0", + "libp2p-tls", + "log", + "parking_lot 0.12.1", + "quinn-proto", + "rand 0.8.5", + "rustls 0.20.8", + "thiserror", + "tokio", +] + +[[package]] +name = "libp2p-request-response" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3236168796727bfcf4927f766393415361e2c644b08bedb6a6b13d957c9a4884" +dependencies = [ + "async-trait", + "bytes", + "futures", + "instant", + "libp2p-core 0.38.0", + "libp2p-swarm", + "log", + "rand 0.8.5", + "smallvec", + "unsigned-varint", +] + +[[package]] +name = "libp2p-swarm" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a35472fe3276b3855c00f1c032ea8413615e030256429ad5349cdf67c6e1a0" +dependencies = [ + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-core 0.38.0", + "libp2p-swarm-derive", + "log", + "pin-project", + "rand 0.8.5", + "smallvec", + "thiserror", + "tokio", + "void", +] + +[[package]] +name = "libp2p-swarm-derive" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d527d5827582abd44a6d80c07ff8b50b4ee238a8979e05998474179e79dc400" +dependencies = [ + "heck 0.4.1", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "libp2p-tcp" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b257baf6df8f2df39678b86c578961d48cc8b68642a12f0f763f56c8e5858d" +dependencies = [ + "futures", + "futures-timer", + "if-watch", + "libc", + "libp2p-core 0.38.0", + "log", + "socket2", + "tokio", +] + +[[package]] +name = "libp2p-tls" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff08d13d0dc66e5e9ba6279c1de417b84fa0d0adc3b03e5732928c180ec02781" +dependencies = [ + "futures", + "futures-rustls", + "libp2p-core 0.39.1", + "libp2p-identity", + "rcgen 0.10.0", + "ring", + "rustls 0.20.8", + "thiserror", + "webpki 0.22.0", + "x509-parser 0.14.0", + "yasna", +] + +[[package]] +name = "libp2p-wasm-ext" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb1a35299860e0d4b3c02a3e74e3b293ad35ae0cee8a056363b0c862d082069" +dependencies = [ + "futures", + "js-sys", + "libp2p-core 0.38.0", + "parity-send-wrapper", + "wasm-bindgen", + "wasm-bindgen-futures", +] + +[[package]] +name = "libp2p-webrtc" +version = "0.4.0-alpha" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb6cd86dd68cba72308ea05de1cebf3ba0ae6e187c40548167955d4e3970f6a" +dependencies = [ + "async-trait", + "asynchronous-codec", + "bytes", + "futures", + "futures-timer", + "hex", + "if-watch", + "libp2p-core 0.38.0", + "libp2p-noise", + "log", + "multihash 0.16.3", + "prost", + "prost-build", + "prost-codec", + "rand 0.8.5", + "rcgen 0.9.3", + "serde", + "stun", + "thiserror", + "tinytemplate", + "tokio", + "tokio-util", + "webrtc", +] + +[[package]] +name = "libp2p-websocket" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d705506030d5c0aaf2882437c70dab437605f21c5f9811978f694e6917a3b54" +dependencies = [ + "either", + "futures", + "futures-rustls", + "libp2p-core 0.38.0", + "log", + "parking_lot 0.12.1", + "quicksink", + "rw-stream-sink", + "soketto", + "url", + "webpki-roots", +] + +[[package]] +name = "libp2p-yamux" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f63594a0aa818642d9d4915c791945053877253f08a3626f13416b5cd928a29" +dependencies = [ + "futures", + "libp2p-core 0.38.0", + "log", + "parking_lot 0.12.1", + "thiserror", + "yamux", +] + +[[package]] +name = "librocksdb-sys" +version = "0.8.3+7.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "557b255ff04123fcc176162f56ed0c9cd42d8f357cf55b3fabeb60f7413741b3" +dependencies = [ + "bindgen", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", + "tikv-jemalloc-sys", +] + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "linregress" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "475015a7f8f017edb28d2e69813be23500ad4b32cfe3421c4148efc97324ee52" +dependencies = [ + "nalgebra", +] + +[[package]] +name = "linux-raw-sys" +version = "0.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d" + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "linux-raw-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd550e73688e6d578f0ac2119e32b797a327631a42f9433e59d02e139c8df60d" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if 1.0.0", + "value-bag", +] + +[[package]] +name = "lru" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" +dependencies = [ + "hashbrown 0.12.3", +] + +[[package]] +name = "lru" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e7d46de488603ffdd5f30afbc64fbba2378214a2c3a2fb83abf3d33126df17" +dependencies = [ + "hashbrown 0.13.2", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "lz4" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +dependencies = [ + "libc", + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "matrixmultiply" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84" +dependencies = [ + "rawpointer", +] + +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memfd" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" +dependencies = [ + "rustix 0.36.11", +] + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memory-db" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808b50db46293432a45e63bc15ea51e0ab4c0a1647b8eb114e31a3e698dd6fbe" +dependencies = [ + "hash-db", +] + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "merlin" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "messages-relay" +version = "0.1.0" +dependencies = [ + "async-std", + "async-trait", + "bp-messages", + "finality-relay", + "futures", + "hex", + "log", + "num-traits", + "parking_lot 0.12.1", + "relay-utils", + "sp-arithmetic", +] + +[[package]] +name = "mick-jaeger" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69672161530e8aeca1d1400fbf3f1a1747ff60ea604265a4e906c2442df20532" +dependencies = [ + "futures", + "rand 0.8.5", + "thrift", +] + +[[package]] +name = "millau-bridge-node" +version = "0.1.0" +dependencies = [ + "clap 4.2.2", + "frame-benchmarking", + "frame-benchmarking-cli", + "jsonrpsee", + "millau-runtime", + "mmr-rpc", + "node-inspect", + "pallet-transaction-payment-rpc", + "sc-basic-authorship", + "sc-cli", + "sc-client-api", + "sc-consensus", + "sc-consensus-aura", + "sc-consensus-beefy", + "sc-consensus-beefy-rpc", + "sc-consensus-grandpa", + "sc-consensus-grandpa-rpc", + "sc-executor", + "sc-keystore", + "sc-network-common", + "sc-rpc", + "sc-service", + "sc-telemetry", + "sc-transaction-pool", + "serde_json", + "sp-consensus-aura", + "sp-consensus-beefy", + "sp-consensus-grandpa", + "sp-core", + "sp-runtime", + "sp-timestamp", + "substrate-build-script-utils", + "substrate-frame-rpc-system", +] + +[[package]] +name = "millau-runtime" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-millau", + "bp-parachains", + "bp-polkadot-core", + "bp-relayers", + "bp-rialto", + "bp-rialto-parachain", + "bp-runtime", + "bp-westend", + "bridge-runtime-common", + "env_logger", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-rpc-runtime-api", + "hex-literal 0.4.1", + "pallet-aura", + "pallet-balances", + "pallet-beefy", + "pallet-beefy-mmr", + "pallet-bridge-grandpa", + "pallet-bridge-messages", + "pallet-bridge-parachains", + "pallet-bridge-relayers", + "pallet-grandpa", + "pallet-mmr", + "pallet-session", + "pallet-shift-session-manager", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-utility", + "pallet-xcm", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-consensus-beefy", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 5.0.0", + "sp-transaction-pool", + "sp-version", + "static_assertions", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.45.0", +] + +[[package]] +name = "mmr-gadget" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "log", + "parity-scale-codec", + "sc-client-api", + "sc-offchain", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-consensus-beefy", + "sp-core", + "sp-mmr-primitives", + "sp-runtime", +] + +[[package]] +name = "mmr-rpc" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "anyhow", + "jsonrpsee", + "parity-scale-codec", + "serde", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-mmr-primitives", + "sp-runtime", +] + +[[package]] +name = "mockall" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e4a1c770583dac7ab5e2f6c139153b783a53a1bbee9729613f193e59828326" +dependencies = [ + "cfg-if 1.0.0", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0" +dependencies = [ + "cfg-if 1.0.0", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "multiaddr" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aebdb21e90f81d13ed01dc84123320838e53963c2ca94b60b305d3fa64f31e" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "multibase", + "multihash 0.16.3", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + +[[package]] +name = "multiaddr" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b36f567c7099511fa8612bbbb52dda2419ce0bdbacf31714e3a5ffdb766d3bd" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "log", + "multibase", + "multihash 0.17.0", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + +[[package]] +name = "multibase" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + +[[package]] +name = "multihash" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c346cf9999c631f002d8f977c4eaeaa0e6386f16007202308d0b3757522c2cc" +dependencies = [ + "blake2b_simd", + "blake2s_simd", + "blake3", + "core2", + "digest 0.10.6", + "multihash-derive", + "sha2 0.10.6", + "sha3", + "unsigned-varint", +] + +[[package]] +name = "multihash" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" +dependencies = [ + "core2", + "digest 0.10.6", + "multihash-derive", + "sha2 0.10.6", + "unsigned-varint", +] + +[[package]] +name = "multihash-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" +dependencies = [ + "proc-macro-crate", + "proc-macro-error", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "multistream-select" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8552ab875c1313b97b8d20cb857b9fd63e2d1d6a0a1b53ce9821e575405f27a" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project", + "smallvec", + "unsigned-varint", +] + +[[package]] +name = "nalgebra" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68d47bba83f9e2006d117a9a33af1524e655516b8919caac694427a6fb1e511" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d232c68884c0c99810a5a4d333ef7e47689cfd0edc85efc9e54e1e6bf5212766" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "names" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7d66043b25d4a6cccb23619d10c19c25304b355a7dccd4a8e11423dd2382146" +dependencies = [ + "rand 0.8.5", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" + +[[package]] +name = "netlink-packet-core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +dependencies = [ + "anyhow", + "byteorder", + "libc", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-route" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ea4302b9759a7a88242299225ea3688e63c85ea136371bb6cf94fd674efaab" +dependencies = [ + "anyhow", + "bitflags", + "byteorder", + "libc", + "netlink-packet-core", + "netlink-packet-utils", +] + +[[package]] +name = "netlink-packet-utils" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ede8a08c71ad5a95cdd0e4e52facd37190977039a4704eb82a283f713747d34" +dependencies = [ + "anyhow", + "byteorder", + "paste", + "thiserror", +] + +[[package]] +name = "netlink-proto" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +dependencies = [ + "bytes", + "futures", + "log", + "netlink-packet-core", + "netlink-sys", + "thiserror", + "tokio", +] + +[[package]] +name = "netlink-sys" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6471bf08e7ac0135876a9581bf3217ef0333c191c128d34878079f42ee150411" +dependencies = [ + "bytes", + "futures", + "libc", + "log", + "tokio", +] + +[[package]] +name = "nix" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "libc", + "memoffset 0.6.5", +] + +[[package]] +name = "node-inspect" +version = "0.9.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a14236059c2d3da052fb08295082341aa7b87240" +dependencies = [ + "clap 4.2.2", + "parity-scale-codec", + "sc-cli", + "sc-client-api", + "sc-executor", + "sc-service", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "ntapi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec 0.7.2", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "crc32fast", + "hashbrown 0.12.3", + "indexmap", + "memchr", +] + +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e20717fa0541f39bd146692035c37bedfa532b3e5071b35761082407546b2a" +dependencies = [ + "asn1-rs 0.3.1", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs 0.5.2", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a95792af3c4e0153c3914df2261bedd30a98476f94dc892b67dfe1d89d433a04" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "orchestra" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "227585216d05ba65c7ab0a0450a3cf2cbd81a98862a54c4df8e14d5ac6adb015" +dependencies = [ + "async-trait", + "dyn-clonable", + "futures", + "futures-timer", + "orchestra-proc-macro", + "pin-project", + "prioritized-metered-channel", + "thiserror", + "tracing", +] + +[[package]] +name = "orchestra-proc-macro" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2871aadd82a2c216ee68a69837a526dfe788ecbe74c4c5038a6acdbff6653066" +dependencies = [ + "expander 0.0.6", + "itertools", + "petgraph", + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "ordered-float" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" +dependencies = [ + "num-traits", +] + +[[package]] +name = "p256" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +dependencies = [ + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.6", +] + +[[package]] +name = "p384" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc8c5bf642dde52bb9e87c0ecd8ca5a76faac2eeed98dedb7c717997e1080aa" +dependencies = [ + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.6", +] + +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if 1.0.0", + "libm 0.1.4", +] + +[[package]] +name = "pallet-aura" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-consensus-aura", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-authority-discovery" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "pallet-session", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-authority-discovery", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-authorship" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-babe" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-consensus-babe", + "sp-consensus-vrf", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-bags-list" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-tracing", +] + +[[package]] +name = "pallet-balances" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-beefy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "scale-info", + "serde", + "sp-consensus-beefy", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-beefy-mmr" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "binary-merkle-tree", + "frame-support", + "frame-system", + "log", + "pallet-beefy", + "pallet-mmr", + "pallet-session", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-consensus-beefy", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-bounties" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-treasury", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-bridge-beefy" +version = "0.1.0" +dependencies = [ + "bp-beefy", + "bp-runtime", + "bp-test-utils", + "ckb-merkle-mountain-range 0.3.2", + "frame-support", + "frame-system", + "log", + "pallet-beefy-mmr", + "pallet-mmr", + "parity-scale-codec", + "rand 0.8.5", + "scale-info", + "serde", + "sp-consensus-beefy", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-bridge-grandpa" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-runtime", + "bp-test-utils", + "finality-grandpa", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-consensus-grandpa", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-trie", +] + +[[package]] +name = "pallet-bridge-messages" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-runtime", + "bp-test-utils", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "num-traits", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-bridge-parachains" +version = "0.1.0" +dependencies = [ + "bp-header-chain", + "bp-parachains", + "bp-polkadot-core", + "bp-runtime", + "bp-test-utils", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-bridge-grandpa", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-trie", +] + +[[package]] +name = "pallet-bridge-relayers" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-relayers", + "bp-runtime", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-balances", + "pallet-bridge-messages", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-child-bounties" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-bounties", + "pallet-treasury", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-collective" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-conviction-voting" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-democracy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-election-provider-multi-phase" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-election-provider-support-benchmarking", + "parity-scale-codec", + "rand 0.8.5", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std 5.0.0", + "strum", +] + +[[package]] +name = "pallet-election-provider-support-benchmarking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-system", + "parity-scale-codec", + "sp-npos-elections", + "sp-runtime", +] + +[[package]] +name = "pallet-elections-phragmen" +version = "5.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-fast-unstake" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-grandpa" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-consensus-grandpa", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-identity" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "enumflags2", + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-im-online" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "parity-scale-codec", + "scale-info", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-indices" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-keyring", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-membership" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-mmr" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-mmr-primitives", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-multisig" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-nis" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-nomination-pools" +version = "1.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-nomination-pools-benchmarking" +version = "1.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "pallet-bags-list", + "pallet-nomination-pools", + "pallet-staking", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-runtime-interface", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-nomination-pools-runtime-api" +version = "1.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "pallet-nomination-pools", + "parity-scale-codec", + "sp-api", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-offences" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "log", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-offences-benchmarking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-babe", + "pallet-balances", + "pallet-grandpa", + "pallet-im-online", + "pallet-offences", + "pallet-session", + "pallet-staking", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-preimage" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-proxy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-ranked-collective" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-recovery" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-referenda" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "assert_matches", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-scheduler" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-weights", +] + +[[package]] +name = "pallet-session" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", + "sp-trie", +] + +[[package]] +name = "pallet-session-benchmarking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-session", + "pallet-staking", + "rand 0.8.5", + "sp-runtime", + "sp-session", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-shift-session-manager" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "pallet-session", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-society" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "rand_chacha 0.2.2", + "scale-info", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-staking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "log", + "pallet-authorship", + "pallet-session", + "parity-scale-codec", + "rand_chacha 0.2.2", + "scale-info", + "serde", + "sp-application-crypto", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-staking-reward-curve" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "pallet-staking-reward-fn" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "log", + "sp-arithmetic", +] + +[[package]] +name = "pallet-staking-runtime-api" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "sp-api", +] + +[[package]] +name = "pallet-state-trie-migration" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-sudo" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-timestamp" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-timestamp", +] + +[[package]] +name = "pallet-tips" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-treasury", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-transaction-payment" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-transaction-payment-rpc" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "jsonrpsee", + "pallet-transaction-payment-rpc-runtime-api", + "parity-scale-codec", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-rpc", + "sp-runtime", + "sp-weights", +] + +[[package]] +name = "pallet-transaction-payment-rpc-runtime-api" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "pallet-transaction-payment", + "parity-scale-codec", + "sp-api", + "sp-runtime", + "sp-weights", +] + +[[package]] +name = "pallet-treasury" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "pallet-balances", + "parity-scale-codec", + "scale-info", + "serde", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-utility" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-vesting" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-whitelist" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "pallet-xcm" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bounded-collections", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "xcm", + "xcm-executor", +] + +[[package]] +name = "pallet-xcm-benchmarks" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "parity-scale-codec", + "scale-info", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "parachain-info" +version = "0.1.0" +source = "git+https://github.com/paritytech/cumulus?branch=master#df9ed2455462e8c470a8a7ead44023b6eec79ed3" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "frame-system", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "parachains-relay" +version = "0.1.0" +dependencies = [ + "async-std", + "async-trait", + "bp-polkadot-core", + "futures", + "log", + "parity-scale-codec", + "relay-substrate-client", + "relay-utils", + "sp-core", +] + +[[package]] +name = "parity-db" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bfb81cf5c90a222db2fb7b3a7cbf8cc7f38dfb6647aca4d98edf8281f56ed5" +dependencies = [ + "blake2", + "crc32fast", + "fs2", + "hex", + "libc", + "log", + "lz4", + "memmap2", + "parking_lot 0.12.1", + "rand 0.8.5", + "siphasher", + "snap", +] + +[[package]] +name = "parity-scale-codec" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" +dependencies = [ + "arrayvec 0.7.2", + "bitvec", + "byte-slice-cast", + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "parity-send-wrapper" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" + +[[package]] +name = "parity-util-mem" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" +dependencies = [ + "cfg-if 1.0.0", + "ethereum-types", + "hashbrown 0.12.3", + "impl-trait-for-tuples", + "lru 0.8.1", + "parity-util-mem-derive", + "parking_lot 0.12.1", + "primitive-types", + "smallvec", + "winapi", +] + +[[package]] +name = "parity-util-mem-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" +dependencies = [ + "proc-macro2 1.0.56", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "parity-wasm" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" + +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.7", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +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.6", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pest" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cbd939b234e95d72bc393d51788aec68aeeb5d51e748ca08ff3aad58cb722f7" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a81186863f3d0a27340815be8f2078dd8050b14cd71913db9fbda795e5f707d7" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75a1ef20bf3193c15ac345acb32e26b3dc3223aff4d77ae4fc5359567683796b" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "pest_meta" +version = "2.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e3b284b1f13a20dc5ebc90aff59a51b8d7137c221131b52a7260c08cbc1cc80" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.6", +] + +[[package]] +name = "petgraph" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" +dependencies = [ + "fixedbitset", + "indexmap", +] + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "pin-project-lite" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d2820d87d2b008616e5c27212dd9e0e694fb4c6b522de06094106813328cb49" +dependencies = [ + "der 0.7.1", + "spki 0.7.0", +] + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "platforms" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" + +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + +[[package]] +name = "polkadot-approval-distribution" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "polkadot-node-jaeger", + "polkadot-node-metrics", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-primitives", + "rand 0.8.5", + "tracing-gum", +] + +[[package]] +name = "polkadot-availability-bitfield-distribution" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "polkadot-node-network-protocol", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "rand 0.8.5", + "tracing-gum", +] + +[[package]] +name = "polkadot-availability-distribution" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "derive_more", + "fatality", + "futures", + "lru 0.9.0", + "parity-scale-codec", + "polkadot-erasure-coding", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "rand 0.8.5", + "sp-core", + "sp-keystore", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-availability-recovery" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "fatality", + "futures", + "lru 0.9.0", + "parity-scale-codec", + "polkadot-erasure-coding", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "rand 0.8.5", + "sc-network", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-cli" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "clap 4.2.2", + "frame-benchmarking-cli", + "futures", + "log", + "polkadot-client", + "polkadot-node-core-pvf", + "polkadot-node-metrics", + "polkadot-service", + "sc-cli", + "sc-executor", + "sc-service", + "sc-storage-monitor", + "sc-sysinfo", + "sc-tracing", + "sp-core", + "sp-io", + "sp-keyring", + "substrate-build-script-utils", + "thiserror", + "try-runtime-cli", +] + +[[package]] +name = "polkadot-client" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "async-trait", + "frame-benchmarking", + "frame-benchmarking-cli", + "frame-system", + "frame-system-rpc-runtime-api", + "futures", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "polkadot-core-primitives", + "polkadot-node-core-parachains-inherent", + "polkadot-primitives", + "polkadot-runtime", + "polkadot-runtime-common", + "sc-client-api", + "sc-consensus", + "sc-executor", + "sc-service", + "sp-api", + "sp-authority-discovery", + "sp-block-builder", + "sp-blockchain", + "sp-consensus", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-consensus-grandpa", + "sp-core", + "sp-inherents", + "sp-keyring", + "sp-mmr-primitives", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-storage", + "sp-timestamp", + "sp-transaction-pool", +] + +[[package]] +name = "polkadot-collator-protocol" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "always-assert", + "bitvec", + "fatality", + "futures", + "futures-timer", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "sp-core", + "sp-keystore", + "sp-runtime", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-core-primitives" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "polkadot-dispute-distribution" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "derive_more", + "fatality", + "futures", + "futures-timer", + "indexmap", + "lru 0.9.0", + "parity-scale-codec", + "polkadot-erasure-coding", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "sc-network", + "sp-application-crypto", + "sp-keystore", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-erasure-coding" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "parity-scale-codec", + "polkadot-node-primitives", + "polkadot-primitives", + "reed-solomon-novelpoly", + "sp-core", + "sp-trie", + "thiserror", +] + +[[package]] +name = "polkadot-gossip-support" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "futures-timer", + "polkadot-node-network-protocol", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "rand 0.8.5", + "rand_chacha 0.3.1", + "sc-network", + "sp-application-crypto", + "sp-core", + "sp-keystore", + "tracing-gum", +] + +[[package]] +name = "polkadot-network-bridge" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "always-assert", + "async-trait", + "bytes", + "fatality", + "futures", + "parity-scale-codec", + "parking_lot 0.12.1", + "polkadot-node-metrics", + "polkadot-node-network-protocol", + "polkadot-node-subsystem", + "polkadot-overseer", + "polkadot-primitives", + "sc-network", + "sp-consensus", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-collation-generation" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "parity-scale-codec", + "polkadot-erasure-coding", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "sp-core", + "sp-maybe-compressed-blob", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-approval-voting" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "derive_more", + "futures", + "futures-timer", + "kvdb", + "lru 0.9.0", + "merlin", + "parity-scale-codec", + "polkadot-node-jaeger", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-overseer", + "polkadot-primitives", + "sc-keystore", + "schnorrkel", + "sp-application-crypto", + "sp-consensus", + "sp-consensus-slots", + "sp-runtime", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-av-store" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "futures", + "futures-timer", + "kvdb", + "parity-scale-codec", + "polkadot-erasure-coding", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-overseer", + "polkadot-primitives", + "sp-consensus", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-backing" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "fatality", + "futures", + "polkadot-erasure-coding", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "polkadot-statement-table", + "sp-keystore", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-bitfield-signing" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "sp-keystore", + "thiserror", + "tracing-gum", + "wasm-timer", +] + +[[package]] +name = "polkadot-node-core-candidate-validation" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "parity-scale-codec", + "polkadot-node-core-pvf", + "polkadot-node-metrics", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-parachain", + "polkadot-primitives", + "sp-maybe-compressed-blob", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-chain-api" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "polkadot-node-metrics", + "polkadot-node-subsystem", + "polkadot-primitives", + "sc-client-api", + "sc-consensus-babe", + "sp-blockchain", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-chain-selection" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "futures-timer", + "kvdb", + "parity-scale-codec", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-dispute-coordinator" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "fatality", + "futures", + "kvdb", + "lru 0.9.0", + "parity-scale-codec", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "sc-keystore", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-parachains-inherent" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "polkadot-node-subsystem", + "polkadot-overseer", + "polkadot-primitives", + "sp-blockchain", + "sp-inherents", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-provisioner" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "fatality", + "futures", + "futures-timer", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "rand 0.8.5", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-pvf" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "always-assert", + "assert_matches", + "cpu-time", + "futures", + "futures-timer", + "libc", + "parity-scale-codec", + "pin-project", + "polkadot-core-primitives", + "polkadot-node-metrics", + "polkadot-node-primitives", + "polkadot-parachain", + "polkadot-primitives", + "rand 0.8.5", + "rayon", + "sc-executor", + "sc-executor-common", + "sc-executor-wasmtime", + "slotmap", + "sp-core", + "sp-externalities", + "sp-io", + "sp-maybe-compressed-blob", + "sp-tracing", + "sp-wasm-interface", + "substrate-build-script-utils", + "tempfile", + "tikv-jemalloc-ctl", + "tokio", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-pvf-checker" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-overseer", + "polkadot-primitives", + "sp-keystore", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-runtime-api" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "futures", + "lru 0.9.0", + "polkadot-node-metrics", + "polkadot-node-subsystem", + "polkadot-node-subsystem-types", + "polkadot-primitives", + "sp-consensus-babe", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-jaeger" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "lazy_static", + "log", + "mick-jaeger", + "parity-scale-codec", + "parking_lot 0.12.1", + "polkadot-node-primitives", + "polkadot-primitives", + "sc-network", + "sp-core", + "thiserror", + "tokio", +] + +[[package]] +name = "polkadot-node-metrics" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bs58", + "futures", + "futures-timer", + "log", + "parity-scale-codec", + "polkadot-primitives", + "prioritized-metered-channel", + "sc-cli", + "sc-service", + "sc-tracing", + "substrate-prometheus-endpoint", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-network-protocol" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "async-trait", + "derive_more", + "fatality", + "futures", + "hex", + "parity-scale-codec", + "polkadot-node-jaeger", + "polkadot-node-primitives", + "polkadot-primitives", + "rand 0.8.5", + "sc-authority-discovery", + "sc-network", + "strum", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-primitives" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bounded-vec", + "futures", + "parity-scale-codec", + "polkadot-parachain", + "polkadot-primitives", + "schnorrkel", + "serde", + "sp-application-crypto", + "sp-consensus-babe", + "sp-consensus-vrf", + "sp-core", + "sp-keystore", + "sp-maybe-compressed-blob", + "sp-runtime", + "thiserror", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "polkadot-node-subsystem" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "polkadot-node-jaeger", + "polkadot-node-subsystem-types", + "polkadot-overseer", +] + +[[package]] +name = "polkadot-node-subsystem-types" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "async-trait", + "derive_more", + "futures", + "orchestra", + "polkadot-node-jaeger", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-primitives", + "polkadot-statement-table", + "sc-network", + "smallvec", + "sp-api", + "sp-authority-discovery", + "sp-consensus-babe", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "polkadot-node-subsystem-util" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "async-trait", + "derive_more", + "fatality", + "futures", + "futures-channel", + "itertools", + "kvdb", + "lru 0.9.0", + "parity-db", + "parity-scale-codec", + "parking_lot 0.11.2", + "pin-project", + "polkadot-node-jaeger", + "polkadot-node-metrics", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-overseer", + "polkadot-primitives", + "prioritized-metered-channel", + "rand 0.8.5", + "sp-application-crypto", + "sp-core", + "sp-keystore", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-overseer" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "lru 0.9.0", + "orchestra", + "parking_lot 0.12.1", + "polkadot-node-metrics", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem-types", + "polkadot-primitives", + "sc-client-api", + "sp-api", + "sp-core", + "tikv-jemalloc-ctl", + "tracing-gum", +] + +[[package]] +name = "polkadot-parachain" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bounded-collections", + "derive_more", + "frame-support", + "parity-scale-codec", + "polkadot-core-primitives", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "polkadot-primitives" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "hex-literal 0.3.4", + "parity-scale-codec", + "polkadot-core-primitives", + "polkadot-parachain", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-authority-discovery", + "sp-consensus-slots", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "polkadot-rpc" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "jsonrpsee", + "mmr-rpc", + "pallet-transaction-payment-rpc", + "polkadot-primitives", + "sc-chain-spec", + "sc-client-api", + "sc-consensus-babe", + "sc-consensus-babe-rpc", + "sc-consensus-beefy", + "sc-consensus-beefy-rpc", + "sc-consensus-epochs", + "sc-consensus-grandpa", + "sc-consensus-grandpa-rpc", + "sc-rpc", + "sc-sync-state-rpc", + "sc-transaction-pool-api", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-consensus", + "sp-consensus-babe", + "sp-keystore", + "sp-runtime", + "substrate-frame-rpc-system", + "substrate-state-trie-migration-rpc", +] + +[[package]] +name = "polkadot-runtime" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "frame-benchmarking", + "frame-election-provider-support", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal 0.3.4", + "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-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", + "parity-scale-codec", + "polkadot-primitives", + "polkadot-runtime-common", + "polkadot-runtime-constants", + "polkadot-runtime-parachains", + "rustc-hex", + "scale-info", + "serde", + "serde_derive", + "smallvec", + "sp-api", + "sp-arithmetic", + "sp-authority-discovery", + "sp-block-builder", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-inherents", + "sp-io", + "sp-mmr-primitives", + "sp-npos-elections", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", + "sp-transaction-pool", + "sp-version", + "static_assertions", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "polkadot-runtime-common" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "frame-benchmarking", + "frame-election-provider-support", + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "libsecp256k1", + "log", + "pallet-authorship", + "pallet-babe", + "pallet-balances", + "pallet-election-provider-multi-phase", + "pallet-fast-unstake", + "pallet-session", + "pallet-staking", + "pallet-staking-reward-fn", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-treasury", + "pallet-vesting", + "parity-scale-codec", + "polkadot-primitives", + "polkadot-runtime-parachains", + "rustc-hex", + "scale-info", + "serde", + "serde_derive", + "slot-range-helper", + "sp-api", + "sp-core", + "sp-inherents", + "sp-io", + "sp-npos-elections", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", + "static_assertions", + "xcm", +] + +[[package]] +name = "polkadot-runtime-constants" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-core", + "sp-runtime", + "sp-weights", +] + +[[package]] +name = "polkadot-runtime-metrics" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bs58", + "parity-scale-codec", + "polkadot-primitives", + "sp-std 5.0.0", + "sp-tracing", +] + +[[package]] +name = "polkadot-runtime-parachains" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitflags", + "bitvec", + "derive_more", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-authority-discovery", + "pallet-authorship", + "pallet-babe", + "pallet-balances", + "pallet-session", + "pallet-staking", + "pallet-timestamp", + "pallet-vesting", + "parity-scale-codec", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-runtime-metrics", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rustc-hex", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", + "static_assertions", + "xcm", + "xcm-executor", +] + +[[package]] +name = "polkadot-service" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "async-trait", + "frame-benchmarking-cli", + "frame-support", + "frame-system-rpc-runtime-api", + "futures", + "hex-literal 0.3.4", + "kusama-runtime", + "kvdb", + "kvdb-rocksdb", + "log", + "lru 0.9.0", + "mmr-gadget", + "pallet-babe", + "pallet-im-online", + "pallet-staking", + "pallet-transaction-payment-rpc-runtime-api", + "parity-db", + "polkadot-approval-distribution", + "polkadot-availability-bitfield-distribution", + "polkadot-availability-distribution", + "polkadot-availability-recovery", + "polkadot-client", + "polkadot-collator-protocol", + "polkadot-dispute-distribution", + "polkadot-gossip-support", + "polkadot-network-bridge", + "polkadot-node-collation-generation", + "polkadot-node-core-approval-voting", + "polkadot-node-core-av-store", + "polkadot-node-core-backing", + "polkadot-node-core-bitfield-signing", + "polkadot-node-core-candidate-validation", + "polkadot-node-core-chain-api", + "polkadot-node-core-chain-selection", + "polkadot-node-core-dispute-coordinator", + "polkadot-node-core-parachains-inherent", + "polkadot-node-core-provisioner", + "polkadot-node-core-pvf-checker", + "polkadot-node-core-runtime-api", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-types", + "polkadot-node-subsystem-util", + "polkadot-overseer", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-rpc", + "polkadot-runtime", + "polkadot-runtime-constants", + "polkadot-runtime-parachains", + "polkadot-statement-distribution", + "rococo-runtime", + "sc-authority-discovery", + "sc-basic-authorship", + "sc-block-builder", + "sc-chain-spec", + "sc-client-api", + "sc-client-db", + "sc-consensus", + "sc-consensus-babe", + "sc-consensus-beefy", + "sc-consensus-grandpa", + "sc-consensus-slots", + "sc-executor", + "sc-keystore", + "sc-network", + "sc-network-common", + "sc-network-sync", + "sc-offchain", + "sc-service", + "sc-sync-state-rpc", + "sc-sysinfo", + "sc-telemetry", + "sc-transaction-pool", + "serde", + "serde_json", + "sp-api", + "sp-authority-discovery", + "sp-block-builder", + "sp-blockchain", + "sp-consensus", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-consensus-grandpa", + "sp-core", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-mmr-primitives", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-state-machine", + "sp-storage", + "sp-timestamp", + "sp-transaction-pool", + "sp-trie", + "substrate-prometheus-endpoint", + "thiserror", + "tracing-gum", + "westend-runtime", +] + +[[package]] +name = "polkadot-statement-distribution" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "arrayvec 0.5.2", + "fatality", + "futures", + "indexmap", + "parity-scale-codec", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-util", + "polkadot-primitives", + "sp-keystore", + "sp-staking", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-statement-table" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "parity-scale-codec", + "polkadot-primitives", + "sp-core", +] + +[[package]] +name = "polling" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e1f879b2998099c2d69ab9605d145d5b661195627eccc680002c4918a7fb6fa" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if 1.0.0", + "concurrent-queue", + "libc", + "log", + "pin-project-lite 0.2.9", + "windows-sys 0.45.0", +] + +[[package]] +name = "poly1305" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" +dependencies = [ + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash 0.4.1", +] + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash 0.4.1", +] + +[[package]] +name = "polyval" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef234e08c11dfcb2e56f79fd70f6f2eb7f025c0ce2333e82f4f0518ecad30c6" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "opaque-debug 0.3.0", + "universal-hash 0.5.0", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "predicates" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2 1.0.56", + "syn 1.0.109", +] + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "prioritized-metered-channel" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382698e48a268c832d0b181ed438374a6bb708a82a8ca273bb0f61c74cf209c4" +dependencies = [ + "coarsetime", + "crossbeam-queue", + "derive_more", + "futures", + "futures-timer", + "nanorand", + "thiserror", + "tracing", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "version_check", +] + +[[package]] +name = "proc-macro-warning" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4f284d87b9cedc2ff57223cbc4e3937cd6063c01e92c8e2a8c080df0013933" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prometheus" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449811d15fbdf5ceb5c1144416066429cf82316e2ec8ce0c1f6f8a02e7bbcf8c" +dependencies = [ + "cfg-if 1.0.0", + "fnv", + "lazy_static", + "memchr", + "parking_lot 0.12.1", + "thiserror", +] + +[[package]] +name = "prometheus-client" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83cd1b99916654a69008fd66b4f9397fbe08e6e51dfe23d4417acf5d3b8cb87c" +dependencies = [ + "dtoa", + "itoa", + "parking_lot 0.12.1", + "prometheus-client-derive-text-encode", +] + +[[package]] +name = "prometheus-client-derive-text-encode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a455fbcb954c1a7decf3c586e860fd7889cddf4b8e164be736dbac95a953cd" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "prost" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48e50df39172a3e7eb17e14642445da64996989bc212b583015435d39a58537" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools", + "lazy_static", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 1.0.109", + "tempfile", + "which", +] + +[[package]] +name = "prost-codec" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc34979ff898b6e141106178981ce2596c387ea6e62533facfc61a37fc879c0" +dependencies = [ + "asynchronous-codec", + "bytes", + "prost", + "thiserror", + "unsigned-varint", +] + +[[package]] +name = "prost-derive" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea9b0f8cbe5e15a8a042d030bd96668db28ecb567ec37d691971ff5731d2b1b" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "prost-types" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "379119666929a1afd7a043aa6cf96fa67a6dce9af60c88095a4686dbce4c9c88" +dependencies = [ + "prost", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +dependencies = [ + "byteorder", +] + +[[package]] +name = "quicksink" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77de3c815e5a160b1539c6592796801df2043ae35e123b46d73380cfa57af858" +dependencies = [ + "futures-core", + "futures-sink", + "pin-project-lite 0.1.12", +] + +[[package]] +name = "quinn-proto" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4ced82a24bb281af338b9e8f94429b6eca01b4e66d899f40031f074e74c9" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.20.8", + "slab", + "thiserror", + "tinyvec", + "tracing", + "webpki 0.22.0", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2 1.0.56", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.8", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "rbtag" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c64936fcc0b811890a9d90020f3df5cec9c604efde88af7db6a35d365132a3" +dependencies = [ + "rbtag_derive", +] + +[[package]] +name = "rbtag_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75511b710ccca8adbb211e04763bd8c78fed585b0ec188a20ed9b0dd95567c4" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "rcgen" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" +dependencies = [ + "pem", + "ring", + "time 0.3.20", + "x509-parser 0.13.2", + "yasna", +] + +[[package]] +name = "rcgen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +dependencies = [ + "pem", + "ring", + "time 0.3.20", + "yasna", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.8", + "redox_syscall 0.2.16", + "thiserror", +] + +[[package]] +name = "reed-solomon-novelpoly" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd8f48b2066e9f69ab192797d66da804d1935bf22763204ed3675740cb0f221" +dependencies = [ + "derive_more", + "fs-err", + "itertools", + "static_init 0.5.2", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43faa91b1c8b36841ee70e97188a869d37ae21759da6846d4be66de5bf7b12c" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "regalloc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "region" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + +[[package]] +name = "relay-bridge-hub-kusama-client" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-kusama", + "bp-bridge-hub-polkadot", + "bp-header-chain", + "bp-messages", + "bp-parachains", + "bp-polkadot", + "bp-runtime", + "bridge-runtime-common", + "parity-scale-codec", + "relay-substrate-client", + "scale-info", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "relay-bridge-hub-polkadot-client" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-kusama", + "bp-bridge-hub-polkadot", + "bp-header-chain", + "bp-kusama", + "bp-messages", + "bp-parachains", + "bp-polkadot-core", + "bp-runtime", + "bridge-runtime-common", + "parity-scale-codec", + "relay-substrate-client", + "scale-info", + "sp-consensus-grandpa", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "relay-bridge-hub-rococo-client" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-rococo", + "bp-bridge-hub-wococo", + "bp-header-chain", + "bp-messages", + "bp-parachains", + "bp-runtime", + "bp-wococo", + "bridge-runtime-common", + "parity-scale-codec", + "relay-substrate-client", + "scale-info", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "relay-bridge-hub-wococo-client" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-rococo", + "bp-bridge-hub-wococo", + "bp-header-chain", + "bp-messages", + "bp-parachains", + "bp-polkadot-core", + "bp-rococo", + "bp-runtime", + "bridge-runtime-common", + "parity-scale-codec", + "relay-substrate-client", + "scale-info", + "sp-consensus-grandpa", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "relay-kusama-client" +version = "0.1.0" +dependencies = [ + "bp-kusama", + "bp-runtime", + "relay-substrate-client", + "relay-utils", + "sp-core", +] + +[[package]] +name = "relay-millau-client" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-millau", + "bp-runtime", + "frame-support", + "frame-system", + "millau-runtime", + "pallet-transaction-payment", + "parity-scale-codec", + "relay-substrate-client", + "relay-utils", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "relay-polkadot-client" +version = "0.1.0" +dependencies = [ + "bp-polkadot", + "bp-runtime", + "relay-substrate-client", + "relay-utils", + "sp-core", +] + +[[package]] +name = "relay-rialto-client" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-rialto", + "bp-runtime", + "frame-support", + "frame-system", + "pallet-transaction-payment", + "parity-scale-codec", + "relay-substrate-client", + "relay-utils", + "rialto-runtime", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "relay-rialto-parachain-client" +version = "0.1.0" +dependencies = [ + "bp-bridge-hub-cumulus", + "bp-header-chain", + "bp-messages", + "bp-millau", + "bp-polkadot-core", + "bp-rialto-parachain", + "bp-runtime", + "bridge-runtime-common", + "parity-scale-codec", + "relay-substrate-client", + "scale-info", + "sp-core", + "sp-runtime", + "sp-weights", + "subxt", +] + +[[package]] +name = "relay-rococo-client" +version = "0.1.0" +dependencies = [ + "bp-rococo", + "bp-runtime", + "relay-substrate-client", + "relay-utils", + "sp-core", +] + +[[package]] +name = "relay-substrate-client" +version = "0.1.0" +dependencies = [ + "async-std", + "async-trait", + "bp-header-chain", + "bp-messages", + "bp-polkadot-core", + "bp-runtime", + "finality-relay", + "frame-support", + "frame-system", + "futures", + "jsonrpsee", + "log", + "num-traits", + "pallet-balances", + "pallet-bridge-messages", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-utility", + "parity-scale-codec", + "rand 0.8.5", + "relay-utils", + "sc-chain-spec", + "sc-rpc-api", + "sc-transaction-pool-api", + "scale-info", + "sp-core", + "sp-rpc", + "sp-runtime", + "sp-std 5.0.0", + "sp-trie", + "sp-version", + "thiserror", + "tokio", + "xcm", +] + +[[package]] +name = "relay-utils" +version = "0.1.0" +dependencies = [ + "ansi_term", + "anyhow", + "async-std", + "async-trait", + "backoff", + "bp-runtime", + "env_logger", + "futures", + "isahc", + "jsonpath_lib", + "log", + "num-traits", + "serde_json", + "sp-runtime", + "substrate-prometheus-endpoint", + "sysinfo", + "thiserror", + "time 0.3.20", + "tokio", +] + +[[package]] +name = "relay-westend-client" +version = "0.1.0" +dependencies = [ + "bp-runtime", + "bp-westend", + "relay-substrate-client", + "relay-utils", + "sp-core", +] + +[[package]] +name = "relay-wococo-client" +version = "0.1.0" +dependencies = [ + "bp-runtime", + "bp-wococo", + "relay-substrate-client", + "relay-utils", + "sp-core", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac 0.12.1", + "zeroize", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "rialto-bridge-node" +version = "0.1.0" +dependencies = [ + "clap 4.2.2", + "frame-benchmarking", + "frame-benchmarking-cli", + "frame-support", + "node-inspect", + "polkadot-node-core-pvf", + "polkadot-primitives", + "polkadot-runtime-parachains", + "polkadot-service", + "rialto-runtime", + "sc-cli", + "sc-executor", + "sc-service", + "serde_json", + "sp-authority-discovery", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-consensus-grandpa", + "sp-core", + "sp-runtime", + "substrate-build-script-utils", +] + +[[package]] +name = "rialto-parachain-collator" +version = "0.1.0" +dependencies = [ + "clap 4.2.2", + "cumulus-client-cli", + "cumulus-client-consensus-aura", + "cumulus-client-consensus-common", + "cumulus-client-network", + "cumulus-client-service", + "cumulus-primitives-core", + "cumulus-primitives-parachain-inherent", + "cumulus-relay-chain-interface", + "frame-benchmarking", + "frame-benchmarking-cli", + "jsonrpsee", + "log", + "pallet-transaction-payment-rpc", + "parity-scale-codec", + "polkadot-cli", + "polkadot-primitives", + "polkadot-service", + "rialto-parachain-runtime", + "sc-basic-authorship", + "sc-chain-spec", + "sc-cli", + "sc-client-api", + "sc-consensus", + "sc-executor", + "sc-network", + "sc-network-sync", + "sc-rpc", + "sc-rpc-api", + "sc-service", + "sc-telemetry", + "sc-tracing", + "sc-transaction-pool", + "serde", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-keystore", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-timestamp", + "sp-transaction-pool", + "substrate-build-script-utils", + "substrate-frame-rpc-system", + "substrate-prometheus-endpoint", +] + +[[package]] +name = "rialto-parachain-runtime" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-millau", + "bp-relayers", + "bp-rialto-parachain", + "bp-runtime", + "bridge-runtime-common", + "cumulus-pallet-aura-ext", + "cumulus-pallet-dmp-queue", + "cumulus-pallet-parachain-system", + "cumulus-pallet-xcm", + "cumulus-pallet-xcmp-queue", + "cumulus-primitives-core", + "cumulus-primitives-timestamp", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "hex-literal 0.4.1", + "pallet-aura", + "pallet-balances", + "pallet-bridge-grandpa", + "pallet-bridge-messages", + "pallet-bridge-relayers", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-xcm", + "parachain-info", + "parity-scale-codec", + "polkadot-parachain", + "scale-info", + "sp-api", + "sp-block-builder", + "sp-consensus-aura", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 5.0.0", + "sp-transaction-pool", + "sp-version", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "rialto-runtime" +version = "0.1.0" +dependencies = [ + "bp-messages", + "bp-millau", + "bp-relayers", + "bp-rialto", + "bp-runtime", + "bridge-runtime-common", + "env_logger", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-rpc-runtime-api", + "pallet-authority-discovery", + "pallet-babe", + "pallet-balances", + "pallet-beefy", + "pallet-beefy-mmr", + "pallet-bridge-beefy", + "pallet-bridge-grandpa", + "pallet-bridge-messages", + "pallet-bridge-relayers", + "pallet-grandpa", + "pallet-mmr", + "pallet-session", + "pallet-shift-session-manager", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-xcm", + "parity-scale-codec", + "polkadot-primitives", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "scale-info", + "sp-api", + "sp-authority-discovery", + "sp-block-builder", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-inherents", + "sp-io", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-std 5.0.0", + "sp-transaction-pool", + "sp-version", + "static_assertions", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rocksdb" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9562ea1d70c0cc63a34a22d977753b50cca91cc6b6527750463bd5dd8697bc" +dependencies = [ + "libc", + "librocksdb-sys", +] + +[[package]] +name = "rococo-runtime" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "binary-merkle-tree", + "frame-benchmarking", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal 0.3.4", + "log", + "pallet-authority-discovery", + "pallet-authorship", + "pallet-babe", + "pallet-balances", + "pallet-beefy", + "pallet-beefy-mmr", + "pallet-bounties", + "pallet-child-bounties", + "pallet-collective", + "pallet-democracy", + "pallet-elections-phragmen", + "pallet-grandpa", + "pallet-identity", + "pallet-im-online", + "pallet-indices", + "pallet-membership", + "pallet-mmr", + "pallet-multisig", + "pallet-nis", + "pallet-offences", + "pallet-preimage", + "pallet-proxy", + "pallet-recovery", + "pallet-scheduler", + "pallet-session", + "pallet-society", + "pallet-staking", + "pallet-state-trie-migration", + "pallet-sudo", + "pallet-timestamp", + "pallet-tips", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", + "pallet-utility", + "pallet-vesting", + "pallet-xcm", + "pallet-xcm-benchmarks", + "parity-scale-codec", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "rococo-runtime-constants", + "scale-info", + "serde", + "serde_derive", + "smallvec", + "sp-api", + "sp-authority-discovery", + "sp-block-builder", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-inherents", + "sp-io", + "sp-mmr-primitives", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", + "sp-transaction-pool", + "sp-version", + "static_assertions", + "substrate-wasm-builder", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "rococo-runtime-constants" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-core", + "sp-runtime", + "sp-weights", +] + +[[package]] +name = "rpassword" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +dependencies = [ + "libc", + "rtoolbox", + "winapi", +] + +[[package]] +name = "rtcp" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1919efd6d4a6a85d13388f9487549bb8e359f17198cc03ffd72f79b553873691" +dependencies = [ + "bytes", + "thiserror", + "webrtc-util", +] + +[[package]] +name = "rtnetlink" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322c53fd76a18698f1c27381d58091de3a043d356aa5bd0d510608b565f469a0" +dependencies = [ + "futures", + "log", + "netlink-packet-route", + "netlink-proto", + "nix", + "thiserror", + "tokio", +] + +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "rtp" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a095411ff00eed7b12e4c6a118ba984d113e1079582570d56a5ee723f11f80" +dependencies = [ + "async-trait", + "bytes", + "rand 0.8.5", + "serde", + "thiserror", + "webrtc-util", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.17", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "0.35.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "727a1a6d65f786ec22df8a81ca3121107f235970dc1705ed681d3e6e8b9cd5f9" +dependencies = [ + "bitflags", + "errno 0.2.8", + "io-lifetimes 0.7.5", + "libc", + "linux-raw-sys 0.0.46", + "windows-sys 0.42.0", +] + +[[package]] +name = "rustix" +version = "0.36.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" +dependencies = [ + "bitflags", + "errno 0.2.8", + "io-lifetimes 1.0.9", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b24138615de35e32031d041a09032ef3487a616d901ca4db224e7d557efae2" +dependencies = [ + "bitflags", + "errno 0.3.0", + "io-lifetimes 1.0.9", + "libc", + "linux-raw-sys 0.3.0", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64 0.13.1", + "log", + "ring", + "sct 0.6.1", + "webpki 0.21.4", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct 0.7.0", + "webpki 0.22.0", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.0", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "rw-stream-sink" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26338f5e09bb721b85b135ea05af7767c90b52f6de4f087d4f4a3a9d64e7dc04" +dependencies = [ + "futures", + "pin-project", + "static_assertions", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "safe_arch" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sc-allocator" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "log", + "sp-core", + "sp-wasm-interface", + "thiserror", +] + +[[package]] +name = "sc-authority-discovery" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "ip_network", + "libp2p", + "log", + "parity-scale-codec", + "prost", + "prost-build", + "rand 0.8.5", + "sc-client-api", + "sc-network", + "sc-network-common", + "sp-api", + "sp-authority-discovery", + "sp-blockchain", + "sp-core", + "sp-keystore", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "sc-basic-authorship" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "futures-timer", + "log", + "parity-scale-codec", + "sc-block-builder", + "sc-client-api", + "sc-proposer-metrics", + "sc-telemetry", + "sc-transaction-pool-api", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-inherents", + "sp-runtime", + "substrate-prometheus-endpoint", +] + +[[package]] +name = "sc-block-builder" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "sc-client-api", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-core", + "sp-inherents", + "sp-runtime", +] + +[[package]] +name = "sc-chain-spec" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "memmap2", + "sc-chain-spec-derive", + "sc-client-api", + "sc-executor", + "sc-network", + "sc-telemetry", + "serde", + "serde_json", + "sp-blockchain", + "sp-core", + "sp-runtime", + "sp-state-machine", +] + +[[package]] +name = "sc-chain-spec-derive" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "sc-cli" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "chrono", + "clap 4.2.2", + "fdlimit", + "futures", + "libp2p", + "log", + "names", + "parity-scale-codec", + "rand 0.8.5", + "regex", + "rpassword", + "sc-client-api", + "sc-client-db", + "sc-keystore", + "sc-network", + "sc-network-common", + "sc-service", + "sc-telemetry", + "sc-tracing", + "sc-utils", + "serde", + "serde_json", + "sp-blockchain", + "sp-core", + "sp-keyring", + "sp-keystore", + "sp-panic-handler", + "sp-runtime", + "sp-version", + "thiserror", + "tiny-bip39", + "tokio", +] + +[[package]] +name = "sc-client-api" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "fnv", + "futures", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-executor", + "sc-transaction-pool-api", + "sc-utils", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-database", + "sp-externalities", + "sp-keystore", + "sp-runtime", + "sp-state-machine", + "sp-storage", + "substrate-prometheus-endpoint", +] + +[[package]] +name = "sc-client-db" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "hash-db", + "kvdb", + "kvdb-memorydb", + "kvdb-rocksdb", + "linked-hash-map", + "log", + "parity-db", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-client-api", + "sc-state-db", + "schnellru", + "sp-arithmetic", + "sp-blockchain", + "sp-core", + "sp-database", + "sp-runtime", + "sp-state-machine", + "sp-trie", +] + +[[package]] +name = "sc-consensus" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "libp2p", + "log", + "mockall", + "parking_lot 0.12.1", + "sc-client-api", + "sc-utils", + "serde", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "sp-state-machine", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "sc-consensus-aura" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "futures", + "log", + "parity-scale-codec", + "sc-block-builder", + "sc-client-api", + "sc-consensus", + "sc-consensus-slots", + "sc-telemetry", + "sp-api", + "sp-application-crypto", + "sp-block-builder", + "sp-blockchain", + "sp-consensus", + "sp-consensus-aura", + "sp-consensus-slots", + "sp-core", + "sp-inherents", + "sp-keystore", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "sc-consensus-babe" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "fork-tree", + "futures", + "log", + "merlin", + "num-bigint", + "num-rational", + "num-traits", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-client-api", + "sc-consensus", + "sc-consensus-epochs", + "sc-consensus-slots", + "sc-keystore", + "sc-telemetry", + "scale-info", + "schnorrkel", + "sp-api", + "sp-application-crypto", + "sp-block-builder", + "sp-blockchain", + "sp-consensus", + "sp-consensus-babe", + "sp-consensus-slots", + "sp-consensus-vrf", + "sp-core", + "sp-inherents", + "sp-keystore", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "sc-consensus-babe-rpc" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "jsonrpsee", + "sc-consensus-babe", + "sc-consensus-epochs", + "sc-rpc-api", + "serde", + "sp-api", + "sp-application-crypto", + "sp-blockchain", + "sp-consensus", + "sp-consensus-babe", + "sp-core", + "sp-keystore", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sc-consensus-beefy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "async-trait", + "fnv", + "futures", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-client-api", + "sc-consensus", + "sc-keystore", + "sc-network", + "sc-network-common", + "sc-network-gossip", + "sc-network-sync", + "sc-utils", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-beefy", + "sp-core", + "sp-keystore", + "sp-mmr-primitives", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", + "wasm-timer", +] + +[[package]] +name = "sc-consensus-beefy-rpc" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "jsonrpsee", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-consensus-beefy", + "sc-rpc", + "serde", + "sp-consensus-beefy", + "sp-core", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sc-consensus-epochs" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "fork-tree", + "parity-scale-codec", + "sc-client-api", + "sc-consensus", + "sp-blockchain", + "sp-runtime", +] + +[[package]] +name = "sc-consensus-grandpa" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "ahash 0.8.3", + "array-bytes 4.2.0", + "async-trait", + "dyn-clone", + "finality-grandpa", + "fork-tree", + "futures", + "futures-timer", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "rand 0.8.5", + "sc-block-builder", + "sc-chain-spec", + "sc-client-api", + "sc-consensus", + "sc-network", + "sc-network-common", + "sc-network-gossip", + "sc-telemetry", + "sc-utils", + "serde_json", + "sp-api", + "sp-application-crypto", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-grandpa", + "sp-core", + "sp-keystore", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "sc-consensus-grandpa-rpc" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "finality-grandpa", + "futures", + "jsonrpsee", + "log", + "parity-scale-codec", + "sc-client-api", + "sc-consensus-grandpa", + "sc-rpc", + "serde", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sc-consensus-slots" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "log", + "parity-scale-codec", + "sc-client-api", + "sc-consensus", + "sc-telemetry", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-slots", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-state-machine", +] + +[[package]] +name = "sc-executor" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "lru 0.8.1", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-executor-common", + "sc-executor-wasmi", + "sc-executor-wasmtime", + "sp-api", + "sp-core", + "sp-externalities", + "sp-io", + "sp-panic-handler", + "sp-runtime-interface", + "sp-trie", + "sp-version", + "sp-wasm-interface", + "tracing", + "wasmi", +] + +[[package]] +name = "sc-executor-common" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "sc-allocator", + "sp-maybe-compressed-blob", + "sp-wasm-interface", + "thiserror", + "wasm-instrument", + "wasmi", +] + +[[package]] +name = "sc-executor-wasmi" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "log", + "sc-allocator", + "sc-executor-common", + "sp-runtime-interface", + "sp-wasm-interface", + "wasmi", +] + +[[package]] +name = "sc-executor-wasmtime" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "anyhow", + "cfg-if 1.0.0", + "libc", + "log", + "once_cell", + "rustix 0.36.11", + "sc-allocator", + "sc-executor-common", + "sp-runtime-interface", + "sp-wasm-interface", + "wasmtime", +] + +[[package]] +name = "sc-informant" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "ansi_term", + "futures", + "futures-timer", + "log", + "sc-client-api", + "sc-network", + "sc-network-common", + "sp-blockchain", + "sp-runtime", +] + +[[package]] +name = "sc-keystore" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "async-trait", + "parking_lot 0.12.1", + "serde_json", + "sp-application-crypto", + "sp-core", + "sp-keystore", + "thiserror", +] + +[[package]] +name = "sc-network" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "async-channel", + "async-trait", + "asynchronous-codec", + "bytes", + "either", + "fnv", + "futures", + "futures-timer", + "ip_network", + "libp2p", + "linked_hash_set", + "log", + "lru 0.8.1", + "mockall", + "parity-scale-codec", + "parking_lot 0.12.1", + "pin-project", + "rand 0.8.5", + "sc-block-builder", + "sc-client-api", + "sc-consensus", + "sc-network-common", + "sc-peerset", + "sc-utils", + "serde", + "serde_json", + "smallvec", + "snow", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", + "unsigned-varint", + "zeroize", +] + +[[package]] +name = "sc-network-bitswap" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "cid", + "futures", + "libp2p", + "log", + "prost", + "prost-build", + "sc-client-api", + "sc-network", + "sc-network-common", + "sp-blockchain", + "sp-runtime", + "thiserror", + "unsigned-varint", +] + +[[package]] +name = "sc-network-common" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "async-trait", + "bitflags", + "bytes", + "futures", + "futures-timer", + "libp2p", + "parity-scale-codec", + "prost-build", + "sc-consensus", + "sc-peerset", + "sc-utils", + "serde", + "smallvec", + "sp-blockchain", + "sp-consensus", + "sp-consensus-grandpa", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", + "zeroize", +] + +[[package]] +name = "sc-network-gossip" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "ahash 0.8.3", + "futures", + "futures-timer", + "libp2p", + "log", + "lru 0.8.1", + "sc-network", + "sc-network-common", + "sc-peerset", + "sp-runtime", + "substrate-prometheus-endpoint", + "tracing", +] + +[[package]] +name = "sc-network-light" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "futures", + "libp2p", + "log", + "parity-scale-codec", + "prost", + "prost-build", + "sc-client-api", + "sc-network", + "sc-network-common", + "sc-peerset", + "sp-blockchain", + "sp-core", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sc-network-sync" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "async-trait", + "fork-tree", + "futures", + "futures-timer", + "libp2p", + "log", + "lru 0.8.1", + "mockall", + "parity-scale-codec", + "prost", + "prost-build", + "sc-client-api", + "sc-consensus", + "sc-network", + "sc-network-common", + "sc-peerset", + "sc-utils", + "smallvec", + "sp-arithmetic", + "sp-blockchain", + "sp-consensus", + "sp-consensus-grandpa", + "sp-core", + "sp-runtime", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "sc-network-transactions" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "futures", + "libp2p", + "log", + "parity-scale-codec", + "pin-project", + "sc-network", + "sc-network-common", + "sc-peerset", + "sc-utils", + "sp-consensus", + "sp-runtime", + "substrate-prometheus-endpoint", +] + +[[package]] +name = "sc-offchain" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "bytes", + "fnv", + "futures", + "futures-timer", + "hyper", + "hyper-rustls", + "libp2p", + "num_cpus", + "once_cell", + "parity-scale-codec", + "parking_lot 0.12.1", + "rand 0.8.5", + "sc-client-api", + "sc-network", + "sc-network-common", + "sc-peerset", + "sc-utils", + "sp-api", + "sp-core", + "sp-offchain", + "sp-runtime", + "threadpool", + "tracing", +] + +[[package]] +name = "sc-peerset" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "libp2p", + "log", + "sc-utils", + "serde_json", + "wasm-timer", +] + +[[package]] +name = "sc-proposer-metrics" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "log", + "substrate-prometheus-endpoint", +] + +[[package]] +name = "sc-rpc" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "jsonrpsee", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-block-builder", + "sc-chain-spec", + "sc-client-api", + "sc-rpc-api", + "sc-tracing", + "sc-transaction-pool-api", + "sc-utils", + "serde_json", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-keystore", + "sp-offchain", + "sp-rpc", + "sp-runtime", + "sp-session", + "sp-version", + "tokio", +] + +[[package]] +name = "sc-rpc-api" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "jsonrpsee", + "parity-scale-codec", + "sc-chain-spec", + "sc-transaction-pool-api", + "scale-info", + "serde", + "serde_json", + "sp-core", + "sp-rpc", + "sp-runtime", + "sp-version", + "thiserror", +] + +[[package]] +name = "sc-rpc-server" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "http", + "jsonrpsee", + "log", + "serde_json", + "substrate-prometheus-endpoint", + "tokio", + "tower", + "tower-http", +] + +[[package]] +name = "sc-rpc-spec-v2" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "futures", + "futures-util", + "hex", + "jsonrpsee", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-chain-spec", + "sc-client-api", + "sc-transaction-pool-api", + "serde", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-runtime", + "sp-version", + "thiserror", + "tokio-stream", +] + +[[package]] +name = "sc-service" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "directories", + "exit-future", + "futures", + "futures-timer", + "jsonrpsee", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "pin-project", + "rand 0.8.5", + "sc-block-builder", + "sc-chain-spec", + "sc-client-api", + "sc-client-db", + "sc-consensus", + "sc-executor", + "sc-informant", + "sc-keystore", + "sc-network", + "sc-network-bitswap", + "sc-network-common", + "sc-network-light", + "sc-network-sync", + "sc-network-transactions", + "sc-offchain", + "sc-rpc", + "sc-rpc-server", + "sc-rpc-spec-v2", + "sc-storage-monitor", + "sc-sysinfo", + "sc-telemetry", + "sc-tracing", + "sc-transaction-pool", + "sc-transaction-pool-api", + "sc-utils", + "serde", + "serde_json", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-externalities", + "sp-keystore", + "sp-runtime", + "sp-session", + "sp-state-machine", + "sp-storage", + "sp-transaction-pool", + "sp-transaction-storage-proof", + "sp-trie", + "sp-version", + "static_init 1.0.3", + "substrate-prometheus-endpoint", + "tempfile", + "thiserror", + "tokio", + "tracing", + "tracing-futures", +] + +[[package]] +name = "sc-state-db" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "sp-core", +] + +[[package]] +name = "sc-storage-monitor" +version = "0.1.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "clap 4.2.2", + "fs4", + "futures", + "log", + "sc-client-db", + "sc-utils", + "sp-core", + "thiserror", + "tokio", +] + +[[package]] +name = "sc-sync-state-rpc" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "jsonrpsee", + "parity-scale-codec", + "sc-chain-spec", + "sc-client-api", + "sc-consensus-babe", + "sc-consensus-epochs", + "sc-consensus-grandpa", + "serde", + "serde_json", + "sp-blockchain", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sc-sysinfo" +version = "6.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "libc", + "log", + "rand 0.8.5", + "rand_pcg", + "regex", + "sc-telemetry", + "serde", + "serde_json", + "sp-core", + "sp-io", + "sp-std 5.0.0", +] + +[[package]] +name = "sc-telemetry" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "chrono", + "futures", + "libp2p", + "log", + "parking_lot 0.12.1", + "pin-project", + "rand 0.8.5", + "sc-utils", + "serde", + "serde_json", + "thiserror", + "wasm-timer", +] + +[[package]] +name = "sc-tracing" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "ansi_term", + "atty", + "chrono", + "lazy_static", + "libc", + "log", + "once_cell", + "parking_lot 0.12.1", + "regex", + "rustc-hash", + "sc-client-api", + "sc-rpc-server", + "sc-tracing-proc-macro", + "serde", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-rpc", + "sp-runtime", + "sp-tracing", + "thiserror", + "tracing", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "sc-tracing-proc-macro" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "sc-transaction-pool" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "futures", + "futures-timer", + "linked-hash-map", + "log", + "num-traits", + "parity-scale-codec", + "parking_lot 0.12.1", + "sc-client-api", + "sc-transaction-pool-api", + "sc-utils", + "serde", + "sp-api", + "sp-blockchain", + "sp-core", + "sp-runtime", + "sp-tracing", + "sp-transaction-pool", + "substrate-prometheus-endpoint", + "thiserror", +] + +[[package]] +name = "sc-transaction-pool-api" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "futures", + "log", + "serde", + "sp-blockchain", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "sc-utils" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-channel", + "futures", + "futures-timer", + "lazy_static", + "log", + "parking_lot 0.12.1", + "prometheus", + "sp-arithmetic", +] + +[[package]] +name = "scale-bits" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd7aca73785181cc41f0bbe017263e682b585ca660540ba569133901d013ecf" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "scale-decode" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d823d4be477fc33321f93d08fb6c2698273d044f01362dc27573a750deb7c233" +dependencies = [ + "parity-scale-codec", + "scale-bits", + "scale-info", + "thiserror", +] + +[[package]] +name = "scale-info" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cfdffd972d76b22f3d7f81c8be34b2296afd3a25e0a547bd9abe340a4dbbe97" +dependencies = [ + "bitvec", + "cfg-if 1.0.0", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61fa974aea2d63dd18a4ec3a49d59af9f34178c73a4f56d2f18205628d00681e" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "scale-value" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a5e7810815bd295da73e4216d1dfbced3c7c7c7054d70fa5f6e4c58123fff4" +dependencies = [ + "either", + "frame-metadata", + "parity-scale-codec", + "scale-bits", + "scale-decode", + "scale-info", + "serde", + "thiserror", + "yap", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "schnellru" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +dependencies = [ + "ahash 0.8.3", + "cfg-if 1.0.0", + "hashbrown 0.13.2", +] + +[[package]] +name = "schnorrkel" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "curve25519-dalek 2.1.3", + "getrandom 0.1.16", + "merlin", + "rand 0.7.3", + "rand_core 0.5.1", + "sha2 0.8.2", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sdp" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d22a5ef407871893fd72b4562ee15e4742269b173959db4b8df6f538c414e13" +dependencies = [ + "rand 0.8.5", + "substring", + "thiserror", + "url", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct 0.1.1", + "der 0.6.1", + "generic-array 0.14.6", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48518a2b5775ba8ca5b46596aae011caa431e6ce7e4a67ead66d92f08884220e" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.1", + "generic-array 0.14.6", + "pkcs8 0.10.1", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +dependencies = [ + "digest 0.10.6", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "signal-hook" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-async-std" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4aa94397e2023af5b7cff5b8d4785e935cfb77f0e4aab0cae3b26258ace556" +dependencies = [ + "async-io", + "futures-lite", + "libc", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +dependencies = [ + "digest 0.10.6", + "rand_core 0.6.4", +] + +[[package]] +name = "simba" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50582927ed6f77e4ac020c057f37a268fc6aebc29225050365aacbb9deeeddc4" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" + +[[package]] +name = "slot-range-helper" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "enumn", + "parity-scale-codec", + "paste", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "sluice" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" +dependencies = [ + "async-channel", + "futures-core", + "futures-io", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "snap" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" + +[[package]] +name = "snow" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733" +dependencies = [ + "aes-gcm 0.9.4", + "blake2", + "chacha20poly1305", + "curve25519-dalek 4.0.0-rc.1", + "rand_core 0.6.4", + "ring", + "rustc_version", + "sha2 0.10.6", + "subtle", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +dependencies = [ + "base64 0.13.1", + "bytes", + "flate2", + "futures", + "http", + "httparse", + "log", + "rand 0.8.5", + "sha-1", +] + +[[package]] +name = "sp-api" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "scale-info", + "sp-api-proc-macro", + "sp-core", + "sp-metadata-ir", + "sp-runtime", + "sp-state-machine", + "sp-std 5.0.0", + "sp-trie", + "sp-version", + "thiserror", +] + +[[package]] +name = "sp-api-proc-macro" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "Inflector", + "blake2", + "expander 1.0.0", + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "sp-application-crypto" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-arithmetic" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std 5.0.0", + "static_assertions", +] + +[[package]] +name = "sp-authority-discovery" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-block-builder" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "sp-api", + "sp-inherents", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-blockchain" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "log", + "lru 0.8.1", + "parity-scale-codec", + "parking_lot 0.12.1", + "sp-api", + "sp-consensus", + "sp-database", + "sp-runtime", + "sp-state-machine", + "thiserror", +] + +[[package]] +name = "sp-consensus" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "futures", + "log", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-state-machine", + "thiserror", +] + +[[package]] +name = "sp-consensus-aura" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-application-crypto", + "sp-consensus", + "sp-consensus-slots", + "sp-inherents", + "sp-runtime", + "sp-std 5.0.0", + "sp-timestamp", +] + +[[package]] +name = "sp-consensus-babe" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "merlin", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-consensus", + "sp-consensus-slots", + "sp-consensus-vrf", + "sp-core", + "sp-inherents", + "sp-keystore", + "sp-runtime", + "sp-std 5.0.0", + "sp-timestamp", +] + +[[package]] +name = "sp-consensus-beefy" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "lazy_static", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-io", + "sp-mmr-primitives", + "sp-runtime", + "sp-std 5.0.0", + "strum", +] + +[[package]] +name = "sp-consensus-grandpa" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "finality-grandpa", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-application-crypto", + "sp-core", + "sp-keystore", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-consensus-slots" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-std 5.0.0", + "sp-timestamp", +] + +[[package]] +name = "sp-consensus-vrf" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "scale-info", + "schnorrkel", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-core" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "array-bytes 4.2.0", + "bitflags", + "blake2", + "bounded-collections", + "bs58", + "dyn-clonable", + "ed25519-zebra", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde", + "lazy_static", + "libsecp256k1", + "log", + "merlin", + "parity-scale-codec", + "parking_lot 0.12.1", + "primitive-types", + "rand 0.8.5", + "regex", + "scale-info", + "schnorrkel", + "secp256k1", + "secrecy", + "serde", + "sp-core-hashing 5.0.0", + "sp-debug-derive", + "sp-externalities", + "sp-runtime-interface", + "sp-std 5.0.0", + "sp-storage", + "ss58-registry", + "substrate-bip39", + "thiserror", + "tiny-bip39", + "zeroize", +] + +[[package]] +name = "sp-core-hashing" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "blake2b_simd", + "byteorder", + "digest 0.10.6", + "sha2 0.10.6", + "sha3", + "sp-std 5.0.0", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc2d1947252b7a4e403b0a260f596920443742791765ec111daa2bbf98eff25" +dependencies = [ + "blake2", + "byteorder", + "digest 0.10.6", + "sha2 0.10.6", + "sha3", + "sp-std 6.0.0", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing-proc-macro" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "sp-core-hashing 5.0.0", + "syn 2.0.14", +] + +[[package]] +name = "sp-database" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "kvdb", + "parking_lot 0.12.1", +] + +[[package]] +name = "sp-debug-derive" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "sp-externalities" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-std 5.0.0", + "sp-storage", +] + +[[package]] +name = "sp-inherents" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "impl-trait-for-tuples", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", + "thiserror", +] + +[[package]] +name = "sp-io" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "bytes", + "ed25519", + "ed25519-dalek", + "futures", + "libsecp256k1", + "log", + "parity-scale-codec", + "rustversion", + "secp256k1", + "sp-core", + "sp-externalities", + "sp-keystore", + "sp-runtime-interface", + "sp-state-machine", + "sp-std 5.0.0", + "sp-tracing", + "sp-trie", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-keyring" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "lazy_static", + "sp-core", + "sp-runtime", + "strum", +] + +[[package]] +name = "sp-keystore" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "futures", + "merlin", + "parity-scale-codec", + "parking_lot 0.12.1", + "schnorrkel", + "serde", + "sp-core", + "sp-externalities", + "thiserror", +] + +[[package]] +name = "sp-maybe-compressed-blob" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "thiserror", + "zstd 0.12.3+zstd.1.5.2", +] + +[[package]] +name = "sp-metadata-ir" +version = "0.1.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-mmr-primitives" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "ckb-merkle-mountain-range 0.5.2", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-api", + "sp-core", + "sp-debug-derive", + "sp-runtime", + "sp-std 5.0.0", + "thiserror", +] + +[[package]] +name = "sp-npos-elections" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-arithmetic", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-offchain" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "sp-api", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "sp-panic-handler" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "backtrace", + "lazy_static", + "regex", +] + +[[package]] +name = "sp-rpc" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "rustc-hash", + "serde", + "sp-core", +] + +[[package]] +name = "sp-runtime" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "paste", + "rand 0.8.5", + "scale-info", + "serde", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-std 5.0.0", + "sp-weights", +] + +[[package]] +name = "sp-runtime-interface" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "primitive-types", + "sp-externalities", + "sp-runtime-interface-proc-macro", + "sp-std 5.0.0", + "sp-storage", + "sp-tracing", + "sp-wasm-interface", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "sp-session" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-api", + "sp-core", + "sp-runtime", + "sp-staking", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-staking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-state-machine" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "parking_lot 0.12.1", + "rand 0.8.5", + "smallvec", + "sp-core", + "sp-externalities", + "sp-panic-handler", + "sp-std 5.0.0", + "sp-trie", + "thiserror", + "tracing", +] + +[[package]] +name = "sp-std" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" + +[[package]] +name = "sp-std" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af0ee286f98455272f64ac5bb1384ff21ac029fbb669afbaf48477faff12760e" + +[[package]] +name = "sp-storage" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-timestamp" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "futures-timer", + "log", + "parity-scale-codec", + "sp-inherents", + "sp-runtime", + "sp-std 5.0.0", + "thiserror", +] + +[[package]] +name = "sp-tracing" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "sp-std 5.0.0", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sp-transaction-pool" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "sp-api", + "sp-runtime", +] + +[[package]] +name = "sp-transaction-storage-proof" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "log", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-inherents", + "sp-runtime", + "sp-std 5.0.0", + "sp-trie", +] + +[[package]] +name = "sp-trie" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "ahash 0.8.3", + "hash-db", + "hashbrown 0.13.2", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot 0.12.1", + "scale-info", + "schnellru", + "sp-core", + "sp-std 5.0.0", + "thiserror", + "tracing", + "trie-db", + "trie-root", +] + +[[package]] +name = "sp-version" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-core-hashing-proc-macro", + "sp-runtime", + "sp-std 5.0.0", + "sp-version-proc-macro", + "thiserror", +] + +[[package]] +name = "sp-version-proc-macro" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "sp-wasm-interface" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std 5.0.0", + "wasmi", + "wasmtime", +] + +[[package]] +name = "sp-weights" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic", + "sp-core", + "sp-debug-derive", + "sp-std 5.0.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0445c905640145c7ea8c1993555957f65e7c46d0535b91ba501bc9bfc85522f" +dependencies = [ + "base64ct", + "der 0.7.1", +] + +[[package]] +name = "ss58-registry" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecf0bd63593ef78eca595a7fc25e9a443ca46fe69fd472f8f09f5245cdcd769d" +dependencies = [ + "Inflector", + "num-format", + "proc-macro2 1.0.56", + "quote 1.0.26", + "serde", + "serde_json", + "unicode-xid 0.2.4", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "static_init" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11b73400442027c4adedda20a9f9b7945234a5bd8d5f7e86da22bd5d0622369c" +dependencies = [ + "cfg_aliases", + "libc", + "parking_lot 0.11.2", + "static_init_macro 0.5.0", +] + +[[package]] +name = "static_init" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" +dependencies = [ + "bitflags", + "cfg_aliases", + "libc", + "parking_lot 0.11.2", + "parking_lot_core 0.8.6", + "static_init_macro 1.0.2", + "winapi", +] + +[[package]] +name = "static_init_macro" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2261c91034a1edc3fc4d1b80e89d82714faede0515c14a75da10cb941546bbf" +dependencies = [ + "cfg_aliases", + "memchr", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "static_init_macro" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" +dependencies = [ + "cfg_aliases", + "memchr", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "storage-proof-fuzzer" +version = "0.1.0" +dependencies = [ + "bp-runtime", + "env_logger", + "honggfuzz", + "log", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-std 5.0.0", + "sp-trie", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap 2.34.0", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck 0.3.3", + "proc-macro-error", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2 1.0.56", + "quote 1.0.26", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "stun" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e94b1ec00bad60e6410e058b52f1c66de3dc5fe4d62d09b3e52bb7d3b73e25" +dependencies = [ + "base64 0.13.1", + "crc", + "lazy_static", + "md-5", + "rand 0.8.5", + "ring", + "subtle", + "thiserror", + "tokio", + "url", + "webrtc-util", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +dependencies = [ + "hmac 0.11.0", + "pbkdf2 0.8.0", + "schnorrkel", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "substrate-build-script-utils" +version = "3.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "platforms 2.0.0", +] + +[[package]] +name = "substrate-frame-rpc-system" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "frame-system-rpc-runtime-api", + "futures", + "jsonrpsee", + "log", + "parity-scale-codec", + "sc-rpc-api", + "sc-transaction-pool-api", + "sp-api", + "sp-block-builder", + "sp-blockchain", + "sp-core", + "sp-runtime", +] + +[[package]] +name = "substrate-prometheus-endpoint" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "hyper", + "log", + "prometheus", + "thiserror", + "tokio", +] + +[[package]] +name = "substrate-relay" +version = "1.0.1" +dependencies = [ + "anyhow", + "async-std", + "async-trait", + "bp-header-chain", + "bp-messages", + "bp-millau", + "bp-parachains", + "bp-polkadot-core", + "bp-rialto", + "bp-rialto-parachain", + "bp-runtime", + "bp-test-utils", + "bridge-runtime-common", + "finality-grandpa", + "frame-support", + "futures", + "hex", + "hex-literal 0.4.1", + "log", + "millau-runtime", + "num-format", + "num-traits", + "pallet-bridge-parachains", + "parachains-relay", + "parity-scale-codec", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "rbtag", + "relay-bridge-hub-kusama-client", + "relay-bridge-hub-polkadot-client", + "relay-bridge-hub-rococo-client", + "relay-bridge-hub-wococo-client", + "relay-kusama-client", + "relay-millau-client", + "relay-polkadot-client", + "relay-rialto-client", + "relay-rialto-parachain-client", + "relay-rococo-client", + "relay-substrate-client", + "relay-utils", + "relay-westend-client", + "relay-wococo-client", + "rialto-runtime", + "signal-hook", + "signal-hook-async-std", + "sp-core", + "sp-keyring", + "sp-runtime", + "structopt", + "strum", + "substrate-relay-helper", + "tempfile", + "xcm", +] + +[[package]] +name = "substrate-relay-helper" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-std", + "async-trait", + "bp-header-chain", + "bp-messages", + "bp-parachains", + "bp-polkadot-core", + "bp-relayers", + "bp-rialto", + "bp-rialto-parachain", + "bp-rococo", + "bp-runtime", + "bp-wococo", + "bridge-runtime-common", + "finality-grandpa", + "finality-relay", + "frame-support", + "frame-system", + "futures", + "hex", + "log", + "messages-relay", + "num-traits", + "pallet-balances", + "pallet-bridge-grandpa", + "pallet-bridge-messages", + "pallet-bridge-parachains", + "pallet-transaction-payment", + "parachains-relay", + "parity-scale-codec", + "relay-rialto-client", + "relay-rococo-client", + "relay-substrate-client", + "relay-utils", + "relay-wococo-client", + "rialto-runtime", + "sp-consensus-grandpa", + "sp-core", + "sp-runtime", + "thiserror", +] + +[[package]] +name = "substrate-rpc-client" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "jsonrpsee", + "log", + "sc-rpc-api", + "serde", + "sp-runtime", +] + +[[package]] +name = "substrate-state-trie-migration-rpc" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "jsonrpsee", + "log", + "parity-scale-codec", + "sc-client-api", + "sc-rpc-api", + "scale-info", + "serde", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-trie", + "trie-db", +] + +[[package]] +name = "substrate-wasm-builder" +version = "5.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "ansi_term", + "build-helper", + "cargo_metadata", + "filetime", + "sp-maybe-compressed-blob", + "strum", + "tempfile", + "toml 0.7.3", + "walkdir", + "wasm-opt", +] + +[[package]] +name = "substring" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" +dependencies = [ + "autocfg", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "subxt" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54639dba6a113584083968b6a8f457dedae612abe1bd214762101ca29f12e332" +dependencies = [ + "base58", + "blake2", + "derivative", + "frame-metadata", + "futures", + "getrandom 0.2.8", + "hex", + "impl-serde", + "parity-scale-codec", + "parking_lot 0.12.1", + "primitive-types", + "scale-bits", + "scale-decode", + "scale-info", + "scale-value", + "serde", + "serde_json", + "sp-core-hashing 6.0.0", + "subxt-macro", + "subxt-metadata", + "thiserror", + "tracing", +] + +[[package]] +name = "subxt-codegen" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e86cb719003f1cedf2710a6e55ca4c37aba4c989bbd3b81dd1c52af9e4827e" +dependencies = [ + "darling", + "frame-metadata", + "heck 0.4.1", + "hex", + "jsonrpsee", + "parity-scale-codec", + "proc-macro-error", + "proc-macro2 1.0.56", + "quote 1.0.26", + "scale-info", + "subxt-metadata", + "syn 1.0.109", + "tokio", +] + +[[package]] +name = "subxt-macro" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74c08de402a78c4c06c3ee3702c80e519efdcb65911348e018b6998d04404916" +dependencies = [ + "darling", + "proc-macro-error", + "subxt-codegen", + "syn 1.0.109", +] + +[[package]] +name = "subxt-metadata" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2593ab5f53435e6352675af4f9851342607f37785d84c7a3fb3139550d3c35f0" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-core-hashing 6.0.0", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "unicode-xid 0.2.4", +] + +[[package]] +name = "sysinfo" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2f3ca6693feb29a89724516f016488e9aafc7f37264f898593ee4b942f31b" +dependencies = [ + "cfg-if 1.0.0", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "winapi", +] + +[[package]] +name = "system-configuration" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75182f12f490e953596550b65ee31bda7c8e043d9386174b353bda50838c3fd" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" + +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "redox_syscall 0.3.5", + "rustix 0.37.3", + "windows-sys 0.45.0", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "thousands" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820" + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "thrift" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b82ca8f46f95b3ce96081fe3dd89160fdea970c254bb72925255d1b62aae692e" +dependencies = [ + "byteorder", + "integer-encoding", + "log", + "ordered-float", + "threadpool", +] + +[[package]] +name = "tikv-jemalloc-ctl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37706572f4b151dff7a0146e040804e9c26fe3a3118591112f05cf12a4216c1" +dependencies = [ + "libc", + "paste", + "tikv-jemalloc-sys", +] + +[[package]] +name = "tikv-jemalloc-sys" +version = "0.5.3+5.3.0-patched" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a678df20055b43e57ef8cddde41cdfda9a3c1a060b67f4c5836dfb1d78543ba8" +dependencies = [ + "cc", + "libc", +] + +[[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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +dependencies = [ + "itoa", + "libc", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +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.6", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +dependencies = [ + "autocfg", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot 0.12.1", + "pin-project-lite 0.2.9", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.45.0", +] + +[[package]] +name = "tokio-macros" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.8", + "tokio", + "webpki 0.22.0", +] + +[[package]] +name = "tokio-stream" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +dependencies = [ + "futures-core", + "pin-project-lite 0.2.9", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite 0.2.9", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite 0.2.9", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if 1.0.0", + "log", + "pin-project-lite 0.2.9", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-gum" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "polkadot-node-jaeger", + "polkadot-primitives", + "tracing", + "tracing-gum-proc-macro", +] + +[[package]] +name = "tracing-gum-proc-macro" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "expander 2.0.0", + "proc-macro-crate", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "parking_lot 0.11.2", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "trie-db" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "767abe6ffed88a1889671a102c2861ae742726f52e0a5a425b92c9fbfa7e9c85" +dependencies = [ + "hash-db", + "hashbrown 0.13.2", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-root" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" +dependencies = [ + "hash-db", +] + +[[package]] +name = "trust-dns-proto" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" +dependencies = [ + "async-trait", + "cfg-if 1.0.0", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.2.3", + "ipnet", + "lazy_static", + "rand 0.8.5", + "smallvec", + "socket2", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" +dependencies = [ + "cfg-if 1.0.0", + "futures-util", + "ipconfig", + "lazy_static", + "lru-cache", + "parking_lot 0.12.1", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", + "trust-dns-proto", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "try-runtime-cli" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#a6cb6d0fb79c303c9af513e856abfb61fc6d8d74" +dependencies = [ + "async-trait", + "clap 4.2.2", + "frame-remote-externalities", + "hex", + "log", + "parity-scale-codec", + "sc-cli", + "sc-executor", + "sc-service", + "serde", + "serde_json", + "sp-api", + "sp-consensus-aura", + "sp-consensus-babe", + "sp-core", + "sp-debug-derive", + "sp-externalities", + "sp-inherents", + "sp-io", + "sp-keystore", + "sp-rpc", + "sp-runtime", + "sp-state-machine", + "sp-timestamp", + "sp-transaction-storage-proof", + "sp-version", + "sp-weights", + "substrate-rpc-client", + "zstd 0.12.3+zstd.1.5.2", +] + +[[package]] +name = "tt-call" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f195fd851901624eee5a58c4bb2b4f06399148fcd0ed336e6f1cb60a9881df" + +[[package]] +name = "turn" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4712ee30d123ec7ae26d1e1b218395a16c87cdbaf4b3925d170d684af62ea5e8" +dependencies = [ + "async-trait", + "base64 0.13.1", + "futures", + "log", + "md-5", + "rand 0.8.5", + "ring", + "stun", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if 1.0.0", + "digest 0.10.6", + "rand 0.8.5", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + +[[package]] +name = "universal-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unsigned-varint" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" +dependencies = [ + "asynchronous-codec", + "bytes", + "futures-io", + "futures-util", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna 0.3.0", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +dependencies = [ + "getrandom 0.2.8", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "value-bag" +version = "1.0.0-alpha.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" +dependencies = [ + "ctor", + "version_check", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "waitgroup" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1f50000a783467e6c0200f9d10642f4bc424e39efc1b770203e88b488f79292" +dependencies = [ + "atomic-waker", +] + +[[package]] +name = "waker-fn" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote 1.0.26", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "wasm-instrument" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa1dafb3e60065305741e83db35c6c2584bb3725b692b5b66148a38d72ace6cd" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "wasm-opt" +version = "0.111.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a303793cbc01fb96551badfc7367db6007396bba6bac97936b3c8b6f7fdb41" +dependencies = [ + "anyhow", + "libc", + "strum", + "strum_macros", + "tempfile", + "thiserror", + "wasm-opt-cxx-sys", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-cxx-sys" +version = "0.111.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c9deb56f8a9f2ec177b3bd642a8205621835944ed5da55f2388ef216aca5a4" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-sys" +version = "0.111.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4432e28b542738a9776cedf92e8a99d8991c7b4667ee2c7ccddfb479dd2856a7" +dependencies = [ + "anyhow", + "cc", + "cxx", + "cxx-build", + "regex", +] + +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmi" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c326c93fbf86419608361a2c925a31754cf109da1b8b55737070b4d6669422" +dependencies = [ + "parity-wasm", + "wasmi-validation", + "wasmi_core", +] + +[[package]] +name = "wasmi-validation" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ff416ad1ff0c42e5a926ed5d5fab74c0f098749aa0ad8b2a34b982ce0e867b" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "wasmi_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" +dependencies = [ + "downcast-rs", + "libm 0.2.6", + "memory_units", + "num-rational", + "num-traits", + "region", +] + +[[package]] +name = "wasmparser" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" +dependencies = [ + "indexmap", + "url", +] + +[[package]] +name = "wasmtime" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e89f9819523447330ffd70367ef4a18d8c832e24e8150fe054d1d912841632" +dependencies = [ + "anyhow", + "bincode", + "cfg-if 1.0.0", + "indexmap", + "libc", + "log", + "object 0.29.0", + "once_cell", + "paste", + "psm", + "rayon", + "serde", + "target-lexicon", + "wasmparser", + "wasmtime-cache", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd3a5e46c198032da934469f3a6e48649d1f9142438e4fd4617b68a35644b8a" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "wasmtime-cache" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b389ae9b678b9c3851091a4804f4182d688d27aff7abc9aa37fa7be37d8ecffa" +dependencies = [ + "anyhow", + "base64 0.13.1", + "bincode", + "directories-next", + "file-per-thread-logger", + "log", + "rustix 0.36.11", + "serde", + "sha2 0.10.6", + "toml 0.5.11", + "windows-sys 0.42.0", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "wasmtime-cranelift" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b2c92a08c0db6efffd88fdc97d7aa9c7c63b03edb0971dbca745469f820e8c" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli 0.26.2", + "log", + "object 0.29.0", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a6db9fc52985ba06ca601f2ff0ff1f526c5d724c7ac267b47326304b0c97883" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli 0.26.2", + "indexmap", + "log", + "object 0.29.0", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b77e3a52cd84d0f7f18554afa8060cfe564ccac61e3b0802d3fd4084772fa5f6" +dependencies = [ + "addr2line 0.17.0", + "anyhow", + "bincode", + "cfg-if 1.0.0", + "cpp_demangle", + "gimli 0.26.2", + "log", + "object 0.29.0", + "rustc-demangle", + "serde", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0245e8a9347017c7185a72e215218a802ff561545c242953c11ba00fccc930f" +dependencies = [ + "object 0.29.0", + "once_cell", + "rustix 0.36.11", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d412e9340ab1c83867051d8d1d7c90aa8c9afc91da086088068e2734e25064" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d594e791b5fdd4dbaf8cf7ae62f2e4ff85018ce90f483ca6f42947688e48827d" +dependencies = [ + "anyhow", + "cc", + "cfg-if 1.0.0", + "indexmap", + "libc", + "log", + "mach", + "memfd", + "memoffset 0.6.5", + "paste", + "rand 0.8.5", + "rustix 0.36.11", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-jit-debug", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-types" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6688d6f96d4dbc1f89fab626c56c1778936d122b5f4ae7a57c2eb42b8d982e2" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki 0.22.0", +] + +[[package]] +name = "webrtc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3bc9049bdb2cea52f5fd4f6f728184225bdb867ed0dc2410eab6df5bdd67bb" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "hex", + "interceptor", + "lazy_static", + "log", + "rand 0.8.5", + "rcgen 0.9.3", + "regex", + "ring", + "rtcp", + "rtp", + "rustls 0.19.1", + "sdp", + "serde", + "serde_json", + "sha2 0.10.6", + "stun", + "thiserror", + "time 0.3.20", + "tokio", + "turn", + "url", + "waitgroup", + "webrtc-data", + "webrtc-dtls", + "webrtc-ice", + "webrtc-mdns", + "webrtc-media", + "webrtc-sctp", + "webrtc-srtp", + "webrtc-util", +] + +[[package]] +name = "webrtc-data" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef36a4d12baa6e842582fe9ec16a57184ba35e1a09308307b67d43ec8883100" +dependencies = [ + "bytes", + "derive_builder", + "log", + "thiserror", + "tokio", + "webrtc-sctp", + "webrtc-util", +] + +[[package]] +name = "webrtc-dtls" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942be5bd85f072c3128396f6e5a9bfb93ca8c1939ded735d177b7bcba9a13d05" +dependencies = [ + "aes 0.6.0", + "aes-gcm 0.10.1", + "async-trait", + "bincode", + "block-modes", + "byteorder", + "ccm", + "curve25519-dalek 3.2.0", + "der-parser 8.2.0", + "elliptic-curve 0.12.3", + "hkdf", + "hmac 0.12.1", + "log", + "oid-registry 0.6.1", + "p256", + "p384", + "rand 0.8.5", + "rand_core 0.6.4", + "rcgen 0.9.3", + "ring", + "rustls 0.19.1", + "sec1 0.3.0", + "serde", + "sha1", + "sha2 0.10.6", + "signature 1.6.4", + "subtle", + "thiserror", + "tokio", + "webpki 0.21.4", + "webrtc-util", + "x25519-dalek 2.0.0-pre.1", + "x509-parser 0.13.2", +] + +[[package]] +name = "webrtc-ice" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465a03cc11e9a7d7b4f9f99870558fe37a102b65b93f8045392fef7c67b39e80" +dependencies = [ + "arc-swap", + "async-trait", + "crc", + "log", + "rand 0.8.5", + "serde", + "serde_json", + "stun", + "thiserror", + "tokio", + "turn", + "url", + "uuid", + "waitgroup", + "webrtc-mdns", + "webrtc-util", +] + +[[package]] +name = "webrtc-mdns" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f08dfd7a6e3987e255c4dbe710dde5d94d0f0574f8a21afa95d171376c143106" +dependencies = [ + "log", + "socket2", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-media" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2a3c157a040324e5049bcbd644ffc9079e6738fa2cfab2bcff64e5cc4c00d7" +dependencies = [ + "byteorder", + "bytes", + "derive_builder", + "displaydoc", + "rand 0.8.5", + "rtp", + "thiserror", + "webrtc-util", +] + +[[package]] +name = "webrtc-sctp" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d47adcd9427eb3ede33d5a7f3424038f63c965491beafcc20bc650a2f6679c0" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "crc", + "log", + "rand 0.8.5", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-srtp" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6183edc4c1c6c0175f8812eefdce84dfa0aea9c3ece71c2bf6ddd3c964de3da5" +dependencies = [ + "aead 0.4.3", + "aes 0.7.5", + "aes-gcm 0.9.4", + "async-trait", + "byteorder", + "bytes", + "ctr 0.8.0", + "hmac 0.11.0", + "log", + "rtcp", + "rtp", + "sha-1", + "subtle", + "thiserror", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f1db1727772c05cf7a2cfece52c3aca8045ca1e176cd517d323489aa3c6d87" +dependencies = [ + "async-trait", + "bitflags", + "bytes", + "cc", + "ipnet", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.8.5", + "thiserror", + "tokio", + "winapi", +] + +[[package]] +name = "westend-runtime" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bitvec", + "frame-benchmarking", + "frame-election-provider-support", + "frame-executive", + "frame-support", + "frame-system", + "frame-system-benchmarking", + "frame-system-rpc-runtime-api", + "frame-try-runtime", + "hex-literal 0.3.4", + "log", + "pallet-authority-discovery", + "pallet-authorship", + "pallet-babe", + "pallet-bags-list", + "pallet-balances", + "pallet-collective", + "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-multisig", + "pallet-nomination-pools", + "pallet-nomination-pools-benchmarking", + "pallet-nomination-pools-runtime-api", + "pallet-offences", + "pallet-offences-benchmarking", + "pallet-preimage", + "pallet-proxy", + "pallet-recovery", + "pallet-scheduler", + "pallet-session", + "pallet-session-benchmarking", + "pallet-society", + "pallet-staking", + "pallet-staking-reward-curve", + "pallet-staking-runtime-api", + "pallet-state-trie-migration", + "pallet-sudo", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-transaction-payment-rpc-runtime-api", + "pallet-treasury", + "pallet-utility", + "pallet-vesting", + "pallet-xcm", + "pallet-xcm-benchmarks", + "parity-scale-codec", + "polkadot-parachain", + "polkadot-primitives", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "rustc-hex", + "scale-info", + "serde", + "serde_derive", + "smallvec", + "sp-api", + "sp-authority-discovery", + "sp-block-builder", + "sp-consensus-babe", + "sp-consensus-beefy", + "sp-core", + "sp-inherents", + "sp-io", + "sp-mmr-primitives", + "sp-npos-elections", + "sp-offchain", + "sp-runtime", + "sp-session", + "sp-staking", + "sp-std 5.0.0", + "sp-transaction-pool", + "sp-version", + "substrate-wasm-builder", + "westend-runtime-constants", + "xcm", + "xcm-builder", + "xcm-executor", +] + +[[package]] +name = "westend-runtime-constants" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "frame-support", + "polkadot-primitives", + "polkadot-runtime-common", + "smallvec", + "sp-core", + "sp-runtime", + "sp-weights", +] + +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "wide" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b689b6c49d6549434bf944e6b0f39238cf63693cb7a147e9d887507fffa3b223" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" +dependencies = [ + "windows_aarch64_msvc 0.34.0", + "windows_i686_gnu 0.34.0", + "windows_i686_msvc 0.34.0", + "windows_x86_64_gnu 0.34.0", + "windows_x86_64_msvc 0.34.0", +] + +[[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deac0939bd6e4f24ab5919fbf751c97a8cfc8543bb083a305ed5c0c10bb241d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x25519-dalek" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f" +dependencies = [ + "curve25519-dalek 3.2.0", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df" +dependencies = [ + "curve25519-dalek 3.2.0", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9bace5b5589ffead1afb76e43e34cff39cd0f3ce7e170ae0c29e53b88eb1c" +dependencies = [ + "asn1-rs 0.3.1", + "base64 0.13.1", + "data-encoding", + "der-parser 7.0.0", + "lazy_static", + "nom", + "oid-registry 0.4.0", + "ring", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs 0.5.2", + "base64 0.13.1", + "data-encoding", + "der-parser 8.2.0", + "lazy_static", + "nom", + "oid-registry 0.6.1", + "rusticata-macros", + "thiserror", + "time 0.3.20", +] + +[[package]] +name = "xcm" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "bounded-collections", + "derivative", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-weights", + "xcm-procedural", +] + +[[package]] +name = "xcm-builder" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "frame-support", + "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-transaction-payment", + "parity-scale-codec", + "polkadot-parachain", + "scale-info", + "sp-arithmetic", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "xcm", + "xcm-executor", +] + +[[package]] +name = "xcm-executor" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "environmental", + "frame-benchmarking", + "frame-support", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 5.0.0", + "sp-weights", + "xcm", +] + +[[package]] +name = "xcm-procedural" +version = "0.9.39" +source = "git+https://github.com/paritytech/polkadot?branch=master#ae96e09e6ad1810b8d04d4530c07173e604a763d" +dependencies = [ + "Inflector", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.14", +] + +[[package]] +name = "yamux" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d9ba232399af1783a58d8eb26f6b5006fbefe2dc9ef36bd283324792d03ea5" +dependencies = [ + "futures", + "log", + "nohash-hasher", + "parking_lot 0.12.1", + "rand 0.8.5", + "static_assertions", +] + +[[package]] +name = "yap" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc77f52dc9e9b10d55d3f4462c3b7fc393c4f17975d641542833ab2d3bc26ef" + +[[package]] +name = "yasna" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aed2e7a52e3744ab4d0c05c20aa065258e84c49fd4226f5191b2ed29712710b4" +dependencies = [ + "time 0.3.20", +] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +dependencies = [ + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.12.3+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +dependencies = [ + "zstd-safe 6.0.5+zstd.1.5.4", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-safe" +version = "6.0.5+zstd.1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.7+zstd.1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" +dependencies = [ + "cc", + "libc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000000..8048b9fcdcd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,59 @@ +[workspace] +resolver = "2" + +members = [ + "bin/millau/node", + "bin/millau/runtime", + "bin/rialto/node", + "bin/rialto/runtime", + "bin/rialto-parachain/node", + "bin/rialto-parachain/runtime", + "bin/runtime-common", + "fuzz/storage-proof", + "modules/beefy", + "modules/grandpa", + "modules/messages", + "modules/parachains", + "modules/relayers", + "modules/shift-session-manager", + "primitives/beefy", + "primitives/chain-bridge-hub-cumulus", + "primitives/chain-bridge-hub-kusama", + "primitives/chain-bridge-hub-polkadot", + "primitives/chain-bridge-hub-rococo", + "primitives/chain-bridge-hub-wococo", + "primitives/chain-kusama", + "primitives/chain-millau", + "primitives/chain-polkadot", + "primitives/chain-rialto", + "primitives/chain-rialto-parachain", + "primitives/chain-rococo", + "primitives/chain-westend", + "primitives/chain-wococo", + "primitives/header-chain", + "primitives/messages", + "primitives/parachains", + "primitives/polkadot-core", + "primitives/relayers", + "primitives/runtime", + "primitives/test-utils", + "relays/bin-substrate", + "relays/client-bridge-hub-kusama", + "relays/client-bridge-hub-polkadot", + "relays/client-bridge-hub-rococo", + "relays/client-bridge-hub-wococo", + "relays/client-kusama", + "relays/client-millau", + "relays/client-polkadot", + "relays/client-rialto", + "relays/client-rialto-parachain", + "relays/client-rococo", + "relays/client-substrate", + "relays/client-westend", + "relays/client-wococo", + "relays/finality", + "relays/lib-substrate-relay", + "relays/messages", + "relays/parachains", + "relays/utils", +] diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..a64b59e7081 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,72 @@ +# Builds images used by the bridge. +# +# In particular, it can be used to build Substrate nodes and bridge relayers. The binary that gets +# built can be specified with the `PROJECT` build-arg. For example, to build the `substrate-relay` +# you would do the following: +# +# `docker build . -t local/substrate-relay --build-arg=PROJECT=substrate-relay` +# +# See the `deployments/README.md` for all the available `PROJECT` values. + +FROM docker.io/paritytech/bridges-ci:production as builder +USER root +WORKDIR /parity-bridges-common + +COPY . . + +ARG PROJECT=substrate-relay +RUN cargo build --release --verbose -p ${PROJECT} && \ + strip ./target/release/${PROJECT} + +# In this final stage we copy over the final binary and do some checks +# to make sure that everything looks good. +FROM docker.io/library/ubuntu:20.04 as runtime + +# show backtraces +ENV RUST_BACKTRACE 1 +ENV DEBIAN_FRONTEND=noninteractive + +RUN set -eux; \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + curl ca-certificates libssl-dev && \ + update-ca-certificates && \ + groupadd -g 1000 user && \ + useradd -u 1000 -g user -s /bin/sh -m user && \ + # apt clean up + apt-get autoremove -y && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# switch to non-root user +USER user + +WORKDIR /home/user + +ARG PROJECT=substrate-relay + +COPY --chown=user:user --from=builder /parity-bridges-common/target/release/${PROJECT} ./ +COPY --chown=user:user --from=builder /parity-bridges-common/deployments/local-scripts/bridge-entrypoint.sh ./ + +# check if executable works in this container +RUN ./${PROJECT} --version + +ENV PROJECT=$PROJECT +ENTRYPOINT ["/home/user/bridge-entrypoint.sh"] + +# metadata +ARG VCS_REF=master +ARG BUILD_DATE="" +ARG VERSION="" + +LABEL org.opencontainers.image.title="${PROJECT}" \ + org.opencontainers.image.description="${PROJECT} - component of Parity Bridges Common" \ + org.opencontainers.image.source="https://github.com/paritytech/parity-bridges-common/blob/${VCS_REF}/Dockerfile" \ + org.opencontainers.image.url="https://github.com/paritytech/parity-bridges-common/blob/${VCS_REF}/Dockerfile" \ + org.opencontainers.image.documentation="https://github.com/paritytech/parity-bridges-common/blob/${VCS_REF}/README.md" \ + org.opencontainers.image.created="${BUILD_DATE}" \ + org.opencontainers.image.version="${VERSION}" \ + org.opencontainers.image.revision="${VCS_REF}" \ + org.opencontainers.image.authors="devops-team@parity.io" \ + org.opencontainers.image.vendor="Parity Technologies" \ + org.opencontainers.image.licenses="GPL-3.0 License" diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000000..733c072369c --- /dev/null +++ b/LICENSE @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/README.md b/README.md new file mode 100644 index 00000000000..aab6007d2cd --- /dev/null +++ b/README.md @@ -0,0 +1,259 @@ +# Parity Bridges Common + +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. + +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 🚧 + +## Contents + +- [Installation](#installation) +- [High-Level Architecture](#high-level-architecture) +- [Project Layout](#project-layout) +- [Running the Bridge](#running-the-bridge) +- [How to send a message](#how-to-send-a-message) +- [Community](#community) + +## 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: + +```bash +rustup install nightly +rustup target add wasm32-unknown-unknown --toolchain nightly +``` + +Once this is configured you can build and test the repo as follows: + +``` +git clone https://github.com/paritytech/parity-bridges-common.git +cd parity-bridges-common +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): + +```bash +docker pull paritytech/bridges-ci:production +mkdir ~/cache +chown 1000:1000 ~/cache #processes in the container runs as "nonroot" user with UID 1000 +docker run --rm -it -w /shellhere/parity-bridges-common \ + -v /home/$(whoami)/cache/:/cache/ \ + -v "$(pwd)":/shellhere/parity-bridges-common \ + -e CARGO_HOME=/cache/cargo/ \ + -e SCCACHE_DIR=/cache/sccache/ \ + -e CARGO_TARGET_DIR=/cache/target/ paritytech/bridges-ci:production cargo build --all +#artifacts can be found in ~/cache/target +``` + +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. + +## 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. + +``` ++---------------+ +---------------+ +| | | | +| Rialto | | Millau | +| | | | ++-------+-------+ +-------+-------+ + ^ ^ + | +---------------+ | + | | | | + +-----> | Bridge Relay | <-------+ + | | + +---------------+ +``` + +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. + +## 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. + +``` +├── 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 +│ └── ... +├── primitives // Code shared between modules, runtimes, and relays +│ └── ... +├── relays // Application for sending finality proofs and messages between chains +│ └── ... +└── 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 --unsafe-ws-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. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..65f2f3bff05 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,14 @@ +# Security Policy + +Thanks for helping make the Parity ecosystem more secure. Security is one of our first priorities. + +## 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. + +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. + diff --git a/bin/.keep b/bin/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/bin/millau/node/Cargo.toml b/bin/millau/node/Cargo.toml new file mode 100644 index 00000000000..21b5cd02559 --- /dev/null +++ b/bin/millau/node/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "millau-bridge-node" +description = "Substrate node compatible with Millau runtime" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +build = "build.rs" +repository = "https://github.com/paritytech/parity-bridges-common/" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +clap = { version = "4.2.2", features = ["derive"] } +jsonrpsee = { version = "0.16.2", features = ["server"] } +serde_json = "1.0.96" + +# Bridge dependencies + +millau-runtime = { path = "../runtime" } + +# Substrate Dependencies + +sc-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus-beefy-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } +node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" } +mmr-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master"} +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus-grandpa-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } +substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-network-common = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[build-dependencies] +substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = [] +runtime-benchmarks = [ + "millau-runtime/runtime-benchmarks", +] diff --git a/bin/millau/node/build.rs b/bin/millau/node/build.rs new file mode 100644 index 00000000000..d9b50049e26 --- /dev/null +++ b/bin/millau/node/build.rs @@ -0,0 +1,23 @@ +// Copyright 2019-2021 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 . + +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/bin/millau/node/src/chain_spec.rs b/bin/millau/node/src/chain_spec.rs new file mode 100644 index 00000000000..8669ca92cc8 --- /dev/null +++ b/bin/millau/node/src/chain_spec.rs @@ -0,0 +1,235 @@ +// Copyright 2019-2021 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 . + +use millau_runtime::{ + AccountId, AuraConfig, BalancesConfig, BeefyConfig, BridgeRialtoMessagesConfig, + BridgeRialtoParachainMessagesConfig, BridgeWestendGrandpaConfig, GenesisConfig, GrandpaConfig, + SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY, +}; +use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_consensus_beefy::crypto::AuthorityId as BeefyId; +use sp_consensus_grandpa::AuthorityId as GrandpaId; +use sp_core::{sr25519, Pair, Public}; +use sp_runtime::traits::{IdentifyAccount, Verify}; + +/// "Names" of the authorities accounts at local testnet. +const LOCAL_AUTHORITIES_ACCOUNTS: [&str; 5] = ["Alice", "Bob", "Charlie", "Dave", "Eve"]; +/// "Names" of the authorities accounts at development testnet. +const DEV_AUTHORITIES_ACCOUNTS: [&str; 1] = [LOCAL_AUTHORITIES_ACCOUNTS[0]]; +/// "Names" of all possible authorities accounts. +const ALL_AUTHORITIES_ACCOUNTS: [&str; 5] = LOCAL_AUTHORITIES_ACCOUNTS; +/// "Name" of the `sudo` account. +const SUDO_ACCOUNT: &str = "Sudo"; +/// "Name" of the account, which owns the with-Westend GRANDPA pallet. +const WESTEND_GRANDPA_PALLET_OWNER: &str = "Westend.GrandpaOwner"; +/// "Name" of the account, which owns the with-Rialto messages pallet. +const RIALTO_MESSAGES_PALLET_OWNER: &str = "Rialto.MessagesOwner"; +/// "Name" of the account, which owns the with-RialtoParachain messages pallet. +const RIALTO_PARACHAIN_MESSAGES_PALLET_OWNER: &str = "RialtoParachain.MessagesOwner"; + +/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. +pub type ChainSpec = sc_service::GenericChainSpec; + +/// The chain specification option. This is expected to come in from the CLI and +/// is little more than one of a number of alternatives which can easily be converted +/// from a string (`--chain=...`) into a `ChainSpec`. +#[derive(Clone, Debug)] +pub enum Alternative { + /// Whatever the current runtime is, with just Alice as an auth. + Development, + /// Whatever the current runtime is, with simple Alice/Bob/Charlie/Dave/Eve auths. + LocalTestnet, +} + +/// Helper function to generate a crypto pair from seed +pub fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{seed}"), None) + .expect("static values are valid; qed") + .public() +} + +type AccountPublic = ::Signer; + +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed(seed: &str) -> AccountId +where + AccountPublic: From<::Public>, +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + +/// Helper function to generate an authority key for Aura +pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, BeefyId, GrandpaId) { + ( + get_account_id_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + ) +} + +impl Alternative { + /// Get an actual chain config from one of the alternatives. + pub(crate) fn load(self) -> ChainSpec { + let properties = Some( + serde_json::json!({ + "tokenDecimals": 9, + "tokenSymbol": "MLAU" + }) + .as_object() + .expect("Map given; qed") + .clone(), + ); + match self { + Alternative::Development => ChainSpec::from_genesis( + "Millau Development", + "millau_dev", + sc_service::ChainType::Development, + || { + testnet_genesis( + DEV_AUTHORITIES_ACCOUNTS + .into_iter() + .map(get_authority_keys_from_seed) + .collect(), + get_account_id_from_seed::(SUDO_ACCOUNT), + endowed_accounts(), + true, + ) + }, + vec![], + None, + None, + None, + properties, + None, + ), + Alternative::LocalTestnet => ChainSpec::from_genesis( + "Millau Local", + "millau_local", + sc_service::ChainType::Local, + || { + testnet_genesis( + LOCAL_AUTHORITIES_ACCOUNTS + .into_iter() + .map(get_authority_keys_from_seed) + .collect(), + get_account_id_from_seed::(SUDO_ACCOUNT), + endowed_accounts(), + true, + ) + }, + vec![], + None, + None, + None, + properties, + None, + ), + } + } +} + +/// We're using the same set of endowed accounts on all Millau chains (dev/local) to make +/// sure that all accounts, required for bridge to be functional (e.g. relayers fund account, +/// accounts used by relayers in our test deployments, accounts used for demonstration +/// purposes), are all available on these chains. +fn endowed_accounts() -> Vec { + let all_authorities = ALL_AUTHORITIES_ACCOUNTS.iter().flat_map(|x| { + [ + get_account_id_from_seed::(x), + get_account_id_from_seed::(&format!("{x}//stash")), + ] + }); + vec![ + // Sudo account + get_account_id_from_seed::(SUDO_ACCOUNT), + // Regular (unused) accounts + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Ferdie//stash"), + // Accounts, used by Westend<>Millau bridge + get_account_id_from_seed::(WESTEND_GRANDPA_PALLET_OWNER), + get_account_id_from_seed::("Westend.HeadersRelay1"), + get_account_id_from_seed::("Westend.HeadersRelay2"), + get_account_id_from_seed::("Westend.WestmintHeaders1"), + get_account_id_from_seed::("Westend.WestmintHeaders2"), + // Accounts, used by Rialto<>Millau bridge + get_account_id_from_seed::(RIALTO_MESSAGES_PALLET_OWNER), + get_account_id_from_seed::("Rialto.HeadersAndMessagesRelay"), + get_account_id_from_seed::("Rialto.OutboundMessagesRelay.Lane00000001"), + get_account_id_from_seed::("Rialto.InboundMessagesRelay.Lane00000001"), + get_account_id_from_seed::("Rialto.MessagesSender"), + // Accounts, used by RialtoParachain<>Millau bridge + get_account_id_from_seed::(RIALTO_PARACHAIN_MESSAGES_PALLET_OWNER), + get_account_id_from_seed::("RialtoParachain.HeadersAndMessagesRelay1"), + get_account_id_from_seed::("RialtoParachain.HeadersAndMessagesRelay2"), + get_account_id_from_seed::("RialtoParachain.RialtoHeadersRelay1"), + get_account_id_from_seed::("RialtoParachain.RialtoHeadersRelay2"), + get_account_id_from_seed::("RialtoParachain.MessagesSender"), + ] + .into_iter() + .chain(all_authorities) + .collect() +} + +fn session_keys(aura: AuraId, beefy: BeefyId, grandpa: GrandpaId) -> SessionKeys { + SessionKeys { aura, beefy, grandpa } +} + +fn testnet_genesis( + initial_authorities: Vec<(AccountId, AuraId, BeefyId, GrandpaId)>, + root_key: AccountId, + endowed_accounts: Vec, + _enable_println: bool, +) -> GenesisConfig { + GenesisConfig { + system: SystemConfig { + code: WASM_BINARY.expect("Millau development WASM not available").to_vec(), + }, + balances: BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 50)).collect(), + }, + aura: AuraConfig { authorities: Vec::new() }, + beefy: BeefyConfig::default(), + grandpa: GrandpaConfig { authorities: Vec::new() }, + sudo: SudoConfig { key: Some(root_key) }, + session: SessionConfig { + keys: initial_authorities + .iter() + .map(|x| { + (x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone(), x.3.clone())) + }) + .collect::>(), + }, + bridge_westend_grandpa: BridgeWestendGrandpaConfig { + // for our deployments to avoid multiple same-nonces transactions: + // //Alice is already used to initialize Rialto<->Millau bridge + // => let's use //Westend.GrandpaOwner to initialize Westend->Millau bridge + owner: Some(get_account_id_from_seed::(WESTEND_GRANDPA_PALLET_OWNER)), + ..Default::default() + }, + bridge_rialto_messages: BridgeRialtoMessagesConfig { + owner: Some(get_account_id_from_seed::(RIALTO_MESSAGES_PALLET_OWNER)), + ..Default::default() + }, + bridge_rialto_parachain_messages: BridgeRialtoParachainMessagesConfig { + owner: Some(get_account_id_from_seed::( + RIALTO_PARACHAIN_MESSAGES_PALLET_OWNER, + )), + ..Default::default() + }, + xcm_pallet: Default::default(), + } +} diff --git a/bin/millau/node/src/cli.rs b/bin/millau/node/src/cli.rs new file mode 100644 index 00000000000..12499b5718d --- /dev/null +++ b/bin/millau/node/src/cli.rs @@ -0,0 +1,73 @@ +// Copyright 2019-2021 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 . + +use clap::Parser; +use sc_cli::RunCmd; + +#[derive(Debug, Parser)] +pub struct Cli { + #[structopt(subcommand)] + pub subcommand: Option, + + #[structopt(flatten)] + pub run: RunCmd, +} + +/// Possible subcommands of the main binary. +#[derive(Debug, Parser)] +#[allow(clippy::large_enum_variant)] +pub enum Subcommand { + /// Key management CLI utilities + #[clap(subcommand)] + Key(sc_cli::KeySubcommand), + + /// Verify a signature for a message, provided on `STDIN`, with a given (public or secret) key. + Verify(sc_cli::VerifyCmd), + + /// Generate a seed that provides a vanity address. + Vanity(sc_cli::VanityCmd), + + /// Sign a message, with a given (secret) key. + Sign(sc_cli::SignCmd), + + /// 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), + + /// Inspect blocks or extrinsics. + Inspect(node_inspect::cli::InspectCmd), + + /// Benchmark runtime pallets. + #[clap(subcommand)] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} diff --git a/bin/millau/node/src/command.rs b/bin/millau/node/src/command.rs new file mode 100644 index 00000000000..b8dff87f8f2 --- /dev/null +++ b/bin/millau/node/src/command.rs @@ -0,0 +1,159 @@ +// Copyright 2019-2021 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 . + +use crate::{ + cli::{Cli, Subcommand}, + service, + service::new_partial, +}; +use frame_benchmarking_cli::BenchmarkCmd; +use millau_runtime::{Block, RuntimeApi}; +use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; +use sc_service::PartialComponents; + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "Millau Bridge Node".into() + } + + fn impl_version() -> String { + env!("CARGO_PKG_VERSION").into() + } + + fn description() -> String { + "Millau Bridge Node".into() + } + + fn author() -> String { + "Parity Technologies".into() + } + + fn support_url() -> String { + "https://github.com/paritytech/parity-bridges-common/".into() + } + + fn copyright_start_year() -> i32 { + 2019 + } + + fn executable_name() -> String { + "millau-bridge-node".into() + } + + fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { + &millau_runtime::VERSION + } + + fn load_spec(&self, id: &str) -> Result, String> { + Ok(Box::new( + match id { + "" | "dev" => crate::chain_spec::Alternative::Development, + "local" => crate::chain_spec::Alternative::LocalTestnet, + _ => return Err(format!("Unsupported chain specification: {id}")), + } + .load(), + )) + } +} + +/// Parse and run command line arguments +pub fn run() -> sc_cli::Result<()> { + let cli = Cli::from_args(); + // make sure to set correct crypto version. + sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::custom( + millau_runtime::SS58Prefix::get() as u16, + )); + + match &cli.subcommand { + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + match cmd { + BenchmarkCmd::Pallet(cmd) => + if cfg!(feature = "runtime-benchmarks") { + runner + .sync_run(|config| cmd.run::(config)) + } else { + println!( + "Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + ); + Ok(()) + }, + _ => Err("Unsupported benchmarking subcommand".into()), + } + }, + Some(Subcommand::Key(cmd)) => cmd.run(&cli), + Some(Subcommand::Sign(cmd)) => cmd.run(), + Some(Subcommand::Verify(cmd)) => cmd.run(), + Some(Subcommand::Vanity(cmd)) => cmd.run(), + 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, .. } = + 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, .. } = 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, .. } = 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, .. } = + 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, .. } = new_partial(&config)?; + Ok((cmd.run(client, backend, None), task_manager)) + }) + }, + Some(Subcommand::Inspect(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).map_err(sc_cli::Error::Service) + }) + }, + } +} diff --git a/bin/millau/node/src/lib.rs b/bin/millau/node/src/lib.rs new file mode 100644 index 00000000000..382d1c2d7fb --- /dev/null +++ b/bin/millau/node/src/lib.rs @@ -0,0 +1,32 @@ +// Copyright 2019-2021 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 . + +//! Substrate Node Template CLI library. +#![warn(missing_docs)] + +mod chain_spec; +#[macro_use] +mod service; +mod cli; +mod command; + +/// Node run result. +pub type Result = sc_cli::Result<()>; + +/// Run node. +pub fn run() -> Result { + command::run() +} diff --git a/bin/millau/node/src/main.rs b/bin/millau/node/src/main.rs new file mode 100644 index 00000000000..cf6dd9f733a --- /dev/null +++ b/bin/millau/node/src/main.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2021 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 . + +//! Millau bridge node. + +#![warn(missing_docs)] + +mod chain_spec; +#[macro_use] +mod service; +mod cli; +mod command; + +/// Run the Millau Node +fn main() -> sc_cli::Result<()> { + command::run() +} diff --git a/bin/millau/node/src/service.rs b/bin/millau/node/src/service.rs new file mode 100644 index 00000000000..07cd29a0d6d --- /dev/null +++ b/bin/millau/node/src/service.rs @@ -0,0 +1,453 @@ +// Copyright 2019-2021 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 . + +//! Service and ServiceFactory implementation. Specialized wrapper over substrate service. + +use jsonrpsee::RpcModule; +use millau_runtime::{self, opaque::Block, RuntimeApi}; +use sc_client_api::BlockBackend; +use sc_consensus_aura::{CompatibilityMode, ImportQueueParams, SlotProportion, StartAuraParams}; +use sc_consensus_grandpa::SharedVoterState; +pub use sc_executor::NativeElseWasmExecutor; +use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; +use sc_service::{error::Error as ServiceError, Configuration, TaskManager}; +use sc_telemetry::{Telemetry, TelemetryWorker}; +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> { + millau_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + millau_runtime::native_version() + } +} + +type FullClient = + sc_service::TFullClient>; +type FullBackend = sc_service::TFullBackend; +type FullSelectChain = sc_consensus::LongestChain; + +#[allow(clippy::type_complexity)] +pub fn new_partial( + config: &Configuration, +) -> Result< + sc_service::PartialComponents< + FullClient, + FullBackend, + FullSelectChain, + sc_consensus::DefaultImportQueue, + sc_transaction_pool::FullPool, + ( + sc_consensus_grandpa::GrandpaBlockImport< + FullBackend, + Block, + FullClient, + FullSelectChain, + >, + sc_consensus_grandpa::LinkHalf, + sc_consensus_beefy::BeefyVoterLinks, + sc_consensus_beefy::BeefyRPCLinks, + 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 heap_pages = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); + let executor = NativeElseWasmExecutor::::new_with_wasm_executor( + WasmExecutor::builder() + .with_execution_method(config.wasm_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .build(), + ); + + 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 (grandpa_block_import, grandpa_link) = sc_consensus_grandpa::block_import( + client.clone(), + &client, + select_chain.clone(), + telemetry.as_ref().map(|x| x.handle()), + )?; + + let (beefy_block_import, beefy_voter_links, beefy_rpc_links) = + sc_consensus_beefy::beefy_block_import_and_links( + grandpa_block_import.clone(), + backend.clone(), + client.clone(), + config.prometheus_registry().cloned(), + ); + + let slot_duration = sc_consensus_aura::slot_duration(&*client)?; + + let import_queue = + sc_consensus_aura::import_queue::(ImportQueueParams { + block_import: beefy_block_import, + justification_import: Some(Box::new(grandpa_block_import.clone())), + client: client.clone(), + create_inherent_data_providers: move |_, ()| async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + }, + spawner: &task_manager.spawn_essential_handle(), + registry: config.prometheus_registry(), + check_for_equivocation: Default::default(), + telemetry: telemetry.as_ref().map(|x| x.handle()), + compatibility_mode: CompatibilityMode::None, + })?; + + Ok(sc_service::PartialComponents { + client, + backend, + task_manager, + import_queue, + keystore_container, + select_chain, + transaction_pool, + other: (grandpa_block_import, grandpa_link, beefy_voter_links, beefy_rpc_links, telemetry), + }) +} + +/// Builds a new service for a full client. +pub fn new_full(mut config: Configuration) -> Result { + use sc_network_common::sync::warp::WarpSyncParams; + + let sc_service::PartialComponents { + client, + backend, + mut task_manager, + import_queue, + keystore_container, + select_chain, + transaction_pool, + other: (block_import, grandpa_link, beefy_voter_links, beefy_rpc_links, mut telemetry), + } = new_partial(&config)?; + + let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"); + + // Note: GrandPa is pushed before the Polkadot-specific protocols. This doesn't change + // anything in terms of behaviour, but makes the logs more consistent with the other + // Substrate nodes. + let grandpa_protocol_name = sc_consensus_grandpa::protocol_standard_name( + &client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"), + &config.chain_spec, + ); + config + .network + .extra_sets + .push(sc_consensus_grandpa::grandpa_peers_set_config(grandpa_protocol_name.clone())); + + let beefy_gossip_proto_name = + sc_consensus_beefy::gossip_protocol_name(genesis_hash, config.chain_spec.fork_id()); + // `beefy_on_demand_justifications_handler` is given to `beefy-gadget` task to be run, + // while `beefy_req_resp_cfg` is added to `config.network.request_response_protocols`. + let (beefy_on_demand_justifications_handler, beefy_req_resp_cfg) = + sc_consensus_beefy::communication::request_response::BeefyJustifsRequestHandler::new( + genesis_hash, + config.chain_spec.fork_id(), + client.clone(), + config.prometheus_registry().cloned(), + ); + config + .network + .extra_sets + .push(sc_consensus_beefy::communication::beefy_peers_set_config( + beefy_gossip_proto_name.clone(), + )); + config.network.request_response_protocols.push(beefy_req_resp_cfg); + + let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new( + backend.clone(), + grandpa_link.shared_authority_set().clone(), + Vec::default(), + )); + + 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, + block_announce_validator_builder: None, + warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), + })?; + + if config.offchain_worker.enabled { + sc_service::build_offchain_workers( + &config, + task_manager.spawn_handle(), + client.clone(), + network.clone(), + ); + } + + let role = config.role.clone(); + let force_authoring = config.force_authoring; + let backoff_authoring_blocks: Option<()> = None; + let name = config.network.node_name.clone(); + let enable_grandpa = !config.disable_grandpa; + let prometheus_registry = config.prometheus_registry().cloned(); + let shared_voter_state = SharedVoterState::empty(); + + let rpc_extensions_builder = { + use sc_consensus_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider; + + use mmr_rpc::{Mmr, MmrApiServer}; + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use sc_consensus_beefy_rpc::{Beefy, BeefyApiServer}; + use sc_consensus_grandpa_rpc::{Grandpa, GrandpaApiServer}; + use sc_rpc::DenyUnsafe; + use substrate_frame_rpc_system::{System, SystemApiServer}; + + let backend = backend.clone(); + let client = client.clone(); + let pool = transaction_pool.clone(); + + let justification_stream = grandpa_link.justification_stream(); + let shared_authority_set = grandpa_link.shared_authority_set().clone(); + let shared_voter_state = shared_voter_state.clone(); + + let finality_proof_provider = GrandpaFinalityProofProvider::new_for_service( + backend, + Some(shared_authority_set.clone()), + ); + + Box::new(move |_, subscription_executor: sc_rpc::SubscriptionTaskExecutor| { + let mut io = RpcModule::new(()); + let map_err = |e| sc_service::Error::Other(format!("{e}")); + io.merge(System::new(client.clone(), pool.clone(), DenyUnsafe::No).into_rpc()) + .map_err(map_err)?; + io.merge(TransactionPayment::new(client.clone()).into_rpc()).map_err(map_err)?; + io.merge( + Grandpa::new( + subscription_executor.clone(), + shared_authority_set.clone(), + shared_voter_state.clone(), + justification_stream.clone(), + finality_proof_provider.clone(), + ) + .into_rpc(), + ) + .map_err(map_err)?; + io.merge( + Beefy::::new( + beefy_rpc_links.from_voter_justif_stream.clone(), + beefy_rpc_links.from_voter_best_beefy_stream.clone(), + subscription_executor, + ) + .map_err(|e| sc_service::Error::Other(format!("{e}")))? + .into_rpc(), + ) + .map_err(map_err)?; + io.merge(Mmr::new(client.clone()).into_rpc()).map_err(map_err)?; + Ok(io) + }) + }; + + let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { + network: network.clone(), + client: client.clone(), + keystore: keystore_container.keystore(), + task_manager: &mut task_manager, + transaction_pool: transaction_pool.clone(), + sync_service: sync_service.clone(), + rpc_builder: rpc_extensions_builder, + backend: backend.clone(), + system_rpc_tx, + config, + tx_handler_controller, + telemetry: telemetry.as_mut(), + })?; + + if role.is_authority() { + let proposer_factory = sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|x| x.handle()), + ); + + let slot_duration = sc_consensus_aura::slot_duration(&*client)?; + + let aura = sc_consensus_aura::start_aura::( + StartAuraParams { + slot_duration, + client: client.clone(), + select_chain, + block_import, + proposer_factory, + create_inherent_data_providers: move |_, ()| async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + }, + force_authoring, + backoff_authoring_blocks, + keystore: keystore_container.keystore(), + sync_oracle: sync_service.clone(), + justification_sync_link: sync_service.clone(), + block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32), + max_block_proposal_slot_portion: None, + telemetry: telemetry.as_ref().map(|x| x.handle()), + compatibility_mode: CompatibilityMode::None, + }, + )?; + + // the AURA authoring task is considered essential, i.e. if it + // fails we take down the service with it. + task_manager + .spawn_essential_handle() + .spawn_blocking("aura", Some("block-authoring"), aura); + } + + // if the node isn't actively participating in consensus then it doesn't + // need a keystore, regardless of which protocol we use below. + let keystore = if role.is_authority() { Some(keystore_container.keystore()) } else { None }; + + let justifications_protocol_name = beefy_on_demand_justifications_handler.protocol_name(); + let payload_provider = sp_consensus_beefy::mmr::MmrRootProvider::new(client.clone()); + let beefy_params = sc_consensus_beefy::BeefyParams { + client: client.clone(), + backend, + payload_provider, + runtime: client, + key_store: keystore.clone(), + network_params: sc_consensus_beefy::BeefyNetworkParams { + network: network.clone(), + sync: sync_service.clone(), + gossip_protocol_name: beefy_gossip_proto_name, + justifications_protocol_name, + _phantom: core::marker::PhantomData::, + }, + min_block_delta: 2, + prometheus_registry: prometheus_registry.clone(), + links: beefy_voter_links, + on_demand_justifications_handler: beefy_on_demand_justifications_handler, + }; + + // Start the BEEFY bridge gadget. + task_manager.spawn_essential_handle().spawn_blocking( + "beefy-gadget", + None, + sc_consensus_beefy::start_beefy_gadget::<_, _, _, _, _, _, _>(beefy_params), + ); + + let grandpa_config = sc_consensus_grandpa::Config { + // FIXME #1578 make this available through chainspec + gossip_duration: Duration::from_millis(333), + justification_period: 512, + name: Some(name), + observer_enabled: false, + keystore, + local_role: role, + telemetry: telemetry.as_ref().map(|x| x.handle()), + protocol_name: grandpa_protocol_name, + }; + + if enable_grandpa { + // start the full GRANDPA voter + // NOTE: non-authorities could run the GRANDPA observer protocol, but at + // this point the full voter should provide better guarantees of block + // 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 = sc_consensus_grandpa::GrandpaParams { + config: grandpa_config, + link: grandpa_link, + network, + sync: sync_service, + voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(), + prometheus_registry, + shared_voter_state, + telemetry: telemetry.as_ref().map(|x| x.handle()), + }; + + // the GRANDPA voter task is considered infallible, i.e. + // if it fails we take down the service with it. + task_manager.spawn_essential_handle().spawn_blocking( + "grandpa-voter", + None, + sc_consensus_grandpa::run_grandpa_voter(grandpa_config)?, + ); + } + + network_starter.start_network(); + Ok(task_manager) +} diff --git a/bin/millau/runtime/Cargo.toml b/bin/millau/runtime/Cargo.toml new file mode 100644 index 00000000000..e1a55ea6f24 --- /dev/null +++ b/bin/millau/runtime/Cargo.toml @@ -0,0 +1,144 @@ +[package] +name = "millau-runtime" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +repository = "https://github.com/paritytech/parity-bridges-common/" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +hex-literal = "0.4" +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +# Bridge dependencies + +bp-messages = { path = "../../../primitives/messages", default-features = false } +bp-millau = { path = "../../../primitives/chain-millau", default-features = false } +bp-parachains = { path = "../../../primitives/parachains", default-features = false } +bp-polkadot-core = { path = "../../../primitives/polkadot-core", default-features = false } +bp-relayers = { path = "../../../primitives/relayers", default-features = false } +bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false } +bp-rialto-parachain = { path = "../../../primitives/chain-rialto-parachain", default-features = false } +bp-runtime = { path = "../../../primitives/runtime", default-features = false } +bp-westend = { path = "../../../primitives/chain-westend", default-features = false } +bridge-runtime-common = { path = "../../runtime-common", default-features = false } +pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false } +pallet-bridge-messages = { path = "../../../modules/messages", default-features = false } +pallet-bridge-parachains = { path = "../../../modules/parachains", default-features = false } +pallet-bridge-relayers = { path = "../../../modules/relayers", default-features = false } +pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false } + +# Substrate Dependencies + +sp-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, features = ["historical"]} +pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-utility = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +# Polkadot Dependencies +pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } + +[dev-dependencies] +bridge-runtime-common = { path = "../../runtime-common", features = ["integrity-test", "std"] } +env_logger = "0.10" +static_assertions = "1.1" + +[build-dependencies] +substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = ["std"] +std = [ + "sp-consensus-beefy/std", + "bp-messages/std", + "bp-millau/std", + "bp-parachains/std", + "bp-polkadot-core/std", + "bp-relayers/std", + "bp-rialto/std", + "bp-rialto-parachain/std", + "bp-runtime/std", + "bp-westend/std", + "bridge-runtime-common/std", + "codec/std", + "frame-executive/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "pallet-aura/std", + "pallet-balances/std", + "pallet-beefy/std", + "pallet-beefy-mmr/std", + "pallet-bridge-grandpa/std", + "pallet-bridge-messages/std", + "pallet-bridge-parachains/std", + "pallet-bridge-relayers/std", + "pallet-grandpa/std", + "pallet-mmr/std", + "pallet-session/std", + "pallet-shift-session-manager/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "pallet-utility/std", + "pallet-xcm/std", + "scale-info/std", + "sp-api/std", + "sp-block-builder/std", + "sp-consensus-aura/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", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", +] +runtime-benchmarks = [ + "bridge-runtime-common/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-bridge-messages/runtime-benchmarks", + "pallet-bridge-parachains/runtime-benchmarks", + "pallet-bridge-relayers/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] diff --git a/bin/millau/runtime/build.rs b/bin/millau/runtime/build.rs new file mode 100644 index 00000000000..cc865704327 --- /dev/null +++ b/bin/millau/runtime/build.rs @@ -0,0 +1,25 @@ +// Copyright 2019-2021 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 . + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .import_memory() + .export_heap_base() + .build() +} diff --git a/bin/millau/runtime/src/lib.rs b/bin/millau/runtime/src/lib.rs new file mode 100644 index 00000000000..4e6f1e43e8c --- /dev/null +++ b/bin/millau/runtime/src/lib.rs @@ -0,0 +1,1159 @@ +// Copyright 2019-2021 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 . + +//! The Millau 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 = "256"] +// Runtime-generated enums +#![allow(clippy::large_enum_variant)] +// From construct_runtime macro +#![allow(clippy::from_over_into)] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +pub mod rialto_messages; +pub mod rialto_parachain_messages; +pub mod xcm_config; + +use bp_parachains::SingleParaStoredHeaderDataBuilder; +#[cfg(feature = "runtime-benchmarks")] +use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; +use bp_runtime::HeaderId; +use pallet_grandpa::{ + fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, +}; +use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo}; +use sp_api::impl_runtime_apis; +use sp_consensus_aura::sr25519::AuthorityId as AuraId; +use sp_consensus_beefy::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet}; +use sp_core::OpaqueMetadata; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{Block as BlockT, IdentityLookup, Keccak256, NumberFor, OpaqueKeys}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, FixedPointNumber, Perquintill, +}; +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +// to be able to use Millau runtime in `bridge-runtime-common` tests +pub use bridge_runtime_common; + +// A few exports that help ease life for downstream crates. +pub use frame_support::{ + construct_runtime, + dispatch::DispatchClass, + parameter_types, + traits::{ + ConstU32, ConstU64, ConstU8, Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem, + }, + weights::{ + constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, IdentityFee, RuntimeDbWeight, + Weight, + }, + RuntimeDebug, StorageValue, +}; + +pub use frame_system::Call as SystemCall; +pub use pallet_balances::Call as BalancesCall; +pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall; +pub use pallet_bridge_messages::Call as MessagesCall; +pub use pallet_bridge_parachains::Call as BridgeParachainsCall; +pub use pallet_sudo::Call as SudoCall; +pub use pallet_timestamp::Call as TimestampCall; +pub use pallet_xcm::Call as XcmCall; + +use bridge_runtime_common::{ + generate_bridge_reject_obsolete_headers_and_messages, + refund_relayer_extension::{ + ActualFeeRefund, RefundBridgedParachainMessages, RefundableMessagesLane, + RefundableParachain, + }, +}; +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +pub use sp_runtime::{Perbill, Permill}; + +/// An index to a block. +pub type BlockNumber = bp_millau::BlockNumber; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = bp_millau::Signature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = bp_millau::AccountId; + +/// The type for looking up accounts. We don't expect more than 4 billion of them, but you +/// never know... +pub type AccountIndex = u32; + +/// Balance of an account. +pub type Balance = bp_millau::Balance; + +/// Index of a transaction in the chain. +pub type Index = bp_millau::Index; + +/// A hash of some data used by the chain. +pub type Hash = bp_millau::Hash; + +/// Hashing algorithm used by the chain. +pub type Hashing = bp_millau::Hasher; + +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core data structures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + + /// Opaque block header type. + pub type Header = generic::Header; + /// Opaque block type. + pub type Block = generic::Block; + /// Opaque block identifier type. + pub type BlockId = generic::BlockId; +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + pub beefy: Beefy, + pub grandpa: Grandpa, + } +} + +/// This runtime version. +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("millau-runtime"), + impl_name: create_runtime_str!("millau-runtime"), + authoring_version: 1, + spec_version: 1, + impl_version: 1, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + 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 BlockHashCount: BlockNumber = 250; + pub const Version: RuntimeVersion = VERSION; + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 60_000_000, // ~0.06 ms = ~60 µs + write: 200_000_000, // ~0.2 ms = 200 µs + }; + pub const SS58Prefix: u8 = 60; +} + +impl frame_system::Config for Runtime { + /// The basic call filter to use in dispatchable. + type BaseCallFilter = frame_support::traits::Everything; + /// 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 = IdentityLookup; + /// The index type for storing how many extrinsics an account has signed. + type Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = Hashing; + /// The header type. + type Header = generic::Header; + /// 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; + /// Version of the runtime. + type Version = Version; + /// Provides information about the pallet setup in the runtime. + type PalletInfo = PalletInfo; + /// 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 data to be stored in an account. + type AccountData = pallet_balances::AccountData; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// Block and extrinsics weights: base values and limits. + type BlockWeights = bp_millau::BlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = bp_millau::BlockLength; + /// The weight of database operations that the runtime can invoke. + type DbWeight = DbWeight; + /// The designated SS58 prefix of this chain. + type SS58Prefix = SS58Prefix; + /// The set code logic, just the default since we're not a parachain. + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_aura::Config for Runtime { + type AuthorityId = AuraId; + type MaxAuthorities = ConstU32<10>; + type DisabledValidators = (); +} + +impl pallet_beefy::Config for Runtime { + type BeefyId = BeefyId; + type MaxAuthorities = ConstU32<10>; + type MaxSetIdSessionEntries = ConstU64<0>; + type OnNewValidatorSet = MmrLeaf; + type WeightInfo = (); + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); +} + +impl pallet_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + type WeightInfo = (); + type MaxAuthorities = ConstU32<10>; + type MaxSetIdSessionEntries = ConstU64<0>; + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); +} + +/// MMR helper types. +mod mmr { + use super::Runtime; + pub use pallet_mmr::primitives::*; + use sp_runtime::traits::Keccak256; + + pub type Leaf = <::LeafData as LeafDataProvider>::LeafData; + pub type Hash = ::Output; + pub type Hashing = ::Hashing; +} + +impl pallet_mmr::Config for Runtime { + const INDEXING_PREFIX: &'static [u8] = b"mmr"; + type Hashing = Keccak256; + type Hash = mmr::Hash; + type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; + type WeightInfo = (); + type LeafData = pallet_beefy_mmr::Pallet; +} + +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); +} + +pub struct BeefyDummyDataProvider; + +impl sp_consensus_beefy::mmr::BeefyDataProvider<()> for BeefyDummyDataProvider { + fn extra_data() {} +} + +impl pallet_beefy_mmr::Config for Runtime { + type LeafVersion = LeafVersion; + type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; + type LeafExtra = (); + type BeefyDataProvider = BeefyDummyDataProvider; +} + +parameter_types! { + pub const MinimumPeriod: u64 = bp_millau::SLOT_DURATION / 2; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the UNIX epoch. + type Moment = u64; + type OnTimestampSet = Aura; + type MinimumPeriod = MinimumPeriod; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + type WeightInfo = (); +} + +parameter_types! { + pub const ExistentialDeposit: bp_millau::Balance = 500; +} + +impl pallet_balances::Config for Runtime { + /// 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; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + type WeightInfo = (); + // For weight estimation, we assume that the most locks on an individual account will be 50. + // This number may need to be adjusted in the future if this assumption no longer holds true. + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + pub const TransactionBaseFee: Balance = 0; + pub const TransactionByteFee: Balance = 1; + // values for following parameters are copied from polkadot repo, but it is fine + // not to sync them - we're not going to make Rialto a full copy of one of Polkadot-like chains + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); + pub MaximumMultiplier: Multiplier = sp_runtime::traits::Bounded::max_value(); +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = bp_millau::WeightToFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< + Runtime, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, + >; + type RuntimeEvent = RuntimeEvent; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; +} + +parameter_types! { + /// Authorities are changing every 5 minutes. + pub const Period: BlockNumber = bp_millau::SESSION_LENGTH; + pub const Offset: BlockNumber = 0; +} + +impl pallet_session::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValidatorId = ::AccountId; + type ValidatorIdOf = (); + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionManager = pallet_shift_session_manager::Pallet; + type SessionHandler = ::KeyTypeIdProviders; + type Keys = SessionKeys; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + type WeightInfo = (); +} + +impl pallet_bridge_relayers::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Reward = Balance; + type PaymentProcedure = + bp_relayers::PayRewardFromAccount, AccountId>; + type WeightInfo = (); +} + +pub type RialtoGrandpaInstance = (); +impl pallet_bridge_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = bp_rialto::Rialto; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = ConstU32<{ bp_rialto::DAYS }>; + type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; +} + +pub type WestendGrandpaInstance = pallet_bridge_grandpa::Instance1; +impl pallet_bridge_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = bp_westend::Westend; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = ConstU32<{ bp_westend::DAYS }>; + type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; +} + +impl pallet_shift_session_manager::Config for Runtime {} + +parameter_types! { + pub const MaxMessagesToPruneAtOnce: bp_messages::MessageNonce = 8; + pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = + bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + pub const RootAccountForPayments: Option = None; + pub const RialtoChainId: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID; + pub const RialtoParachainChainId: bp_runtime::ChainId = bp_runtime::RIALTO_PARACHAIN_CHAIN_ID; + pub RialtoActiveOutboundLanes: &'static [bp_messages::LaneId] = &[rialto_messages::XCM_LANE]; + pub RialtoParachainActiveOutboundLanes: &'static [bp_messages::LaneId] = &[rialto_parachain_messages::XCM_LANE]; +} + +/// Instance of the messages pallet used to relay messages to/from Rialto chain. +pub type WithRialtoMessagesInstance = (); + +impl pallet_bridge_messages::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; + type ActiveOutboundLanes = RialtoActiveOutboundLanes; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = crate::rialto_messages::ToRialtoMaximalOutboundPayloadSize; + type OutboundPayload = crate::rialto_messages::ToRialtoMessagePayload; + + type InboundPayload = crate::rialto_messages::FromRialtoMessagePayload; + type InboundRelayer = bp_rialto::AccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = crate::rialto_messages::RialtoAsTargetHeaderChain; + type LaneMessageVerifier = crate::rialto_messages::ToRialtoMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + Runtime, + WithRialtoMessagesInstance, + frame_support::traits::ConstU64<100_000>, + >; + + type SourceHeaderChain = crate::rialto_messages::RialtoAsSourceHeaderChain; + type MessageDispatch = crate::rialto_messages::FromRialtoMessageDispatch; + type BridgedChainId = RialtoChainId; +} + +/// Instance of the messages pallet used to relay messages to/from RialtoParachain chain. +pub type WithRialtoParachainMessagesInstance = pallet_bridge_messages::Instance1; + +impl pallet_bridge_messages::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; + type ActiveOutboundLanes = RialtoParachainActiveOutboundLanes; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = + crate::rialto_parachain_messages::ToRialtoParachainMaximalOutboundPayloadSize; + type OutboundPayload = crate::rialto_parachain_messages::ToRialtoParachainMessagePayload; + + type InboundPayload = crate::rialto_parachain_messages::FromRialtoParachainMessagePayload; + type InboundRelayer = bp_rialto_parachain::AccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = crate::rialto_parachain_messages::RialtoParachainAsTargetHeaderChain; + type LaneMessageVerifier = crate::rialto_parachain_messages::ToRialtoParachainMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + Runtime, + WithRialtoParachainMessagesInstance, + frame_support::traits::ConstU64<100_000>, + >; + + type SourceHeaderChain = crate::rialto_parachain_messages::RialtoParachainAsSourceHeaderChain; + type MessageDispatch = crate::rialto_parachain_messages::FromRialtoParachainMessageDispatch; + type BridgedChainId = RialtoParachainChainId; +} + +parameter_types! { + pub const RialtoParachainMessagesLane: bp_messages::LaneId = rialto_parachain_messages::XCM_LANE; + pub const RialtoParachainId: u32 = bp_rialto_parachain::RIALTO_PARACHAIN_ID; + pub const RialtoParasPalletName: &'static str = bp_rialto::PARAS_PALLET_NAME; + pub const WestendParasPalletName: &'static str = bp_westend::PARAS_PALLET_NAME; + pub const MaxRialtoParaHeadDataSize: u32 = bp_rialto::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; + pub const MaxWestendParaHeadDataSize: u32 = bp_westend::MAX_NESTED_PARACHAIN_HEAD_DATA_SIZE; +} + +/// Instance of the with-Rialto parachains pallet. +pub type WithRialtoParachainsInstance = (); + +impl pallet_bridge_parachains::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight; + type BridgesGrandpaPalletInstance = RialtoGrandpaInstance; + type ParasPalletName = RialtoParasPalletName; + type ParaStoredHeaderDataBuilder = + SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ConstU32<1024>; + type MaxParaHeadDataSize = MaxRialtoParaHeadDataSize; +} + +/// Instance of the with-Westend parachains pallet. +pub type WithWestendParachainsInstance = pallet_bridge_parachains::Instance1; + +impl pallet_bridge_parachains::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight; + type BridgesGrandpaPalletInstance = WestendGrandpaInstance; + type ParasPalletName = WestendParasPalletName; + type ParaStoredHeaderDataBuilder = SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ConstU32<1024>; + type MaxParaHeadDataSize = MaxWestendParaHeadDataSize; +} + +impl pallet_utility::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = (); +} + +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = opaque::Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event}, + Utility: pallet_utility, + + // Must be before session. + Aura: pallet_aura::{Pallet, Config}, + + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + + // Consensus support. + Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event}, + ShiftSessionManager: pallet_shift_session_manager::{Pallet}, + + // BEEFY Bridges support. + Beefy: pallet_beefy::{Pallet, Storage, Config}, + Mmr: pallet_mmr::{Pallet, Storage}, + MmrLeaf: pallet_beefy_mmr::{Pallet, Storage}, + + // Rialto bridge modules. + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, + BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage, Event}, + BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, + + // Westend bridge modules. + BridgeWestendGrandpa: pallet_bridge_grandpa::::{Pallet, Call, Config, Storage, Event}, + BridgeWestendParachains: pallet_bridge_parachains::::{Pallet, Call, Storage, Event}, + + // RialtoParachain bridge modules. + BridgeRialtoParachains: pallet_bridge_parachains::{Pallet, Call, Storage, Event}, + BridgeRialtoParachainMessages: pallet_bridge_messages::::{Pallet, Call, Storage, Event, Config}, + + // Pallet for sending XCM. + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, + } +); + +generate_bridge_reject_obsolete_headers_and_messages! { + RuntimeCall, AccountId, + // Grandpa + BridgeRialtoGrandpa, BridgeWestendGrandpa, + // Parachains + BridgeRialtoParachains, + //Messages + BridgeRialtoMessages, BridgeRialtoParachainMessages +} + +bp_runtime::generate_static_str_provider!(BridgeRefundRialtoPara2000Lane0Msgs); +/// Signed extension that refunds relayers that are delivering messages from the Rialto parachain. +pub type PriorityBoostPerMessage = ConstU64<921_900_294>; +pub type BridgeRefundRialtoParachainMessages = RefundBridgedParachainMessages< + Runtime, + RefundableParachain, + RefundableMessagesLane, + ActualFeeRefund, + PriorityBoostPerMessage, + StrBridgeRefundRialtoPara2000Lane0Msgs, +>; + +/// The address format for describing accounts. +pub type Address = AccountId; +/// 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::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, + BridgeRejectObsoleteHeadersAndMessages, + BridgeRefundRialtoParachainMessages, +); +/// The payload being signed in transactions. +pub type SignedPayload = generic::SignedPayload; +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = generic::CheckedExtrinsic; +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +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_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 frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + 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_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().to_vec() + } + } + + 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 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 sp_consensus_beefy::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: sp_consensus_beefy::EquivocationProof< + NumberFor, + sp_consensus_beefy::crypto::AuthorityId, + sp_consensus_beefy::crypto::Signature + >, + _key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { None } + + fn generate_key_ownership_proof( + _set_id: sp_consensus_beefy::ValidatorSetId, + _authority_id: sp_consensus_beefy::crypto::AuthorityId, + ) -> Option { None } + } + + impl pallet_mmr::primitives::MmrApi< + Block, + mmr::Hash, + BlockNumber, + > 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 fg_primitives::GrandpaApi for Runtime { + fn current_set_id() -> fg_primitives::SetId { + Grandpa::current_set_id() + } + + fn grandpa_authorities() -> GrandpaAuthorityList { + Grandpa::grandpa_authorities() + } + + fn submit_report_equivocation_unsigned_extrinsic( + equivocation_proof: fg_primitives::EquivocationProof< + ::Hash, + 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: GrandpaId, + ) -> Option { + // NOTE: this is the only implementation possible since we've + // defined our key owner proof type as a bottom type (i.e. a type + // with no values). + None + } + } + + impl bp_rialto::RialtoFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeRialtoGrandpa::best_finalized() + } + } + + impl bp_westend::WestendFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeWestendGrandpa::best_finalized() + } + } + + impl bp_westend::WestmintFinalityApi for Runtime { + fn best_finalized() -> Option> { + pallet_bridge_parachains::Pallet::< + Runtime, + WithWestendParachainsInstance, + >::best_parachain_head_id::().unwrap_or(None) + } + } + + impl bp_rialto_parachain::RialtoParachainFinalityApi for Runtime { + fn best_finalized() -> Option> { + pallet_bridge_parachains::Pallet::< + Runtime, + WithRialtoParachainsInstance, + >::best_parachain_head_id::().unwrap_or(None) + } + } + + impl bp_rialto::ToRialtoOutboundLaneApi 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, + WithRialtoMessagesInstance, + >(lane, begin, end) + } + } + + impl bp_rialto::FromRialtoInboundLaneApi 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, + WithRialtoMessagesInstance, + >(lane, messages) + } + } + + impl bp_rialto_parachain::ToRialtoParachainOutboundLaneApi 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, + WithRialtoParachainMessagesInstance, + >(lane, begin, end) + } + } + + impl bp_rialto_parachain::FromRialtoParachainInboundLaneApi 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, + WithRialtoParachainMessagesInstance, + >(lane, messages) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(extra: bool) -> ( + Vec, + Vec, + ) { + use frame_benchmarking::{list_benchmark, Benchmarking, BenchmarkList}; + use frame_support::traits::StorageInfoTrait; + + use pallet_bridge_messages::benchmarking::Pallet as MessagesBench; + use pallet_bridge_parachains::benchmarking::Pallet as ParachainsBench; + use pallet_bridge_relayers::benchmarking::Pallet as RelayersBench; + + let mut list = Vec::::new(); + + list_benchmark!(list, extra, RialtoParachainMessages, MessagesBench::); + list_benchmark!(list, extra, RialtoMessages, MessagesBench::); + list_benchmark!(list, extra, pallet_bridge_grandpa, BridgeRialtoGrandpa); + list_benchmark!(list, extra, pallet_bridge_parachains, ParachainsBench::); + list_benchmark!(list, extra, pallet_bridge_relayers, RelayersBench::); + + let storage_info = AllPalletsWithSystem::storage_info(); + + return (list, storage_info) + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig, + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, TrackedStorageKey, add_benchmark}; + + let whitelist: Vec = vec![ + // Block Number + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").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(), + // Caller 0 Account + hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da946c154ffd9992e395af90b5b13cc6f295c77033fce8a9045824a6690bbf99c6db269502f0a8d1d2a008542d5690a0749").to_vec().into(), + ]; + + let mut batches = Vec::::new(); + let params = (&config, &whitelist); + + use bridge_runtime_common::messages_benchmarking::{ + prepare_message_delivery_proof_from_grandpa_chain, + prepare_message_delivery_proof_from_parachain, + prepare_message_proof_from_grandpa_chain, + prepare_message_proof_from_parachain, + }; + use pallet_bridge_messages::benchmarking::{ + Pallet as MessagesBench, + Config as MessagesConfig, + MessageDeliveryProofParams, + MessageProofParams, + }; + use pallet_bridge_parachains::benchmarking::{ + Pallet as ParachainsBench, + Config as ParachainsConfig, + }; + use pallet_bridge_relayers::benchmarking::{ + Pallet as RelayersBench, + Config as RelayersConfig, + }; + use rialto_messages::WithRialtoMessageBridge; + use rialto_parachain_messages::WithRialtoParachainMessageBridge; + + impl MessagesConfig for Runtime { + fn prepare_message_proof( + params: MessageProofParams, + ) -> (rialto_messages::FromRialtoMessagesProof, Weight) { + prepare_message_proof_from_parachain::< + Runtime, + WithRialtoParachainsInstance, + WithRialtoParachainMessageBridge, + >(params, xcm::v3::Junctions::Here) + } + + fn prepare_message_delivery_proof( + params: MessageDeliveryProofParams, + ) -> rialto_messages::ToRialtoMessagesDeliveryProof { + prepare_message_delivery_proof_from_parachain::< + Runtime, + WithRialtoParachainsInstance, + WithRialtoParachainMessageBridge, + >(params) + } + + fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { + let lane = >::bench_lane_id(); + let bridged_chain_id = bp_runtime::RIALTO_PARACHAIN_CHAIN_ID; + pallet_bridge_relayers::Pallet::::relayer_reward( + relayer, + RewardsAccountParams::new(lane, bridged_chain_id, RewardsAccountOwner::BridgedChain) + ).is_some() + } + } + + impl MessagesConfig for Runtime { + fn prepare_message_proof( + params: MessageProofParams, + ) -> (rialto_messages::FromRialtoMessagesProof, Weight) { + prepare_message_proof_from_grandpa_chain::< + Runtime, + RialtoGrandpaInstance, + WithRialtoMessageBridge, + >(params, xcm::v3::Junctions::Here) + } + + fn prepare_message_delivery_proof( + params: MessageDeliveryProofParams, + ) -> rialto_messages::ToRialtoMessagesDeliveryProof { + prepare_message_delivery_proof_from_grandpa_chain::< + Runtime, + RialtoGrandpaInstance, + WithRialtoMessageBridge, + >(params) + } + + fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool { + let lane = >::bench_lane_id(); + let bridged_chain_id = bp_runtime::RIALTO_CHAIN_ID; + pallet_bridge_relayers::Pallet::::relayer_reward( + relayer, + RewardsAccountParams::new(lane, bridged_chain_id, RewardsAccountOwner::BridgedChain) + ).is_some() + } + } + + impl ParachainsConfig for Runtime { + fn parachains() -> Vec { + use bp_runtime::Parachain; + vec![bp_polkadot_core::parachains::ParaId(bp_rialto_parachain::RialtoParachain::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)>, + ) { + bridge_runtime_common::parachains_benchmarking::prepare_parachain_heads_proof::< + Runtime, + WithRialtoParachainsInstance, + >( + parachains, + parachain_head_size, + proof_size, + ) + } + } + + impl RelayersConfig for Runtime { + fn prepare_environment( + account_params: RewardsAccountParams, + reward: Balance, + ) { + use frame_support::traits::fungible::Mutate; + let rewards_account = bp_relayers::PayRewardFromAccount::< + Balances, + AccountId + >::rewards_account(account_params); + Balances::mint_into(&rewards_account, reward).unwrap(); + } + } + + add_benchmark!( + params, + batches, + RialtoParachainMessages, + MessagesBench:: + ); + add_benchmark!( + params, + batches, + RialtoMessages, + MessagesBench:: + ); + add_benchmark!(params, batches, pallet_bridge_grandpa, BridgeRialtoGrandpa); + add_benchmark!( + params, + batches, + pallet_bridge_parachains, + ParachainsBench:: + ); + add_benchmark!(params, batches, pallet_bridge_relayers, RelayersBench::); + + Ok(batches) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn call_size() { + const BRIDGES_PALLETS_MAX_CALL_SIZE: usize = 200; + assert!( + core::mem::size_of::>() <= + BRIDGES_PALLETS_MAX_CALL_SIZE + ); + assert!( + core::mem::size_of::>() <= + BRIDGES_PALLETS_MAX_CALL_SIZE + ); + const MAX_CALL_SIZE: usize = 230; // value from polkadot-runtime tests + assert!(core::mem::size_of::() <= MAX_CALL_SIZE); + } +} diff --git a/bin/millau/runtime/src/rialto_messages.rs b/bin/millau/runtime/src/rialto_messages.rs new file mode 100644 index 00000000000..84535283d48 --- /dev/null +++ b/bin/millau/runtime/src/rialto_messages.rs @@ -0,0 +1,199 @@ +// Copyright 2019-2021 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 . + +//! Everything required to serve Millau <-> Rialto messages. + +use crate::{RialtoGrandpaInstance, Runtime, RuntimeOrigin, WithRialtoMessagesInstance}; + +use bp_messages::LaneId; +use bridge_runtime_common::{ + messages::{ + self, source::TargetHeaderChainAdapter, target::SourceHeaderChainAdapter, MessageBridge, + }, + messages_xcm_extension::{XcmBlobHauler, XcmBlobHaulerAdapter}, +}; +use frame_support::{parameter_types, weights::Weight, RuntimeDebug}; +use xcm::latest::prelude::*; +use xcm_builder::HaulBlobExporter; + +/// Default lane that is used to send messages to Rialto. +pub const XCM_LANE: LaneId = LaneId([0, 0, 0, 0]); +/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge +/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual +/// tests, confirming that we don't break encoding somewhere between. +pub const BASE_XCM_WEIGHT_TWICE: Weight = crate::xcm_config::BaseXcmWeight::get().saturating_mul(2); + +parameter_types! { + /// Weight credit for our test messages. + /// + /// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge + /// (it is prepended with `UniversalOrigin` instruction). + pub const WeightCredit: Weight = BASE_XCM_WEIGHT_TWICE; +} + +/// Message payload for Millau -> Rialto messages. +pub type ToRialtoMessagePayload = messages::source::FromThisChainMessagePayload; + +/// Message verifier for Millau -> Rialto messages. +pub type ToRialtoMessageVerifier = + messages::source::FromThisChainMessageVerifier; + +/// Message payload for Rialto -> Millau messages. +pub type FromRialtoMessagePayload = messages::target::FromBridgedChainMessagePayload; + +/// Messages proof for Rialto -> Millau messages. +pub type FromRialtoMessagesProof = messages::target::FromBridgedChainMessagesProof; + +/// Messages delivery proof for Millau -> Rialto messages. +pub type ToRialtoMessagesDeliveryProof = + messages::source::FromBridgedChainMessagesDeliveryProof; + +/// Call-dispatch based message dispatch for Rialto -> Millau messages. +pub type FromRialtoMessageDispatch = + bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatch< + bp_millau::Millau, + bp_rialto::Rialto, + crate::xcm_config::OnMillauBlobDispatcher, + (), + >; + +/// Maximal outbound payload size of Millau -> Rialto messages. +pub type ToRialtoMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + +/// Millau <-> Rialto message bridge. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct WithRialtoMessageBridge; + +impl MessageBridge for WithRialtoMessageBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; + + type ThisChain = Millau; + type BridgedChain = Rialto; + type BridgedHeaderChain = + pallet_bridge_grandpa::GrandpaChainHeaders; +} + +/// Millau chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Millau; + +impl messages::UnderlyingChainProvider for Millau { + type Chain = bp_millau::Millau; +} + +impl messages::ThisChainWithMessages for Millau { + type RuntimeOrigin = RuntimeOrigin; +} + +/// Rialto chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Rialto; +/// Rialto as source header chain. +pub type RialtoAsSourceHeaderChain = SourceHeaderChainAdapter; +/// Rialto as target header chain. +pub type RialtoAsTargetHeaderChain = TargetHeaderChainAdapter; + +impl messages::UnderlyingChainProvider for Rialto { + type Chain = bp_rialto::Rialto; +} + +impl messages::BridgedChainWithMessages for Rialto {} + +/// Export XCM messages to be relayed to Rialto. +pub type ToRialtoBlobExporter = HaulBlobExporter< + XcmBlobHaulerAdapter, + crate::xcm_config::RialtoNetwork, + (), +>; + +/// To-Rialto XCM hauler. +pub struct ToRialtoXcmBlobHauler; + +impl XcmBlobHauler for ToRialtoXcmBlobHauler { + type MessageSender = pallet_bridge_messages::Pallet; + type MessageSenderOrigin = RuntimeOrigin; + + fn message_sender_origin() -> RuntimeOrigin { + pallet_xcm::Origin::from(MultiLocation::new(1, crate::xcm_config::UniversalLocation::get())) + .into() + } + + fn xcm_lane() -> LaneId { + XCM_LANE + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{Runtime, WithRialtoMessagesInstance}; + + use bridge_runtime_common::{ + assert_complete_bridge_types, + integrity::{ + assert_complete_bridge_constants, check_message_lane_weights, + AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, + AssertCompleteBridgeConstants, + }, + }; + + #[test] + fn ensure_millau_message_lane_weights_are_correct() { + check_message_lane_weights::( + bp_rialto::EXTRA_STORAGE_PROOF_SIZE, + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + ); + } + + #[test] + fn ensure_bridge_integrity() { + assert_complete_bridge_types!( + runtime: Runtime, + with_bridged_chain_grandpa_instance: RialtoGrandpaInstance, + with_bridged_chain_messages_instance: WithRialtoMessagesInstance, + bridge: WithRialtoMessageBridge, + this_chain: bp_millau::Millau, + bridged_chain: bp_rialto::Rialto, + ); + + assert_complete_bridge_constants::< + Runtime, + RialtoGrandpaInstance, + WithRialtoMessagesInstance, + WithRialtoMessageBridge, + >(AssertCompleteBridgeConstants { + this_chain_constants: AssertChainConstants { + block_length: bp_millau::BlockLength::get(), + block_weights: bp_millau::BlockWeights::get(), + }, + messages_pallet_constants: AssertBridgeMessagesPalletConstants { + max_unrewarded_relayers_in_bridged_confirmation_tx: + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + max_unconfirmed_messages_in_bridged_confirmation_tx: + bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + bridged_chain_id: bp_runtime::RIALTO_CHAIN_ID, + }, + pallet_names: AssertBridgePalletNames { + with_this_chain_messages_pallet_name: bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME, + with_bridged_chain_grandpa_pallet_name: bp_rialto::WITH_RIALTO_GRANDPA_PALLET_NAME, + with_bridged_chain_messages_pallet_name: + bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME, + }, + }); + } +} diff --git a/bin/millau/runtime/src/rialto_parachain_messages.rs b/bin/millau/runtime/src/rialto_parachain_messages.rs new file mode 100644 index 00000000000..bef8a281188 --- /dev/null +++ b/bin/millau/runtime/src/rialto_parachain_messages.rs @@ -0,0 +1,209 @@ +// Copyright 2019-2021 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 . + +//! Everything required to serve Millau <-> RialtoParachain messages. + +use crate::{ + Runtime, RuntimeOrigin, WithRialtoParachainMessagesInstance, WithRialtoParachainsInstance, +}; + +use bp_messages::LaneId; +use bridge_runtime_common::{ + messages::{ + self, source::TargetHeaderChainAdapter, target::SourceHeaderChainAdapter, MessageBridge, + }, + messages_xcm_extension::{XcmBlobHauler, XcmBlobHaulerAdapter}, +}; +use frame_support::{parameter_types, weights::Weight, RuntimeDebug}; +use xcm::latest::prelude::*; +use xcm_builder::HaulBlobExporter; + +/// Default lane that is used to send messages to Rialto parachain. +pub const XCM_LANE: LaneId = LaneId([0, 0, 0, 0]); +/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge +/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual +/// tests, confirming that we don't break encoding somewhere between. +pub const BASE_XCM_WEIGHT_TWICE: Weight = crate::xcm_config::BaseXcmWeight::get().saturating_mul(2); + +parameter_types! { + /// Weight credit for our test messages. + /// + /// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge + /// (it is prepended with `UniversalOrigin` instruction). + pub const WeightCredit: Weight = BASE_XCM_WEIGHT_TWICE; +} + +/// Message payload for Millau -> RialtoParachain messages. +pub type ToRialtoParachainMessagePayload = messages::source::FromThisChainMessagePayload; + +/// Message verifier for Millau -> RialtoParachain messages. +pub type ToRialtoParachainMessageVerifier = + messages::source::FromThisChainMessageVerifier; + +/// Message payload for RialtoParachain -> Millau messages. +pub type FromRialtoParachainMessagePayload = messages::target::FromBridgedChainMessagePayload; + +/// Call-dispatch based message dispatch for RialtoParachain -> Millau messages. +pub type FromRialtoParachainMessageDispatch = + bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatch< + bp_millau::Millau, + bp_rialto::Rialto, + crate::xcm_config::OnMillauBlobDispatcher, + (), + >; + +/// Maximal outbound payload size of Millau -> RialtoParachain messages. +pub type ToRialtoParachainMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + +/// Millau <-> RialtoParachain message bridge. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct WithRialtoParachainMessageBridge; + +impl MessageBridge for WithRialtoParachainMessageBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; + + type ThisChain = Millau; + type BridgedChain = RialtoParachain; + type BridgedHeaderChain = pallet_bridge_parachains::ParachainHeaders< + Runtime, + WithRialtoParachainsInstance, + bp_rialto_parachain::RialtoParachain, + >; +} + +/// Millau chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Millau; + +impl messages::UnderlyingChainProvider for Millau { + type Chain = bp_millau::Millau; +} + +impl messages::ThisChainWithMessages for Millau { + type RuntimeOrigin = RuntimeOrigin; +} + +/// RialtoParachain chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct RialtoParachain; +/// RialtoParachain as source header chain. +pub type RialtoParachainAsSourceHeaderChain = + SourceHeaderChainAdapter; +/// RialtoParachain as target header chain. +pub type RialtoParachainAsTargetHeaderChain = + TargetHeaderChainAdapter; + +impl messages::UnderlyingChainProvider for RialtoParachain { + type Chain = bp_rialto_parachain::RialtoParachain; +} + +impl messages::BridgedChainWithMessages for RialtoParachain {} + +/// Export XCM messages to be relayed to Rialto. +pub type ToRialtoParachainBlobExporter = HaulBlobExporter< + XcmBlobHaulerAdapter, + crate::xcm_config::RialtoParachainNetwork, + (), +>; + +/// To-RialtoParachain XCM hauler. +pub struct ToRialtoParachainXcmBlobHauler; + +impl XcmBlobHauler for ToRialtoParachainXcmBlobHauler { + type MessageSender = + pallet_bridge_messages::Pallet; + type MessageSenderOrigin = RuntimeOrigin; + + fn message_sender_origin() -> RuntimeOrigin { + pallet_xcm::Origin::from(MultiLocation::new(1, crate::xcm_config::UniversalLocation::get())) + .into() + } + + fn xcm_lane() -> LaneId { + XCM_LANE + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + PriorityBoostPerMessage, RialtoGrandpaInstance, Runtime, + WithRialtoParachainMessagesInstance, + }; + + use bridge_runtime_common::{ + assert_complete_bridge_types, + integrity::{ + assert_complete_bridge_constants, check_message_lane_weights, + AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, + AssertCompleteBridgeConstants, + }, + }; + + #[test] + fn ensure_millau_message_lane_weights_are_correct() { + check_message_lane_weights::( + bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE, + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + ); + } + + #[test] + fn ensure_bridge_integrity() { + assert_complete_bridge_types!( + runtime: Runtime, + with_bridged_chain_grandpa_instance: RialtoGrandpaInstance, + with_bridged_chain_messages_instance: WithRialtoParachainMessagesInstance, + bridge: WithRialtoParachainMessageBridge, + this_chain: bp_millau::Millau, + bridged_chain: bp_rialto::Rialto, + ); + + assert_complete_bridge_constants::< + Runtime, + RialtoGrandpaInstance, + WithRialtoParachainMessagesInstance, + WithRialtoParachainMessageBridge, + >(AssertCompleteBridgeConstants { + this_chain_constants: AssertChainConstants { + block_length: bp_millau::BlockLength::get(), + block_weights: bp_millau::BlockWeights::get(), + }, + messages_pallet_constants: AssertBridgeMessagesPalletConstants { + max_unrewarded_relayers_in_bridged_confirmation_tx: + bp_rialto_parachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + max_unconfirmed_messages_in_bridged_confirmation_tx: + bp_rialto_parachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + bridged_chain_id: bp_runtime::RIALTO_PARACHAIN_CHAIN_ID, + }, + pallet_names: AssertBridgePalletNames { + with_this_chain_messages_pallet_name: bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME, + with_bridged_chain_grandpa_pallet_name: bp_rialto::WITH_RIALTO_GRANDPA_PALLET_NAME, + with_bridged_chain_messages_pallet_name: + bp_rialto_parachain::WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME, + }, + }); + + bridge_runtime_common::priority_calculator::ensure_priority_boost_is_sane::< + Runtime, + WithRialtoParachainMessagesInstance, + PriorityBoostPerMessage, + >(1_000_000); + } +} diff --git a/bin/millau/runtime/src/xcm_config.rs b/bin/millau/runtime/src/xcm_config.rs new file mode 100644 index 00000000000..4aaec83771b --- /dev/null +++ b/bin/millau/runtime/src/xcm_config.rs @@ -0,0 +1,373 @@ +// Copyright 2019-2021 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 . + +//! XCM configurations for the Millau runtime. + +use super::{ + rialto_messages::ToRialtoBlobExporter, + rialto_parachain_messages::ToRialtoParachainBlobExporter, AccountId, AllPalletsWithSystem, + Balances, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, XcmPallet, +}; +use bp_millau::WeightToFee; +use bridge_runtime_common::CustomNetworkId; +use frame_support::{ + parameter_types, + traits::{ConstU32, Everything, Nothing}, + weights::Weight, +}; +use frame_system::EnsureRoot; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, CurrencyAdapter as XcmCurrencyAdapter, IsConcrete, MintLocation, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + UsingComponents, +}; +use xcm_executor::traits::ExportXcm; + +parameter_types! { + /// The location of the `MLAU` 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 Millau network ID. + pub const ThisNetwork: NetworkId = CustomNetworkId::Millau.as_network_id(); + /// The Rialto network ID. + pub const RialtoNetwork: NetworkId = CustomNetworkId::Rialto.as_network_id(); + /// The RialtoParachain network ID. + pub const RialtoParachainNetwork: NetworkId = CustomNetworkId::RialtoParachain.as_network_id(); + + /// 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, MintLocation) = (XcmPallet::check_account(), 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 directly alias an `AccountId32` into a local account. + AccountId32Aliases, +); + +/// Our asset transactor. This is what allows us to interest with the runtime facilities from the +/// point of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. +/// +/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // We can convert the MultiLocations with our converter above: + SovereignAccountOf, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We track our teleports in/out to keep total issuance correct. + CheckAccount, +>; + +/// 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, + // 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 XCM router. We are not sending messages to sibling/parent/child chains here. +pub type XcmRouter = (); + +/// The barriers one of which must be passed for an XCM message to be executed. +pub type Barrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, +); + +/// Dispatches received XCM messages from other chain. +pub type OnMillauBlobDispatcher = xcm_builder::BridgeBlobDispatcher< + crate::xcm_config::XcmRouter, + crate::xcm_config::UniversalLocation, +>; + +/// XCM weigher type. +pub type XcmWeigher = xcm_builder::FixedWeightBounds; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = XcmWeigher; + // 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 = ConstU32<64>; + type FeeManager = (); + type MessageExporter = ToRialtoOrRialtoParachainSwitchExporter; + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; +} + +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. +pub type LocalOriginToLocation = ( + // Usual Signed origin to be used in XCM as a corresponding AccountId32 + SignedToAccountId32, +); + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = None; +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // We don't allow any messages to be sent via the transaction yet. This is basically safe to + // enable, (safe the possibility of someone spamming the parachain if they're willing to pay + // the DOT 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 = (); + // 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 = XcmWeigher; + 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 = frame_support::traits::ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type AdminOrigin = EnsureRoot; +} + +pub struct ToRialtoOrRialtoParachainSwitchExporter; + +impl ExportXcm for ToRialtoOrRialtoParachainSwitchExporter { + 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 { + if network == RialtoNetwork::get() { + ToRialtoBlobExporter::validate(network, channel, universal_source, destination, message) + .map(|result| ((RialtoNetwork::get(), result.0), result.1)) + } else if network == RialtoParachainNetwork::get() { + ToRialtoParachainBlobExporter::validate( + network, + channel, + universal_source, + destination, + message, + ) + .map(|result| ((RialtoParachainNetwork::get(), result.0), result.1)) + } else { + Err(SendError::Unroutable) + } + } + + fn deliver(ticket: Self::Ticket) -> Result { + let (network, ticket) = ticket; + if network == RialtoNetwork::get() { + ToRialtoBlobExporter::deliver(ticket) + } else if network == RialtoParachainNetwork::get() { + ToRialtoParachainBlobExporter::deliver(ticket) + } else { + Err(SendError::Unroutable) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + rialto_messages::FromRialtoMessageDispatch, WithRialtoMessagesInstance, + WithRialtoParachainMessagesInstance, + }; + use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + LaneId, MessageKey, + }; + use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; + use codec::Encode; + use pallet_bridge_messages::OutboundLanes; + use xcm_executor::XcmExecutor; + + fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new( + frame_system::GenesisConfig::default().build_storage::().unwrap(), + ) + } + + fn prepare_outbound_xcm_message(destination: NetworkId) -> Xcm { + vec![ExportMessage { + network: destination, + destination: destination.into(), + xcm: vec![Instruction::Trap(42)].into(), + }] + .into() + } + + #[test] + fn xcm_messages_to_rialto_are_sent_using_bridge_exporter() { + new_test_ext().execute_with(|| { + // ensure that the there are no messages queued + assert_eq!( + OutboundLanes::::get( + crate::rialto_messages::XCM_LANE + ) + .latest_generated_nonce, + 0, + ); + + // export message instruction "sends" message to Rialto + XcmExecutor::::execute_xcm_in_credit( + Here, + prepare_outbound_xcm_message(RialtoNetwork::get()), + Default::default(), + Weight::MAX, + Weight::MAX, + ) + .ensure_complete() + .expect("runtime configuration must be correct"); + + // ensure that the message has been queued + assert_eq!( + OutboundLanes::::get( + crate::rialto_messages::XCM_LANE + ) + .latest_generated_nonce, + 1, + ); + }) + } + + #[test] + fn xcm_messages_to_rialto_parachain_are_sent_using_bridge_exporter() { + new_test_ext().execute_with(|| { + // ensure that the there are no messages queued + assert_eq!( + OutboundLanes::::get( + crate::rialto_parachain_messages::XCM_LANE + ) + .latest_generated_nonce, + 0, + ); + + // export message instruction "sends" message to Rialto + XcmExecutor::::execute_xcm_in_credit( + Here, + prepare_outbound_xcm_message(RialtoParachainNetwork::get()), + Default::default(), + Weight::MAX, + Weight::MAX, + ) + .ensure_complete() + .expect("runtime configuration must be correct"); + + // ensure that the message has been queued + assert_eq!( + OutboundLanes::::get( + crate::rialto_parachain_messages::XCM_LANE + ) + .latest_generated_nonce, + 1, + ); + }) + } + + fn prepare_inbound_bridge_message() -> DispatchMessage> { + let xcm = xcm::VersionedXcm::::V3(vec![Instruction::Trap(42)].into()); + let location = + xcm::VersionedInteriorMultiLocation::V3(X1(GlobalConsensus(ThisNetwork::get()))); + // this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor + // or public fields, so just tuple + let bridge_message = (location, xcm).encode(); + DispatchMessage { + key: MessageKey { lane_id: LaneId([0, 0, 0, 0]), nonce: 1 }, + data: DispatchMessageData { payload: Ok(bridge_message) }, + } + } + + #[test] + fn xcm_messages_from_rialto_are_dispatched() { + let incoming_message = prepare_inbound_bridge_message(); + + // we care only about handing message to the XCM dispatcher, so we don't care about its + // actual dispatch + let dispatch_result = + FromRialtoMessageDispatch::dispatch(&AccountId::from([0u8; 32]), incoming_message); + assert!(matches!( + dispatch_result.dispatch_level_result, + XcmBlobMessageDispatchResult::NotDispatched(_), + )); + } + + #[test] + fn xcm_messages_from_rialto_parachain_are_dispatched() { + let incoming_message = prepare_inbound_bridge_message(); + + // we care only about handing message to the XCM dispatcher, so we don't care about its + // actual dispatch + let dispatch_result = + FromRialtoMessageDispatch::dispatch(&AccountId::from([0u8; 32]), incoming_message); + assert!(matches!( + dispatch_result.dispatch_level_result, + XcmBlobMessageDispatchResult::NotDispatched(_), + )); + } +} diff --git a/bin/rialto-parachain/node/Cargo.toml b/bin/rialto-parachain/node/Cargo.toml new file mode 100644 index 00000000000..2315eb94a11 --- /dev/null +++ b/bin/rialto-parachain/node/Cargo.toml @@ -0,0 +1,81 @@ +[package] +name = "rialto-parachain-collator" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +repository = "https://github.com/paritytech/parity-bridges-common/" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[build-dependencies] +substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[[bin]] +name = 'rialto-parachain-collator' + +[features] +default = [] +runtime-benchmarks = ['rialto-parachain-runtime/runtime-benchmarks'] + +[dependencies] +clap = { version = "4.2.2", features = ["derive"] } +log = '0.4.17' +codec = { package = 'parity-scale-codec', version = '3.1.5' } +serde = { version = '1.0', features = ['derive'] } + +# RPC related Dependencies +jsonrpsee = { version = "0.16.2", features = ["server"] } + +# Local Dependencies +rialto-parachain-runtime = { path = '../runtime' } + +# Substrate Dependencies +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } + +pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } + +substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } + +## Substrate Client Dependencies +sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-network-sync = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "master"} +sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } + +## Substrate Primitive Dependencies +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" } + +# Cumulus dependencies +cumulus-client-consensus-aura = { git = "https://github.com/paritytech/cumulus", branch = "master" } +cumulus-client-consensus-common = { git = "https://github.com/paritytech/cumulus", branch = "master" } +cumulus-client-cli = { git = "https://github.com/paritytech/cumulus", branch = "master" } +cumulus-client-network = { git = "https://github.com/paritytech/cumulus", branch = "master" } +cumulus-client-service = { git = "https://github.com/paritytech/cumulus", branch = "master" } +cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "master" } +cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/cumulus", branch = "master" } +cumulus-relay-chain-interface = { git = "https://github.com/paritytech/cumulus", branch = "master" } + +# Polkadot dependencies +polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } diff --git a/bin/rialto-parachain/node/build.rs b/bin/rialto-parachain/node/build.rs new file mode 100644 index 00000000000..8ba8a31e9a7 --- /dev/null +++ b/bin/rialto-parachain/node/build.rs @@ -0,0 +1,22 @@ +// Copyright 2019-2021 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 . + +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/bin/rialto-parachain/node/src/chain_spec.rs b/bin/rialto-parachain/node/src/chain_spec.rs new file mode 100644 index 00000000000..bfce4f717c6 --- /dev/null +++ b/bin/rialto-parachain/node/src/chain_spec.rs @@ -0,0 +1,198 @@ +// Copyright 2020-2021 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 . + +use cumulus_primitives_core::ParaId; +use rialto_parachain_runtime::{AccountId, AuraId, BridgeMillauMessagesConfig, Signature}; +use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; +use sc_service::ChainType; +use serde::{Deserialize, Serialize}; +use sp_core::{sr25519, Pair, Public}; +use sp_runtime::traits::{IdentifyAccount, Verify}; + +/// "Names" of the authorities accounts at local testnet. +const LOCAL_AUTHORITIES_ACCOUNTS: [&str; 2] = ["Alice", "Bob"]; +/// "Names" of the authorities accounts at development testnet. +const DEV_AUTHORITIES_ACCOUNTS: [&str; 2] = LOCAL_AUTHORITIES_ACCOUNTS; +/// "Names" of all possible authorities accounts. +const ALL_AUTHORITIES_ACCOUNTS: [&str; 2] = LOCAL_AUTHORITIES_ACCOUNTS; +/// "Name" of the `sudo` account. +const SUDO_ACCOUNT: &str = "Sudo"; +/// "Name" of the account, which owns the with-Millau messages pallet. +const MILLAU_MESSAGES_PALLET_OWNER: &str = "Millau.MessagesOwner"; + +/// Specialized `ChainSpec` for the normal parachain runtime. +pub type ChainSpec = + sc_service::GenericChainSpec; + +/// Helper function to generate a crypto pair from seed +pub fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{seed}"), None) + .expect("static values are valid; qed") + .public() +} + +/// The extensions for the [`ChainSpec`]. +#[derive( + Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, +)] +#[serde(deny_unknown_fields)] +pub struct Extensions { + /// The relay chain of the Parachain. + pub relay_chain: String, + /// The id of the Parachain. + pub para_id: u32, +} + +impl Extensions { + /// Try to get the extension from the given `ChainSpec`. + pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { + sc_chain_spec::get_extension(chain_spec.extensions()) + } +} + +type AccountPublic = ::Signer; + +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed(seed: &str) -> AccountId +where + AccountPublic: From<::Public>, +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + +/// We're using the same set of endowed accounts on all RialtoParachain chains (dev/local) to make +/// sure that all accounts, required for bridge to be functional (e.g. relayers fund account, +/// accounts used by relayers in our test deployments, accounts used for demonstration +/// purposes), are all available on these chains. +fn endowed_accounts() -> Vec { + let all_authorities = ALL_AUTHORITIES_ACCOUNTS.iter().flat_map(|x| { + [ + get_account_id_from_seed::(x), + get_account_id_from_seed::(&format!("{x}//stash")), + ] + }); + vec![ + // Sudo account + get_account_id_from_seed::(SUDO_ACCOUNT), + // Regular (unused) accounts + 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::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + // Accounts, used by RialtoParachain<>Millau bridge + get_account_id_from_seed::(MILLAU_MESSAGES_PALLET_OWNER), + get_account_id_from_seed::("Millau.HeadersAndMessagesRelay1"), + get_account_id_from_seed::("Millau.HeadersAndMessagesRelay2"), + get_account_id_from_seed::("Millau.MessagesSender"), + ] + .into_iter() + .chain(all_authorities) + .collect() +} + +pub fn development_config(id: ParaId) -> ChainSpec { + // 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(), 12.into()); + + ChainSpec::from_genesis( + // Name + "Development", + // ID + "dev", + ChainType::Local, + move || { + testnet_genesis( + get_account_id_from_seed::(SUDO_ACCOUNT), + DEV_AUTHORITIES_ACCOUNTS.into_iter().map(get_from_seed::).collect(), + endowed_accounts(), + id, + ) + }, + vec![], + None, + None, + None, + None, + Extensions { + relay_chain: "rococo-local".into(), // You MUST set this to the correct network! + para_id: id.into(), + }, + ) +} + +pub fn local_testnet_config(id: ParaId) -> ChainSpec { + // 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(), 12.into()); + + ChainSpec::from_genesis( + // Name + "Local Testnet", + // ID + "local_testnet", + ChainType::Local, + move || { + testnet_genesis( + get_account_id_from_seed::(SUDO_ACCOUNT), + LOCAL_AUTHORITIES_ACCOUNTS.into_iter().map(get_from_seed::).collect(), + endowed_accounts(), + id, + ) + }, + Vec::new(), + None, + None, + None, + None, + Extensions { + relay_chain: "rococo-local".into(), // You MUST set this to the correct network! + para_id: id.into(), + }, + ) +} + +fn testnet_genesis( + root_key: AccountId, + initial_authorities: Vec, + endowed_accounts: Vec, + id: ParaId, +) -> rialto_parachain_runtime::GenesisConfig { + rialto_parachain_runtime::GenesisConfig { + system: rialto_parachain_runtime::SystemConfig { + code: rialto_parachain_runtime::WASM_BINARY + .expect("WASM binary was not build, please build it!") + .to_vec(), + }, + balances: rialto_parachain_runtime::BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(), + }, + sudo: rialto_parachain_runtime::SudoConfig { key: Some(root_key) }, + parachain_info: rialto_parachain_runtime::ParachainInfoConfig { parachain_id: id }, + aura: rialto_parachain_runtime::AuraConfig { authorities: initial_authorities }, + aura_ext: Default::default(), + bridge_millau_messages: BridgeMillauMessagesConfig { + owner: Some(get_account_id_from_seed::(MILLAU_MESSAGES_PALLET_OWNER)), + ..Default::default() + }, + } +} diff --git a/bin/rialto-parachain/node/src/cli.rs b/bin/rialto-parachain/node/src/cli.rs new file mode 100644 index 00000000000..a003c91113c --- /dev/null +++ b/bin/rialto-parachain/node/src/cli.rs @@ -0,0 +1,142 @@ +// Copyright 2020-2021 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 . + +#![allow(clippy::large_enum_variant)] + +use crate::chain_spec; +use clap::Parser; +use std::path::PathBuf; + +/// Sub-commands supported by the collator. +#[derive(Debug, Parser)] +pub enum Subcommand { + /// Export the genesis state of the parachain. + #[clap(name = "export-genesis-state")] + ExportGenesisState(ExportGenesisStateCommand), + + /// Export the genesis wasm of the parachain. + #[clap(name = "export-genesis-wasm")] + ExportGenesisWasm(ExportGenesisWasmCommand), + + /// 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(cumulus_client_cli::PurgeChainCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), + + /// The custom benchmark subcommand benchmarking runtime pallets. + #[clap(subcommand)] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} + +/// Command for exporting the genesis state of the parachain +#[derive(Debug, Parser)] +pub struct ExportGenesisStateCommand { + /// Output file name or stdout if unspecified. + #[clap(action)] + pub output: Option, + + /// Id of the parachain this state is for. + /// + /// Default: 100 + #[clap(long, conflicts_with = "chain")] + pub parachain_id: Option, + + /// Write output in binary. Default is to write in hex. + #[clap(short, long)] + pub raw: bool, + + /// The name of the chain for that the genesis state should be exported. + #[clap(long, conflicts_with = "parachain-id")] + pub chain: Option, +} + +/// Command for exporting the genesis wasm file. +#[derive(Debug, Parser)] +pub struct ExportGenesisWasmCommand { + /// Output file name or stdout if unspecified. + #[clap(action)] + pub output: Option, + + /// Write output in binary. Default is to write in hex. + #[clap(short, long)] + pub raw: bool, + + /// The name of the chain for that the genesis wasm file should be exported. + #[clap(long)] + pub chain: Option, +} + +#[derive(Debug, Parser)] +#[clap( + propagate_version = true, + args_conflicts_with_subcommands = true, + subcommand_negates_reqs = true +)] +pub struct Cli { + #[clap(subcommand)] + pub subcommand: Option, + + #[clap(long)] + pub parachain_id: Option, + + #[clap(flatten)] + pub run: cumulus_client_cli::RunCmd, + + /// Relaychain arguments + #[clap(raw = true)] + pub relaychain_args: Vec, +} + +#[derive(Debug)] +pub struct RelayChainCli { + /// The actual relay chain CLI object. + pub base: polkadot_cli::RunCmd, + + /// Optional chain id that should be passed to the relay chain. + pub chain_id: Option, + + /// The base path that should be used by the relay chain. + pub base_path: Option, +} + +impl RelayChainCli { + /// Parse the relay chain CLI parameters using the para chain `Configuration`. + pub fn new<'a>( + para_config: &sc_service::Configuration, + relay_chain_args: impl Iterator, + ) -> Self { + let extension = chain_spec::Extensions::try_get(&*para_config.chain_spec); + let chain_id = extension.map(|e| e.relay_chain.clone()); + let base_path = para_config.base_path.as_ref().map(|x| x.path().join("rialto-bridge-node")); + Self { base_path, chain_id, base: polkadot_cli::RunCmd::parse_from(relay_chain_args) } + } +} diff --git a/bin/rialto-parachain/node/src/command.rs b/bin/rialto-parachain/node/src/command.rs new file mode 100644 index 00000000000..7393b014732 --- /dev/null +++ b/bin/rialto-parachain/node/src/command.rs @@ -0,0 +1,445 @@ +// Copyright 2020-2021 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 . + +use crate::{ + chain_spec, + cli::{Cli, RelayChainCli, Subcommand}, + service::{new_partial, ParachainRuntimeExecutor}, +}; +use codec::Encode; +use cumulus_client_cli::generate_genesis_block; +use cumulus_primitives_core::ParaId; +use frame_benchmarking_cli::BenchmarkCmd; +use log::info; +use rialto_parachain_runtime::{Block, RuntimeApi}; +use sc_cli::{ + ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, + NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli, +}; +use sc_service::config::{BasePath, PrometheusConfig}; +use sp_core::hexdisplay::HexDisplay; +use sp_runtime::traits::{AccountIdConversion, Block as BlockT}; +use std::{io::Write, net::SocketAddr}; + +fn load_spec( + id: &str, + para_id: ParaId, +) -> std::result::Result, String> { + Ok(match id { + "dev" => Box::new(chain_spec::development_config(para_id)), + "" | "local" => Box::new(chain_spec::local_testnet_config(para_id)), + path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?), + }) +} + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "Parachain Collator Template".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + format!( + "Parachain Collator Template\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relaychain node.\n\n\ + {} [parachain-args] -- [relaychain-args]", + Self::executable_name() + ) + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/substrate-developer-hub/substrate-parachain-template/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2017 + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + load_spec(id, self.parachain_id.unwrap_or(2000).into()) + } + + fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { + &rialto_parachain_runtime::VERSION + } +} + +impl SubstrateCli for RelayChainCli { + fn impl_name() -> String { + "Parachain Collator Template".into() + } + + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn description() -> String { + "Parachain Collator Template\n\nThe command-line arguments provided first will be \ + passed to the parachain node, while the arguments provided after -- will be passed \ + to the relaychain node.\n\n\ + parachain-collator [parachain-args] -- [relaychain-args]" + .into() + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/substrate-developer-hub/substrate-parachain-template/issues/new".into() + } + + fn copyright_start_year() -> i32 { + 2017 + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id) + } + + fn native_runtime_version(chain_spec: &Box) -> &'static RuntimeVersion { + polkadot_cli::Cli::native_runtime_version(chain_spec) + } +} + +fn extract_genesis_wasm(chain_spec: &dyn sc_service::ChainSpec) -> Result> { + let mut storage = chain_spec.build_storage()?; + + storage + .top + .remove(sp_core::storage::well_known_keys::CODE) + .ok_or_else(|| "Could not find wasm file in genesis state!".into()) +} + +macro_rules! construct_async_run { + (|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{ + let runner = $cli.create_runner($cmd)?; + runner.async_run(|$config| { + let $components = new_partial::< + RuntimeApi, + _ + >( + &$config, + crate::service::parachain_build_import_queue, + )?; + let task_manager = $components.task_manager; + { $( $code )* }.map(|v| (v, task_manager)) + }) + }} +} + +/// Parse command line arguments into service configuration. +pub fn run() -> Result<()> { + let cli = Cli::from_args(); + sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::custom( + rialto_parachain_runtime::SS58Prefix::get() as u16, + )); + + match &cli.subcommand { + 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)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.import_queue)) + }) + }, + Some(Subcommand::ExportBlocks(cmd)) => { + construct_async_run!(|components, cli, cmd, config| Ok( + cmd.run(components.client, config.database) + )) + }, + Some(Subcommand::ExportState(cmd)) => { + construct_async_run!(|components, cli, cmd, config| Ok( + cmd.run(components.client, config.chain_spec) + )) + }, + Some(Subcommand::ImportBlocks(cmd)) => { + construct_async_run!(|components, cli, cmd, config| { + Ok(cmd.run(components.client, components.import_queue)) + }) + }, + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| { + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()), + ); + + let polkadot_config = SubstrateCli::create_configuration( + &polkadot_cli, + &polkadot_cli, + config.tokio_handle.clone(), + ) + .map_err(|err| format!("Relay chain argument error: {err}"))?; + + cmd.run(config, polkadot_config) + }) + }, + Some(Subcommand::Revert(cmd)) => { + construct_async_run!(|components, cli, cmd, config| Ok(cmd.run( + components.client, + components.backend, + None + ))) + }, + Some(Subcommand::ExportGenesisState(params)) => { + let mut builder = sc_cli::LoggerBuilder::new(""); + builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); + let _ = builder.init(); + + let spec = load_spec( + ¶ms.chain.clone().unwrap_or_default(), + params.parachain_id.expect("Missing ParaId").into(), + )?; + let state_version = Cli::native_runtime_version(&spec).state_version(); + let block: Block = generate_genesis_block(&*spec, state_version)?; + let raw_header = block.header().encode(); + let output_buf = if params.raw { + raw_header + } else { + format!("0x{:?}", HexDisplay::from(&block.header().encode())).into_bytes() + }; + + if let Some(output) = ¶ms.output { + std::fs::write(output, output_buf)?; + } else { + std::io::stdout().write_all(&output_buf)?; + } + + Ok(()) + }, + Some(Subcommand::ExportGenesisWasm(params)) => { + let mut builder = sc_cli::LoggerBuilder::new(""); + builder.with_profiling(sc_tracing::TracingReceiver::Log, ""); + let _ = builder.init(); + + let raw_wasm_blob = + extract_genesis_wasm(&*cli.load_spec(¶ms.chain.clone().unwrap_or_default())?)?; + let output_buf = if params.raw { + raw_wasm_blob + } else { + format!("0x{:?}", HexDisplay::from(&raw_wasm_blob)).into_bytes() + }; + + if let Some(output) = ¶ms.output { + std::fs::write(output, output_buf)?; + } else { + std::io::stdout().write_all(&output_buf)?; + } + + Ok(()) + }, + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + match cmd { + BenchmarkCmd::Pallet(cmd) => + if cfg!(feature = "runtime-benchmarks") { + runner.sync_run(|config| cmd.run::(config)) + } else { + println!( + "Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + ); + Ok(()) + }, + _ => Err("Unsupported benchmarking subcommand".into()), + } + }, + None => { + let runner = cli.create_runner(&cli.run.normalize())?; + let collator_options = cli.run.collator_options(); + + runner.run_node_until_exit(|config| async move { + let para_id = + chain_spec::Extensions::try_get(&*config.chain_spec).map(|e| e.para_id); + + let polkadot_cli = RelayChainCli::new( + &config, + [RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()), + ); + + let id = ParaId::from(cli.parachain_id.or(para_id).expect("Missing ParaId")); + + let parachain_account = + AccountIdConversion::::into_account_truncating(&id); + + let state_version = + RelayChainCli::native_runtime_version(&config.chain_spec).state_version(); + let block: Block = generate_genesis_block(&*config.chain_spec, state_version) + .map_err(|e| format!("{e:?}"))?; + let genesis_state = format!("0x{:?}", HexDisplay::from(&block.header().encode())); + + let polkadot_config = SubstrateCli::create_configuration( + &polkadot_cli, + &polkadot_cli, + config.tokio_handle.clone(), + ) + .map_err(|err| format!("Relay chain argument error: {err}"))?; + + info!("Parachain id: {:?}", id); + info!("Parachain Account: {}", parachain_account); + info!("Parachain genesis state: {}", genesis_state); + info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); + + crate::service::start_node(config, polkadot_config, collator_options, id) + .await + .map(|r| r.0) + .map_err(Into::into) + }) + }, + } +} + +impl DefaultConfigurationValues for RelayChainCli { + fn p2p_listen_port() -> u16 { + 30334 + } + + fn rpc_ws_listen_port() -> u16 { + 9945 + } + + fn rpc_http_listen_port() -> u16 { + 9934 + } + + fn prometheus_listen_port() -> u16 { + 9616 + } +} + +impl CliConfiguration for RelayChainCli { + fn shared_params(&self) -> &SharedParams { + self.base.base.shared_params() + } + + fn import_params(&self) -> Option<&ImportParams> { + self.base.base.import_params() + } + + fn network_params(&self) -> Option<&NetworkParams> { + self.base.base.network_params() + } + + fn keystore_params(&self) -> Option<&KeystoreParams> { + self.base.base.keystore_params() + } + + fn base_path(&self) -> Result> { + Ok(self + .shared_params() + .base_path()? + .or_else(|| self.base_path.clone().map(Into::into))) + } + + fn rpc_http(&self, default_listen_port: u16) -> Result> { + self.base.base.rpc_http(default_listen_port) + } + + fn rpc_ipc(&self) -> Result> { + self.base.base.rpc_ipc() + } + + fn rpc_ws(&self, default_listen_port: u16) -> Result> { + self.base.base.rpc_ws(default_listen_port) + } + + fn prometheus_config( + &self, + default_listen_port: u16, + chain_spec: &Box, + ) -> Result> { + self.base.base.prometheus_config(default_listen_port, chain_spec) + } + + fn init( + &self, + _support_url: &String, + _impl_version: &String, + _logger_hook: F, + _config: &sc_service::Configuration, + ) -> Result<()> + where + F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), + { + unreachable!("PolkadotCli is never initialized; qed"); + } + + fn chain_id(&self, is_dev: bool) -> Result { + let chain_id = self.base.base.chain_id(is_dev)?; + + Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id }) + } + + fn role(&self, is_dev: bool) -> Result { + self.base.base.role(is_dev) + } + + fn transaction_pool(&self, is_dev: bool) -> Result { + self.base.base.transaction_pool(is_dev) + } + + fn rpc_methods(&self) -> Result { + self.base.base.rpc_methods() + } + + fn rpc_ws_max_connections(&self) -> Result> { + self.base.base.rpc_ws_max_connections() + } + + fn rpc_cors(&self, is_dev: bool) -> Result>> { + self.base.base.rpc_cors(is_dev) + } + + fn default_heap_pages(&self) -> Result> { + self.base.base.default_heap_pages() + } + + fn force_authoring(&self) -> Result { + self.base.base.force_authoring() + } + + fn disable_grandpa(&self) -> Result { + self.base.base.disable_grandpa() + } + + fn max_runtime_instances(&self) -> Result> { + self.base.base.max_runtime_instances() + } + + fn announce_block(&self) -> Result { + self.base.base.announce_block() + } + + fn telemetry_endpoints( + &self, + chain_spec: &Box, + ) -> Result> { + self.base.base.telemetry_endpoints(chain_spec) + } +} diff --git a/bin/rialto-parachain/node/src/lib.rs b/bin/rialto-parachain/node/src/lib.rs new file mode 100644 index 00000000000..3ec291596b7 --- /dev/null +++ b/bin/rialto-parachain/node/src/lib.rs @@ -0,0 +1,18 @@ +// Copyright 2020-2021 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 . + +pub mod chain_spec; +pub mod service; diff --git a/bin/rialto-parachain/node/src/main.rs b/bin/rialto-parachain/node/src/main.rs new file mode 100644 index 00000000000..2b4e0b438d1 --- /dev/null +++ b/bin/rialto-parachain/node/src/main.rs @@ -0,0 +1,29 @@ +// Copyright 2020-2021 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 . + +//! Substrate Parachain Node Template CLI + +#![warn(missing_docs)] + +mod chain_spec; +#[macro_use] +mod service; +mod cli; +mod command; + +fn main() -> sc_cli::Result<()> { + command::run() +} diff --git a/bin/rialto-parachain/node/src/service.rs b/bin/rialto-parachain/node/src/service.rs new file mode 100644 index 00000000000..24eb94e655d --- /dev/null +++ b/bin/rialto-parachain/node/src/service.rs @@ -0,0 +1,510 @@ +// Copyright 2020-2021 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 . + +//! Rialto parachain node service. +//! +//! The code is mostly copy of `polkadot-parachains/src/service.rs` file from Cumulus +//! repository with some parts removed. We have added two RPC extensions to the original +//! service: `pallet_transaction_payment_rpc::TransactionPaymentApi` and +//! `substrate_frame_rpc_system::SystemApi`. + +// std +use std::{sync::Arc, time::Duration}; + +// Local Runtime Types +use rialto_parachain_runtime::RuntimeApi; + +// Cumulus Imports +use cumulus_client_cli::CollatorOptions; +use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion}; +use cumulus_client_consensus_common::{ + ParachainBlockImport as TParachainBlockImport, ParachainConsensus, +}; +use cumulus_client_network::BlockAnnounceValidator; +use cumulus_client_service::{ + prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, +}; +use cumulus_primitives_core::ParaId; +use cumulus_relay_chain_interface::RelayChainInterface; +use sc_consensus::ImportQueue; +// Substrate Imports +use sc_executor::{ + HeapAllocStrategy, NativeElseWasmExecutor, NativeExecutionDispatch, WasmExecutor, + DEFAULT_HEAP_ALLOC_STRATEGY, +}; +use sc_network::NetworkBlock; +use sc_network_sync::SyncingService; +use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager}; +use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; +use sp_api::ConstructRuntimeApi; +use sp_keystore::KeystorePtr; +use sp_runtime::traits::BlakeTwo256; +use substrate_prometheus_endpoint::Registry; + +// Runtime type overrides +type BlockNumber = u32; +type Header = sp_runtime::generic::Header; +pub type Block = sp_runtime::generic::Block; + +type ParachainClient = + TFullClient>; +type ParachainBackend = TFullBackend; +type ParachainBlockImport = + TParachainBlockImport>, ParachainBackend>; + +pub type ParachainRuntimeExecutor = ExecutorDispatch; + +// Our native executor instance. +pub struct ExecutorDispatch; + +impl NativeExecutionDispatch for ExecutorDispatch { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + rialto_parachain_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + rialto_parachain_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 +/// be able to perform chain operations. +#[allow(clippy::type_complexity)] +pub fn new_partial( + config: &Configuration, + build_import_queue: BIQ, +) -> Result< + PartialComponents< + ParachainClient, + ParachainBackend, + (), + sc_consensus::DefaultImportQueue>, + sc_transaction_pool::FullPool>, + (ParachainBlockImport, Option, Option), + >, + sc_service::Error, +> +where + RuntimeApi: ConstructRuntimeApi> + Send + Sync + 'static, + RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue + + sp_api::Metadata + + sp_session::SessionKeys + + sp_api::ApiExt< + Block, + StateBackend = sc_client_api::StateBackendFor, + > + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder, + sc_client_api::StateBackendFor: sp_api::StateBackend, + BIQ: FnOnce( + Arc>, + ParachainBlockImport, + &Configuration, + Option, + &TaskManager, + ) -> Result< + sc_consensus::DefaultImportQueue>, + sc_service::Error, + >, +{ + 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 heap_pages = config + .default_heap_pages + .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); + let executor = + sc_executor::NativeElseWasmExecutor::::new_with_wasm_executor( + WasmExecutor::builder() + .with_execution_method(config.wasm_method) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .with_max_runtime_instances(config.max_runtime_instances) + .with_runtime_cache_size(config.runtime_cache_size) + .build(), + ); + + 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_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); + + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let transaction_pool = sc_transaction_pool::BasicPool::new_full( + config.transaction_pool.clone(), + config.role.is_authority().into(), + config.prometheus_registry(), + task_manager.spawn_essential_handle(), + client.clone(), + ); + + let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let import_queue = build_import_queue( + client.clone(), + block_import.clone(), + config, + telemetry.as_ref().map(|telemetry| telemetry.handle()), + &task_manager, + )?; + + let params = PartialComponents { + backend, + client, + import_queue, + keystore_container, + task_manager, + transaction_pool, + select_chain: (), + other: (block_import, telemetry, telemetry_worker_handle), + }; + + Ok(params) +} + +/// Start a node with the given parachain `Configuration` and relay chain `Configuration`. +/// +/// This is the actual implementation that is abstract over the executor and the runtime api. +#[sc_tracing::logging::prefix_logs_with("Parachain")] +async fn start_node_impl( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + id: ParaId, + rpc_ext_builder: RB, + build_import_queue: BIQ, + build_consensus: BIC, +) -> 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< + Block, + StateBackend = sc_client_api::StateBackendFor, + > + sp_offchain::OffchainWorkerApi + + sp_block_builder::BlockBuilder + + cumulus_primitives_core::CollectCollationInfo, + sc_client_api::StateBackendFor: sp_api::StateBackend, + RB: Fn( + sc_rpc_api::DenyUnsafe, + Arc>, + Arc>>, + ) -> Result, sc_service::Error> + + Send + + Clone + + 'static, + BIQ: FnOnce( + Arc>, + ParachainBlockImport, + &Configuration, + Option, + &TaskManager, + ) -> Result< + sc_consensus::DefaultImportQueue>, + sc_service::Error, + >, + BIC: FnOnce( + Arc>, + ParachainBlockImport, + Option<&Registry>, + Option, + &TaskManager, + Arc, + Arc>>, + Arc>, + KeystorePtr, + bool, + ) -> 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 mut task_manager = params.task_manager; + let (relay_chain_interface, collator_key) = + cumulus_client_service::build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options, + None, + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let client = params.client.clone(); + let backend = params.backend.clone(); + let block_announce_validator = BlockAnnounceValidator::new(relay_chain_interface.clone(), id); + + let force_authoring = parachain_config.force_authoring; + 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 (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + sc_service::build_network(sc_service::BuildNetworkParams { + config: ¶chain_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + spawn_handle: task_manager.spawn_handle(), + import_queue: params.import_queue, + block_announce_validator_builder: Some(Box::new(|_| { + Box::new(block_announce_validator) + })), + warp_sync_params: None, + })?; + + let rpc_client = client.clone(); + let rpc_transaction_pool = transaction_pool.clone(); + let rpc_extensions_builder = Box::new(move |deny_unsafe, _| { + rpc_ext_builder(deny_unsafe, rpc_client.clone(), rpc_transaction_pool.clone()) + }); + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + rpc_builder: rpc_extensions_builder.clone(), + 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(), + })?; + + 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)))?; + + if validator { + let parachain_consensus = build_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, + params.keystore_container.keystore(), + force_authoring, + )?; + + let spawner = task_manager.spawn_handle(); + + let params = StartCollatorParams { + para_id: id, + block_status: client.clone(), + announce_block, + client: client.clone(), + task_manager: &mut task_manager, + relay_chain_interface, + spawner, + parachain_consensus, + import_queue: import_queue_service, + collator_key: collator_key.expect("Command line arguments do not allow this. qed"), + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle), + }; + + start_collator(params).await?; + } else { + let params = StartFullNodeParams { + client: client.clone(), + announce_block, + task_manager: &mut task_manager, + para_id: id, + relay_chain_interface, + relay_chain_slot_duration, + import_queue: import_queue_service, + recovery_handle: Box::new(overseer_handle), + }; + + start_full_node(params)?; + } + + start_network.start_network(); + + Ok((task_manager, client)) +} + +/// Build the import queue for the the parachain runtime. +#[allow(clippy::type_complexity)] +pub fn parachain_build_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry: Option, + task_manager: &TaskManager, +) -> Result>, sc_service::Error> +{ + let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?; + + cumulus_client_consensus_aura::import_queue::< + sp_consensus_aura::sr25519::AuthorityPair, + _, + _, + _, + _, + _, + >(cumulus_client_consensus_aura::ImportQueueParams { + block_import, + client, + create_inherent_data_providers: move |_, _| async move { + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + }, + registry: config.prometheus_registry(), + spawner: &task_manager.spawn_essential_handle(), + telemetry, + }) + .map_err(Into::into) +} + +/// Start a normal parachain node. +pub async fn start_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + id: ParaId, +) -> sc_service::error::Result<(TaskManager, Arc>)> { + start_node_impl::( + parachain_config, + polkadot_config, + collator_options, + id, + |_deny_unsafe, client, pool| { + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; + use sc_rpc::DenyUnsafe; + use substrate_frame_rpc_system::{System, SystemApiServer}; + + let mut io = jsonrpsee::RpcModule::new(()); + let map_err = |e| sc_service::Error::Other(format!("{e}")); + io.merge(System::new(client.clone(), pool, DenyUnsafe::No).into_rpc()) + .map_err(map_err)?; + io.merge(TransactionPayment::new(client).into_rpc()).map_err(map_err)?; + Ok(io) + }, + parachain_build_import_queue, + |client, + block_import, + prometheus_registry, + telemetry, + task_manager, + relay_chain_interface, + transaction_pool, + sync_oracle, + keystore, + force_authoring| { + let client2 = client.clone(); + let block_import2 = block_import; + 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, + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + Ok(AuraConsensus::build::( + BuildAuraConsensusParams { + proposer_factory, + create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = + cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( + relay_parent, + &relay_chain_interface, + &validation_data, + id, + ).await; + let time = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *time, + slot_duration, + ); + + let parachain_inherent = parachain_inherent.ok_or_else(|| { + Box::::from( + "Failed to create parachain inherent", + ) + })?; + Ok((slot, time, parachain_inherent)) + } + }, + block_import: block_import2, + para_client: client2, + backoff_authoring_blocks: Option::<()>::None, + sync_oracle, + keystore, + force_authoring, + slot_duration, + // We got around 500ms for proposing + block_proposal_slot_portion: SlotProportion::new(1f32 / 24f32), + telemetry, + max_block_proposal_slot_portion: None, + }, + )) + }, + ) + .await +} diff --git a/bin/rialto-parachain/runtime/Cargo.toml b/bin/rialto-parachain/runtime/Cargo.toml new file mode 100644 index 00000000000..53f57e02619 --- /dev/null +++ b/bin/rialto-parachain/runtime/Cargo.toml @@ -0,0 +1,139 @@ +[package] +name = "rialto-parachain-runtime" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +repository = "https://github.com/paritytech/parity-bridges-common/" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[build-dependencies] +substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[dependencies] +codec = { package = 'parity-scale-codec', version = '3.1.5', default-features = false, features = ['derive']} +hex-literal = "0.4" +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +# Bridge depedencies + +bp-messages = { path = "../../../primitives/messages", default-features = false } +bp-millau = { path = "../../../primitives/chain-millau", default-features = false } +bp-relayers = { path = "../../../primitives/relayers", default-features = false } +bp-runtime = { path = "../../../primitives/runtime", default-features = false } +bp-rialto-parachain = { path = "../../../primitives/chain-rialto-parachain", default-features = false } +bridge-runtime-common = { path = "../../runtime-common", default-features = false } +pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false } +pallet-bridge-messages = { path = "../../../modules/messages", default-features = false } +pallet-bridge-relayers = { path = "../../../modules/relayers", default-features = false } + +# Substrate Dependencies +## Substrate Primitive Dependencies +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-consensus-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +## Substrate FRAME Dependencies +frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +## Substrate Pallet Dependencies +pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +# Cumulus Dependencies +cumulus-pallet-aura-ext = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } +cumulus-pallet-parachain-system = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } +cumulus-pallet-dmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } +cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } +cumulus-pallet-xcmp-queue = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } +cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } +cumulus-primitives-timestamp = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } +parachain-info = { git = "https://github.com/paritytech/cumulus", branch = "master", default-features = false } + +# Polkadot Dependencies +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } + +[dev-dependencies] +bridge-runtime-common = { path = "../../runtime-common", features = ["integrity-test"] } + +[features] +default = ['std'] +runtime-benchmarks = [ + 'sp-runtime/runtime-benchmarks', + 'frame-benchmarking', + 'frame-support/runtime-benchmarks', + 'frame-system-benchmarking/runtime-benchmarks', + 'frame-system/runtime-benchmarks', + 'pallet-balances/runtime-benchmarks', + 'pallet-timestamp/runtime-benchmarks', + 'pallet-xcm/runtime-benchmarks', + 'xcm-builder/runtime-benchmarks', +] +std = [ + "bp-messages/std", + "bp-millau/std", + "bp-relayers/std", + "bp-runtime/std", + "bp-rialto-parachain/std", + "bridge-runtime-common/std", + "codec/std", + "scale-info/std", + "sp-api/std", + "sp-std/std", + "sp-io/std", + "sp-core/std", + "sp-runtime/std", + "sp-version/std", + "sp-offchain/std", + "sp-session/std", + "sp-block-builder/std", + "sp-transaction-pool/std", + "sp-inherents/std", + "frame-support/std", + "frame-executive/std", + "frame-system/std", + "frame-system-rpc-runtime-api/std", + "pallet-balances/std", + "pallet-bridge-grandpa/std", + "pallet-bridge-messages/std", + "pallet-bridge-relayers/std", + "pallet-timestamp/std", + "pallet-sudo/std", + "pallet-transaction-payment/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-xcm/std", + "parachain-info/std", + "polkadot-parachain/std", + "cumulus-pallet-aura-ext/std", + "cumulus-pallet-parachain-system/std", + "cumulus-pallet-xcmp-queue/std", + "cumulus-pallet-xcm/std", + "cumulus-primitives-core/std", + "cumulus-primitives-timestamp/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", + "pallet-aura/std", + "sp-consensus-aura/std", +] diff --git a/bin/rialto-parachain/runtime/build.rs b/bin/rialto-parachain/runtime/build.rs new file mode 100644 index 00000000000..65095bd1b7e --- /dev/null +++ b/bin/rialto-parachain/runtime/build.rs @@ -0,0 +1,25 @@ +// Copyright 2019-2021 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 . + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .export_heap_base() + .import_memory() + .build() +} diff --git a/bin/rialto-parachain/runtime/src/lib.rs b/bin/rialto-parachain/runtime/src/lib.rs new file mode 100644 index 00000000000..cd4e256f420 --- /dev/null +++ b/bin/rialto-parachain/runtime/src/lib.rs @@ -0,0 +1,959 @@ +// Copyright 2019-2021 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 . + +//! The Rialto parachain runtime. This can be compiled with `#[no_std]`, ready for Wasm. +//! +//! Originally a copy of runtime from . + +#![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")); + +use bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages; +use codec::{Decode, Encode}; +use cumulus_pallet_parachain_system::AnyRelayNumber; +use scale_info::TypeInfo; +use sp_api::impl_runtime_apis; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{AccountIdLookup, Block as BlockT, DispatchInfoOf, SignedExtension}, + transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, + ApplyExtrinsicResult, +}; + +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +// A few exports that help ease life for downstream crates. +use bp_runtime::HeaderId; +pub use frame_support::{ + construct_runtime, + dispatch::DispatchClass, + match_types, parameter_types, + traits::{ConstU32, Everything, IsInVec, Nothing, Randomness}, + weights::{ + constants::{ + BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, + }, + IdentityFee, Weight, + }, + StorageValue, +}; +pub use frame_system::{Call as SystemCall, EnsureRoot}; +pub use pallet_balances::Call as BalancesCall; +pub use pallet_sudo::Call as SudoCall; +pub use pallet_timestamp::Call as TimestampCall; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; + +pub use bp_rialto_parachain::{ + AccountId, Balance, BlockLength, BlockNumber, BlockWeights, Hash, Hasher as Hashing, Header, + Index, Signature, MAXIMUM_BLOCK_WEIGHT, +}; + +pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall; +pub use pallet_bridge_messages::Call as MessagesCall; +pub use pallet_xcm::Call as XcmCall; + +// Polkadot & XCM imports +use bridge_runtime_common::CustomNetworkId; +use pallet_xcm::XcmPassthrough; +use polkadot_parachain::primitives::Sibling; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, CurrencyAdapter, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, + NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, + SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + SovereignSignedViaLocation, TakeWeightCredit, UsingComponents, +}; +use xcm_executor::{Config, XcmExecutor}; + +pub mod millau_messages; + +// generate signed extension that rejects obsolete bridge transactions +generate_bridge_reject_obsolete_headers_and_messages! { + RuntimeCall, AccountId, + // Grandpa + BridgeMillauGrandpa, + // Messages + BridgeMillauMessages +} + +/// Dummy signed extension that does nothing. +/// +/// We're using it to have the same set of signed extensions on all parachains with bridge pallets +/// deployed (bridge hubs and rialto parachain). +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub struct DummyBridgeRefundMillauMessages; + +impl SignedExtension for DummyBridgeRefundMillauMessages { + const IDENTIFIER: &'static str = "DummyBridgeRefundMillauMessages"; + type AccountId = AccountId; + type Call = RuntimeCall; + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed(&self) -> Result { + Ok(()) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } +} + +/// 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, + DummyBridgeRefundMillauMessages, +); +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = generic::CheckedExtrinsic; +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +/// This runtime version. +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("template-parachain"), + impl_name: create_runtime_str!("template-parachain"), + authoring_version: 1, + spec_version: 1, + impl_version: 0, + apis: RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 0, +}; + +/// 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 = 12000; + +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + +pub const EPOCH_DURATION_IN_BLOCKS: u32 = 10 * MINUTES; + +// Time is measured by 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; + +// Unit = the base number of indivisible units for balances +pub const UNIT: Balance = 1_000_000_000_000; +pub const MILLIUNIT: Balance = 1_000_000_000; +pub const MICROUNIT: Balance = 1_000_000; + +// 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. +pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); + +/// 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 BlockHashCount: BlockNumber = 250; + pub const Version: RuntimeVersion = VERSION; + pub const SS58Prefix: u8 = 48; +} + +// 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 Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = Hashing; + /// The header type. + type Header = generic::Header; + /// 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; + 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 = (); + /// The basic call filter to use in dispatchable. + type BaseCallFilter = Everything; + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// Block & extrinsics weights: base values and limits. + type BlockWeights = BlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = BlockLength; + /// 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>; +} + +parameter_types! { + pub const MinimumPeriod: u64 = SLOT_DURATION / 2; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the Unix epoch. + type Moment = u64; + type OnTimestampSet = (); + type MinimumPeriod = MinimumPeriod; + type WeightInfo = (); +} + +parameter_types! { + pub const ExistentialDeposit: u128 = MILLIUNIT; + pub const TransferFee: u128 = MILLIUNIT; + pub const CreationFee: u128 = MILLIUNIT; + pub const TransactionByteFee: u128 = MICROUNIT; + pub const OperationalFeeMultiplier: u8 = 5; +} + +impl pallet_balances::Config for Runtime { + /// 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 = pallet_balances::weights::SubstrateWeight; + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type OperationalFeeMultiplier = OperationalFeeMultiplier; + type WeightToFee = IdentityFee; + type LengthToFee = IdentityFee; + type FeeMultiplierUpdate = (); + type RuntimeEvent = RuntimeEvent; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeCall = RuntimeCall; + type RuntimeEvent = RuntimeEvent; +} + +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 = AnyRelayNumber; +} + +impl parachain_info::Config for Runtime {} + +impl cumulus_pallet_aura_ext::Config for Runtime {} + +parameter_types! { + pub const RelayLocation: MultiLocation = MultiLocation::parent(); + pub const RelayNetwork: NetworkId = CustomNetworkId::Rialto.as_network_id(); + pub RelayOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into(); + pub UniversalLocation: InteriorMultiLocation = ThisNetwork::get().into(); + /// The Millau network ID. + pub const MillauNetwork: NetworkId = CustomNetworkId::Millau.as_network_id(); + /// The RialtoParachain network ID. + pub const ThisNetwork: NetworkId = CustomNetworkId::RialtoParachain.as_network_id(); +} + +/// 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 default `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 assets on this chain. +pub type LocalAssetTransactor = 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. + (), +>; + +/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, +/// ready for dispatching a transaction with XCM `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 + // 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 + // `Origin::Signed` origin of the same 32-byte value. + SignedAccountId32AsNative, + // Xcm origins can be represented natively under the Xcm pallet's Xcm origin. + XcmPassthrough, +); + +// TODO: until https://github.com/paritytech/parity-bridges-common/issues/1417 is fixed (in either way), +// the following constant must match the similar constant in the Millau runtime. + +parameter_types! { + /// The amount of weight an XCM operation takes. We don't care much about those values as we're on testnet. + pub const UnitWeightCost: Weight = Weight::from_parts(1_000_000, 1024); + // One UNIT buys 1 second of weight. + pub const WeightPrice: (MultiLocation, u128) = (MultiLocation::parent(), UNIT); + pub const MaxInstructions: u32 = 100; + pub const MaxAuthorities: u32 = 100_000; + pub MaxAssetsIntoHolding: u32 = 64; +} + +match_types! { + pub type ParentOrParentsUnitPlurality: impl Contains = { + MultiLocation { parents: 1, interior: Here } | + MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) } + }; +} + +pub type Barrier = TakeWeightCredit; + +/// Dispatches received XCM messages from other chain. +pub type OnRialtoParachainBlobDispatcher = + xcm_builder::BridgeBlobDispatcher; + +/// XCM weigher type. +pub type XcmWeigher = FixedWeightBounds; + +pub struct XcmConfig; +impl Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = XcmOriginToTransactDispatchOrigin; + type IsReserve = NativeAsset; + type IsTeleporter = NativeAsset; // <- should be enough to allow teleportation of UNIT + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = XcmWeigher; + type Trader = UsingComponents, RelayLocation, AccountId, Balances, ()>; + type ResponseHandler = PolkadotXcm; + type AssetTrap = PolkadotXcm; + type AssetClaims = PolkadotXcm; + type SubscriptionService = PolkadotXcm; + type PalletInstancesInfo = (); + type MaxAssetsIntoHolding = MaxAssetsIntoHolding; + type AssetLocker = (); + type AssetExchanger = (); + type FeeManager = (); + type MessageExporter = millau_messages::ToMillauBlobExporter; + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; +} + +/// No local origins on this chain are allowed to dispatch XCM sends/executions. +pub type LocalOriginToLocation = SignedToAccountId32; + +/// The XCM router. We are not sending messages to sibling/parent/child chains here. +pub type XcmRouter = (); + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = None; +} + +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 = Everything; + type XcmReserveTransferFilter = Everything; + type Weigher = XcmWeigher; + 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 = (); + type MaxLockers = frame_support::traits::ConstU32<8>; + type UniversalLocation = UniversalLocation; + type WeightInfo = pallet_xcm::TestWeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type AdminOrigin = frame_system::EnsureRoot; +} + +impl cumulus_pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; +} + +impl cumulus_pallet_xcmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ChannelInfo = ParachainSystem; + type VersionWrapper = (); + type ExecuteOverweightOrigin = EnsureRoot; + type ControllerOrigin = EnsureRoot; + type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin; + type WeightInfo = (); + type PriceForSiblingDelivery = (); +} + +impl cumulus_pallet_dmp_queue::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type XcmExecutor = XcmExecutor; + type ExecuteOverweightOrigin = frame_system::EnsureRoot; +} + +impl pallet_aura::Config for Runtime { + type AuthorityId = AuraId; + type DisabledValidators = (); + type MaxAuthorities = MaxAuthorities; +} + +impl pallet_bridge_relayers::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Reward = Balance; + type PaymentProcedure = + bp_relayers::PayRewardFromAccount, AccountId>; + type WeightInfo = (); +} + +pub type MillauGrandpaInstance = (); +impl pallet_bridge_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = bp_millau::Millau; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = ConstU32<{ bp_millau::DAYS as u32 }>; + type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; +} + +parameter_types! { + pub const MaxMessagesToPruneAtOnce: bp_messages::MessageNonce = 8; + pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + pub const RootAccountForPayments: Option = None; + pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID; + pub ActiveOutboundLanes: &'static [bp_messages::LaneId] = &[millau_messages::XCM_LANE]; +} + +/// Instance of the messages pallet used to relay messages to/from Millau chain. +pub type WithMillauMessagesInstance = (); + +impl pallet_bridge_messages::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; + type ActiveOutboundLanes = ActiveOutboundLanes; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize; + type OutboundPayload = crate::millau_messages::ToMillauMessagePayload; + + type InboundPayload = crate::millau_messages::FromMillauMessagePayload; + type InboundRelayer = bp_millau::AccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = crate::millau_messages::MillauAsTargetHeaderChain; + type LaneMessageVerifier = crate::millau_messages::ToMillauMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + Runtime, + WithMillauMessagesInstance, + frame_support::traits::ConstU128<100_000>, + >; + + type SourceHeaderChain = crate::millau_messages::MillauAsSourceHeaderChain; + type MessageDispatch = crate::millau_messages::FromMillauMessageDispatch; + type BridgedChainId = BridgedChainId; +} + +// Create the runtime by composing the FRAME pallets that were previously configured. +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = generic::Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + Sudo: pallet_sudo::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + + ParachainSystem: cumulus_pallet_parachain_system::{Pallet, Call, Storage, Inherent, Event} = 20, + ParachainInfo: parachain_info::{Pallet, Storage, Config} = 21, + + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event} = 30, + + Aura: pallet_aura::{Pallet, Config}, + AuraExt: cumulus_pallet_aura_ext::{Pallet, Config}, + + // XCM helpers. + XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Call, Storage, Event} = 50, + PolkadotXcm: pallet_xcm::{Pallet, Call, Event, Origin} = 51, + CumulusXcm: cumulus_pallet_xcm::{Pallet, Call, Event, Origin} = 52, + DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event} = 53, + + // Millau bridge modules. + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, + BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage, Event}, + BridgeMillauMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, + } +); + +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_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 decode_session_keys( + encoded: Vec, + ) -> Option, KeyTypeId)>> { + SessionKeys::decode_into_raw_public_keys(&encoded) + } + + fn generate_session_keys(seed: Option>) -> Vec { + SessionKeys::generate(seed) + } + } + + 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().to_vec() + } + } + + 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) -> Index { + 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 bp_millau::MillauFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeMillauGrandpa::best_finalized() + } + } + + impl bp_millau::ToMillauOutboundLaneApi 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, + WithMillauMessagesInstance, + >(lane, begin, end) + } + } + + impl bp_millau::FromMillauInboundLaneApi 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, + WithMillauMessagesInstance, + >(lane, messages) + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark for Runtime { + fn benchmark_metadata(_extra: bool) -> ( + Vec, + Vec, + ) { + todo!("TODO: fix or remove") + } + + fn dispatch_benchmark( + config: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey}; + + use frame_system_benchmarking::Pallet as SystemBench; + impl frame_system_benchmarking::Config for Runtime {} + + 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_benchmark!(params, batches, frame_system, SystemBench::); + add_benchmark!(params, batches, pallet_balances, Balances); + add_benchmark!(params, batches, pallet_timestamp, Timestamp); + + Ok(batches) + } + } +} + +struct CheckInherents; + +impl cumulus_pallet_parachain_system::CheckInherents for CheckInherents { + fn check_inherents( + block: &Block, + relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof, + ) -> sp_inherents::CheckInherentsResult { + let relay_chain_slot = relay_state_proof + .read_slot() + .expect("Could not read the relay chain slot from the proof"); + + let inherent_data = + cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration( + relay_chain_slot, + sp_std::time::Duration::from_secs(6), + ) + .create_inherent_data() + .expect("Could not create the timestamp inherent data"); + + inherent_data.check_extrinsics(block) + } +} + +cumulus_pallet_parachain_system::register_validate_block!( + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, + CheckInherents = CheckInherents, +); + +#[cfg(test)] +mod tests { + use super::*; + use crate::millau_messages::{FromMillauMessageDispatch, XCM_LANE}; + use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + LaneId, MessageKey, + }; + use bridge_runtime_common::{ + integrity::check_additional_signed, messages_xcm_extension::XcmBlobMessageDispatchResult, + }; + use codec::Encode; + use pallet_bridge_messages::OutboundLanes; + use sp_runtime::generic::Era; + use xcm_executor::XcmExecutor; + + fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new( + frame_system::GenesisConfig::default().build_storage::().unwrap(), + ) + } + + fn prepare_outbound_xcm_message(destination: NetworkId) -> Xcm { + vec![ExportMessage { + network: destination, + destination: destination.into(), + xcm: vec![Instruction::Trap(42)].into(), + }] + .into() + } + + #[test] + fn xcm_messages_to_millau_are_sent_using_bridge_exporter() { + new_test_ext().execute_with(|| { + // ensure that the there are no messages queued + assert_eq!( + OutboundLanes::::get(XCM_LANE) + .latest_generated_nonce, + 0, + ); + + // export message instruction "sends" message to Rialto + XcmExecutor::::execute_xcm_in_credit( + Here, + prepare_outbound_xcm_message(MillauNetwork::get()), + Default::default(), + Weight::MAX, + Weight::MAX, + ) + .ensure_complete() + .expect("runtime configuration must be correct"); + + // ensure that the message has been queued + assert_eq!( + OutboundLanes::::get(XCM_LANE) + .latest_generated_nonce, + 1, + ); + }) + } + + fn prepare_inbound_bridge_message() -> DispatchMessage> { + let xcm = xcm::VersionedXcm::::V3(vec![Instruction::Trap(42)].into()); + let location = + xcm::VersionedInteriorMultiLocation::V3(X1(GlobalConsensus(ThisNetwork::get()))); + // this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor + // or public fields, so just tuple + let bridge_message = (location, xcm).encode(); + DispatchMessage { + key: MessageKey { lane_id: LaneId([0, 0, 0, 0]), nonce: 1 }, + data: DispatchMessageData { payload: Ok(bridge_message) }, + } + } + + #[test] + fn xcm_messages_from_millau_are_dispatched() { + new_test_ext().execute_with(|| { + let incoming_message = prepare_inbound_bridge_message(); + + // we care only about handing message to the XCM dispatcher, so we don't care about its + // actual dispatch + let dispatch_result = + FromMillauMessageDispatch::dispatch(&AccountId::from([0u8; 32]), incoming_message); + assert!(matches!( + dispatch_result.dispatch_level_result, + XcmBlobMessageDispatchResult::NotDispatched(_), + )); + }); + } + + #[test] + fn ensure_signed_extension_definition_is_correct() { + 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, + DummyBridgeRefundMillauMessages, + ); + let indirect_payload = bp_rialto_parachain::SignedExtension::new( + ((), (), (), (), Era::Immortal, 10.into(), (), 10.into(), (), ()), + None, + ); + assert_eq!(payload.encode(), indirect_payload.encode()); + + check_additional_signed::(); + } +} diff --git a/bin/rialto-parachain/runtime/src/millau_messages.rs b/bin/rialto-parachain/runtime/src/millau_messages.rs new file mode 100644 index 00000000000..5d4a92b5091 --- /dev/null +++ b/bin/rialto-parachain/runtime/src/millau_messages.rs @@ -0,0 +1,138 @@ +// Copyright 2019-2021 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 . + +//! Everything required to serve Millau <-> RialtoParachain messages. + +// TODO: this is almost exact copy of `millau_messages.rs` from Rialto runtime. +// Should be extracted to a separate crate and reused here. + +use crate::{MillauGrandpaInstance, Runtime, RuntimeOrigin, WithMillauMessagesInstance}; + +use bp_messages::LaneId; +use bridge_runtime_common::{ + messages::{ + self, source::TargetHeaderChainAdapter, target::SourceHeaderChainAdapter, MessageBridge, + }, + messages_xcm_extension::{XcmBlobHauler, XcmBlobHaulerAdapter}, +}; +use frame_support::{parameter_types, weights::Weight, RuntimeDebug}; +use xcm::latest::prelude::*; +use xcm_builder::HaulBlobExporter; + +/// Default lane that is used to send messages to Millau. +pub const XCM_LANE: LaneId = LaneId([0, 0, 0, 0]); +/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge +/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual +/// tests, confirming that we don't break encoding somewhere between. +pub const BASE_XCM_WEIGHT_TWICE: Weight = crate::UnitWeightCost::get().saturating_mul(2); + +parameter_types! { + /// Weight credit for our test messages. + /// + /// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge + /// (it is prepended with `UniversalOrigin` instruction). + pub const WeightCredit: Weight = BASE_XCM_WEIGHT_TWICE; +} + +/// Message payload for RialtoParachain -> Millau messages. +pub type ToMillauMessagePayload = messages::source::FromThisChainMessagePayload; + +/// Message verifier for RialtoParachain -> Millau messages. +pub type ToMillauMessageVerifier = + messages::source::FromThisChainMessageVerifier; + +/// Message payload for Millau -> RialtoParachain messages. +pub type FromMillauMessagePayload = messages::target::FromBridgedChainMessagePayload; + +/// Call-dispatch based message dispatch for Millau -> RialtoParachain messages. +pub type FromMillauMessageDispatch = + bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatch< + bp_rialto_parachain::RialtoParachain, + bp_millau::Millau, + crate::OnRialtoParachainBlobDispatcher, + (), + >; + +/// Messages proof for Millau -> RialtoParachain messages. +pub type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesProof; + +/// Messages delivery proof for RialtoParachain -> Millau messages. +pub type ToMillauMessagesDeliveryProof = + messages::source::FromBridgedChainMessagesDeliveryProof; + +/// Maximal outbound payload size of Rialto -> Millau messages. +pub type ToMillauMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + +/// Millau <-> RialtoParachain message bridge. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct WithMillauMessageBridge; + +impl MessageBridge for WithMillauMessageBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = + bp_rialto_parachain::WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME; + + type ThisChain = RialtoParachain; + type BridgedChain = Millau; + type BridgedHeaderChain = + pallet_bridge_grandpa::GrandpaChainHeaders; +} + +/// RialtoParachain chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct RialtoParachain; + +impl messages::UnderlyingChainProvider for RialtoParachain { + type Chain = bp_rialto_parachain::RialtoParachain; +} + +impl messages::ThisChainWithMessages for RialtoParachain { + type RuntimeOrigin = RuntimeOrigin; +} + +/// Millau chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Millau; +/// Millau as source header chain. +pub type MillauAsSourceHeaderChain = SourceHeaderChainAdapter; +/// Millau as target header chain. +pub type MillauAsTargetHeaderChain = TargetHeaderChainAdapter; + +impl messages::UnderlyingChainProvider for Millau { + type Chain = bp_millau::Millau; +} + +impl messages::BridgedChainWithMessages for Millau {} + +/// Export XCM messages to be relayed to Millau. +pub type ToMillauBlobExporter = + HaulBlobExporter, crate::MillauNetwork, ()>; + +/// To-Millau XCM hauler. +pub struct ToMillauXcmBlobHauler; + +impl XcmBlobHauler for ToMillauXcmBlobHauler { + type MessageSender = pallet_bridge_messages::Pallet; + type MessageSenderOrigin = RuntimeOrigin; + + fn message_sender_origin() -> RuntimeOrigin { + pallet_xcm::Origin::from(MultiLocation::new(1, crate::UniversalLocation::get())).into() + } + + fn xcm_lane() -> LaneId { + XCM_LANE + } +} diff --git a/bin/rialto/node/Cargo.toml b/bin/rialto/node/Cargo.toml new file mode 100644 index 00000000000..23c7d3315e7 --- /dev/null +++ b/bin/rialto/node/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "rialto-bridge-node" +description = "Substrate node compatible with Rialto runtime" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +build = "build.rs" +repository = "https://github.com/paritytech/parity-bridges-common/" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +clap = { version = "4.2.2", features = ["derive"] } +serde_json = "1.0.96" + +# Bridge dependencies + +rialto-runtime = { path = "../runtime" } + +# Substrate Dependencies + +sp-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } +node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master"} +sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } + +# Polkadot Dependencies +polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, features = [ "full-node", "polkadot-native" ] } + +[build-dependencies] +substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = [] +runtime-benchmarks = [ + "polkadot-service/runtime-benchmarks", + "rialto-runtime/runtime-benchmarks", +] diff --git a/bin/rialto/node/build.rs b/bin/rialto/node/build.rs new file mode 100644 index 00000000000..d9b50049e26 --- /dev/null +++ b/bin/rialto/node/build.rs @@ -0,0 +1,23 @@ +// Copyright 2019-2021 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 . + +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/bin/rialto/node/src/chain_spec.rs b/bin/rialto/node/src/chain_spec.rs new file mode 100644 index 00000000000..ceb82d45b38 --- /dev/null +++ b/bin/rialto/node/src/chain_spec.rs @@ -0,0 +1,289 @@ +// Copyright 2019-2021 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 . + +use frame_support::weights::Weight; +use polkadot_primitives::v4::{AssignmentId, ValidatorId}; +use rialto_runtime::{ + AccountId, BabeConfig, BalancesConfig, BeefyConfig, BridgeMillauMessagesConfig, + ConfigurationConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature, + SudoConfig, SystemConfig, WASM_BINARY, +}; +use serde_json::json; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use sp_consensus_babe::AuthorityId as BabeId; +use sp_consensus_beefy::crypto::AuthorityId as BeefyId; +use sp_consensus_grandpa::AuthorityId as GrandpaId; +use sp_core::{sr25519, Pair, Public}; +use sp_runtime::traits::{IdentifyAccount, Verify}; + +/// "Names" of the authorities accounts at local testnet. +const LOCAL_AUTHORITIES_ACCOUNTS: [&str; 5] = ["Alice", "Bob", "Charlie", "Dave", "Eve"]; +/// "Names" of the authorities accounts at development testnet. +const DEV_AUTHORITIES_ACCOUNTS: [&str; 1] = [LOCAL_AUTHORITIES_ACCOUNTS[0]]; +/// "Names" of all possible authorities accounts. +const ALL_AUTHORITIES_ACCOUNTS: [&str; 5] = LOCAL_AUTHORITIES_ACCOUNTS; +/// "Name" of the `sudo` account. +const SUDO_ACCOUNT: &str = "Sudo"; +/// "Name" of the account, which owns the with-Millau messages pallet. +const MILLAU_MESSAGES_PALLET_OWNER: &str = "Millau.MessagesOwner"; + +/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. +pub type ChainSpec = + sc_service::GenericChainSpec; + +/// The chain specification option. This is expected to come in from the CLI and +/// is little more than one of a number of alternatives which can easily be converted +/// from a string (`--chain=...`) into a `ChainSpec`. +#[derive(Clone, Debug)] +pub enum Alternative { + /// Whatever the current runtime is, with just Alice as an auth. + Development, + /// Whatever the current runtime is, with simple Alice/Bob/Charlie/Dave/Eve auths. + LocalTestnet, +} + +/// Helper function to generate a crypto pair from seed +pub fn get_from_seed(seed: &str) -> ::Public { + TPublic::Pair::from_string(&format!("//{seed}"), None) + .expect("static values are valid; qed") + .public() +} + +type AccountPublic = ::Signer; + +/// Helper function to generate an account ID from seed +pub fn get_account_id_from_seed(seed: &str) -> AccountId +where + AccountPublic: From<::Public>, +{ + AccountPublic::from(get_from_seed::(seed)).into_account() +} + +/// Helper function to generate authority keys. +pub fn get_authority_keys_from_seed( + s: &str, +) -> (AccountId, BabeId, BeefyId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { + ( + get_account_id_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + get_from_seed::(s), + ) +} + +impl Alternative { + /// Get an actual chain config from one of the alternatives. + pub(crate) fn load(self) -> ChainSpec { + let properties = Some( + json!({ + "tokenDecimals": 9, + "tokenSymbol": "RLT" + }) + .as_object() + .expect("Map given; qed") + .clone(), + ); + match self { + Alternative::Development => ChainSpec::from_genesis( + "Rialto Development", + "rialto_dev", + sc_service::ChainType::Development, + || { + testnet_genesis( + DEV_AUTHORITIES_ACCOUNTS + .into_iter() + .map(get_authority_keys_from_seed) + .collect(), + get_account_id_from_seed::(SUDO_ACCOUNT), + endowed_accounts(), + true, + ) + }, + vec![], + None, + None, + None, + properties, + Default::default(), + ), + Alternative::LocalTestnet => ChainSpec::from_genesis( + "Rialto Local", + "rialto_local", + sc_service::ChainType::Local, + || { + testnet_genesis( + LOCAL_AUTHORITIES_ACCOUNTS + .into_iter() + .map(get_authority_keys_from_seed) + .collect(), + get_account_id_from_seed::(SUDO_ACCOUNT), + endowed_accounts(), + true, + ) + }, + vec![], + None, + None, + None, + properties, + Default::default(), + ), + } + } +} + +/// We're using the same set of endowed accounts on all Millau chains (dev/local) to make +/// sure that all accounts, required for bridge to be functional (e.g. relayers fund account, +/// accounts used by relayers in our test deployments, accounts used for demonstration +/// purposes), are all available on these chains. +fn endowed_accounts() -> Vec { + let all_authorities = ALL_AUTHORITIES_ACCOUNTS.iter().flat_map(|x| { + [ + get_account_id_from_seed::(x), + get_account_id_from_seed::(&format!("{x}//stash")), + ] + }); + vec![ + // Sudo account + get_account_id_from_seed::(SUDO_ACCOUNT), + // Regular (unused) accounts + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("Ferdie//stash"), + // Accounts, used by Rialto<>Millau bridge + get_account_id_from_seed::(MILLAU_MESSAGES_PALLET_OWNER), + get_account_id_from_seed::("Millau.HeadersAndMessagesRelay"), + get_account_id_from_seed::("Millau.OutboundMessagesRelay.Lane00000001"), + get_account_id_from_seed::("Millau.InboundMessagesRelay.Lane00000001"), + get_account_id_from_seed::("Millau.MessagesSender"), + ] + .into_iter() + .chain(all_authorities) + .collect() +} + +fn session_keys( + babe: BabeId, + beefy: BeefyId, + grandpa: GrandpaId, + para_validator: ValidatorId, + para_assignment: AssignmentId, + authority_discovery: AuthorityDiscoveryId, +) -> SessionKeys { + SessionKeys { babe, beefy, grandpa, para_validator, para_assignment, authority_discovery } +} + +fn testnet_genesis( + initial_authorities: Vec<( + AccountId, + BabeId, + BeefyId, + GrandpaId, + ValidatorId, + AssignmentId, + AuthorityDiscoveryId, + )>, + root_key: AccountId, + endowed_accounts: Vec, + _enable_println: bool, +) -> GenesisConfig { + GenesisConfig { + system: SystemConfig { + code: WASM_BINARY.expect("Rialto development WASM not available").to_vec(), + }, + balances: BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 50)).collect(), + }, + babe: BabeConfig { + authorities: Vec::new(), + epoch_config: Some(rialto_runtime::BABE_GENESIS_EPOCH_CONFIG), + }, + beefy: BeefyConfig::default(), + grandpa: GrandpaConfig { authorities: Vec::new() }, + sudo: SudoConfig { key: Some(root_key) }, + session: SessionConfig { + keys: initial_authorities + .iter() + .map(|x| { + ( + x.0.clone(), + x.0.clone(), + session_keys( + x.1.clone(), + x.2.clone(), + x.3.clone(), + x.4.clone(), + x.5.clone(), + x.6.clone(), + ), + ) + }) + .collect::>(), + }, + authority_discovery: Default::default(), + hrmp: Default::default(), + // this configuration is exact copy of configuration from Polkadot repo + // (see /node/service/src/chain_spec.rs:default_parachains_host_configuration) + configuration: ConfigurationConfig { + config: polkadot_runtime_parachains::configuration::HostConfiguration { + validation_upgrade_cooldown: 2u32, + validation_upgrade_delay: 2, + code_retention_period: 1200, + max_code_size: polkadot_primitives::v4::MAX_CODE_SIZE, + max_pov_size: polkadot_primitives::v4::MAX_POV_SIZE, + max_head_data_size: 32 * 1024, + group_rotation_frequency: 20, + chain_availability_period: 4, + thread_availability_period: 4, + max_upward_queue_count: 8, + max_upward_queue_size: 1024 * 1024, + max_downward_message_size: 1024 * 1024, + ump_service_total_weight: Weight::from_parts( + 100_000_000_000, + polkadot_primitives::v4::MAX_POV_SIZE as u64, + ), + max_upward_message_size: 50 * 1024, + max_upward_message_num_per_candidate: 5, + hrmp_sender_deposit: 0, + hrmp_recipient_deposit: 0, + hrmp_channel_max_capacity: 8, + hrmp_channel_max_total_size: 8 * 1024, + hrmp_max_parachain_inbound_channels: 4, + hrmp_max_parathread_inbound_channels: 4, + hrmp_channel_max_message_size: 1024 * 1024, + hrmp_max_parachain_outbound_channels: 4, + hrmp_max_parathread_outbound_channels: 4, + hrmp_max_message_num_per_candidate: 5, + dispute_period: 6, + no_show_slots: 2, + n_delay_tranches: 25, + needed_approvals: 2, + relay_vrf_modulo_samples: 2, + zeroth_delay_tranche_width: 0, + minimum_validation_upgrade_delay: 5, + ..Default::default() + }, + }, + paras: Default::default(), + bridge_millau_messages: BridgeMillauMessagesConfig { + owner: Some(get_account_id_from_seed::(MILLAU_MESSAGES_PALLET_OWNER)), + ..Default::default() + }, + xcm_pallet: Default::default(), + } +} diff --git a/bin/rialto/node/src/cli.rs b/bin/rialto/node/src/cli.rs new file mode 100644 index 00000000000..98323c9d9ca --- /dev/null +++ b/bin/rialto/node/src/cli.rs @@ -0,0 +1,88 @@ +// Copyright 2019-2021 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 . + +use clap::Parser; +use sc_cli::RunCmd; + +#[derive(Debug, Parser)] +pub struct Cli { + #[structopt(subcommand)] + pub subcommand: Option, + + #[structopt(flatten)] + pub run: RunCmd, +} + +/// Possible subcommands of the main binary. +#[derive(Debug, Parser)] +#[allow(clippy::large_enum_variant)] +pub enum Subcommand { + /// Key management CLI utilities + #[clap(subcommand)] + Key(sc_cli::KeySubcommand), + + /// Verify a signature for a message, provided on `STDIN`, with a given (public or secret) key. + Verify(sc_cli::VerifyCmd), + + /// Generate a seed that provides a vanity address. + Vanity(sc_cli::VanityCmd), + + /// Sign a message, with a given (secret) key. + Sign(sc_cli::SignCmd), + + /// 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), + + /// Inspect blocks or extrinsics. + Inspect(node_inspect::cli::InspectCmd), + + /// Benchmark runtime pallets. + #[clap(subcommand)] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), + + /// FOR INTERNAL USE: analog of the "prepare-worker" command of the polkadot binary. + #[clap(name = "prepare-worker", hide = true)] + PvfPrepareWorker(ValidationWorkerCommand), + + /// FOR INTERNAL USE: analog of the "execute-worker" command of the polkadot binary. + #[clap(name = "execute-worker", hide = true)] + PvfExecuteWorker(ValidationWorkerCommand), +} + +/// Validation worker command. +#[derive(Debug, Parser)] +pub struct ValidationWorkerCommand { + /// The path to the validation host's socket. + pub socket_path: String, +} diff --git a/bin/rialto/node/src/command.rs b/bin/rialto/node/src/command.rs new file mode 100644 index 00000000000..0bff2e523b4 --- /dev/null +++ b/bin/rialto/node/src/command.rs @@ -0,0 +1,222 @@ +// Copyright 2019-2021 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 . + +use crate::cli::{Cli, Subcommand}; +use frame_benchmarking_cli::BenchmarkCmd; +use rialto_runtime::{Block, RuntimeApi}; +use sc_cli::{ChainSpec, RuntimeVersion, SubstrateCli}; + +impl SubstrateCli for Cli { + fn impl_name() -> String { + "Rialto Bridge Node".into() + } + + fn impl_version() -> String { + env!("CARGO_PKG_VERSION").into() + } + + fn description() -> String { + "Rialto Bridge Node".into() + } + + fn author() -> String { + "Parity Technologies".into() + } + + fn support_url() -> String { + "https://github.com/paritytech/parity-bridges-common/".into() + } + + fn copyright_start_year() -> i32 { + 2019 + } + + fn executable_name() -> String { + "rialto-bridge-node".into() + } + + fn native_runtime_version(_: &Box) -> &'static RuntimeVersion { + &rialto_runtime::VERSION + } + + fn load_spec(&self, id: &str) -> Result, String> { + Ok(Box::new( + match id { + "" | "dev" => crate::chain_spec::Alternative::Development, + "local" => crate::chain_spec::Alternative::LocalTestnet, + _ => return Err(format!("Unsupported chain specification: {id}")), + } + .load(), + )) + } +} + +// Rialto native executor instance. +pub struct ExecutorDispatch; + +impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + rialto_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + rialto_runtime::native_version() + } +} + +/// Parse and run command line arguments +pub fn run() -> sc_cli::Result<()> { + let cli = Cli::from_args(); + sp_core::crypto::set_default_ss58_version(sp_core::crypto::Ss58AddressFormat::custom( + rialto_runtime::SS58Prefix::get() as u16, + )); + + match &cli.subcommand { + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + match cmd { + BenchmarkCmd::Pallet(cmd) => + if cfg!(feature = "runtime-benchmarks") { + runner.sync_run(|config| cmd.run::(config)) + } else { + println!( + "Benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + ); + Ok(()) + }, + _ => Err("Unsupported benchmarking subcommand".into()), + } + }, + Some(Subcommand::Key(cmd)) => cmd.run(&cli), + Some(Subcommand::Sign(cmd)) => cmd.run(), + Some(Subcommand::Verify(cmd)) => cmd.run(), + Some(Subcommand::Vanity(cmd)) => cmd.run(), + 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(|mut config| { + let (client, _, import_queue, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; + Ok((cmd.run(client, import_queue), task_manager)) + }) + }, + Some(Subcommand::ExportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|mut config| { + let (client, _, _, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; + Ok((cmd.run(client, config.database), task_manager)) + }) + }, + Some(Subcommand::ExportState(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|mut config| { + let (client, _, _, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; + Ok((cmd.run(client, config.chain_spec), task_manager)) + }) + }, + Some(Subcommand::ImportBlocks(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|mut config| { + let (client, _, import_queue, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; + 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(|mut config| { + let (client, backend, _, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; + Ok((cmd.run(client, backend, None), task_manager)) + }) + }, + Some(Subcommand::Inspect(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run::(config)) + }, + Some(Subcommand::PvfPrepareWorker(cmd)) => { + let mut builder = sc_cli::LoggerBuilder::new(""); + builder.with_colors(false); + let _ = builder.init(); + + polkadot_node_core_pvf::prepare_worker_entrypoint(&cmd.socket_path, None); + Ok(()) + }, + Some(crate::cli::Subcommand::PvfExecuteWorker(cmd)) => { + let mut builder = sc_cli::LoggerBuilder::new(""); + builder.with_colors(false); + let _ = builder.init(); + + polkadot_node_core_pvf::execute_worker_entrypoint(&cmd.socket_path, None); + Ok(()) + }, + None => { + let runner = cli.create_runner(&cli.run)?; + + // some parameters that are used by polkadot nodes, but that are not used by our binary + // let jaeger_agent = None; + // let grandpa_pause = None; + // let no_beefy = true; + // let telemetry_worker_handler = None; + // let is_collator = crate::service::IsCollator::No; + let overseer_gen = polkadot_service::overseer::RealOverseerGen; + runner.run_node_until_exit(|config| async move { + let is_collator = polkadot_service::IsCollator::No; + let grandpa_pause = None; + let enable_beefy = true; + let jaeger_agent = None; + let telemetry_worker_handle = None; + let program_path = None; + let overseer_enable_anyways = false; + + polkadot_service::new_full::( + config, + is_collator, + grandpa_pause, + enable_beefy, + jaeger_agent, + telemetry_worker_handle, + program_path, + overseer_enable_anyways, + overseer_gen, + None, + None, + None, + ) + .map(|full| full.task_manager) + .map_err(service_error) + }) + }, + } +} + +// We don't want to change 'service.rs' too much to ease future updates => it'll keep using +// its own error enum like original polkadot service does. +fn service_error(err: polkadot_service::Error) -> sc_cli::Error { + sc_cli::Error::Application(Box::new(err)) +} diff --git a/bin/rialto/node/src/main.rs b/bin/rialto/node/src/main.rs new file mode 100644 index 00000000000..6dea84a309b --- /dev/null +++ b/bin/rialto/node/src/main.rs @@ -0,0 +1,28 @@ +// Copyright 2019-2021 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 . + +//! Rialto bridge node. + +#![warn(missing_docs)] + +mod chain_spec; +mod cli; +mod command; + +/// Run the Rialto Node +fn main() -> sc_cli::Result<()> { + command::run() +} diff --git a/bin/rialto/runtime/Cargo.toml b/bin/rialto/runtime/Cargo.toml new file mode 100644 index 00000000000..2b68e72d6f8 --- /dev/null +++ b/bin/rialto/runtime/Cargo.toml @@ -0,0 +1,142 @@ +[package] +name = "rialto-runtime" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +repository = "https://github.com/paritytech/parity-bridges-common/" +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.5.0", default-features = false, features = ["derive"] } + +# Bridge dependencies + +bp-messages = { path = "../../../primitives/messages", default-features = false } +bp-millau = { path = "../../../primitives/chain-millau", default-features = false } +bp-relayers = { path = "../../../primitives/relayers", default-features = false } +bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false } +bp-runtime = { path = "../../../primitives/runtime", default-features = false } +bridge-runtime-common = { path = "../../runtime-common", default-features = false } +pallet-bridge-beefy = { path = "../../../modules/beefy", default-features = false } +pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false } +pallet-bridge-messages = { path = "../../../modules/messages", default-features = false } +pallet-bridge-relayers = { path = "../../../modules/relayers", default-features = false } +pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false } + +# Substrate Dependencies + +sp-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, features = ["historical"]} +pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-inherents = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-offchain = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +# Polkadot (parachain) Dependencies +pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } + +[dev-dependencies] +bridge-runtime-common = { path = "../../runtime-common", features = ["integrity-test"] } +env_logger = "0.10" +static_assertions = "1.1" + +[build-dependencies] +substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = ["std"] +std = [ + "sp-consensus-beefy/std", + "bp-messages/std", + "bp-millau/std", + "bp-relayers/std", + "bp-rialto/std", + "bp-runtime/std", + "bridge-runtime-common/std", + "codec/std", + "frame-benchmarking/std", + "frame-executive/std", + "frame-support/std", + "frame-system-rpc-runtime-api/std", + "frame-system/std", + "pallet-authority-discovery/std", + "pallet-babe/std", + "pallet-balances/std", + "pallet-beefy/std", + "pallet-beefy-mmr/std", + "pallet-bridge-beefy/std", + "pallet-bridge-grandpa/std", + "pallet-bridge-messages/std", + "pallet-bridge-relayers/std", + "pallet-grandpa/std", + "pallet-mmr/std", + "pallet-xcm/std", + "pallet-session/std", + "pallet-shift-session-manager/std", + "pallet-sudo/std", + "pallet-timestamp/std", + "pallet-transaction-payment-rpc-runtime-api/std", + "pallet-transaction-payment/std", + "polkadot-primitives/std", + "polkadot-runtime-common/std", + "polkadot-runtime-parachains/std", + "scale-info/std", + "sp-api/std", + "sp-authority-discovery/std", + "sp-block-builder/std", + "sp-consensus-babe/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", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", +] +runtime-benchmarks = [ + "bridge-runtime-common/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-bridge-messages/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] diff --git a/bin/rialto/runtime/build.rs b/bin/rialto/runtime/build.rs new file mode 100644 index 00000000000..cc865704327 --- /dev/null +++ b/bin/rialto/runtime/build.rs @@ -0,0 +1,25 @@ +// Copyright 2019-2021 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 . + +use substrate_wasm_builder::WasmBuilder; + +fn main() { + WasmBuilder::new() + .with_current_project() + .import_memory() + .export_heap_base() + .build() +} diff --git a/bin/rialto/runtime/src/lib.rs b/bin/rialto/runtime/src/lib.rs new file mode 100644 index 00000000000..aeb0a3a7c57 --- /dev/null +++ b/bin/rialto/runtime/src/lib.rs @@ -0,0 +1,986 @@ +// Copyright 2019-2021 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 . + +//! The Rialto 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 = "256"] +// Runtime-generated enums +#![allow(clippy::large_enum_variant)] +// From construct_runtime macro +#![allow(clippy::from_over_into)] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +pub mod millau_messages; +pub mod parachains; +pub mod xcm_config; + +use bp_runtime::HeaderId; +use pallet_grandpa::{ + fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList, +}; +use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo}; +use sp_api::impl_runtime_apis; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use sp_consensus_beefy::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet}; +use sp_core::OpaqueMetadata; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{AccountIdLookup, Block as BlockT, Keccak256, NumberFor, OpaqueKeys}, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, FixedPointNumber, Perquintill, +}; +use sp_std::{collections::btree_map::BTreeMap, prelude::*}; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +// A few exports that help ease life for downstream crates. +pub use frame_support::{ + construct_runtime, + dispatch::DispatchClass, + parameter_types, + traits::{ + ConstU32, ConstU64, ConstU8, Currency, ExistenceRequirement, Imbalance, KeyOwnerProofSystem, + }, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, IdentityFee, RuntimeDbWeight, Weight}, + StorageValue, +}; + +pub use frame_system::Call as SystemCall; +pub use pallet_balances::Call as BalancesCall; +pub use pallet_bridge_beefy::Call as BridgeBeefyCall; +pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall; +pub use pallet_bridge_messages::Call as MessagesCall; +pub use pallet_sudo::Call as SudoCall; +pub use pallet_timestamp::Call as TimestampCall; +pub use pallet_xcm::Call as XcmCall; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; +pub use sp_runtime::{Perbill, Permill}; + +/// An index to a block. +pub type BlockNumber = bp_rialto::BlockNumber; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = bp_rialto::Signature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = bp_rialto::AccountId; + +/// The type for looking up accounts. We don't expect more than 4 billion of them, but you +/// never know... +pub type AccountIndex = u32; + +/// Balance of an account. +pub type Balance = bp_rialto::Balance; + +/// Index of a transaction in the chain. +pub type Index = bp_rialto::Index; + +/// A hash of some data used by the chain. +pub type Hash = bp_rialto::Hash; + +/// Hashing algorithm used by the chain. +pub type Hashing = bp_rialto::Hasher; + +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core data structures. +pub mod opaque { + use super::*; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + + /// Opaque block header type. + pub type Header = generic::Header; + /// Opaque block type. + pub type Block = generic::Block; + /// Opaque block identifier type. + pub type BlockId = generic::BlockId; +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub babe: Babe, + pub grandpa: Grandpa, + pub beefy: Beefy, + pub para_validator: Initializer, + pub para_assignment: SessionInfo, + pub authority_discovery: AuthorityDiscovery, + } +} + +/// This runtime version. +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("rialto-runtime"), + impl_name: create_runtime_str!("rialto-runtime"), + authoring_version: 1, + spec_version: 1, + 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() } +} + +parameter_types! { + pub const BlockHashCount: BlockNumber = 250; + pub const Version: RuntimeVersion = VERSION; + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { + read: 60_000_000, // ~0.06 ms = ~60 µs + write: 200_000_000, // ~0.2 ms = 200 µs + }; + pub const SS58Prefix: u8 = 48; +} + +impl frame_system::Config for Runtime { + /// The basic call filter to use in dispatchable. + type BaseCallFilter = frame_support::traits::Everything; + /// 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 Index = Index; + /// The index type for blocks. + type BlockNumber = BlockNumber; + /// The type for hashing blocks and tries. + type Hash = Hash; + /// The hashing algorithm used. + type Hashing = Hashing; + /// The header type. + type Header = generic::Header; + /// 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; + /// Version of the runtime. + type Version = Version; + /// Provides information about the pallet setup in the runtime. + type PalletInfo = PalletInfo; + /// 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 data to be stored in an account. + type AccountData = pallet_balances::AccountData; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + /// Weight information for the extrinsics of this pallet. + type SystemWeightInfo = (); + /// Block and extrinsics weights: base values and limits. + type BlockWeights = bp_rialto::BlockWeights; + /// The maximum length of a block (in bytes). + type BlockLength = bp_rialto::BlockLength; + /// The weight of database operations that the runtime can invoke. + type DbWeight = DbWeight; + /// The designated SS58 prefix of this chain. + type SS58Prefix = SS58Prefix; + /// The set code logic, just the default since we're not a parachain. + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +/// The BABE epoch configuration at genesis. +pub const BABE_GENESIS_EPOCH_CONFIG: sp_consensus_babe::BabeEpochConfiguration = + sp_consensus_babe::BabeEpochConfiguration { + c: bp_rialto::time_units::PRIMARY_PROBABILITY, + allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryVRFSlots, + }; + +parameter_types! { + pub const EpochDuration: u64 = bp_rialto::EPOCH_DURATION_IN_SLOTS as u64; + pub const ExpectedBlockTime: bp_rialto::Moment = bp_rialto::time_units::MILLISECS_PER_BLOCK; +} + +impl pallet_babe::Config for Runtime { + type EpochDuration = EpochDuration; + type ExpectedBlockTime = ExpectedBlockTime; + // session module is the trigger + type EpochChangeTrigger = pallet_babe::ExternalTrigger; + + type DisabledValidators = (); + + type WeightInfo = (); + + type MaxAuthorities = ConstU32<10>; + + // equivocation related configuration - we don't expect any equivocations in our testnets + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); +} + +impl pallet_beefy::Config for Runtime { + type BeefyId = BeefyId; + type MaxAuthorities = ConstU32<10>; + type MaxSetIdSessionEntries = ConstU64<0>; + type OnNewValidatorSet = MmrLeaf; + type WeightInfo = (); + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); +} + +impl pallet_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + type WeightInfo = (); + type MaxAuthorities = ConstU32<10>; + type MaxSetIdSessionEntries = ConstU64<0>; + type KeyOwnerProof = sp_core::Void; + type EquivocationReportSystem = (); +} + +impl pallet_mmr::Config for Runtime { + const INDEXING_PREFIX: &'static [u8] = b"mmr"; + type Hashing = Keccak256; + type Hash = ::Output; + type LeafData = pallet_beefy_mmr::Pallet; + type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest; + type WeightInfo = (); +} + +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); +} + +pub struct BeefyDummyDataProvider; + +impl sp_consensus_beefy::mmr::BeefyDataProvider<()> for BeefyDummyDataProvider { + fn extra_data() {} +} + +impl pallet_beefy_mmr::Config for Runtime { + type LeafVersion = LeafVersion; + type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; + type LeafExtra = (); + type BeefyDataProvider = BeefyDummyDataProvider; +} + +parameter_types! { + pub const MinimumPeriod: u64 = bp_rialto::SLOT_DURATION / 2; +} + +impl pallet_timestamp::Config for Runtime { + /// A timestamp: milliseconds since the UNIX epoch. + type Moment = bp_rialto::Moment; + type OnTimestampSet = Babe; + type MinimumPeriod = MinimumPeriod; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + type WeightInfo = (); +} + +parameter_types! { + pub const ExistentialDeposit: bp_rialto::Balance = 500; +} + +impl pallet_balances::Config for Runtime { + /// 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; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + type WeightInfo = (); + // For weight estimation, we assume that the most locks on an individual account will be 50. + // This number may need to be adjusted in the future if this assumption no longer holds true. + type MaxLocks = ConstU32<50>; + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + pub const TransactionBaseFee: Balance = 0; + pub const TransactionByteFee: Balance = 1; + // values for following parameters are copied from polkadot repo, but it is fine + // not to sync them - we're not going to make Rialto a full copy of one of Polkadot-like chains + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); + pub MaximumMultiplier: Multiplier = sp_runtime::traits::Bounded::max_value(); +} + +impl pallet_transaction_payment::Config for Runtime { + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = bp_rialto::WeightToFee; + type LengthToFee = bp_rialto::WeightToFee; + type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< + Runtime, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, + >; + type RuntimeEvent = RuntimeEvent; +} + +impl pallet_sudo::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; +} + +impl pallet_session::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ValidatorId = ::AccountId; + type ValidatorIdOf = (); + type ShouldEndSession = Babe; + type NextSessionRotation = Babe; + type SessionManager = pallet_shift_session_manager::Pallet; + type SessionHandler = ::KeyTypeIdProviders; + type Keys = SessionKeys; + // TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/78) + type WeightInfo = (); +} + +impl pallet_authority_discovery::Config for Runtime { + type MaxAuthorities = ConstU32<10>; +} + +impl pallet_bridge_relayers::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Reward = Balance; + type PaymentProcedure = + bp_relayers::PayRewardFromAccount, AccountId>; + type WeightInfo = (); +} + +pub type MillauGrandpaInstance = (); +impl pallet_bridge_grandpa::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = bp_millau::Millau; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = ConstU32<{ bp_millau::DAYS as u32 }>; + type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; +} + +impl pallet_shift_session_manager::Config for Runtime {} + +parameter_types! { + pub const MaxMessagesToPruneAtOnce: bp_messages::MessageNonce = 8; + pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + pub const RootAccountForPayments: Option = None; + pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID; + pub ActiveOutboundLanes: &'static [bp_messages::LaneId] = &[millau_messages::XCM_LANE]; +} + +/// Instance of the messages pallet used to relay messages to/from Millau chain. +pub type WithMillauMessagesInstance = (); + +impl pallet_bridge_messages::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; + type ActiveOutboundLanes = ActiveOutboundLanes; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize; + type OutboundPayload = crate::millau_messages::ToMillauMessagePayload; + + type InboundPayload = crate::millau_messages::FromMillauMessagePayload; + type InboundRelayer = bp_millau::AccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = crate::millau_messages::MillauAsTargetHeaderChain; + type LaneMessageVerifier = crate::millau_messages::ToMillauMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + Runtime, + WithMillauMessagesInstance, + frame_support::traits::ConstU128<100_000>, + >; + + type SourceHeaderChain = crate::millau_messages::MillauAsSourceHeaderChain; + type MessageDispatch = crate::millau_messages::FromMillauMessageDispatch; + type BridgedChainId = BridgedChainId; +} + +pub type MillauBeefyInstance = (); +impl pallet_bridge_beefy::Config for Runtime { + type MaxRequests = frame_support::traits::ConstU32<16>; + type CommitmentsToKeep = frame_support::traits::ConstU32<8>; + type BridgedChain = bp_millau::Millau; +} + +construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = opaque::Block, + UncheckedExtrinsic = UncheckedExtrinsic + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Sudo: pallet_sudo::{Pallet, Call, Config, Storage, Event}, + + // Must be before session. + Babe: pallet_babe::{Pallet, Call, Storage, Config, ValidateUnsigned}, + + Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + + // Consensus support. + AuthorityDiscovery: pallet_authority_discovery::{Pallet, Config}, + Session: pallet_session::{Pallet, Call, Storage, Event, Config}, + Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event}, + ShiftSessionManager: pallet_shift_session_manager::{Pallet}, + + // BEEFY Bridges support. + Beefy: pallet_beefy::{Pallet, Storage, Config}, + Mmr: pallet_mmr::{Pallet, Storage}, + MmrLeaf: pallet_beefy_mmr::{Pallet, Storage}, + + // Millau bridge modules. + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, + BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage, Event}, + BridgeMillauMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, + + // Millau bridge modules (BEEFY based). + BridgeMillauBeefy: pallet_bridge_beefy::{Pallet, Call, Storage}, + + // Parachain modules. + ParachainsOrigin: polkadot_runtime_parachains::origin::{Pallet, Origin}, + Configuration: polkadot_runtime_parachains::configuration::{Pallet, Call, Storage, Config}, + Shared: polkadot_runtime_parachains::shared::{Pallet, Call, Storage}, + Inclusion: polkadot_runtime_parachains::inclusion::{Pallet, Call, Storage, Event}, + ParasInherent: polkadot_runtime_parachains::paras_inherent::{Pallet, Call, Storage, Inherent}, + Scheduler: polkadot_runtime_parachains::scheduler::{Pallet, Storage}, + Paras: polkadot_runtime_parachains::paras::{Pallet, Call, Storage, Event, Config}, + Initializer: polkadot_runtime_parachains::initializer::{Pallet, Call, Storage}, + Dmp: polkadot_runtime_parachains::dmp::{Pallet, Call, Storage}, + Ump: polkadot_runtime_parachains::ump::{Pallet, Call, Storage, Event}, + Hrmp: polkadot_runtime_parachains::hrmp::{Pallet, Call, Storage, Event, Config}, + SessionInfo: polkadot_runtime_parachains::session_info::{Pallet, Storage}, + ParaSessionInfo: polkadot_runtime_parachains::session_info::{Pallet, Storage}, + ParasDisputes: polkadot_runtime_parachains::disputes::{Pallet, Call, Storage, Event}, + ParasSlashing: polkadot_runtime_parachains::disputes::slashing::{Pallet, Call, Storage, ValidateUnsigned}, + + // Parachain Onboarding Pallets + Registrar: polkadot_runtime_common::paras_registrar::{Pallet, Call, Storage, Event}, + Slots: polkadot_runtime_common::slots::{Pallet, Call, Storage, Event}, + ParasSudoWrapper: polkadot_runtime_common::paras_sudo_wrapper::{Pallet, Call}, + + // Pallet for sending XCM. + XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event, Origin, Config} = 99, + } +); + +/// 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::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, +); +/// The payload being signed in transactions. +pub type SignedPayload = generic::SignedPayload; +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; +/// Extrinsic type that has already been checked. +pub type CheckedExtrinsic = generic::CheckedExtrinsic; +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, +>; + +/// MMR helper types. +mod mmr { + use super::Runtime; + pub use pallet_mmr::primitives::*; + + pub type Leaf = <::LeafData as LeafDataProvider>::LeafData; + pub type Hash = ::Hash; + pub type Hashing = ::Hashing; +} + +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_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 frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + fn account_nonce(account: AccountId) -> Index { + System::account_nonce(account) + } + } + + impl sp_consensus_beefy::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: sp_consensus_beefy::EquivocationProof< + NumberFor, + sp_consensus_beefy::crypto::AuthorityId, + sp_consensus_beefy::crypto::Signature + >, + _key_owner_proof: sp_consensus_beefy::OpaqueKeyOwnershipProof, + ) -> Option<()> { None } + + fn generate_key_ownership_proof( + _set_id: sp_consensus_beefy::ValidatorSetId, + _authority_id: sp_consensus_beefy::crypto::AuthorityId, + ) -> Option { None } + } + + impl pallet_mmr::primitives::MmrApi< + Block, + mmr::Hash, + BlockNumber, + > 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 bp_millau::MillauFinalityApi for Runtime { + fn best_finalized() -> Option> { + BridgeMillauGrandpa::best_finalized() + } + } + + 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_consensus_babe::BabeApi for Runtime { + fn configuration() -> sp_consensus_babe::BabeConfiguration { + // The choice of `c` parameter (where `1 - c` represents the + // probability of a slot being empty), is done in accordance to the + // slot duration and expected target block time, for safely + // resisting network delays of maximum two seconds. + // + sp_consensus_babe::BabeConfiguration { + slot_duration: Babe::slot_duration(), + epoch_length: EpochDuration::get(), + c: BABE_GENESIS_EPOCH_CONFIG.c, + authorities: Babe::authorities().to_vec(), + randomness: Babe::randomness(), + allowed_slots: BABE_GENESIS_EPOCH_CONFIG.allowed_slots, + } + } + + fn current_epoch_start() -> sp_consensus_babe::Slot { + Babe::current_epoch_start() + } + + fn current_epoch() -> sp_consensus_babe::Epoch { + Babe::current_epoch() + } + + fn next_epoch() -> sp_consensus_babe::Epoch { + Babe::next_epoch() + } + + fn generate_key_ownership_proof( + _slot: sp_consensus_babe::Slot, + _authority_id: sp_consensus_babe::AuthorityId, + ) -> Option { + None + } + + fn submit_report_equivocation_unsigned_extrinsic( + equivocation_proof: sp_consensus_babe::EquivocationProof<::Header>, + key_owner_proof: sp_consensus_babe::OpaqueKeyOwnershipProof, + ) -> Option<()> { + let key_owner_proof = key_owner_proof.decode()?; + + Babe::submit_unsigned_equivocation_report( + equivocation_proof, + key_owner_proof, + ) + } + } + + impl polkadot_primitives::runtime_api::ParachainHost for Runtime { + fn validators() -> Vec { + polkadot_runtime_parachains::runtime_api_impl::v4::validators::() + } + + fn validator_groups() -> (Vec>, polkadot_primitives::v4::GroupRotationInfo) { + polkadot_runtime_parachains::runtime_api_impl::v4::validator_groups::() + } + + fn availability_cores() -> Vec> { + polkadot_runtime_parachains::runtime_api_impl::v4::availability_cores::() + } + + fn persisted_validation_data(para_id: polkadot_primitives::v4::Id, assumption: polkadot_primitives::v4::OccupiedCoreAssumption) + -> Option> { + polkadot_runtime_parachains::runtime_api_impl::v4::persisted_validation_data::(para_id, assumption) + } + + fn assumed_validation_data( + para_id: polkadot_primitives::v4::Id, + expected_persisted_validation_data_hash: Hash, + ) -> Option<(polkadot_primitives::v4::PersistedValidationData, polkadot_primitives::v4::ValidationCodeHash)> { + polkadot_runtime_parachains::runtime_api_impl::v4::assumed_validation_data::( + para_id, + expected_persisted_validation_data_hash, + ) + } + + fn check_validation_outputs( + para_id: polkadot_primitives::v4::Id, + outputs: polkadot_primitives::v4::CandidateCommitments, + ) -> bool { + polkadot_runtime_parachains::runtime_api_impl::v4::check_validation_outputs::(para_id, outputs) + } + + fn session_index_for_child() -> polkadot_primitives::v4::SessionIndex { + polkadot_runtime_parachains::runtime_api_impl::v4::session_index_for_child::() + } + + fn validation_code(para_id: polkadot_primitives::v4::Id, assumption: polkadot_primitives::v4::OccupiedCoreAssumption) + -> Option { + polkadot_runtime_parachains::runtime_api_impl::v4::validation_code::(para_id, assumption) + } + + fn candidate_pending_availability(para_id: polkadot_primitives::v4::Id) -> Option> { + polkadot_runtime_parachains::runtime_api_impl::v4::candidate_pending_availability::(para_id) + } + + fn candidate_events() -> Vec> { + polkadot_runtime_parachains::runtime_api_impl::v4::candidate_events::(|ev| { + match ev { + RuntimeEvent::Inclusion(ev) => { + Some(ev) + } + _ => None, + } + }) + } + + fn session_info(index: polkadot_primitives::v4::SessionIndex) -> Option { + polkadot_runtime_parachains::runtime_api_impl::v4::session_info::(index) + } + + fn dmq_contents(recipient: polkadot_primitives::v4::Id) -> Vec> { + polkadot_runtime_parachains::runtime_api_impl::v4::dmq_contents::(recipient) + } + + fn inbound_hrmp_channels_contents( + recipient: polkadot_primitives::v4::Id + ) -> BTreeMap>> { + polkadot_runtime_parachains::runtime_api_impl::v4::inbound_hrmp_channels_contents::(recipient) + } + + fn validation_code_by_hash(hash: polkadot_primitives::v4::ValidationCodeHash) -> Option { + polkadot_runtime_parachains::runtime_api_impl::v4::validation_code_by_hash::(hash) + } + + fn on_chain_votes() -> Option> { + polkadot_runtime_parachains::runtime_api_impl::v4::on_chain_votes::() + } + + fn submit_pvf_check_statement(stmt: polkadot_primitives::v4::PvfCheckStatement, signature: polkadot_primitives::v4::ValidatorSignature) { + polkadot_runtime_parachains::runtime_api_impl::v4::submit_pvf_check_statement::(stmt, signature) + } + + fn pvfs_require_precheck() -> Vec { + polkadot_runtime_parachains::runtime_api_impl::v4::pvfs_require_precheck::() + } + + fn validation_code_hash(para_id: polkadot_primitives::v4::Id, assumption: polkadot_primitives::v4::OccupiedCoreAssumption) + -> Option + { + polkadot_runtime_parachains::runtime_api_impl::v4::validation_code_hash::(para_id, assumption) + } + + fn disputes() -> Vec<(polkadot_primitives::v4::SessionIndex, polkadot_primitives::v4::CandidateHash, polkadot_primitives::v4::DisputeState)> { + polkadot_runtime_parachains::runtime_api_impl::v4::get_session_disputes::() + } + + fn session_executor_params(session_index: polkadot_primitives::v4::SessionIndex) -> Option { + polkadot_runtime_parachains::runtime_api_impl::v4::session_executor_params::(session_index) + } + } + + impl sp_authority_discovery::AuthorityDiscoveryApi for Runtime { + fn authorities() -> Vec { + polkadot_runtime_parachains::runtime_api_impl::v4::relevant_authority_ids::() + } + } + + 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 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 fg_primitives::GrandpaApi for Runtime { + fn current_set_id() -> fg_primitives::SetId { + Grandpa::current_set_id() + } + + fn grandpa_authorities() -> GrandpaAuthorityList { + Grandpa::grandpa_authorities() + } + + fn submit_report_equivocation_unsigned_extrinsic( + equivocation_proof: fg_primitives::EquivocationProof< + ::Hash, + 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: GrandpaId, + ) -> Option { + // NOTE: this is the only implementation possible since we've + // defined our key owner proof type as a bottom type (i.e. a type + // with no values). + None + } + } + + impl bp_millau::ToMillauOutboundLaneApi 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, + WithMillauMessagesInstance, + >(lane, begin, end) + } + } + + impl bp_millau::FromMillauInboundLaneApi 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, + WithMillauMessagesInstance, + >(lane, messages) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn call_size() { + const BRIDGES_PALLETS_MAX_CALL_SIZE: usize = 200; + assert!( + core::mem::size_of::>() <= + BRIDGES_PALLETS_MAX_CALL_SIZE + ); + assert!( + core::mem::size_of::>() <= + BRIDGES_PALLETS_MAX_CALL_SIZE + ); + // Largest inner Call is `pallet_session::Call` with a size of 224 bytes. This size is a + // result of large `SessionKeys` struct. + // Total size of Rialto runtime Call is 232. + const MAX_CALL_SIZE: usize = 232; + assert!(core::mem::size_of::() <= MAX_CALL_SIZE); + } +} diff --git a/bin/rialto/runtime/src/millau_messages.rs b/bin/rialto/runtime/src/millau_messages.rs new file mode 100644 index 00000000000..ab4b7dd521d --- /dev/null +++ b/bin/rialto/runtime/src/millau_messages.rs @@ -0,0 +1,198 @@ +// Copyright 2019-2021 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 . + +//! Everything required to serve Millau <-> Rialto messages. + +use crate::{MillauGrandpaInstance, Runtime, RuntimeOrigin, WithMillauMessagesInstance}; + +use bp_messages::LaneId; +use bridge_runtime_common::{ + messages::{ + self, source::TargetHeaderChainAdapter, target::SourceHeaderChainAdapter, MessageBridge, + }, + messages_xcm_extension::{XcmBlobHauler, XcmBlobHaulerAdapter}, +}; +use frame_support::{parameter_types, weights::Weight, RuntimeDebug}; +use xcm::latest::prelude::*; +use xcm_builder::HaulBlobExporter; + +/// Lane that is used for XCM messages exchange. +pub const XCM_LANE: LaneId = LaneId([0, 0, 0, 0]); +/// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge +/// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual +/// tests, confirming that we don't break encoding somewhere between. +pub const BASE_XCM_WEIGHT_TWICE: Weight = crate::xcm_config::BaseXcmWeight::get().saturating_mul(2); + +parameter_types! { + /// Weight credit for our test messages. + /// + /// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge + /// (it is prepended with `UniversalOrigin` instruction). + pub const WeightCredit: Weight = BASE_XCM_WEIGHT_TWICE; +} + +/// Message payload for Rialto -> Millau messages. +pub type ToMillauMessagePayload = messages::source::FromThisChainMessagePayload; + +/// Message verifier for Rialto -> Millau messages. +pub type ToMillauMessageVerifier = + messages::source::FromThisChainMessageVerifier; + +/// Message payload for Millau -> Rialto messages. +pub type FromMillauMessagePayload = messages::target::FromBridgedChainMessagePayload; + +/// Call-dispatch based message dispatch for Millau -> Rialto messages. +pub type FromMillauMessageDispatch = + bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatch< + bp_rialto::Rialto, + bp_millau::Millau, + crate::xcm_config::OnRialtoBlobDispatcher, + (), + >; + +/// Messages proof for Millau -> Rialto messages. +pub type FromMillauMessagesProof = messages::target::FromBridgedChainMessagesProof; + +/// Messages delivery proof for Rialto -> Millau messages. +pub type ToMillauMessagesDeliveryProof = + messages::source::FromBridgedChainMessagesDeliveryProof; + +/// Maximal outbound payload size of Rialto -> Millau messages. +pub type ToMillauMaximalOutboundPayloadSize = + messages::source::FromThisChainMaximalOutboundPayloadSize; + +/// Millau <-> Rialto message bridge. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct WithMillauMessageBridge; + +impl MessageBridge for WithMillauMessageBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME; + + type ThisChain = Rialto; + type BridgedChain = Millau; + type BridgedHeaderChain = + pallet_bridge_grandpa::GrandpaChainHeaders; +} + +/// Rialto chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Rialto; + +impl messages::UnderlyingChainProvider for Rialto { + type Chain = bp_rialto::Rialto; +} + +impl messages::ThisChainWithMessages for Rialto { + type RuntimeOrigin = RuntimeOrigin; +} + +/// Millau chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Millau; +/// Millau as source header chain. +pub type MillauAsSourceHeaderChain = SourceHeaderChainAdapter; +/// Millau as target header chain. +pub type MillauAsTargetHeaderChain = TargetHeaderChainAdapter; + +impl messages::UnderlyingChainProvider for Millau { + type Chain = bp_millau::Millau; +} + +impl messages::BridgedChainWithMessages for Millau {} + +/// Export XCM messages to be relayed to Millau. +pub type ToMillauBlobExporter = HaulBlobExporter< + XcmBlobHaulerAdapter, + crate::xcm_config::MillauNetwork, + (), +>; + +/// To-Millau XCM hauler. +pub struct ToMillauXcmBlobHauler; + +impl XcmBlobHauler for ToMillauXcmBlobHauler { + type MessageSender = pallet_bridge_messages::Pallet; + type MessageSenderOrigin = RuntimeOrigin; + + fn message_sender_origin() -> RuntimeOrigin { + pallet_xcm::Origin::from(MultiLocation::new(1, crate::xcm_config::UniversalLocation::get())) + .into() + } + + fn xcm_lane() -> LaneId { + XCM_LANE + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{MillauGrandpaInstance, Runtime, WithMillauMessagesInstance}; + use bridge_runtime_common::{ + assert_complete_bridge_types, + integrity::{ + assert_complete_bridge_constants, check_message_lane_weights, + AssertBridgeMessagesPalletConstants, AssertBridgePalletNames, AssertChainConstants, + AssertCompleteBridgeConstants, + }, + }; + + #[test] + fn ensure_rialto_message_lane_weights_are_correct() { + check_message_lane_weights::( + bp_millau::EXTRA_STORAGE_PROOF_SIZE, + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + ); + } + + #[test] + fn ensure_bridge_integrity() { + assert_complete_bridge_types!( + runtime: Runtime, + with_bridged_chain_grandpa_instance: MillauGrandpaInstance, + with_bridged_chain_messages_instance: WithMillauMessagesInstance, + bridge: WithMillauMessageBridge, + this_chain: bp_rialto::Rialto, + bridged_chain: bp_millau::Millau, + ); + + assert_complete_bridge_constants::< + Runtime, + MillauGrandpaInstance, + WithMillauMessagesInstance, + WithMillauMessageBridge, + >(AssertCompleteBridgeConstants { + this_chain_constants: AssertChainConstants { + block_length: bp_rialto::BlockLength::get(), + block_weights: bp_rialto::BlockWeights::get(), + }, + messages_pallet_constants: AssertBridgeMessagesPalletConstants { + max_unrewarded_relayers_in_bridged_confirmation_tx: + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + max_unconfirmed_messages_in_bridged_confirmation_tx: + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + bridged_chain_id: bp_runtime::MILLAU_CHAIN_ID, + }, + pallet_names: AssertBridgePalletNames { + with_this_chain_messages_pallet_name: bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME, + with_bridged_chain_grandpa_pallet_name: bp_millau::WITH_MILLAU_GRANDPA_PALLET_NAME, + with_bridged_chain_messages_pallet_name: + bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME, + }, + }); + } +} diff --git a/bin/rialto/runtime/src/parachains.rs b/bin/rialto/runtime/src/parachains.rs new file mode 100644 index 00000000000..8ceb27140f0 --- /dev/null +++ b/bin/rialto/runtime/src/parachains.rs @@ -0,0 +1,165 @@ +// Copyright 2019-2021 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 . + +//! Parachains support in Rialto runtime. + +use crate::{ + AccountId, Babe, Balance, Balances, BlockNumber, Registrar, Runtime, RuntimeCall, RuntimeEvent, + RuntimeOrigin, ShiftSessionManager, Slots, UncheckedExtrinsic, +}; + +use frame_support::{parameter_types, traits::KeyOwnerProofSystem}; +use frame_system::EnsureRoot; +use polkadot_primitives::v4::{ValidatorId, ValidatorIndex}; +use polkadot_runtime_common::{paras_registrar, paras_sudo_wrapper, slots}; +use polkadot_runtime_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, initializer as parachains_initializer, + origin as parachains_origin, paras as parachains_paras, + paras_inherent as parachains_paras_inherent, scheduler as parachains_scheduler, + session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump, +}; +use sp_core::crypto::KeyTypeId; +use sp_runtime::transaction_validity::TransactionPriority; + +impl frame_system::offchain::SendTransactionTypes for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type OverarchingCall = RuntimeCall; +} + +/// Special `RewardValidators` that does nothing ;) +pub struct RewardValidators; +impl polkadot_runtime_parachains::inclusion::RewardValidators for RewardValidators { + fn reward_backing(_: impl IntoIterator) {} + fn reward_bitfields(_: impl IntoIterator) {} +} + +// all required parachain modules from `polkadot-runtime-parachains` crate + +impl parachains_configuration::Config for Runtime { + type WeightInfo = parachains_configuration::TestWeightInfo; +} + +impl parachains_dmp::Config for Runtime {} + +impl parachains_hrmp::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type Currency = Balances; + type WeightInfo = parachains_hrmp::TestWeightInfo; +} + +impl parachains_inclusion::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RewardValidators = RewardValidators; + type DisputesHandler = (); +} + +impl parachains_initializer::Config for Runtime { + type Randomness = pallet_babe::RandomnessFromOneEpochAgo; + type ForceOrigin = EnsureRoot; + type WeightInfo = (); +} + +impl parachains_disputes::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RewardValidators = (); + type SlashingHandler = (); + type WeightInfo = parachains_disputes::TestWeightInfo; +} + +impl parachains_slashing::Config for Runtime { + type KeyOwnerProofSystem = (); + type KeyOwnerProof = + >::Proof; + type KeyOwnerIdentification = >::IdentificationTuple; + type HandleReports = (); + type WeightInfo = parachains_slashing::TestWeightInfo; + type BenchmarkingConfig = parachains_slashing::BenchConfig<200>; +} + +impl parachains_origin::Config for Runtime {} + +parameter_types! { + pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value(); +} + +impl parachains_paras::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = parachains_paras::TestWeightInfo; + type UnsignedPriority = ParasUnsignedPriority; + type NextSessionRotation = Babe; +} + +impl parachains_paras_inherent::Config for Runtime { + type WeightInfo = parachains_paras_inherent::TestWeightInfo; +} + +impl parachains_scheduler::Config for Runtime {} + +impl parachains_session_info::Config for Runtime { + type ValidatorSet = ShiftSessionManager; +} + +impl parachains_shared::Config for Runtime {} + +impl parachains_ump::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type UmpSink = (); + type FirstMessageFactorPercent = frame_support::traits::ConstU64<100>; + type ExecuteOverweightOrigin = EnsureRoot; + type WeightInfo = parachains_ump::TestWeightInfo; +} + +// required onboarding pallets. We're not going to use auctions or crowdloans, so they're missing + +parameter_types! { + pub const ParaDeposit: Balance = 0; + pub const DataDepositPerByte: Balance = 0; +} + +impl paras_registrar::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeOrigin = RuntimeOrigin; + type Currency = Balances; + type OnSwap = Slots; + type ParaDeposit = ParaDeposit; + type DataDepositPerByte = DataDepositPerByte; + type WeightInfo = paras_registrar::TestWeightInfo; +} + +parameter_types! { + pub const LeasePeriod: BlockNumber = 10 * bp_rialto::MINUTES; +} + +impl slots::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Registrar = Registrar; + type LeasePeriod = LeasePeriod; + type WeightInfo = slots::TestWeightInfo; + type LeaseOffset = (); + type ForceOrigin = EnsureRoot; +} + +impl paras_sudo_wrapper::Config for Runtime {} diff --git a/bin/rialto/runtime/src/xcm_config.rs b/bin/rialto/runtime/src/xcm_config.rs new file mode 100644 index 00000000000..9f6488b4c4d --- /dev/null +++ b/bin/rialto/runtime/src/xcm_config.rs @@ -0,0 +1,276 @@ +// Copyright 2019-2021 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 . + +//! XCM configurations for the Rialto runtime. + +use super::{ + millau_messages::ToMillauBlobExporter, AccountId, AllPalletsWithSystem, Balances, Runtime, + RuntimeCall, RuntimeEvent, RuntimeOrigin, XcmPallet, +}; +use bp_rialto::WeightToFee; +use bridge_runtime_common::CustomNetworkId; +use frame_support::{ + parameter_types, + traits::{ConstU32, Everything, Nothing}, + weights::Weight, +}; +use frame_system::EnsureRoot; +use xcm::latest::prelude::*; +use xcm_builder::{ + AccountId32Aliases, CurrencyAdapter as XcmCurrencyAdapter, IsConcrete, MintLocation, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + UsingComponents, +}; + +parameter_types! { + /// The location of the `MLAU` 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 Rialto network ID. + pub const ThisNetwork: NetworkId = CustomNetworkId::Rialto.as_network_id(); + /// The Millau network ID. + pub const MillauNetwork: NetworkId = CustomNetworkId::Millau.as_network_id(); + + /// Our XCM location ancestry - i.e. our location within the Consensus Universe. + /// + /// Since Polkadot 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, MintLocation) = (XcmPallet::check_account(), 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 directly alias an `AccountId32` into a local account. + AccountId32Aliases, +); + +/// Our asset transactor. This is what allows us to interest with the runtime facilities from the +/// point of view of XCM-only concepts like `MultiLocation` and `MultiAsset`. +/// +/// Ours is only aware of the Balances pallet, which is mapped to `TokenLocation`. +pub type LocalAssetTransactor = XcmCurrencyAdapter< + // Use this currency: + Balances, + // Use this currency when it is a fungible asset matching the given location or name: + IsConcrete, + // We can convert the MultiLocations with our converter above: + SovereignAccountOf, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // We track our teleports in/out to keep total issuance correct. + CheckAccount, +>; + +/// 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, + // 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 XCM router. We are not sending messages to sibling/parent/child chains here. +pub type XcmRouter = (); + +/// The barriers one of which must be passed for an XCM message to be executed. +pub type Barrier = ( + // Weight that is paid for may be consumed. + TakeWeightCredit, +); + +/// Dispatches received XCM messages from other chain. +pub type OnRialtoBlobDispatcher = xcm_builder::BridgeBlobDispatcher< + crate::xcm_config::XcmRouter, + crate::xcm_config::UniversalLocation, +>; + +/// Incoming XCM weigher type. +pub type XcmWeigher = xcm_builder::FixedWeightBounds; + +pub struct XcmConfig; +impl xcm_executor::Config for XcmConfig { + type RuntimeCall = RuntimeCall; + type XcmSender = (); + type AssetTransactor = LocalAssetTransactor; + type OriginConverter = LocalOriginConverter; + type IsReserve = (); + type IsTeleporter = (); + type UniversalLocation = UniversalLocation; + type Barrier = Barrier; + type Weigher = XcmWeigher; + // 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 = ConstU32<64>; + type FeeManager = (); + type MessageExporter = ToMillauBlobExporter; + type UniversalAliases = Nothing; + type CallDispatcher = RuntimeCall; + type SafeCallFilter = Everything; +} + +/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior +/// location of this chain. +pub type LocalOriginToLocation = ( + // Usual Signed origin to be used in XCM as a corresponding AccountId32 + SignedToAccountId32, +); + +#[cfg(feature = "runtime-benchmarks")] +parameter_types! { + pub ReachableDest: Option = None; +} + +impl pallet_xcm::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + // We don't allow any messages to be sent via the transaction yet. This is basically safe to + // enable, (safe the possibility of someone spamming the parachain if they're willing to pay + // the DOT 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 = XcmWeigher; + 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 = frame_support::traits::ConstU32<8>; + type WeightInfo = pallet_xcm::TestWeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type ReachableDest = ReachableDest; + type AdminOrigin = EnsureRoot; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + millau_messages::{FromMillauMessageDispatch, XCM_LANE}, + WithMillauMessagesInstance, + }; + use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + LaneId, MessageKey, + }; + use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; + use codec::Encode; + use pallet_bridge_messages::OutboundLanes; + use xcm_executor::XcmExecutor; + + fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new( + frame_system::GenesisConfig::default().build_storage::().unwrap(), + ) + } + + fn prepare_outbound_xcm_message(destination: NetworkId) -> Xcm { + vec![ExportMessage { + network: destination, + destination: destination.into(), + xcm: vec![Instruction::Trap(42)].into(), + }] + .into() + } + + #[test] + fn xcm_messages_to_millau_are_sent_using_bridge_exporter() { + new_test_ext().execute_with(|| { + // ensure that the there are no messages queued + assert_eq!( + OutboundLanes::::get(XCM_LANE) + .latest_generated_nonce, + 0, + ); + + // export message instruction "sends" message to Rialto + XcmExecutor::::execute_xcm_in_credit( + Here, + prepare_outbound_xcm_message(MillauNetwork::get()), + Default::default(), + Weight::MAX, + Weight::MAX, + ) + .ensure_complete() + .expect("runtime configuration must be correct"); + + // ensure that the message has been queued + assert_eq!( + OutboundLanes::::get(XCM_LANE) + .latest_generated_nonce, + 1, + ); + }) + } + + fn prepare_inbound_bridge_message() -> DispatchMessage> { + let xcm = xcm::VersionedXcm::::V3(vec![Instruction::Trap(42)].into()); + let location = + xcm::VersionedInteriorMultiLocation::V3(X1(GlobalConsensus(ThisNetwork::get()))); + // this is the `BridgeMessage` from polkadot xcm builder, but it has no constructor + // or public fields, so just tuple + let bridge_message = (location, xcm).encode(); + DispatchMessage { + key: MessageKey { lane_id: LaneId([0, 0, 0, 0]), nonce: 1 }, + data: DispatchMessageData { payload: Ok(bridge_message) }, + } + } + + #[test] + fn xcm_messages_from_millau_are_dispatched() { + let incoming_message = prepare_inbound_bridge_message(); + + // we care only about handing message to the XCM dispatcher, so we don't care about its + // actual dispatch + let dispatch_result = + FromMillauMessageDispatch::dispatch(&AccountId::from([0u8; 32]), incoming_message); + assert!(matches!( + dispatch_result.dispatch_level_result, + XcmBlobMessageDispatchResult::NotDispatched(_), + )); + } +} diff --git a/bin/runtime-common/Cargo.toml b/bin/runtime-common/Cargo.toml new file mode 100644 index 00000000000..3db4ae9abca --- /dev/null +++ b/bin/runtime-common/Cargo.toml @@ -0,0 +1,92 @@ +[package] +name = "bridge-runtime-common" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +repository = "https://github.com/paritytech/parity-bridges-common/" +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"] } +hash-db = { version = "0.16.0", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +static_assertions = { version = "1.1", optional = true } + +# Bridge dependencies + +bp-header-chain = { path = "../../primitives/header-chain", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } +bp-parachains = { path = "../../primitives/parachains", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-relayers = { path = "../../primitives/relayers", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +pallet-bridge-grandpa = { path = "../../modules/grandpa", default-features = false } +pallet-bridge-messages = { path = "../../modules/messages", default-features = false } +pallet-bridge-parachains = { path = "../../modules/parachains", default-features = false } +pallet-bridge-relayers = { path = "../../modules/relayers", default-features = false } + +# Substrate dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-utility = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +# Polkadot dependencies +pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } +xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } + +[dev-dependencies] +bp-test-utils = { path = "../../primitives/test-utils" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-messages/std", + "bp-parachains/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "hash-db/std", + "log/std", + "pallet-bridge-grandpa/std", + "pallet-bridge-messages/std", + "pallet-bridge-parachains/std", + "pallet-bridge-relayers/std", + "pallet-transaction-payment/std", + "pallet-utility/std", + "pallet-xcm/std", + "scale-info/std", + "sp-api/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "sp-trie/std", + "xcm/std", + "xcm-builder/std", + "xcm-executor/std", +] +runtime-benchmarks = [ + "pallet-bridge-grandpa/runtime-benchmarks", + "pallet-bridge-messages/runtime-benchmarks", + "pallet-bridge-parachains/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] +integrity-test = [ + "static_assertions", +] diff --git a/bin/runtime-common/src/integrity.rs b/bin/runtime-common/src/integrity.rs new file mode 100644 index 00000000000..5820dd99b91 --- /dev/null +++ b/bin/runtime-common/src/integrity.rs @@ -0,0 +1,331 @@ +// Copyright 2019-2021 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 . + +//! Integrity tests for chain constants and pallets configuration. +//! +//! Most of the tests in this module assume that the bridge is using standard (see `crate::messages` +//! module for details) configuration. + +use crate::{messages, messages::MessageBridge}; + +use bp_messages::{InboundLaneData, MessageNonce}; +use bp_runtime::{Chain, ChainId}; +use codec::Encode; +use frame_support::{storage::generator::StorageValue, traits::Get}; +use frame_system::limits; +use sp_runtime::traits::SignedExtension; + +/// Macro that ensures that the runtime configuration and chain primitives crate are sharing +/// the same types (index, block number, hash, hasher, account id and header). +#[macro_export] +macro_rules! assert_chain_types( + ( runtime: $r:path, this_chain: $this:path ) => { + { + // if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard + // configuration is used), or something has broke existing configuration (meaning that all bridged chains + // and relays will stop functioning) + use frame_system::Config as SystemConfig; + use static_assertions::assert_type_eq_all; + + assert_type_eq_all!(<$r as SystemConfig>::Index, bp_runtime::IndexOf<$this>); + assert_type_eq_all!(<$r as SystemConfig>::BlockNumber, bp_runtime::BlockNumberOf<$this>); + assert_type_eq_all!(<$r as SystemConfig>::Hash, bp_runtime::HashOf<$this>); + assert_type_eq_all!(<$r as SystemConfig>::Hashing, bp_runtime::HasherOf<$this>); + assert_type_eq_all!(<$r as SystemConfig>::AccountId, bp_runtime::AccountIdOf<$this>); + assert_type_eq_all!(<$r as SystemConfig>::Header, bp_runtime::HeaderOf<$this>); + } + } +); + +/// Macro that ensures that the bridge GRANDPA pallet is configured properly to bridge with given +/// chain. +#[macro_export] +macro_rules! assert_bridge_grandpa_pallet_types( + ( runtime: $r:path, with_bridged_chain_grandpa_instance: $i:path, bridged_chain: $bridged:path ) => { + { + // if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard + // configuration is used), or something has broke existing configuration (meaning that all bridged chains + // and relays will stop functioning) + use pallet_bridge_grandpa::Config as GrandpaConfig; + use static_assertions::assert_type_eq_all; + + assert_type_eq_all!(<$r as GrandpaConfig<$i>>::BridgedChain, $bridged); + } + } +); + +/// Macro that ensures that the bridge messages pallet is configured properly to bridge using given +/// configuration. +#[macro_export] +macro_rules! assert_bridge_messages_pallet_types( + ( + runtime: $r:path, + with_bridged_chain_messages_instance: $i:path, + bridge: $bridge:path + ) => { + { + // if one of asserts fail, then either bridge isn't configured properly (or alternatively - non-standard + // configuration is used), or something has broke existing configuration (meaning that all bridged chains + // and relays will stop functioning) + use $crate::messages::{ + source::{FromThisChainMessagePayload, TargetHeaderChainAdapter}, + target::{FromBridgedChainMessagePayload, SourceHeaderChainAdapter}, + AccountIdOf, BalanceOf, BridgedChain, ThisChain, + }; + use pallet_bridge_messages::Config as MessagesConfig; + use static_assertions::assert_type_eq_all; + + assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, FromThisChainMessagePayload); + + assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundRelayer, AccountIdOf>); + + assert_type_eq_all!(<$r as MessagesConfig<$i>>::TargetHeaderChain, TargetHeaderChainAdapter<$bridge>); + assert_type_eq_all!(<$r as MessagesConfig<$i>>::SourceHeaderChain, SourceHeaderChainAdapter<$bridge>); + } + } +); + +/// Macro that combines four other macro calls - `assert_chain_types`, `assert_bridge_types`, +/// `assert_bridge_grandpa_pallet_types` and `assert_bridge_messages_pallet_types`. It may be used +/// at the chain that is implementing complete standard messages bridge (i.e. with bridge GRANDPA +/// and messages pallets deployed). +#[macro_export] +macro_rules! assert_complete_bridge_types( + ( + runtime: $r:path, + with_bridged_chain_grandpa_instance: $gi:path, + with_bridged_chain_messages_instance: $mi:path, + bridge: $bridge:path, + this_chain: $this:path, + bridged_chain: $bridged:path, + ) => { + $crate::assert_chain_types!(runtime: $r, this_chain: $this); + $crate::assert_bridge_grandpa_pallet_types!( + runtime: $r, + with_bridged_chain_grandpa_instance: $gi, + bridged_chain: $bridged + ); + $crate::assert_bridge_messages_pallet_types!( + runtime: $r, + with_bridged_chain_messages_instance: $mi, + bridge: $bridge + ); + } +); + +/// Parameters for asserting chain-related constants. +#[derive(Debug)] +pub struct AssertChainConstants { + /// Block length limits of the chain. + pub block_length: limits::BlockLength, + /// Block weight limits of the chain. + pub block_weights: limits::BlockWeights, +} + +/// Test that our hardcoded, chain-related constants, are matching chain runtime configuration. +/// +/// In particular, this test ensures that: +/// +/// 1) block weight limits are matching; +/// 2) block size limits are matching. +pub fn assert_chain_constants(params: AssertChainConstants) +where + R: frame_system::Config, +{ + // we don't check runtime version here, because in our case we'll be building relay from one + // repo and runtime will live in another repo, along with outdated relay version. To avoid + // unneeded commits, let's not raise an error in case of version mismatch. + + // if one of following assert fails, it means that we may need to upgrade bridged chain and + // relay to use updated constants. If constants are now smaller than before, it may lead to + // undeliverable messages. + + // `BlockLength` struct is not implementing `PartialEq`, so we compare encoded values here. + assert_eq!( + R::BlockLength::get().encode(), + params.block_length.encode(), + "BlockLength from runtime ({:?}) differ from hardcoded: {:?}", + R::BlockLength::get(), + params.block_length, + ); + // `BlockWeights` struct is not implementing `PartialEq`, so we compare encoded values here + assert_eq!( + R::BlockWeights::get().encode(), + params.block_weights.encode(), + "BlockWeights from runtime ({:?}) differ from hardcoded: {:?}", + R::BlockWeights::get(), + params.block_weights, + ); +} + +/// Test that the constants, used in GRANDPA pallet configuration are valid. +pub fn assert_bridge_grandpa_pallet_constants() +where + R: pallet_bridge_grandpa::Config, + GI: 'static, +{ + assert!( + R::HeadersToKeep::get() > 0, + "HeadersToKeep ({}) must be larger than zero", + R::HeadersToKeep::get(), + ); +} + +/// Parameters for asserting messages pallet constants. +#[derive(Debug)] +pub struct AssertBridgeMessagesPalletConstants { + /// Maximal number of unrewarded relayer entries in a confirmation transaction at the bridged + /// chain. + pub max_unrewarded_relayers_in_bridged_confirmation_tx: MessageNonce, + /// Maximal number of unconfirmed messages in a confirmation transaction at the bridged chain. + pub max_unconfirmed_messages_in_bridged_confirmation_tx: MessageNonce, + /// Identifier of the bridged chain. + pub bridged_chain_id: ChainId, +} + +/// Test that the constants, used in messages pallet configuration are valid. +pub fn assert_bridge_messages_pallet_constants(params: AssertBridgeMessagesPalletConstants) +where + R: pallet_bridge_messages::Config, + MI: 'static, +{ + assert!( + !R::ActiveOutboundLanes::get().is_empty(), + "ActiveOutboundLanes ({:?}) must not be empty", + R::ActiveOutboundLanes::get(), + ); + assert!( + R::MaxUnrewardedRelayerEntriesAtInboundLane::get() <= params.max_unrewarded_relayers_in_bridged_confirmation_tx, + "MaxUnrewardedRelayerEntriesAtInboundLane ({}) must be <= than the hardcoded value for bridged chain: {}", + R::MaxUnrewardedRelayerEntriesAtInboundLane::get(), + params.max_unrewarded_relayers_in_bridged_confirmation_tx, + ); + assert!( + R::MaxUnconfirmedMessagesAtInboundLane::get() <= params.max_unconfirmed_messages_in_bridged_confirmation_tx, + "MaxUnrewardedRelayerEntriesAtInboundLane ({}) must be <= than the hardcoded value for bridged chain: {}", + R::MaxUnconfirmedMessagesAtInboundLane::get(), + params.max_unconfirmed_messages_in_bridged_confirmation_tx, + ); + assert_eq!(R::BridgedChainId::get(), params.bridged_chain_id); +} + +/// Parameters for asserting bridge pallet names. +#[derive(Debug)] +pub struct AssertBridgePalletNames<'a> { + /// Name of the messages pallet, deployed at the bridged chain and used to bridge with this + /// chain. + pub with_this_chain_messages_pallet_name: &'a str, + /// Name of the GRANDPA pallet, deployed at this chain and used to bridge with the bridged + /// chain. + pub with_bridged_chain_grandpa_pallet_name: &'a str, + /// Name of the messages pallet, deployed at this chain and used to bridge with the bridged + /// chain. + pub with_bridged_chain_messages_pallet_name: &'a str, +} + +/// Tests that bridge pallet names used in `construct_runtime!()` macro call are matching constants +/// from chain primitives crates. +pub fn assert_bridge_pallet_names(params: AssertBridgePalletNames) +where + B: MessageBridge, + R: pallet_bridge_grandpa::Config + pallet_bridge_messages::Config, + GI: 'static, + MI: 'static, +{ + assert_eq!(B::BRIDGED_MESSAGES_PALLET_NAME, params.with_this_chain_messages_pallet_name); + assert_eq!( + pallet_bridge_grandpa::PalletOwner::::storage_value_final_key().to_vec(), + bp_runtime::storage_value_key(params.with_bridged_chain_grandpa_pallet_name, "PalletOwner",).0, + ); + assert_eq!( + pallet_bridge_messages::PalletOwner::::storage_value_final_key().to_vec(), + bp_runtime::storage_value_key( + params.with_bridged_chain_messages_pallet_name, + "PalletOwner", + ) + .0, + ); +} + +/// Parameters for asserting complete standard messages bridge. +#[derive(Debug)] +pub struct AssertCompleteBridgeConstants<'a> { + /// Parameters to assert this chain constants. + pub this_chain_constants: AssertChainConstants, + /// Parameters to assert messages pallet constants. + pub messages_pallet_constants: AssertBridgeMessagesPalletConstants, + /// Parameters to assert pallet names constants. + pub pallet_names: AssertBridgePalletNames<'a>, +} + +/// All bridge-related constants tests for the complete standard messages bridge (i.e. with bridge +/// GRANDPA and messages pallets deployed). +pub fn assert_complete_bridge_constants(params: AssertCompleteBridgeConstants) +where + R: frame_system::Config + + pallet_bridge_grandpa::Config + + pallet_bridge_messages::Config, + GI: 'static, + MI: 'static, + B: MessageBridge, +{ + assert_chain_constants::(params.this_chain_constants); + assert_bridge_grandpa_pallet_constants::(); + assert_bridge_messages_pallet_constants::(params.messages_pallet_constants); + assert_bridge_pallet_names::(params.pallet_names); +} + +/// Check that the message lane weights are correct. +pub fn check_message_lane_weights( + bridged_chain_extra_storage_proof_size: u32, + this_chain_max_unrewarded_relayers: MessageNonce, + this_chain_max_unconfirmed_messages: MessageNonce, +) { + type Weights = pallet_bridge_messages::weights::BridgeWeight; + + pallet_bridge_messages::ensure_weights_are_correct::>(); + + let max_incoming_message_proof_size = bridged_chain_extra_storage_proof_size + .saturating_add(messages::target::maximal_incoming_message_size(C::max_extrinsic_size())); + pallet_bridge_messages::ensure_able_to_receive_message::>( + C::max_extrinsic_size(), + C::max_extrinsic_weight(), + max_incoming_message_proof_size, + messages::target::maximal_incoming_message_dispatch_weight(C::max_extrinsic_weight()), + ); + + let max_incoming_inbound_lane_data_proof_size = + InboundLaneData::<()>::encoded_size_hint_u32(this_chain_max_unrewarded_relayers as _); + pallet_bridge_messages::ensure_able_to_receive_confirmation::>( + C::max_extrinsic_size(), + C::max_extrinsic_weight(), + max_incoming_inbound_lane_data_proof_size, + this_chain_max_unrewarded_relayers, + this_chain_max_unconfirmed_messages, + ); +} + +/// 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/bin/runtime-common/src/lib.rs b/bin/runtime-common/src/lib.rs new file mode 100644 index 00000000000..e8a2d2470fa --- /dev/null +++ b/bin/runtime-common/src/lib.rs @@ -0,0 +1,245 @@ +// Copyright 2019-2021 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 . + +//! Common types/functions that may be used by runtimes of all bridged chains. + +#![cfg_attr(not(feature = "std"), no_std)] + +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; +pub mod messages_benchmarking; +pub mod messages_call_ext; +pub mod messages_xcm_extension; +pub mod parachains_benchmarking; +pub mod priority_calculator; +pub mod refund_relayer_extension; + +mod messages_generation; +mod mock; + +#[cfg(feature = "integrity-test")] +pub mod integrity; + +const LOG_TARGET_BRIDGE_DISPATCH: &str = "runtime::bridge-dispatch"; + +/// A duplication of the `FilterCall` trait. +/// +/// We need this trait in order to be able to implement it for the messages pallet, +/// since the implementation is done outside of the pallet crate. +pub trait BridgeRuntimeFilterCall { + /// Checks if a runtime call is valid. + fn validate(call: &Call) -> TransactionValidity; +} + +impl BridgeRuntimeFilterCall for pallet_bridge_grandpa::Pallet +where + T: pallet_bridge_grandpa::Config, + T::RuntimeCall: GrandpaCallSubType, +{ + fn validate(call: &T::RuntimeCall) -> TransactionValidity { + GrandpaCallSubType::::check_obsolete_submit_finality_proof(call) + } +} + +impl BridgeRuntimeFilterCall + for pallet_bridge_parachains::Pallet +where + T: pallet_bridge_parachains::Config, + T::RuntimeCall: ParachainsCallSubtype, +{ + fn validate(call: &T::RuntimeCall) -> TransactionValidity { + ParachainsCallSubtype::::check_obsolete_submit_parachain_heads(call) + } +} + +impl, I: 'static> BridgeRuntimeFilterCall + for pallet_bridge_messages::Pallet +where + T::RuntimeCall: MessagesCallSubType, +{ + /// Validate messages in order to avoid "mining" messages delivery and delivery confirmation + /// transactions, that are delivering outdated messages/confirmations. Without this validation, + /// even honest relayers may lose their funds if there are multiple relays running and + /// submitting the same messages/confirmations. + fn validate(call: &T::RuntimeCall) -> TransactionValidity { + call.check_obsolete_call() + } +} + +/// Declares a runtime-specific `BridgeRejectObsoleteHeadersAndMessages` signed extension. +/// +/// ## Example +/// +/// ```nocompile +/// generate_bridge_reject_obsolete_headers_and_messages!{ +/// Call, AccountId +/// BridgeRialtoGrandpa, BridgeWestendGrandpa, +/// BridgeRialtoParachains +/// } +/// ``` +/// +/// The goal of this extension is to avoid "mining" transactions that provide outdated bridged +/// headers and messages. Without that extension, even honest relayers may lose their funds if +/// there are multiple relays running and submitting the same information. +#[macro_export] +macro_rules! generate_bridge_reject_obsolete_headers_and_messages { + ($call:ty, $account_id:ty, $($filter_call:ty),*) => { + #[derive(Clone, codec::Decode, Default, codec::Encode, Eq, PartialEq, frame_support::RuntimeDebug, scale_info::TypeInfo)] + pub struct BridgeRejectObsoleteHeadersAndMessages; + impl sp_runtime::traits::SignedExtension for BridgeRejectObsoleteHeadersAndMessages { + const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages"; + type AccountId = $account_id; + type Call = $call; + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed(&self) -> sp_std::result::Result< + (), + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(()) + } + + fn validate( + &self, + _who: &Self::AccountId, + call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> sp_runtime::transaction_validity::TransactionValidity { + let valid = sp_runtime::transaction_validity::ValidTransaction::default(); + $( + let valid = valid + .combine_with(<$filter_call as $crate::BridgeRuntimeFilterCall<$call>>::validate(call)?); + )* + Ok(valid) + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + info: &sp_runtime::traits::DispatchInfoOf, + len: usize, + ) -> Result { + self.validate(who, call, info, len).map(drop) + } + } + }; +} + +/// 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 CustomNetworkId { + 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; + use frame_support::{assert_err, assert_ok}; + use sp_runtime::{ + traits::SignedExtension, + transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + }; + + pub struct MockCall { + data: u32, + } + + impl sp_runtime::traits::Dispatchable for MockCall { + type RuntimeOrigin = (); + type Config = (); + type Info = (); + type PostInfo = (); + + fn dispatch( + self, + _origin: Self::RuntimeOrigin, + ) -> sp_runtime::DispatchResultWithInfo { + unimplemented!() + } + } + + struct FirstFilterCall; + impl BridgeRuntimeFilterCall for FirstFilterCall { + fn validate(call: &MockCall) -> TransactionValidity { + if call.data <= 1 { + return InvalidTransaction::Custom(1).into() + } + + Ok(ValidTransaction { priority: 1, ..Default::default() }) + } + } + + struct SecondFilterCall; + impl BridgeRuntimeFilterCall for SecondFilterCall { + fn validate(call: &MockCall) -> TransactionValidity { + if call.data <= 2 { + return InvalidTransaction::Custom(2).into() + } + + Ok(ValidTransaction { priority: 2, ..Default::default() }) + } + } + + #[test] + fn test() { + generate_bridge_reject_obsolete_headers_and_messages!( + MockCall, + (), + FirstFilterCall, + SecondFilterCall + ); + + assert_err!( + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 1 }, &(), 0), + InvalidTransaction::Custom(1) + ); + + assert_err!( + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 2 }, &(), 0), + InvalidTransaction::Custom(2) + ); + + assert_ok!( + BridgeRejectObsoleteHeadersAndMessages.validate(&(), &MockCall { data: 3 }, &(), 0), + ValidTransaction { priority: 3, ..Default::default() } + ) + } +} diff --git a/bin/runtime-common/src/messages.rs b/bin/runtime-common/src/messages.rs new file mode 100644 index 00000000000..9d2e5811380 --- /dev/null +++ b/bin/runtime-common/src/messages.rs @@ -0,0 +1,787 @@ +// Copyright 2019-2021 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 . + +//! Types that allow runtime to act as a source/target endpoint of message lanes. +//! +//! Messages are assumed to be encoded `Call`s of the target chain. Call-dispatch +//! pallet is used to dispatch incoming messages. Message identified by a tuple +//! of to elements - message lane id and message nonce. + +pub use bp_runtime::{UnderlyingChainOf, UnderlyingChainProvider}; + +use bp_header_chain::{HeaderChain, HeaderChainError}; +use bp_messages::{ + source_chain::{LaneMessageVerifier, TargetHeaderChain}, + target_chain::{ProvedLaneMessages, ProvedMessages, SourceHeaderChain}, + InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, +}; +use bp_runtime::{Chain, RawStorageProof, Size, StorageProofChecker, StorageProofError}; +use codec::{Decode, Encode}; +use frame_support::{traits::Get, weights::Weight, RuntimeDebug}; +use hash_db::Hasher; +use scale_info::TypeInfo; +use sp_std::{convert::TryFrom, fmt::Debug, marker::PhantomData, vec::Vec}; + +/// Bidirectional message bridge. +pub trait MessageBridge { + /// Name of the paired messages pallet instance at the Bridged chain. + /// + /// Should be the name that is used in the `construct_runtime!()` macro. + const BRIDGED_MESSAGES_PALLET_NAME: &'static str; + + /// This chain in context of message bridge. + type ThisChain: ThisChainWithMessages; + /// Bridged chain in context of message bridge. + type BridgedChain: BridgedChainWithMessages; + /// Bridged header chain. + type BridgedHeaderChain: HeaderChain>; +} + +/// This chain that has `pallet-bridge-messages` module. +pub trait ThisChainWithMessages: UnderlyingChainProvider { + /// Call origin on the chain. + type RuntimeOrigin; +} + +/// Bridged chain that has `pallet-bridge-messages` module. +pub trait BridgedChainWithMessages: UnderlyingChainProvider {} + +/// This chain in context of message bridge. +pub type ThisChain = ::ThisChain; +/// Bridged chain in context of message bridge. +pub type BridgedChain = ::BridgedChain; +/// Hash used on the chain. +pub type HashOf = bp_runtime::HashOf<::Chain>; +/// Hasher used on the chain. +pub type HasherOf = bp_runtime::HasherOf>; +/// Account id used on the chain. +pub type AccountIdOf = bp_runtime::AccountIdOf>; +/// Type of balances that is used on the chain. +pub type BalanceOf = bp_runtime::BalanceOf>; +/// Type of origin that is used on the chain. +pub type OriginOf = ::RuntimeOrigin; + +/// Error that happens during message verification. +#[derive(Debug, PartialEq, Eq)] +pub enum Error { + /// The message proof is empty. + EmptyMessageProof, + /// Error returned by the bridged header chain. + HeaderChain(HeaderChainError), + /// Error returned while reading/decoding inbound lane data from the storage proof. + InboundLaneStorage(StorageProofError), + /// The declared message weight is incorrect. + InvalidMessageWeight, + /// Declared messages count doesn't match actual value. + MessagesCountMismatch, + /// Error returned while reading/decoding message data from the storage proof. + MessageStorage(StorageProofError), + /// The message is too large. + MessageTooLarge, + /// Error returned while reading/decoding outbound lane data from the storage proof. + OutboundLaneStorage(StorageProofError), + /// Storage proof related error. + StorageProof(StorageProofError), +} + +/// Sub-module that is declaring types required for processing This -> Bridged chain messages. +pub mod source { + use super::*; + + /// Message payload for This -> Bridged chain messages. + pub type FromThisChainMessagePayload = crate::messages_xcm_extension::XcmAsPlainPayload; + + /// Maximal size of outbound message payload. + pub struct FromThisChainMaximalOutboundPayloadSize(PhantomData); + + impl Get for FromThisChainMaximalOutboundPayloadSize { + fn get() -> u32 { + maximal_message_size::() + } + } + + /// Messages delivery proof from bridged chain: + /// + /// - hash of finalized header; + /// - storage proof of inbound lane state; + /// - lane id. + #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] + pub struct FromBridgedChainMessagesDeliveryProof { + /// Hash of the bridge header the proof is for. + pub bridged_header_hash: BridgedHeaderHash, + /// Storage trie proof generated for [`Self::bridged_header_hash`]. + pub storage_proof: RawStorageProof, + /// Lane id of which messages were delivered and the proof is for. + pub lane: LaneId, + } + + impl Size for FromBridgedChainMessagesDeliveryProof { + fn size(&self) -> u32 { + u32::try_from( + self.storage_proof + .iter() + .fold(0usize, |sum, node| sum.saturating_add(node.len())), + ) + .unwrap_or(u32::MAX) + } + } + + /// 'Parsed' message delivery proof - inbound lane id and its state. + pub type ParsedMessagesDeliveryProofFromBridgedChain = + (LaneId, InboundLaneData>>); + + /// Message verifier that is doing all basic checks. + /// + /// This verifier assumes following: + /// + /// - all message lanes are equivalent, so all checks are the same; + /// + /// Following checks are made: + /// + /// - message is rejected if its lane is currently blocked; + /// - message is rejected if there are too many pending (undelivered) messages at the outbound + /// lane; + /// - check that the sender has rights to dispatch the call on target chain using provided + /// dispatch origin; + /// - check that the sender has paid enough funds for both message delivery and dispatch. + #[derive(RuntimeDebug)] + pub struct FromThisChainMessageVerifier(PhantomData); + + impl LaneMessageVerifier>, FromThisChainMessagePayload> + for FromThisChainMessageVerifier + where + B: MessageBridge, + // matches requirements from the `frame_system::Config::Origin` + OriginOf>: Clone + + Into>>, OriginOf>>>, + AccountIdOf>: PartialEq + Clone, + { + type Error = &'static str; + + fn verify_message( + _submitter: &OriginOf>, + _lane: &LaneId, + _lane_outbound_data: &OutboundLaneData, + _payload: &FromThisChainMessagePayload, + ) -> Result<(), Self::Error> { + // IMPORTANT: any error that is returned here is fatal for the bridge, because + // this code is executed at the bridge hub and message sender actually lives + // at some sibling parachain. So we are failing **after** the message has been + // sent and we can't report it back to sender (unless error report mechanism is + // embedded into message and its dispatcher). + + Ok(()) + } + } + + /// Return maximal message size of This -> Bridged chain message. + pub fn maximal_message_size() -> u32 { + super::target::maximal_incoming_message_size( + UnderlyingChainOf::>::max_extrinsic_size(), + ) + } + + /// `TargetHeaderChain` implementation that is using default types and perform default checks. + pub struct TargetHeaderChainAdapter(PhantomData); + + impl TargetHeaderChain>> + for TargetHeaderChainAdapter + { + type Error = Error; + type MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof>>; + + fn verify_message(payload: &FromThisChainMessagePayload) -> Result<(), Self::Error> { + verify_chain_message::(payload) + } + + fn verify_messages_delivery_proof( + proof: Self::MessagesDeliveryProof, + ) -> Result<(LaneId, InboundLaneData>>), Self::Error> { + verify_messages_delivery_proof::(proof) + } + } + + /// Do basic Bridged-chain specific verification of This -> Bridged chain message. + /// + /// Ok result from this function means that the delivery transaction with this message + /// may be 'mined' by the target chain. But the lane may have its own checks (e.g. fee + /// check) that would reject message (see `FromThisChainMessageVerifier`). + pub fn verify_chain_message( + payload: &FromThisChainMessagePayload, + ) -> Result<(), Error> { + // IMPORTANT: any error that is returned here is fatal for the bridge, because + // this code is executed at the bridge hub and message sender actually lives + // at some sibling parachain. So we are failing **after** the message has been + // sent and we can't report it back to sender (unless error report mechanism is + // embedded into message and its dispatcher). + + // apart from maximal message size check (see below), we should also check the message + // dispatch weight here. But we assume that the bridged chain will just push the message + // to some queue (XCMP, UMP, DMP), so the weight is constant and fits the block. + + // The maximal size of extrinsic at Substrate-based chain depends on the + // `frame_system::Config::MaximumBlockLength` and + // `frame_system::Config::AvailableBlockRatio` constants. This check is here to be sure that + // the lane won't stuck because message is too large to fit into delivery transaction. + // + // **IMPORTANT NOTE**: the delivery transaction contains storage proof of the message, not + // the message itself. The proof is always larger than the message. But unless chain state + // is enormously large, it should be several dozens/hundreds of bytes. The delivery + // transaction also contains signatures and signed extensions. Because of this, we reserve + // 1/3 of the the maximal extrinsic weight for this data. + if payload.len() > maximal_message_size::() as usize { + return Err(Error::MessageTooLarge) + } + + Ok(()) + } + + /// Verify proof of This -> Bridged chain messages delivery. + /// + /// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged + /// parachains, please use the `verify_messages_delivery_proof_from_parachain`. + pub fn verify_messages_delivery_proof( + proof: FromBridgedChainMessagesDeliveryProof>>, + ) -> Result, Error> { + let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } = + proof; + B::BridgedHeaderChain::parse_finalized_storage_proof( + bridged_header_hash, + storage_proof, + |mut storage| { + // Messages delivery proof is just proof of single storage key read => any error + // is fatal. + let storage_inbound_lane_data_key = + bp_messages::storage_keys::inbound_lane_data_key( + B::BRIDGED_MESSAGES_PALLET_NAME, + &lane, + ); + let inbound_lane_data = storage + .read_and_decode_mandatory_value(storage_inbound_lane_data_key.0.as_ref()) + .map_err(Error::InboundLaneStorage)?; + + // check that the storage proof doesn't have any untouched trie nodes + storage.ensure_no_unused_nodes().map_err(Error::StorageProof)?; + + Ok((lane, inbound_lane_data)) + }, + ) + .map_err(Error::HeaderChain)? + } +} + +/// Sub-module that is declaring types required for processing Bridged -> This chain messages. +pub mod target { + use super::*; + + /// Decoded Bridged -> This message payload. + pub type FromBridgedChainMessagePayload = crate::messages_xcm_extension::XcmAsPlainPayload; + + /// Messages proof from bridged chain: + /// + /// - hash of finalized header; + /// - storage proof of messages and (optionally) outbound lane state; + /// - lane id; + /// - nonces (inclusive range) of messages which are included in this proof. + #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] + pub struct FromBridgedChainMessagesProof { + /// Hash of the finalized bridged header the proof is for. + pub bridged_header_hash: BridgedHeaderHash, + /// A storage trie proof of messages being delivered. + pub storage_proof: RawStorageProof, + /// Messages in this proof are sent over this lane. + pub lane: LaneId, + /// Nonce of the first message being delivered. + pub nonces_start: MessageNonce, + /// Nonce of the last message being delivered. + pub nonces_end: MessageNonce, + } + + impl Size for FromBridgedChainMessagesProof { + fn size(&self) -> u32 { + u32::try_from( + self.storage_proof + .iter() + .fold(0usize, |sum, node| sum.saturating_add(node.len())), + ) + .unwrap_or(u32::MAX) + } + } + + /// Return maximal dispatch weight of the message we're able to receive. + pub fn maximal_incoming_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight { + maximal_extrinsic_weight / 2 + } + + /// Return maximal message size given maximal extrinsic size. + pub fn maximal_incoming_message_size(maximal_extrinsic_size: u32) -> u32 { + maximal_extrinsic_size / 3 * 2 + } + + /// `SourceHeaderChain` implementation that is using default types and perform default checks. + pub struct SourceHeaderChainAdapter(PhantomData); + + impl SourceHeaderChain for SourceHeaderChainAdapter { + type Error = Error; + type MessagesProof = FromBridgedChainMessagesProof>>; + + fn verify_messages_proof( + proof: Self::MessagesProof, + messages_count: u32, + ) -> Result, Self::Error> { + verify_messages_proof::(proof, messages_count) + } + } + + /// Verify proof of Bridged -> This chain messages. + /// + /// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged + /// parachains, please use the `verify_messages_proof_from_parachain`. + /// + /// The `messages_count` argument verification (sane limits) is supposed to be made + /// outside of this function. This function only verifies that the proof declares exactly + /// `messages_count` messages. + pub fn verify_messages_proof( + proof: FromBridgedChainMessagesProof>>, + messages_count: u32, + ) -> Result, Error> { + let FromBridgedChainMessagesProof { + bridged_header_hash, + storage_proof, + lane, + nonces_start, + nonces_end, + } = proof; + + B::BridgedHeaderChain::parse_finalized_storage_proof( + bridged_header_hash, + storage_proof, + |storage| { + let mut parser = + StorageProofCheckerAdapter::<_, B> { storage, _dummy: Default::default() }; + + // receiving proofs where end < begin is ok (if proof includes outbound lane state) + let messages_in_the_proof = + if let Some(nonces_difference) = nonces_end.checked_sub(nonces_start) { + // let's check that the user (relayer) has passed correct `messages_count` + // (this bounds maximal capacity of messages vec below) + let messages_in_the_proof = nonces_difference.saturating_add(1); + if messages_in_the_proof != MessageNonce::from(messages_count) { + return Err(Error::MessagesCountMismatch) + } + + messages_in_the_proof + } else { + 0 + }; + + // Read messages first. All messages that are claimed to be in the proof must + // be in the proof. So any error in `read_value`, or even missing value is fatal. + // + // Mind that we allow proofs with no messages if outbound lane state is proved. + let mut messages = Vec::with_capacity(messages_in_the_proof as _); + for nonce in nonces_start..=nonces_end { + let message_key = MessageKey { lane_id: lane, nonce }; + let message_payload = parser.read_and_decode_message_payload(&message_key)?; + messages.push(Message { key: message_key, payload: message_payload }); + } + + // Now let's check if proof contains outbound lane state proof. It is optional, so + // we simply ignore `read_value` errors and missing value. + let proved_lane_messages = ProvedLaneMessages { + lane_state: parser.read_and_decode_outbound_lane_data(&lane)?, + messages, + }; + + // Now we may actually check if the proof is empty or not. + if proved_lane_messages.lane_state.is_none() && + proved_lane_messages.messages.is_empty() + { + return Err(Error::EmptyMessageProof) + } + + // check that the storage proof doesn't have any untouched trie nodes + parser.storage.ensure_no_unused_nodes().map_err(Error::StorageProof)?; + + // We only support single lane messages in this generated_schema + let mut proved_messages = ProvedMessages::new(); + proved_messages.insert(lane, proved_lane_messages); + + Ok(proved_messages) + }, + ) + .map_err(Error::HeaderChain)? + } + + struct StorageProofCheckerAdapter { + storage: StorageProofChecker, + _dummy: sp_std::marker::PhantomData, + } + + impl StorageProofCheckerAdapter { + fn read_and_decode_outbound_lane_data( + &mut self, + lane_id: &LaneId, + ) -> Result, Error> { + let storage_outbound_lane_data_key = bp_messages::storage_keys::outbound_lane_data_key( + B::BRIDGED_MESSAGES_PALLET_NAME, + lane_id, + ); + + self.storage + .read_and_decode_opt_value(storage_outbound_lane_data_key.0.as_ref()) + .map_err(Error::OutboundLaneStorage) + } + + fn read_and_decode_message_payload( + &mut self, + message_key: &MessageKey, + ) -> Result { + let storage_message_key = bp_messages::storage_keys::message_key( + B::BRIDGED_MESSAGES_PALLET_NAME, + &message_key.lane_id, + message_key.nonce, + ); + self.storage + .read_and_decode_mandatory_value(storage_message_key.0.as_ref()) + .map_err(Error::MessageStorage) + } + } +} + +/// The `BridgeMessagesCall` used by a chain. +pub type BridgeMessagesCallOf = bp_messages::BridgeMessagesCall< + bp_runtime::AccountIdOf, + target::FromBridgedChainMessagesProof>, + source::FromBridgedChainMessagesDeliveryProof>, +>; + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + messages_generation::{ + encode_all_messages, encode_lane_data, prepare_messages_storage_proof, + }, + mock::*, + }; + use bp_header_chain::StoredHeaderDataBuilder; + use bp_runtime::HeaderId; + use codec::Encode; + use sp_core::H256; + use sp_runtime::traits::Header as _; + + #[test] + fn verify_chain_message_rejects_message_with_too_large_declared_weight() { + assert!(source::verify_chain_message::(&vec![ + 42; + BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT - + 1 + ]) + .is_err()); + } + + #[test] + fn verify_chain_message_rejects_message_too_large_message() { + assert!(source::verify_chain_message::(&vec![ + 0; + source::maximal_message_size::() + as usize + 1 + ],) + .is_err()); + } + + #[test] + fn verify_chain_message_accepts_maximal_message() { + assert_eq!( + source::verify_chain_message::(&vec![ + 0; + source::maximal_message_size::() + as _ + ],), + Ok(()), + ); + } + + fn using_messages_proof( + nonces_end: MessageNonce, + outbound_lane_data: Option, + encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option>, + encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, + test: impl Fn(target::FromBridgedChainMessagesProof) -> R, + ) -> R { + let (state_root, storage_proof) = prepare_messages_storage_proof::( + TEST_LANE_ID, + 1..=nonces_end, + outbound_lane_data, + bp_runtime::StorageProofSize::Minimal(0), + vec![42], + encode_message, + encode_outbound_lane_data, + ); + + sp_io::TestExternalities::new(Default::default()).execute_with(move || { + let bridged_header = BridgedChainHeader::new( + 0, + Default::default(), + state_root, + Default::default(), + Default::default(), + ); + let bridged_header_hash = bridged_header.hash(); + + pallet_bridge_grandpa::BestFinalized::::put(HeaderId( + 0, + bridged_header_hash, + )); + pallet_bridge_grandpa::ImportedHeaders::::insert( + bridged_header_hash, + bridged_header.build(), + ); + test(target::FromBridgedChainMessagesProof { + bridged_header_hash, + storage_proof, + lane: TEST_LANE_ID, + nonces_start: 1, + nonces_end, + }) + }) + } + + #[test] + fn messages_proof_is_rejected_if_declared_less_than_actual_number_of_messages() { + assert_eq!( + using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { + target::verify_messages_proof::(proof, 5) + }), + Err(Error::MessagesCountMismatch), + ); + } + + #[test] + fn messages_proof_is_rejected_if_declared_more_than_actual_number_of_messages() { + assert_eq!( + using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { + target::verify_messages_proof::(proof, 15) + }), + Err(Error::MessagesCountMismatch), + ); + } + + #[test] + fn message_proof_is_rejected_if_header_is_missing_from_the_chain() { + assert_eq!( + using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { + let bridged_header_hash = + pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; + pallet_bridge_grandpa::ImportedHeaders::::remove(bridged_header_hash); + target::verify_messages_proof::(proof, 10) + }), + Err(Error::HeaderChain(HeaderChainError::UnknownHeader)), + ); + } + + #[test] + fn message_proof_is_rejected_if_header_state_root_mismatches() { + assert_eq!( + using_messages_proof(10, None, encode_all_messages, encode_lane_data, |proof| { + let bridged_header_hash = + pallet_bridge_grandpa::BestFinalized::::get().unwrap().1; + pallet_bridge_grandpa::ImportedHeaders::::insert( + bridged_header_hash, + BridgedChainHeader::new( + 0, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ) + .build(), + ); + target::verify_messages_proof::(proof, 10) + }), + Err(Error::HeaderChain(HeaderChainError::StorageProof( + StorageProofError::StorageRootMismatch + ))), + ); + } + + #[test] + fn message_proof_is_rejected_if_it_has_duplicate_trie_nodes() { + assert_eq!( + using_messages_proof(10, None, encode_all_messages, encode_lane_data, |mut proof| { + let node = proof.storage_proof.pop().unwrap(); + proof.storage_proof.push(node.clone()); + proof.storage_proof.push(node); + target::verify_messages_proof::(proof, 10) + },), + Err(Error::HeaderChain(HeaderChainError::StorageProof( + StorageProofError::DuplicateNodesInProof + ))), + ); + } + + #[test] + fn message_proof_is_rejected_if_it_has_unused_trie_nodes() { + assert_eq!( + using_messages_proof(10, None, encode_all_messages, encode_lane_data, |mut proof| { + proof.storage_proof.push(vec![42]); + target::verify_messages_proof::(proof, 10) + },), + Err(Error::StorageProof(StorageProofError::UnusedNodesInTheProof)), + ); + } + + #[test] + fn message_proof_is_rejected_if_required_message_is_missing() { + matches!( + using_messages_proof( + 10, + None, + |n, m| if n != 5 { Some(m.encode()) } else { None }, + encode_lane_data, + |proof| target::verify_messages_proof::(proof, 10) + ), + Err(Error::MessageStorage(StorageProofError::StorageValueEmpty)), + ); + } + + #[test] + fn message_proof_is_rejected_if_message_decode_fails() { + matches!( + using_messages_proof( + 10, + None, + |n, m| { + let mut m = m.encode(); + if n == 5 { + m = vec![42] + } + Some(m) + }, + encode_lane_data, + |proof| target::verify_messages_proof::(proof, 10), + ), + Err(Error::MessageStorage(StorageProofError::StorageValueDecodeFailed(_))), + ); + } + + #[test] + fn message_proof_is_rejected_if_outbound_lane_state_decode_fails() { + matches!( + using_messages_proof( + 10, + Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + encode_all_messages, + |d| { + let mut d = d.encode(); + d.truncate(1); + d + }, + |proof| target::verify_messages_proof::(proof, 10), + ), + Err(Error::OutboundLaneStorage(StorageProofError::StorageValueDecodeFailed(_))), + ); + } + + #[test] + fn message_proof_is_rejected_if_it_is_empty() { + assert_eq!( + using_messages_proof(0, None, encode_all_messages, encode_lane_data, |proof| { + target::verify_messages_proof::(proof, 0) + },), + Err(Error::EmptyMessageProof), + ); + } + + #[test] + fn non_empty_message_proof_without_messages_is_accepted() { + assert_eq!( + using_messages_proof( + 0, + Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + encode_all_messages, + encode_lane_data, + |proof| target::verify_messages_proof::(proof, 0), + ), + Ok(vec![( + TEST_LANE_ID, + ProvedLaneMessages { + lane_state: Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + messages: Vec::new(), + }, + )] + .into_iter() + .collect()), + ); + } + + #[test] + fn non_empty_message_proof_is_accepted() { + assert_eq!( + using_messages_proof( + 1, + Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + encode_all_messages, + encode_lane_data, + |proof| target::verify_messages_proof::(proof, 1), + ), + Ok(vec![( + TEST_LANE_ID, + ProvedLaneMessages { + lane_state: Some(OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 1, + latest_generated_nonce: 1, + }), + messages: vec![Message { + key: MessageKey { lane_id: TEST_LANE_ID, nonce: 1 }, + payload: vec![42], + }], + }, + )] + .into_iter() + .collect()), + ); + } + + #[test] + fn verify_messages_proof_does_not_panic_if_messages_count_mismatches() { + assert_eq!( + using_messages_proof(1, None, encode_all_messages, encode_lane_data, |mut proof| { + proof.nonces_end = u64::MAX; + target::verify_messages_proof::(proof, u32::MAX) + },), + Err(Error::MessagesCountMismatch), + ); + } +} diff --git a/bin/runtime-common/src/messages_api.rs b/bin/runtime-common/src/messages_api.rs new file mode 100644 index 00000000000..199e062fe98 --- /dev/null +++ b/bin/runtime-common/src/messages_api.rs @@ -0,0 +1,66 @@ +// Copyright 2019-2021 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 . + +//! Helpers for implementing various message-related runtime API mthods. + +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; +use sp_std::vec::Vec; + +/// Implementation of the `To*OutboundLaneApi::message_details`. +pub fn outbound_message_details( + lane: LaneId, + begin: MessageNonce, + end: MessageNonce, +) -> Vec +where + Runtime: pallet_bridge_messages::Config, + MessagesPalletInstance: 'static, +{ + (begin..=end) + .filter_map(|nonce| { + let message_data = + pallet_bridge_messages::Pallet::::outbound_message_data(lane, nonce)?; + Some(OutboundMessageDetails { + nonce, + // dispatch message weight is always zero at the source chain, since we're paying for + // dispatch at the target chain + dispatch_weight: frame_support::weights::Weight::zero(), + size: message_data.len() as _, + }) + }) + .collect() +} + +/// Implementation of the `To*InboundLaneApi::message_details`. +pub fn inbound_message_details( + lane: LaneId, + messages: Vec<(MessagePayload, OutboundMessageDetails)>, +) -> Vec +where + Runtime: pallet_bridge_messages::Config, + MessagesPalletInstance: 'static, +{ + messages + .into_iter() + .map(|(payload, details)| { + pallet_bridge_messages::Pallet::::inbound_message_data( + lane, payload, details, + ) + }) + .collect() +} diff --git a/bin/runtime-common/src/messages_benchmarking.rs b/bin/runtime-common/src/messages_benchmarking.rs new file mode 100644 index 00000000000..b067523c305 --- /dev/null +++ b/bin/runtime-common/src/messages_benchmarking.rs @@ -0,0 +1,293 @@ +// Copyright 2019-2021 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 . + +//! Everything required to run benchmarks of messages module, based on +//! `bridge_runtime_common::messages` implementation. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + AccountIdOf, BridgedChain, HashOf, HasherOf, MessageBridge, ThisChain, + }, + messages_generation::{ + encode_all_messages, encode_lane_data, grow_trie_leaf_value, prepare_messages_storage_proof, + }, +}; + +use bp_messages::storage_keys; +use bp_polkadot_core::parachains::ParaHash; +use bp_runtime::{ + record_all_trie_keys, Chain, Parachain, RawStorageProof, 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. +fn prepare_inbound_message( + params: &MessageProofParams, + destination: InteriorMultiLocation, +) -> Vec { + // 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, + _ => 0, + }; + + // if we don't need a correct message, then we may just return some random blob + if !params.is_successful_dispatch_expected { + 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() +} + +/// Prepare proof of messages for the `receive_messages_proof` call. +/// +/// In addition to returning valid messages proof, environment is prepared to verify this message +/// proof. +/// +/// This method is intended to be used when benchmarking pallet, linked to the chain that +/// uses GRANDPA finality. For parachains, please use the `prepare_message_proof_from_parachain` +/// function. +pub fn prepare_message_proof_from_grandpa_chain( + params: MessageProofParams, + message_destination: InteriorMultiLocation, +) -> (FromBridgedChainMessagesProof>>, Weight) +where + R: pallet_bridge_grandpa::Config>>, + FI: 'static, + B: MessageBridge, +{ + // prepare storage proof + let (state_root, storage_proof) = prepare_messages_storage_proof::( + params.lane, + params.message_nonces.clone(), + params.outbound_lane_data.clone(), + params.size, + prepare_inbound_message(¶ms, message_destination), + encode_all_messages, + encode_lane_data, + ); + + // update runtime storage + let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(state_root); + + ( + FromBridgedChainMessagesProof { + bridged_header_hash, + storage_proof, + lane: params.lane, + nonces_start: *params.message_nonces.start(), + nonces_end: *params.message_nonces.end(), + }, + Weight::MAX / 1000, + ) +} + +/// Prepare proof of messages for the `receive_messages_proof` call. +/// +/// In addition to returning valid messages proof, environment is prepared to verify this message +/// proof. +/// +/// This method is intended to be used when benchmarking pallet, linked to the chain that +/// uses parachain finality. For GRANDPA chains, please use the +/// `prepare_message_proof_from_grandpa_chain` function. +pub fn prepare_message_proof_from_parachain( + params: MessageProofParams, + message_destination: InteriorMultiLocation, +) -> (FromBridgedChainMessagesProof>>, Weight) +where + R: pallet_bridge_parachains::Config, + PI: 'static, + B: MessageBridge, + UnderlyingChainOf>: Chain + Parachain, +{ + // prepare storage proof + let (state_root, storage_proof) = prepare_messages_storage_proof::( + params.lane, + params.message_nonces.clone(), + params.outbound_lane_data.clone(), + params.size, + prepare_inbound_message(¶ms, message_destination), + encode_all_messages, + encode_lane_data, + ); + + // update runtime storage + let (_, bridged_header_hash) = + insert_header_to_parachains_pallet::>>(state_root); + + ( + FromBridgedChainMessagesProof { + bridged_header_hash, + storage_proof, + lane: params.lane, + nonces_start: *params.message_nonces.start(), + nonces_end: *params.message_nonces.end(), + }, + Weight::MAX / 1000, + ) +} + +/// Prepare proof of messages delivery for the `receive_messages_delivery_proof` call. +/// +/// This method is intended to be used when benchmarking pallet, linked to the chain that +/// uses GRANDPA finality. For parachains, please use the +/// `prepare_message_delivery_proof_from_parachain` function. +pub fn prepare_message_delivery_proof_from_grandpa_chain( + params: MessageDeliveryProofParams>>, +) -> FromBridgedChainMessagesDeliveryProof>> +where + R: pallet_bridge_grandpa::Config>>, + FI: 'static, + B: MessageBridge, +{ + // prepare storage proof + let lane = params.lane; + let (state_root, storage_proof) = prepare_message_delivery_proof::(params); + + // update runtime storage + let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(state_root); + + FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: bridged_header_hash.into(), + storage_proof, + lane, + } +} + +/// Prepare proof of messages delivery for the `receive_messages_delivery_proof` call. +/// +/// This method is intended to be used when benchmarking pallet, linked to the chain that +/// uses parachain finality. For GRANDPA chains, please use the +/// `prepare_message_delivery_proof_from_grandpa_chain` function. +pub fn prepare_message_delivery_proof_from_parachain( + params: MessageDeliveryProofParams>>, +) -> FromBridgedChainMessagesDeliveryProof>> +where + R: pallet_bridge_parachains::Config, + PI: 'static, + B: MessageBridge, + UnderlyingChainOf>: Chain + Parachain, +{ + // prepare storage proof + let lane = params.lane; + let (state_root, storage_proof) = prepare_message_delivery_proof::(params); + + // update runtime storage + let (_, bridged_header_hash) = + insert_header_to_parachains_pallet::>>(state_root); + + FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: bridged_header_hash.into(), + storage_proof, + lane, + } +} + +/// 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, +) -> (bp_runtime::BlockNumberOf, bp_runtime::HashOf) +where + R: pallet_bridge_grandpa::Config, + GI: 'static, + R::BridgedChain: bp_runtime::Chain, +{ + let bridged_block_number = Zero::zero(); + let bridged_header = bp_runtime::HeaderOf::::new( + bridged_block_number, + Default::default(), + state_root, + Default::default(), + Default::default(), + ); + let bridged_header_hash = bridged_header.hash(); + pallet_bridge_grandpa::initialize_for_benchmarks::(bridged_header); + (bridged_block_number, bridged_header_hash) +} + +/// Insert header to the bridge parachains pallet. +pub(crate) fn insert_header_to_parachains_pallet( + state_root: bp_runtime::HashOf, +) -> (bp_runtime::BlockNumberOf, bp_runtime::HashOf) +where + R: pallet_bridge_parachains::Config, + PI: 'static, + PC: Chain + Parachain, +{ + let bridged_block_number = Zero::zero(); + let bridged_header = bp_runtime::HeaderOf::::new( + bridged_block_number, + Default::default(), + state_root, + Default::default(), + Default::default(), + ); + let bridged_header_hash = bridged_header.hash(); + pallet_bridge_parachains::initialize_for_benchmarks::(bridged_header); + (bridged_block_number, bridged_header_hash) +} diff --git a/bin/runtime-common/src/messages_call_ext.rs b/bin/runtime-common/src/messages_call_ext.rs new file mode 100644 index 00000000000..f3665a8d93b --- /dev/null +++ b/bin/runtime-common/src/messages_call_ext.rs @@ -0,0 +1,634 @@ +// Copyright 2021 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 . + +use crate::messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, +}; +use bp_messages::{InboundLaneData, LaneId, MessageNonce}; +use frame_support::{ + dispatch::CallableCallFor, + traits::{Get, IsSubType}, + RuntimeDebug, +}; +use pallet_bridge_messages::{Config, Pallet}; +use sp_runtime::transaction_validity::TransactionValidity; +use sp_std::ops::RangeInclusive; + +/// Generic info about a messages delivery/confirmation proof. +#[derive(PartialEq, RuntimeDebug)] +pub struct BaseMessagesProofInfo { + /// Message lane, used by the call. + pub lane_id: LaneId, + /// Nonces of messages, included in the call. + /// + /// For delivery transaction, it is nonces of bundled messages. For confirmation + /// transaction, it is nonces that are to be confirmed during the call. + pub bundled_range: RangeInclusive, + /// Nonce of the best message, stored by this chain before the call is dispatched. + /// + /// For delivery transaction, it is the nonce of best delivered message before the call. + /// For confirmation transaction, it is the nonce of best confirmed message before the call. + pub best_stored_nonce: MessageNonce, +} + +impl BaseMessagesProofInfo { + /// Returns true if `bundled_range` continues the `0..=best_stored_nonce` range. + fn appends_to_stored_nonce(&self) -> bool { + *self.bundled_range.start() == self.best_stored_nonce + 1 + } +} + +/// Occupation state of the unrewarded relayers vector. +#[derive(PartialEq, RuntimeDebug)] +#[cfg_attr(test, derive(Default))] +pub struct UnrewardedRelayerOccupation { + /// The number of remaining unoccupied entries for new relayers. + pub free_relayer_slots: MessageNonce, + /// The number of messages that we are ready to accept. + pub free_message_slots: MessageNonce, +} + +/// Info about a `ReceiveMessagesProof` call which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub struct ReceiveMessagesProofInfo { + /// Base messages proof info + pub base: BaseMessagesProofInfo, + /// State of unrewarded relayers vector. + pub unrewarded_relayers: UnrewardedRelayerOccupation, +} + +impl ReceiveMessagesProofInfo { + /// Returns true if: + /// + /// - either inbound lane is ready to accept bundled messages; + /// + /// - or there are no bundled messages, but the inbound lane is blocked by too many unconfirmed + /// messages and/or unrewarded relayers. + fn is_obsolete(&self) -> bool { + // transactions with zero bundled nonces are not allowed, unless they're message + // delivery transactions, which brings reward confirmations required to unblock + // the lane + if self.base.bundled_range.is_empty() { + let empty_transactions_allowed = + // we allow empty transactions when we can't accept delivery from new relayers + self.unrewarded_relayers.free_relayer_slots == 0 || + // or if we can't accept new messages at all + self.unrewarded_relayers.free_message_slots == 0; + + return !empty_transactions_allowed + } + + // otherwise we require bundled messages to continue stored range + !self.base.appends_to_stored_nonce() + } +} + +/// Info about a `ReceiveMessagesDeliveryProof` call which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); + +impl ReceiveMessagesDeliveryProofInfo { + /// Returns true if outbound lane is ready to accept confirmations of bundled messages. + fn is_obsolete(&self) -> bool { + self.0.bundled_range.is_empty() || !self.0.appends_to_stored_nonce() + } +} + +/// Info about a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call +/// which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub enum CallInfo { + ReceiveMessagesProof(ReceiveMessagesProofInfo), + ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo), +} + +/// Helper struct that provides methods for working with a call supported by `CallInfo`. +pub struct CallHelper, I: 'static> { + pub _phantom_data: sp_std::marker::PhantomData<(T, I)>, +} + +impl, I: 'static> CallHelper { + /// Returns true if: + /// + /// - call is `receive_messages_proof` and all messages have been delivered; + /// + /// - call is `receive_messages_delivery_proof` and all messages confirmations have been + /// received. + pub fn was_successful(info: &CallInfo) -> bool { + match info { + CallInfo::ReceiveMessagesProof(info) => { + let inbound_lane_data = + pallet_bridge_messages::InboundLanes::::get(info.base.lane_id); + if info.base.bundled_range.is_empty() { + let post_occupation = + unrewarded_relayers_occupation::(&inbound_lane_data); + // we don't care about `free_relayer_slots` here - it is checked in + // `is_obsolete` and every relayer has delivered at least one message, + // so if relayer slots are released, then message slots are also + // released + return post_occupation.free_message_slots > + info.unrewarded_relayers.free_message_slots + } + + inbound_lane_data.last_delivered_nonce() == *info.base.bundled_range.end() + }, + CallInfo::ReceiveMessagesDeliveryProof(info) => { + let outbound_lane_data = + pallet_bridge_messages::OutboundLanes::::get(info.0.lane_id); + outbound_lane_data.latest_received_nonce == *info.0.bundled_range.end() + }, + } + } +} + +/// Trait representing a call that is a sub type of `pallet_bridge_messages::Call`. +pub trait MessagesCallSubType, I: 'static>: + IsSubType, T>> +{ + /// Create a new instance of `ReceiveMessagesProofInfo` from a `ReceiveMessagesProof` call. + fn receive_messages_proof_info(&self) -> Option; + + /// Create a new instance of `ReceiveMessagesDeliveryProofInfo` from + /// a `ReceiveMessagesDeliveryProof` call. + fn receive_messages_delivery_proof_info(&self) -> Option; + + /// Create a new instance of `CallInfo` from a `ReceiveMessagesProof` + /// or a `ReceiveMessagesDeliveryProof` call. + fn call_info(&self) -> Option; + + /// Create a new instance of `CallInfo` from a `ReceiveMessagesProof` + /// 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. + fn check_obsolete_call(&self) -> TransactionValidity; +} + +impl< + BridgedHeaderHash, + SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof, + >, + TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain< + >::OutboundPayload, + ::AccountId, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof, + >, + Call: IsSubType, T>>, + T: frame_system::Config + + Config, + I: 'static, + > MessagesCallSubType for T::RuntimeCall +{ + fn receive_messages_proof_info(&self) -> Option { + if let Some(pallet_bridge_messages::Call::::receive_messages_proof { + ref proof, + .. + }) = self.is_sub_type() + { + let inbound_lane_data = pallet_bridge_messages::InboundLanes::::get(proof.lane); + + return Some(ReceiveMessagesProofInfo { + base: BaseMessagesProofInfo { + lane_id: proof.lane, + // we want all messages in this range to be new for us. Otherwise transaction + // will be considered obsolete. + bundled_range: proof.nonces_start..=proof.nonces_end, + best_stored_nonce: inbound_lane_data.last_delivered_nonce(), + }, + unrewarded_relayers: unrewarded_relayers_occupation::(&inbound_lane_data), + }) + } + + None + } + + fn receive_messages_delivery_proof_info(&self) -> Option { + if let Some(pallet_bridge_messages::Call::::receive_messages_delivery_proof { + ref proof, + ref relayers_state, + .. + }) = self.is_sub_type() + { + let outbound_lane_data = pallet_bridge_messages::OutboundLanes::::get(proof.lane); + + return Some(ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { + lane_id: proof.lane, + // there's a time frame between message delivery, message confirmation and reward + // confirmation. Because of that, we can't assume that our state has been confirmed + // to the bridged chain. So we are accepting any proof that brings new + // confirmations. + bundled_range: outbound_lane_data.latest_received_nonce + 1..= + relayers_state.last_delivered_nonce, + best_stored_nonce: outbound_lane_data.latest_received_nonce, + })) + } + + None + } + + fn call_info(&self) -> Option { + if let Some(info) = self.receive_messages_proof_info() { + return Some(CallInfo::ReceiveMessagesProof(info)) + } + + if let Some(info) = self.receive_messages_delivery_proof_info() { + return Some(CallInfo::ReceiveMessagesDeliveryProof(info)) + } + + None + } + + fn call_info_for(&self, lane_id: LaneId) -> Option { + self.call_info().filter(|info| { + let actual_lane_id = match info { + CallInfo::ReceiveMessagesProof(info) => info.base.lane_id, + CallInfo::ReceiveMessagesDeliveryProof(info) => info.0.lane_id, + }; + actual_lane_id == lane_id + }) + } + + fn check_obsolete_call(&self) -> TransactionValidity { + match self.call_info() { + Some(CallInfo::ReceiveMessagesProof(proof_info)) if proof_info.is_obsolete() => { + log::trace!( + target: pallet_bridge_messages::LOG_TARGET, + "Rejecting obsolete messages delivery transaction: {:?}", + proof_info + ); + + return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() + }, + Some(CallInfo::ReceiveMessagesDeliveryProof(proof_info)) + if proof_info.is_obsolete() => + { + log::trace!( + target: pallet_bridge_messages::LOG_TARGET, + "Rejecting obsolete messages confirmation transaction: {:?}", + proof_info, + ); + + return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() + }, + _ => {}, + } + + Ok(sp_runtime::transaction_validity::ValidTransaction::default()) + } +} + +/// Returns occupation state of unrewarded relayers vector. +fn unrewarded_relayers_occupation, I: 'static>( + inbound_lane_data: &InboundLaneData, +) -> UnrewardedRelayerOccupation { + UnrewardedRelayerOccupation { + free_relayer_slots: T::MaxUnrewardedRelayerEntriesAtInboundLane::get() + .saturating_sub(inbound_lane_data.relayers.len() as MessageNonce), + free_message_slots: { + let unconfirmed_messages = inbound_lane_data + .last_delivered_nonce() + .saturating_sub(inbound_lane_data.last_confirmed_nonce); + T::MaxUnconfirmedMessagesAtInboundLane::get().saturating_sub(unconfirmed_messages) + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + }, + messages_call_ext::MessagesCallSubType, + mock::{ + MaxUnconfirmedMessagesAtInboundLane, MaxUnrewardedRelayerEntriesAtInboundLane, + TestRuntime, ThisChainRuntimeCall, + }, + }; + use bp_messages::{DeliveredMessages, UnrewardedRelayer, UnrewardedRelayersState}; + use sp_std::ops::RangeInclusive; + + fn fill_unrewarded_relayers() { + let mut inbound_lane_state = + pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); + for n in 0..MaxUnrewardedRelayerEntriesAtInboundLane::get() { + inbound_lane_state.relayers.push_back(UnrewardedRelayer { + relayer: Default::default(), + messages: DeliveredMessages { begin: n + 1, end: n + 1 }, + }); + } + pallet_bridge_messages::InboundLanes::::insert( + LaneId([0, 0, 0, 0]), + inbound_lane_state, + ); + } + + fn fill_unrewarded_messages() { + let mut inbound_lane_state = + pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); + inbound_lane_state.relayers.push_back(UnrewardedRelayer { + relayer: Default::default(), + messages: DeliveredMessages { + begin: 1, + end: MaxUnconfirmedMessagesAtInboundLane::get(), + }, + }); + pallet_bridge_messages::InboundLanes::::insert( + LaneId([0, 0, 0, 0]), + inbound_lane_state, + ); + } + + fn deliver_message_10() { + pallet_bridge_messages::InboundLanes::::insert( + LaneId([0, 0, 0, 0]), + bp_messages::InboundLaneData { relayers: Default::default(), last_confirmed_nonce: 10 }, + ); + } + + fn validate_message_delivery( + nonces_start: bp_messages::MessageNonce, + nonces_end: bp_messages::MessageNonce, + ) -> bool { + ThisChainRuntimeCall::BridgeMessages( + pallet_bridge_messages::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: 42, + messages_count: nonces_end.checked_sub(nonces_start).map(|x| x + 1).unwrap_or(0) + as u32, + dispatch_weight: frame_support::weights::Weight::zero(), + proof: FromBridgedChainMessagesProof { + bridged_header_hash: Default::default(), + storage_proof: vec![], + lane: LaneId([0, 0, 0, 0]), + nonces_start, + nonces_end, + }, + }, + ) + .check_obsolete_call() + .is_ok() + } + + #[test] + fn extension_rejects_obsolete_messages() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver messages 8..=9 + // => tx is rejected + deliver_message_10(); + assert!(!validate_message_delivery(8, 9)); + }); + } + + #[test] + fn extension_rejects_same_message() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to import messages 10..=10 + // => tx is rejected + deliver_message_10(); + assert!(!validate_message_delivery(8, 10)); + }); + } + + #[test] + fn extension_rejects_call_with_some_obsolete_messages() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver messages + // 10..=15 => tx is rejected + deliver_message_10(); + assert!(!validate_message_delivery(10, 15)); + }); + } + + #[test] + fn extension_rejects_call_with_future_messages() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver messages + // 13..=15 => tx is rejected + deliver_message_10(); + assert!(!validate_message_delivery(13, 15)); + }); + } + + #[test] + fn extension_rejects_empty_delivery_with_rewards_confirmations_if_there_are_free_relayer_and_message_slots( + ) { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + assert!(!validate_message_delivery(10, 9)); + }); + } + + #[test] + fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_relayer_slots( + ) { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + fill_unrewarded_relayers(); + assert!(validate_message_delivery(10, 9)); + }); + } + + #[test] + fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_message_slots( + ) { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + fill_unrewarded_messages(); + assert!(validate_message_delivery( + MaxUnconfirmedMessagesAtInboundLane::get(), + MaxUnconfirmedMessagesAtInboundLane::get() - 1 + )); + }); + } + + #[test] + fn extension_accepts_new_messages() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best delivered is message#10 and we're trying to deliver message 11..=15 + // => tx is accepted + deliver_message_10(); + assert!(validate_message_delivery(11, 15)); + }); + } + + fn confirm_message_10() { + pallet_bridge_messages::OutboundLanes::::insert( + LaneId([0, 0, 0, 0]), + bp_messages::OutboundLaneData { + oldest_unpruned_nonce: 0, + latest_received_nonce: 10, + latest_generated_nonce: 10, + }, + ); + } + + fn validate_message_confirmation(last_delivered_nonce: bp_messages::MessageNonce) -> bool { + ThisChainRuntimeCall::BridgeMessages( + pallet_bridge_messages::Call::::receive_messages_delivery_proof { + proof: FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: Default::default(), + storage_proof: Vec::new(), + lane: LaneId([0, 0, 0, 0]), + }, + relayers_state: UnrewardedRelayersState { + last_delivered_nonce, + ..Default::default() + }, + }, + ) + .check_obsolete_call() + .is_ok() + } + + #[test] + fn extension_rejects_obsolete_confirmations() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best confirmed is message#10 and we're trying to confirm message#5 => tx + // is rejected + confirm_message_10(); + assert!(!validate_message_confirmation(5)); + }); + } + + #[test] + fn extension_rejects_same_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best confirmed is message#10 and we're trying to confirm message#10 => + // tx is rejected + confirm_message_10(); + assert!(!validate_message_confirmation(10)); + }); + } + + #[test] + fn extension_rejects_empty_confirmation_even_if_there_are_no_free_unrewarded_entries() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + confirm_message_10(); + fill_unrewarded_relayers(); + assert!(!validate_message_confirmation(10)); + }); + } + + #[test] + fn extension_accepts_new_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + // when current best confirmed is message#10 and we're trying to confirm message#15 => + // tx is accepted + confirm_message_10(); + assert!(validate_message_confirmation(15)); + }); + } + + fn was_message_delivery_successful( + bundled_range: RangeInclusive, + is_empty: bool, + ) -> bool { + CallHelper::::was_successful(&CallInfo::ReceiveMessagesProof( + ReceiveMessagesProofInfo { + base: BaseMessagesProofInfo { + lane_id: LaneId([0, 0, 0, 0]), + bundled_range, + best_stored_nonce: 0, // doesn't matter for `was_successful` + }, + unrewarded_relayers: UnrewardedRelayerOccupation { + free_relayer_slots: 0, // doesn't matter for `was_successful` + free_message_slots: if is_empty { + 0 + } else { + MaxUnconfirmedMessagesAtInboundLane::get() + }, + }, + }, + )) + } + + #[test] + #[allow(clippy::reversed_empty_ranges)] + fn was_successful_returns_false_for_failed_reward_confirmation_transaction() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + fill_unrewarded_messages(); + assert!(!was_message_delivery_successful(10..=9, true)); + }); + } + + #[test] + #[allow(clippy::reversed_empty_ranges)] + fn was_successful_returns_true_for_successful_reward_confirmation_transaction() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + assert!(was_message_delivery_successful(10..=9, true)); + }); + } + + #[test] + fn was_successful_returns_false_for_failed_delivery() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + assert!(!was_message_delivery_successful(10..=12, false)); + }); + } + + #[test] + fn was_successful_returns_false_for_partially_successful_delivery() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + assert!(!was_message_delivery_successful(9..=12, false)); + }); + } + + #[test] + fn was_successful_returns_true_for_successful_delivery() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + deliver_message_10(); + assert!(was_message_delivery_successful(9..=10, false)); + }); + } + + fn was_message_confirmation_successful(bundled_range: RangeInclusive) -> bool { + CallHelper::::was_successful(&CallInfo::ReceiveMessagesDeliveryProof( + ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { + lane_id: LaneId([0, 0, 0, 0]), + bundled_range, + best_stored_nonce: 0, // doesn't matter for `was_successful` + }), + )) + } + + #[test] + fn was_successful_returns_false_for_failed_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + confirm_message_10(); + assert!(!was_message_confirmation_successful(10..=12)); + }); + } + + #[test] + fn was_successful_returns_false_for_partially_successful_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + confirm_message_10(); + assert!(!was_message_confirmation_successful(9..=12)); + }); + } + + #[test] + fn was_successful_returns_true_for_successful_confirmation() { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + confirm_message_10(); + assert!(was_message_confirmation_successful(9..=10)); + }); + } +} diff --git a/bin/runtime-common/src/messages_generation.rs b/bin/runtime-common/src/messages_generation.rs new file mode 100644 index 00000000000..29a869a5c87 --- /dev/null +++ b/bin/runtime-common/src/messages_generation.rs @@ -0,0 +1,119 @@ +// Copyright 2019-2022 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 . + +//! Helpers for generating message storage proofs, that are used by tests and by benchmarks. + +#![cfg(any(feature = "runtime-benchmarks", test))] + +use crate::messages::{BridgedChain, HashOf, HasherOf, MessageBridge}; + +use bp_messages::{ + storage_keys, LaneId, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, +}; +use bp_runtime::{record_all_trie_keys, RawStorageProof, StorageProofSize}; +use codec::Encode; +use sp_std::{ops::RangeInclusive, prelude::*}; +use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; + +/// Simple and correct message data encode function. +pub(crate) fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option> { + Some(m.encode()) +} + +/// Simple and correct outbound lane data encode function. +pub(crate) fn encode_lane_data(d: &OutboundLaneData) -> Vec { + d.encode() +} + +/// Prepare storage proof of given messages. +/// +/// Returns state trie root and nodes with prepared messages. +pub(crate) fn prepare_messages_storage_proof( + lane: LaneId, + message_nonces: RangeInclusive, + outbound_lane_data: Option, + size: StorageProofSize, + message_payload: MessagePayload, + encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option>, + encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, +) -> (HashOf>, RawStorageProof) +where + B: MessageBridge, + HashOf>: Copy + Default, +{ + // prepare Bridged chain storage with messages and (optionally) outbound lane state + let message_count = message_nonces.end().saturating_sub(*message_nonces.start()) + 1; + let mut storage_keys = Vec::with_capacity(message_count as usize + 1); + let mut root = Default::default(); + let mut mdb = MemoryDB::default(); + { + let mut trie = + TrieDBMutBuilderV1::>>::new(&mut mdb, &mut root).build(); + + // insert messages + for (i, nonce) in message_nonces.into_iter().enumerate() { + let message_key = MessageKey { lane_id: lane, nonce }; + let message_payload = match encode_message(nonce, &message_payload) { + Some(message_payload) => + if i == 0 { + grow_trie_leaf_value(message_payload, size) + } else { + message_payload + }, + None => continue, + }; + let storage_key = storage_keys::message_key( + B::BRIDGED_MESSAGES_PALLET_NAME, + &message_key.lane_id, + message_key.nonce, + ) + .0; + trie.insert(&storage_key, &message_payload) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + storage_keys.push(storage_key); + } + + // insert outbound lane state + if let Some(outbound_lane_data) = outbound_lane_data.as_ref().map(encode_outbound_lane_data) + { + let storage_key = + storage_keys::outbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane).0; + trie.insert(&storage_key, &outbound_lane_data) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + storage_keys.push(storage_key); + } + } + + // 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 { + StorageProofSize::Minimal(_) => (), + StorageProofSize::HasLargeLeaf(size) if size as usize > value.len() => { + value.extend(sp_std::iter::repeat(42u8).take(size as usize - value.len())); + }, + StorageProofSize::HasLargeLeaf(_) => (), + } + value +} diff --git a/bin/runtime-common/src/messages_xcm_extension.rs b/bin/runtime-common/src/messages_xcm_extension.rs new file mode 100644 index 00000000000..4ccdd7a4b4d --- /dev/null +++ b/bin/runtime-common/src/messages_xcm_extension.rs @@ -0,0 +1,164 @@ +// Copyright 2023 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 provides utilities for easier XCM handling, e.g: +//! `XcmExecutor` -> `MessageSender` -> `OutboundMessageQueue` +//! | +//! `Relayer` +//! | +//! `XcmRouter` <- `MessageDispatch` <- `InboundMessageQueue` + +use bp_messages::{ + source_chain::MessagesBridge, + target_chain::{DispatchMessage, MessageDispatch}, + LaneId, +}; +use bp_runtime::{messages::MessageDispatchResult, AccountIdOf, Chain}; +use codec::{Decode, Encode}; +use frame_support::{dispatch::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; +use pallet_bridge_messages::WeightInfoExt as MessagesPalletWeights; +use scale_info::TypeInfo; +use sp_runtime::SaturatedConversion; +use xcm_builder::{DispatchBlob, DispatchBlobError, HaulBlob, HaulBlobError}; + +/// Plain "XCM" payload, which we transfer through bridge +pub type XcmAsPlainPayload = sp_std::prelude::Vec; + +/// Message dispatch result type for single message +#[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)] +pub enum XcmBlobMessageDispatchResult { + InvalidPayload, + Dispatched, + NotDispatched(#[codec(skip)] Option), +} + +/// [`XcmBlobMessageDispatch`] is responsible for dispatching received messages +pub struct XcmBlobMessageDispatch +{ + _marker: sp_std::marker::PhantomData<( + SourceBridgeHubChain, + TargetBridgeHubChain, + DispatchBlob, + Weights, + )>, +} + +impl< + SourceBridgeHubChain: Chain, + TargetBridgeHubChain: Chain, + BlobDispatcher: DispatchBlob, + Weights: MessagesPalletWeights, + > MessageDispatch> + for XcmBlobMessageDispatch +{ + type DispatchPayload = XcmAsPlainPayload; + type DispatchLevelResult = XcmBlobMessageDispatchResult; + + fn dispatch_weight(message: &mut DispatchMessage) -> Weight { + match message.data.payload { + Ok(ref payload) => { + let payload_size = payload.encoded_size().saturated_into(); + Weights::message_dispatch_weight(payload_size) + }, + Err(_) => Weight::zero(), + } + } + + fn dispatch( + _relayer_account: &AccountIdOf, + message: DispatchMessage, + ) -> MessageDispatchResult { + let payload = match message.data.payload { + Ok(payload) => payload, + Err(e) => { + log::error!( + target: crate::LOG_TARGET_BRIDGE_DISPATCH, + "[XcmBlobMessageDispatch] payload error: {:?} - message_nonce: {:?}", + e, + message.key.nonce + ); + return MessageDispatchResult { + unspent_weight: Weight::zero(), + dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload, + } + }, + }; + let dispatch_level_result = match BlobDispatcher::dispatch_blob(payload) { + Ok(_) => { + log::debug!( + target: crate::LOG_TARGET_BRIDGE_DISPATCH, + "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob was ok - message_nonce: {:?}", + message.key.nonce + ); + XcmBlobMessageDispatchResult::Dispatched + }, + Err(e) => { + log::error!( + target: crate::LOG_TARGET_BRIDGE_DISPATCH, + "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob failed, error: {:?} - message_nonce: {:?}", + e, message.key.nonce + ); + XcmBlobMessageDispatchResult::NotDispatched(Some(e)) + }, + }; + MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result } + } +} + +/// [`XcmBlobHauler`] is responsible for sending messages to the bridge "point-to-point link" from +/// one side, where on the other it can be dispatched by [`XcmBlobMessageDispatch`]. +pub trait XcmBlobHauler { + /// Runtime message sender adapter. + type MessageSender: MessagesBridge; + + /// Runtime message sender origin, which is used by [`Self::MessageSender`]. + type MessageSenderOrigin; + /// Our location within the Consensus Universe. + fn message_sender_origin() -> Self::MessageSenderOrigin; + + /// Return message lane (as "point-to-point link") used to deliver XCM messages. + fn xcm_lane() -> LaneId; +} + +/// XCM bridge adapter which connects [`XcmBlobHauler`] with [`XcmBlobHauler::MessageSender`] and +/// makes sure that XCM blob is sent to the [`pallet_bridge_messages`] queue to be relayed. +pub struct XcmBlobHaulerAdapter(sp_std::marker::PhantomData); +impl> HaulBlob + for XcmBlobHaulerAdapter +{ + fn haul_blob(blob: sp_std::prelude::Vec) -> Result<(), HaulBlobError> { + let lane = H::xcm_lane(); + H::MessageSender::send_message(H::message_sender_origin(), lane, blob) + .map(|artifacts| (lane, artifacts.nonce).using_encoded(sp_io::hashing::blake2_256)) + .map(|result| { + log::info!( + target: crate::LOG_TARGET_BRIDGE_DISPATCH, + "haul_blob result - ok: {:?} on lane: {:?}", + result, + lane + ) + }) + .map_err(|error| { + log::error!( + target: crate::LOG_TARGET_BRIDGE_DISPATCH, + "haul_blob result - error: {:?} on lane: {:?}", + error, + lane + ); + HaulBlobError::Transport("MessageSenderError") + }) + } +} diff --git a/bin/runtime-common/src/mock.rs b/bin/runtime-common/src/mock.rs new file mode 100644 index 00000000000..036813f6fd5 --- /dev/null +++ b/bin/runtime-common/src/mock.rs @@ -0,0 +1,402 @@ +// Copyright 2019-2021 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 . + +//! 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. + +#![cfg(test)] + +use crate::messages::{ + source::{ + FromThisChainMaximalOutboundPayloadSize, FromThisChainMessagePayload, + FromThisChainMessageVerifier, TargetHeaderChainAdapter, + }, + target::{FromBridgedChainMessagePayload, SourceHeaderChainAdapter}, + BridgedChainWithMessages, HashOf, MessageBridge, ThisChainWithMessages, +}; + +use bp_header_chain::{ChainWithGrandpa, HeaderChain}; +use bp_messages::{target_chain::ForbidInboundMessages, LaneId, MessageNonce}; +use bp_parachains::SingleParaStoredHeaderDataBuilder; +use bp_runtime::{Chain, ChainId, Parachain, UnderlyingChainProvider}; +use codec::{Decode, Encode}; +use frame_support::{ + parameter_types, + weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight}, +}; +use pallet_transaction_payment::Multiplier; +use sp_runtime::{ + testing::H256, + traits::{BlakeTwo256, ConstU32, ConstU64, ConstU8, IdentityLookup}, + FixedPointNumber, Perquintill, +}; + +/// Account identifier at `ThisChain`. +pub type ThisChainAccountId = u64; +/// Balance at `ThisChain`. +pub type ThisChainBalance = u64; +/// Block number at `ThisChain`. +pub type ThisChainBlockNumber = u32; +/// Hash at `ThisChain`. +pub type ThisChainHash = H256; +/// Hasher at `ThisChain`. +pub type ThisChainHasher = BlakeTwo256; +/// Runtime call at `ThisChain`. +pub type ThisChainRuntimeCall = RuntimeCall; +/// Runtime call origin at `ThisChain`. +pub type ThisChainCallOrigin = RuntimeOrigin; +/// Header of `ThisChain`. +pub type ThisChainHeader = sp_runtime::generic::Header; +/// Block of `ThisChain`. +pub type ThisChainBlock = frame_system::mocking::MockBlock; +/// Unchecked extrinsic of `ThisChain`. +pub type ThisChainUncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +/// Account identifier at the `BridgedChain`. +pub type BridgedChainAccountId = u128; +/// Balance at the `BridgedChain`. +pub type BridgedChainBalance = u128; +/// Block number at the `BridgedChain`. +pub type BridgedChainBlockNumber = u32; +/// Hash at the `BridgedChain`. +pub type BridgedChainHash = H256; +/// Hasher at the `BridgedChain`. +pub type BridgedChainHasher = BlakeTwo256; +/// Header of the `BridgedChain`. +pub type BridgedChainHeader = + sp_runtime::generic::Header; + +/// Message lane used in tests. +pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]); +/// Bridged chain id used in tests. +pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; +/// Maximal extrinsic weight at the `BridgedChain`. +pub const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: usize = 2048; +/// Maximal extrinsic size at the `BridgedChain`. +pub const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024; + +frame_support::construct_runtime! { + pub enum TestRuntime where + Block = ThisChainBlock, + NodeBlock = ThisChainBlock, + UncheckedExtrinsic = ThisChainUncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Utility: pallet_utility, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, + BridgeGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage, Event}, + BridgeParachains: pallet_bridge_parachains::{Pallet, Call, Storage, Event}, + BridgeMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, + } +} + +crate::generate_bridge_reject_obsolete_headers_and_messages! { + ThisChainRuntimeCall, ThisChainAccountId, + BridgeGrandpa, BridgeParachains, BridgeMessages +} + +parameter_types! { + pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID]; + pub const BridgedChainId: ChainId = TEST_BRIDGED_CHAIN_ID; + pub const BridgedParasPalletName: &'static str = "Paras"; + pub const ExistentialDeposit: ThisChainBalance = 500; + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); + pub const TransactionBaseFee: ThisChainBalance = 0; + pub const TransactionByteFee: ThisChainBalance = 1; + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); + pub MaximumMultiplier: Multiplier = sp_runtime::traits::Bounded::max_value(); + pub const MaxUnrewardedRelayerEntriesAtInboundLane: MessageNonce = 16; + pub const MaxUnconfirmedMessagesAtInboundLane: MessageNonce = 1_000; +} + +impl frame_system::Config for TestRuntime { + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = ThisChainBlockNumber; + type Hash = ThisChainHash; + type Hashing = ThisChainHasher; + type AccountId = ThisChainAccountId; + type Lookup = IdentityLookup; + type Header = ThisChainHeader; + 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>; +} + +impl pallet_utility::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = (); +} + +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 HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +impl pallet_transaction_payment::Config for TestRuntime { + type OnChargeTransaction = pallet_transaction_payment::CurrencyAdapter; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< + TestRuntime, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, + >; + type RuntimeEvent = RuntimeEvent; +} + +impl pallet_bridge_grandpa::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = BridgedUnderlyingChain; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<4>; + type HeadersToKeep = ConstU32<8>; + type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; +} + +impl pallet_bridge_parachains::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgesGrandpaPalletInstance = (); + type ParasPalletName = BridgedParasPalletName; + type ParaStoredHeaderDataBuilder = + SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ConstU32<8>; + type MaxParaHeadDataSize = ConstU32<1024>; + type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight; +} + +impl pallet_bridge_messages::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; + type ActiveOutboundLanes = ActiveOutboundLanes; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = FromThisChainMaximalOutboundPayloadSize; + type OutboundPayload = FromThisChainMessagePayload; + + type InboundPayload = FromBridgedChainMessagePayload; + type InboundRelayer = BridgedChainAccountId; + type DeliveryPayments = (); + + type TargetHeaderChain = TargetHeaderChainAdapter; + type LaneMessageVerifier = FromThisChainMessageVerifier; + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + TestRuntime, + (), + ConstU64<100_000>, + >; + + type SourceHeaderChain = SourceHeaderChainAdapter; + type MessageDispatch = ForbidInboundMessages<(), FromBridgedChainMessagePayload>; + type BridgedChainId = BridgedChainId; +} + +impl pallet_bridge_relayers::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type Reward = ThisChainBalance; + type PaymentProcedure = (); + type WeightInfo = (); +} + +/// Bridge that is deployed on `ThisChain` and allows sending/receiving messages to/from +/// `BridgedChain`. +#[derive(Debug, PartialEq, Eq)] +pub struct OnThisChainBridge; + +impl MessageBridge for OnThisChainBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = ""; + + type ThisChain = ThisChain; + type BridgedChain = BridgedChain; + type BridgedHeaderChain = pallet_bridge_grandpa::GrandpaChainHeaders; +} + +/// Bridge that is deployed on `BridgedChain` and allows sending/receiving messages to/from +/// `ThisChain`. +#[derive(Debug, PartialEq, Eq)] +pub struct OnBridgedChainBridge; + +impl MessageBridge for OnBridgedChainBridge { + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = ""; + + type ThisChain = BridgedChain; + type BridgedChain = ThisChain; + type BridgedHeaderChain = ThisHeaderChain; +} + +/// Dummy implementation of `HeaderChain` for `ThisChain` at the `BridgedChain`. +pub struct ThisHeaderChain; + +impl HeaderChain for ThisHeaderChain { + fn finalized_header_state_root(_hash: HashOf) -> Option> { + unreachable!() + } +} + +/// Call origin at `BridgedChain`. +#[derive(Clone, Debug)] +pub struct BridgedChainOrigin; + +impl From + for Result, BridgedChainOrigin> +{ + fn from( + _origin: BridgedChainOrigin, + ) -> Result, BridgedChainOrigin> { + unreachable!() + } +} + +/// Underlying chain of `ThisChain`. +pub struct ThisUnderlyingChain; + +impl Chain for ThisUnderlyingChain { + type BlockNumber = ThisChainBlockNumber; + type Hash = ThisChainHash; + type Hasher = ThisChainHasher; + type Header = ThisChainHeader; + type AccountId = ThisChainAccountId; + type Balance = ThisChainBalance; + type Index = u32; + type Signature = sp_runtime::MultiSignature; + + fn max_extrinsic_size() -> u32 { + BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE + } + + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +/// The chain where we are in tests. +pub struct ThisChain; + +impl UnderlyingChainProvider for ThisChain { + type Chain = ThisUnderlyingChain; +} + +impl ThisChainWithMessages for ThisChain { + type RuntimeOrigin = ThisChainCallOrigin; +} + +impl BridgedChainWithMessages for ThisChain {} + +/// Underlying chain of `BridgedChain`. +pub struct BridgedUnderlyingChain; +/// Some parachain under `BridgedChain` consensus. +pub struct BridgedUnderlyingParachain; +/// Runtime call of the `BridgedChain`. +#[derive(Decode, Encode)] +pub struct BridgedChainCall; + +impl Chain for BridgedUnderlyingChain { + type BlockNumber = BridgedChainBlockNumber; + type Hash = BridgedChainHash; + type Hasher = BridgedChainHasher; + type Header = BridgedChainHeader; + type AccountId = BridgedChainAccountId; + type Balance = BridgedChainBalance; + type Index = u32; + type Signature = sp_runtime::MultiSignature; + + fn max_extrinsic_size() -> u32 { + BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl ChainWithGrandpa for BridgedUnderlyingChain { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; + const MAX_AUTHORITIES_COUNT: u32 = 16; + const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + const MAX_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; +} + +impl Chain for BridgedUnderlyingParachain { + type BlockNumber = BridgedChainBlockNumber; + type Hash = BridgedChainHash; + type Hasher = BridgedChainHasher; + type Header = BridgedChainHeader; + type AccountId = BridgedChainAccountId; + type Balance = BridgedChainBalance; + type Index = u32; + type Signature = sp_runtime::MultiSignature; + + fn max_extrinsic_size() -> u32 { + BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl Parachain for BridgedUnderlyingParachain { + const PARACHAIN_ID: u32 = 42; +} + +/// The other, bridged chain, used in tests. +pub struct BridgedChain; + +impl UnderlyingChainProvider for BridgedChain { + type Chain = BridgedUnderlyingChain; +} + +impl ThisChainWithMessages for BridgedChain { + type RuntimeOrigin = BridgedChainOrigin; +} + +impl BridgedChainWithMessages for BridgedChain {} diff --git a/bin/runtime-common/src/parachains_benchmarking.rs b/bin/runtime-common/src/parachains_benchmarking.rs new file mode 100644 index 00000000000..aad53673c3a --- /dev/null +++ b/bin/runtime-common/src/parachains_benchmarking.rs @@ -0,0 +1,88 @@ +// Copyright 2019-2021 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 . + +//! Everything required to run benchmarks of parachains finality module. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::{ + messages_benchmarking::insert_header_to_grandpa_pallet, + messages_generation::grow_trie_leaf_value, +}; + +use bp_parachains::parachain_head_storage_key_at_source; +use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; +use bp_runtime::{record_all_trie_keys, StorageProofSize}; +use codec::Encode; +use frame_support::traits::Get; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use sp_std::prelude::*; +use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; + +/// Prepare proof of messages for the `receive_messages_proof` call. +/// +/// In addition to returning valid messages proof, environment is prepared to verify this message +/// proof. +pub fn prepare_parachain_heads_proof( + parachains: &[ParaId], + parachain_head_size: u32, + size: StorageProofSize, +) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) +where + R: pallet_bridge_parachains::Config + + pallet_bridge_grandpa::Config, + PI: 'static, + >::BridgedChain: + bp_runtime::Chain, +{ + let parachain_head = ParaHead(vec![0u8; parachain_head_size as usize]); + + // insert all heads to the trie + let mut parachain_heads = Vec::with_capacity(parachains.len()); + let mut storage_keys = Vec::with_capacity(parachains.len()); + let mut state_root = Default::default(); + let mut mdb = MemoryDB::default(); + { + let mut trie = + TrieDBMutBuilderV1::::new(&mut mdb, &mut state_root).build(); + + // insert parachain heads + for (i, parachain) in parachains.into_iter().enumerate() { + let storage_key = + parachain_head_storage_key_at_source(R::ParasPalletName::get(), *parachain); + let leaf_data = if i == 0 { + grow_trie_leaf_value(parachain_head.encode(), size) + } else { + parachain_head.encode() + }; + trie.insert(&storage_key.0, &leaf_data) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + storage_keys.push(storage_key); + parachain_heads.push((*parachain, parachain_head.hash())) + } + } + + // generate heads storage proof + let proof = record_all_trie_keys::, _>(&mdb, &state_root) + .map_err(|_| "record_all_trie_keys has failed") + .expect("record_all_trie_keys should not fail in benchmarks"); + + let (relay_block_number, relay_block_hash) = + insert_header_to_grandpa_pallet::(state_root); + + (relay_block_number, relay_block_hash, ParaHeadsProof(proof), parachain_heads) +} diff --git a/bin/runtime-common/src/priority_calculator.rs b/bin/runtime-common/src/priority_calculator.rs new file mode 100644 index 00000000000..590de05fb1c --- /dev/null +++ b/bin/runtime-common/src/priority_calculator.rs @@ -0,0 +1,201 @@ +// Copyright 2021 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 . + +//! Bridge transaction priority calculator. +//! +//! We want to prioritize message delivery transactions with more messages over +//! transactions with less messages. That's because we reject delivery transactions +//! if it contains already delivered message. And if some transaction delivers +//! single message with nonce `N`, then the transaction with nonces `N..=N+100` will +//! be rejected. This can lower bridge throughput down to one message per block. + +use bp_messages::MessageNonce; +use frame_support::traits::Get; +use sp_runtime::transaction_validity::TransactionPriority; + +// reexport everything from `integrity_tests` module +pub use integrity_tests::*; + +/// Compute priority boost for message delivery transaction that delivers +/// given number of messages. +pub fn compute_priority_boost( + messages: MessageNonce, +) -> TransactionPriority +where + PriorityBoostPerMessage: Get, +{ + // we don't want any boost for transaction with single message => minus one + PriorityBoostPerMessage::get().saturating_mul(messages - 1) +} + +#[cfg(not(feature = "integrity-test"))] +mod integrity_tests {} + +#[cfg(feature = "integrity-test")] +mod integrity_tests { + use super::compute_priority_boost; + + use bp_messages::MessageNonce; + use bp_runtime::PreComputedSize; + use frame_support::{ + dispatch::{DispatchClass, DispatchInfo, Dispatchable, Pays, PostDispatchInfo}, + traits::Get, + }; + use pallet_bridge_messages::WeightInfoExt; + use pallet_transaction_payment::OnChargeTransaction; + use sp_runtime::{ + traits::{UniqueSaturatedInto, Zero}, + transaction_validity::TransactionPriority, + FixedPointOperand, SaturatedConversion, Saturating, + }; + + type BalanceOf = + <::OnChargeTransaction as OnChargeTransaction< + T, + >>::Balance; + + /// Ensures that the value of `PriorityBoostPerMessage` matches the value of + /// `tip_boost_per_message`. + /// + /// We want two transactions, `TX1` with `N` messages and `TX2` with `N+1` messages, have almost + /// the same priority if we'll add `tip_boost_per_message` tip to the `TX1`. We want to be sure + /// that if we add plain `PriorityBoostPerMessage` priority to `TX1`, the priority will be close + /// to `TX2` as well. + pub fn ensure_priority_boost_is_sane( + tip_boost_per_message: BalanceOf, + ) where + Runtime: + pallet_transaction_payment::Config + pallet_bridge_messages::Config, + MessagesInstance: 'static, + PriorityBoostPerMessage: Get, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + let priority_boost_per_message = PriorityBoostPerMessage::get(); + let maximal_messages_in_delivery_transaction = + Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); + for messages in 1..=maximal_messages_in_delivery_transaction { + let base_priority = estimate_message_delivery_transaction_priority::< + Runtime, + MessagesInstance, + >(messages, Zero::zero()); + let priority_boost = compute_priority_boost::(messages); + let priority_with_boost = base_priority + priority_boost; + + let tip = tip_boost_per_message.saturating_mul((messages - 1).unique_saturated_into()); + let priority_with_tip = + estimate_message_delivery_transaction_priority::(1, tip); + + const ERROR_MARGIN: TransactionPriority = 5; // 5% + if priority_with_boost.abs_diff(priority_with_tip).saturating_mul(100) / + priority_with_tip > + ERROR_MARGIN + { + panic!( + "The PriorityBoostPerMessage value ({}) must be fixed to: {}", + priority_boost_per_message, + compute_priority_boost_per_message::( + tip_boost_per_message + ), + ); + } + } + } + + /// Compute priority boost that we give to message delivery transaction for additional message. + #[cfg(feature = "integrity-test")] + fn compute_priority_boost_per_message( + tip_boost_per_message: BalanceOf, + ) -> TransactionPriority + where + Runtime: + pallet_transaction_payment::Config + pallet_bridge_messages::Config, + MessagesInstance: 'static, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // esimate priority of transaction that delivers one message and has large tip + let maximal_messages_in_delivery_transaction = + Runtime::MaxUnconfirmedMessagesAtInboundLane::get(); + let small_with_tip_priority = + estimate_message_delivery_transaction_priority::( + 1, + tip_boost_per_message + .saturating_mul(maximal_messages_in_delivery_transaction.saturated_into()), + ); + // estimate priority of transaction that delivers maximal number of messages, but has no tip + let large_without_tip_priority = estimate_message_delivery_transaction_priority::< + Runtime, + MessagesInstance, + >(maximal_messages_in_delivery_transaction, Zero::zero()); + + small_with_tip_priority + .saturating_sub(large_without_tip_priority) + .saturating_div(maximal_messages_in_delivery_transaction - 1) + } + + /// Estimate message delivery transaction priority. + #[cfg(feature = "integrity-test")] + fn estimate_message_delivery_transaction_priority( + messages: MessageNonce, + tip: BalanceOf, + ) -> TransactionPriority + where + Runtime: + pallet_transaction_payment::Config + pallet_bridge_messages::Config, + MessagesInstance: 'static, + Runtime::RuntimeCall: Dispatchable, + BalanceOf: Send + Sync + FixedPointOperand, + { + // just an estimation of extra transaction bytes that are added to every transaction + // (including signature, signed extensions extra and etc + in our case it includes + // all call arguments extept the proof itself) + let base_tx_size = 512; + // let's say we are relaying similar small messages and for every message we add more trie + // nodes to the proof (x0.5 because we expect some nodes to be reused) + let estimated_message_size = 512; + // let's say all our messages have the same dispatch weight + let estimated_message_dispatch_weight = + Runtime::WeightInfo::message_dispatch_weight(estimated_message_size); + // messages proof argument size is (for every message) messages size + some additional + // trie nodes. Some of them are reused by different messages, so let's take 2/3 of default + // "overhead" constant + let messages_proof_size = Runtime::WeightInfo::expected_extra_storage_proof_size() + .saturating_mul(2) + .saturating_div(3) + .saturating_add(estimated_message_size) + .saturating_mul(messages as _); + + // finally we are able to estimate transaction size and weight + let transaction_size = base_tx_size.saturating_add(messages_proof_size); + let transaction_weight = Runtime::WeightInfo::receive_messages_proof_weight( + &PreComputedSize(transaction_size as _), + messages as _, + estimated_message_dispatch_weight.saturating_mul(messages), + ); + + pallet_transaction_payment::ChargeTransactionPayment::::get_priority( + &DispatchInfo { + weight: transaction_weight, + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }, + transaction_size as _, + tip, + Zero::zero(), + ) + } +} diff --git a/bin/runtime-common/src/refund_relayer_extension.rs b/bin/runtime-common/src/refund_relayer_extension.rs new file mode 100644 index 00000000000..925fea2a743 --- /dev/null +++ b/bin/runtime-common/src/refund_relayer_extension.rs @@ -0,0 +1,1349 @@ +// Copyright 2021 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 . + +//! Signed extension that refunds relayer if he has delivered some new messages. +//! It also refunds transaction cost if the transaction is an `utility.batchAll()` +//! with calls that are: delivering new messsage and all necessary underlying headers +//! (parachain or relay chain). + +use crate::messages_call_ext::{ + CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, +}; +use bp_messages::LaneId; +use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; +use bp_runtime::{RangeInclusiveExt, StaticStrProvider}; +use codec::{Decode, Encode}; +use frame_support::{ + dispatch::{CallableCallFor, DispatchInfo, Dispatchable, PostDispatchInfo}, + traits::IsSubType, + weights::Weight, + CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, +}; +use pallet_bridge_grandpa::{ + CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, SubmitFinalityProofInfo, +}; +use pallet_bridge_messages::Config as MessagesConfig; +use pallet_bridge_parachains::{ + BoundedBridgeGrandpaConfig, CallSubType as ParachainsCallSubType, Config as ParachainsConfig, + RelayBlockNumber, SubmitParachainHeadsHelper, SubmitParachainHeadsInfo, +}; +use pallet_bridge_relayers::{Config as RelayersConfig, Pallet as RelayersPallet}; +use pallet_transaction_payment::{Config as TransactionPaymentConfig, OnChargeTransaction}; +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}, + transaction_validity::{ + TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, + }, + DispatchResult, FixedPointOperand, +}; +use sp_std::{marker::PhantomData, vec, vec::Vec}; + +// without this typedef rustfmt fails with internal err +type BalanceOf = + <::OnChargeTransaction as OnChargeTransaction>::Balance; +type CallOf = ::RuntimeCall; + +/// Trait identifying a bridged parachain. A relayer might be refunded for delivering messages +/// coming from this parachain. +pub trait RefundableParachainId { + /// The instance of the bridge parachains pallet. + type Instance; + /// The parachain Id. + type Id: Get; +} + +/// Default implementation of `RefundableParachainId`. +pub struct RefundableParachain(PhantomData<(Instance, Id)>); + +impl RefundableParachainId for RefundableParachain +where + Id: Get, +{ + type Instance = Instance; + type Id = Id; +} + +/// Trait identifying a bridged messages lane. A relayer might be refunded for delivering messages +/// coming from this lane. +pub trait RefundableMessagesLaneId { + /// The instance of the bridge messages pallet. + type Instance; + /// The messages lane id. + type Id: Get; +} + +/// Default implementation of `RefundableMessagesLaneId`. +pub struct RefundableMessagesLane(PhantomData<(Instance, Id)>); + +impl RefundableMessagesLaneId for RefundableMessagesLane +where + Id: Get, +{ + type Instance = Instance; + type Id = Id; +} + +/// Refund calculator. +pub trait RefundCalculator { + // The underlying integer type in which the refund is calculated. + type Balance; + + /// Compute refund for given transaction. + fn compute_refund( + info: &DispatchInfo, + post_info: &PostDispatchInfo, + len: usize, + tip: Self::Balance, + ) -> Self::Balance; +} + +/// `RefundCalculator` implementation which refunds the actual transaction fee. +pub struct ActualFeeRefund(PhantomData); + +impl RefundCalculator for ActualFeeRefund +where + R: TransactionPaymentConfig, + CallOf: Dispatchable, + BalanceOf: FixedPointOperand, +{ + type Balance = BalanceOf; + + fn compute_refund( + info: &DispatchInfo, + post_info: &PostDispatchInfo, + len: usize, + tip: BalanceOf, + ) -> BalanceOf { + pallet_transaction_payment::Pallet::::compute_actual_fee(len as _, info, post_info, tip) + } +} + +/// Data that is crafted in `pre_dispatch` method and used at `post_dispatch`. +#[cfg_attr(test, derive(Debug, PartialEq))] +pub struct PreDispatchData { + /// Transaction submitter (relayer) account. + relayer: AccountId, + /// Type of the call. + call_info: CallInfo, +} + +/// Type of the call that the extension recognizes. +#[derive(RuntimeDebugNoBound, PartialEq)] +pub enum CallInfo { + /// Relay chain finality + parachain finality + message delivery/confirmation calls. + AllFinalityAndMsgs( + SubmitFinalityProofInfo, + SubmitParachainHeadsInfo, + MessagesCallInfo, + ), + /// Parachain finality + message delivery/confirmation calls. + ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), + /// Standalone message delivery/confirmation call. + Msgs(MessagesCallInfo), +} + +impl CallInfo { + /// Returns the pre-dispatch `finality_target` sent to the `SubmitFinalityProof` call. + fn submit_finality_proof_info(&self) -> Option> { + match *self { + Self::AllFinalityAndMsgs(info, _, _) => Some(info), + _ => None, + } + } + + /// Returns the pre-dispatch `SubmitParachainHeadsInfo`. + fn submit_parachain_heads_info(&self) -> Option<&SubmitParachainHeadsInfo> { + match self { + Self::AllFinalityAndMsgs(_, info, _) => Some(info), + Self::ParachainFinalityAndMsgs(info, _) => Some(info), + _ => None, + } + } + + /// Returns the pre-dispatch `ReceiveMessagesProofInfo`. + fn messages_call_info(&self) -> &MessagesCallInfo { + match self { + Self::AllFinalityAndMsgs(_, _, info) => info, + Self::ParachainFinalityAndMsgs(_, info) => info, + Self::Msgs(info) => info, + } + } +} + +/// 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, Para, Msgs, Refund, Priority, Id)>, +); + +impl + RefundBridgedParachainMessages +where + Self: 'static + Send + Sync, + Runtime: UtilityConfig> + + BoundedBridgeGrandpaConfig + + ParachainsConfig + + MessagesConfig, + Para: RefundableParachainId, + Msgs: RefundableMessagesLaneId, + CallOf: Dispatchable + + IsSubType, Runtime>> + + GrandpaCallSubType + + ParachainsCallSubType + + MessagesCallSubType, +{ + 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], + } + } + + fn parse_and_check_for_obsolete_call( + &self, + call: &CallOf, + ) -> Result, TransactionValidityError> { + let calls = self.expand_call(call); + let total_calls = calls.len(); + let mut calls = calls.into_iter().map(Self::check_obsolete_call).rev(); + + let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); + let para_finality_call = calls + .next() + .transpose()? + .and_then(|c| c.submit_parachain_heads_info_for(Para::Id::get())); + let relay_finality_call = + calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + + 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) + } +} + +impl SignedExtension + 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, +{ + const IDENTIFIER: &'static str = Id::STR; + type AccountId = Runtime::AccountId; + type Call = CallOf; + type AdditionalSigned = (); + type Pre = Option>; + + fn additional_signed(&self) -> Result<(), TransactionValidityError> { + Ok(()) + } + + fn validate( + &self, + _who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> TransactionValidity { + // this is the only relevant line of code for the `pre_dispatch` + // + // we're not calling `validato` 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)?; + + // the following code just plays with transaction priority and never returns an error + let mut valid_transaction = ValidTransactionBuilder::default(); + if let Some(parsed_call) = parsed_call { + // we give delivery transactions some boost, that depends on number of messages inside + let messages_call_info = parsed_call.messages_call_info(); + if let MessagesCallInfo::ReceiveMessagesProof(info) = messages_call_info { + // compute total number of messages in transaction + let bundled_messages = info.base.bundled_range.checked_len().unwrap_or(0); + + // a quick check to avoid invalid high-priority transactions + if bundled_messages <= Runtime::MaxUnconfirmedMessagesAtInboundLane::get() { + let priority_boost = crate::priority_calculator::compute_priority_boost::< + Priority, + >(bundled_messages); + valid_transaction = valid_transaction.priority(priority_boost); + } + } + } + + valid_transaction.build() + } + + fn pre_dispatch( + self, + who: &Self::AccountId, + call: &Self::Call, + _info: &DispatchInfoOf, + _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)?; + + Ok(parsed_call.map(|call_info| { + log::trace!( + target: "runtime::bridge", + "{} from parachain {} via {:?} parsed bridge transaction in pre-dispatch: {:?}", + Self::IDENTIFIER, + Para::Id::get(), + Msgs::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 mut extra_weight = Weight::zero(); + let mut extra_size = 0; + + // We don't refund anything if the transaction has failed. + if result.is_err() { + return Ok(()) + } + + // We don't refund anything for transactions that we don't support. + let (relayer, call_info) = match pre { + Some(Some(pre)) => (pre.relayer, pre.call_info), + _ => return Ok(()), + }; + + // check if relay chain state has been updated + if let Some(finality_proof_info) = call_info.submit_finality_proof_info() { + if !SubmitFinalityProofHelper::::was_successful( + finality_proof_info.block_number, + ) { + // we only refund relayer if all calls have updated chain state + log::trace!( + target: "runtime::bridge", + "{} from parachain {} via {:?}: failed to refund relayer {:?}, because \ + relay chain finality proof has not been accepted", + Self::IDENTIFIER, + Para::Id::get(), + Msgs::Id::get(), + relayer, + ); + + return Ok(()) + } + + // there's a conflict between how bridge GRANDPA pallet works and a `utility.batchAll` + // transaction. If relay chain header is mandatory, the GRANDPA pallet returns + // `Pays::No`, because such transaction is mandatory for operating the bridge. But + // `utility.batchAll` transaction always requires payment. But in both cases we'll + // refund relayer - either explicitly here, or using `Pays::No` if he's choosing + // to submit dedicated transaction. + + // submitter has means to include extra weight/bytes in the `submit_finality_proof` + // call, so let's subtract extra weight/size to avoid refunding for this extra stuff + extra_weight = finality_proof_info.extra_weight; + extra_size = finality_proof_info.extra_size; + } + + // check if 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 {:?}: failed to refund relayer {:?}, because \ + parachain finality proof has not been accepted", + Self::IDENTIFIER, + Para::Id::get(), + Msgs::Id::get(), + relayer, + ); + + return Ok(()) + } + } + + // Check if the `ReceiveMessagesProof` call delivered all 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) { + log::trace!( + target: "runtime::bridge", + "{} from parachain {} via {:?}: failed to refund relayer {:?}, because \ + some of messages have not been accepted", + Self::IDENTIFIER, + Para::Id::get(), + Msgs::Id::get(), + relayer, + ); + + return Ok(()) + } + + // 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 + // malicious relayer may use huge tips, effectively depleting account that pay rewards. The + // cost of this attack is nothing. Hence we use zero as tip here. + let tip = Zero::zero(); + + // decrease post-dispatch weight/size using extra weight/size that we know now + let post_info_len = len.saturating_sub(extra_size as usize); + let mut post_info = *post_info; + post_info.actual_weight = + Some(post_info.actual_weight.unwrap_or(info.weight).saturating_sub(extra_weight)); + + // compute the relayer refund + let refund = Refund::compute_refund(info, &post_info, post_info_len, tip); + + // finally - register refund in relayers pallet + let rewards_account_owner = match msgs_call_info { + MessagesCallInfo::ReceiveMessagesProof(_) => RewardsAccountOwner::ThisChain, + MessagesCallInfo::ReceiveMessagesDeliveryProof(_) => RewardsAccountOwner::BridgedChain, + }; + RelayersPallet::::register_relayer_reward( + RewardsAccountParams::new( + Msgs::Id::get(), + Runtime::BridgedChainId::get(), + rewards_account_owner, + ), + &relayer, + refund, + ); + + log::trace!( + target: "runtime::bridge", + "{} from parachain {} via {:?} has registered reward: {:?} for {:?}", + Self::IDENTIFIER, + Para::Id::get(), + Msgs::Id::get(), + refund, + relayer, + ); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, + }, + messages_call_ext::{ + BaseMessagesProofInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, + UnrewardedRelayerOccupation, + }, + mock::*, + }; + use bp_messages::{InboundLaneData, MessageNonce, OutboundLaneData, UnrewardedRelayersState}; + use bp_parachains::{BestParaHeadHash, ParaInfo}; + use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; + use bp_runtime::HeaderId; + use bp_test_utils::{make_default_justification, test_keyring}; + use frame_support::{assert_storage_noop, parameter_types, 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 sp_runtime::{ + traits::{ConstU64, Header as HeaderT}, + transaction_validity::{InvalidTransaction, ValidTransaction}, + DispatchError, + }; + + parameter_types! { + TestParachain: u32 = 1000; + pub TestLaneId: LaneId = TEST_LANE_ID; + pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + TEST_LANE_ID, + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::ThisChain, + ); + pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + TEST_LANE_ID, + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::BridgedChain, + ); + } + + bp_runtime::generate_static_str_provider!(TestExtension); + type TestExtension = RefundBridgedParachainMessages< + TestRuntime, + RefundableParachain<(), TestParachain>, + RefundableMessagesLane<(), TestLaneId>, + ActualFeeRefund, + ConstU64<1>, + StrTestExtension, + >; + + fn relayer_account_at_this_chain() -> ThisChainAccountId { + 0 + } + + fn relayer_account_at_bridged_chain() -> BridgedChainAccountId { + 0 + } + + fn initialize_environment( + best_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_hash: ParaHash, + best_message: MessageNonce, + ) { + let authorities = test_keyring().into_iter().map(|(a, w)| (a.into(), w)).collect(); + let best_relay_header = HeaderId(best_relay_header_number, RelayBlockHash::default()); + pallet_bridge_grandpa::CurrentAuthoritySet::::put( + StoredAuthoritySet::try_new(authorities, 0).unwrap(), + ); + pallet_bridge_grandpa::BestFinalized::::put(best_relay_header); + + let para_id = ParaId(TestParachain::get()); + let para_info = ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: parachain_head_at_relay_header_number, + head_hash: parachain_head_hash, + }, + next_imported_hash_position: 0, + }; + pallet_bridge_parachains::ParasInfo::::insert(para_id, para_info); + + let lane_id = TestLaneId::get(); + let in_lane_data = + InboundLaneData { last_confirmed_nonce: best_message, ..Default::default() }; + pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); + + let out_lane_data = + OutboundLaneData { latest_received_nonce: best_message, ..Default::default() }; + pallet_bridge_messages::OutboundLanes::::insert(lane_id, out_lane_data); + } + + fn submit_relay_header_call(relay_header_number: RelayBlockNumber) -> RuntimeCall { + let relay_header = BridgedChainHeader::new( + relay_header_number, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ); + let relay_justification = make_default_justification(&relay_header); + + RuntimeCall::BridgeGrandpa(GrandpaCall::submit_finality_proof { + finality_target: Box::new(relay_header), + justification: relay_justification, + }) + } + + fn submit_parachain_head_call( + parachain_head_at_relay_header_number: RelayBlockNumber, + ) -> RuntimeCall { + RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { + at_relay_block: (parachain_head_at_relay_header_number, RelayBlockHash::default()), + parachains: vec![(ParaId(TestParachain::get()), [1u8; 32].into())], + parachain_heads_proof: ParaHeadsProof(vec![]), + }) + } + + fn message_delivery_call(best_message: MessageNonce) -> RuntimeCall { + RuntimeCall::BridgeMessages(MessagesCall::receive_messages_proof { + relayer_id_at_bridged_chain: relayer_account_at_bridged_chain(), + proof: FromBridgedChainMessagesProof { + bridged_header_hash: Default::default(), + storage_proof: vec![], + lane: TestLaneId::get(), + nonces_start: pallet_bridge_messages::InboundLanes::::get( + TEST_LANE_ID, + ) + .last_delivered_nonce() + + 1, + nonces_end: best_message, + }, + messages_count: 1, + dispatch_weight: Weight::zero(), + }) + } + + fn message_confirmation_call(best_message: MessageNonce) -> RuntimeCall { + RuntimeCall::BridgeMessages(MessagesCall::receive_messages_delivery_proof { + proof: FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: Default::default(), + storage_proof: vec![], + lane: TestLaneId::get(), + }, + relayers_state: UnrewardedRelayersState { + last_delivered_nonce: best_message, + ..Default::default() + }, + }) + } + + fn parachain_finality_and_delivery_batch_call( + parachain_head_at_relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_parachain_head_call(parachain_head_at_relay_header_number), + message_delivery_call(best_message), + ], + }) + } + + fn parachain_finality_and_confirmation_batch_call( + parachain_head_at_relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_parachain_head_call(parachain_head_at_relay_header_number), + message_confirmation_call(best_message), + ], + }) + } + + fn all_finality_and_delivery_batch_call( + relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_relay_header_call(relay_header_number), + submit_parachain_head_call(parachain_head_at_relay_header_number), + message_delivery_call(best_message), + ], + }) + } + + fn all_finality_and_confirmation_batch_call( + relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: RelayBlockNumber, + best_message: MessageNonce, + ) -> RuntimeCall { + RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + submit_relay_header_call(relay_header_number), + submit_parachain_head_call(parachain_head_at_relay_header_number), + message_confirmation_call(best_message), + ], + }) + } + + fn all_finality_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::AllFinalityAndMsgs( + SubmitFinalityProofInfo { + block_number: 200, + extra_weight: Weight::zero(), + extra_size: 0, + }, + SubmitParachainHeadsInfo { + at_relay_block_number: 200, + para_id: ParaId(TestParachain::get()), + para_head_hash: [1u8; 32].into(), + }, + 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 all_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::AllFinalityAndMsgs( + SubmitFinalityProofInfo { + block_number: 200, + extra_weight: Weight::zero(), + extra_size: 0, + }, + SubmitParachainHeadsInfo { + at_relay_block_number: 200, + para_id: ParaId(TestParachain::get()), + para_head_hash: [1u8; 32].into(), + }, + 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(), + call_info: CallInfo::ParachainFinalityAndMsgs( + SubmitParachainHeadsInfo { + at_relay_block_number: 200, + para_id: ParaId(TestParachain::get()), + para_head_hash: [1u8; 32].into(), + }, + 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 parachain_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::ParachainFinalityAndMsgs( + SubmitParachainHeadsInfo { + at_relay_block_number: 200, + para_id: ParaId(TestParachain::get()), + para_head_hash: [1u8; 32].into(), + }, + MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( + BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + bundled_range: 101..=200, + best_stored_nonce: 100, + }, + )), + ), + } + } + + fn delivery_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::Msgs(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 confirmation_pre_dispatch_data() -> PreDispatchData { + PreDispatchData { + relayer: relayer_account_at_this_chain(), + call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( + ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { + lane_id: TEST_LANE_ID, + bundled_range: 101..=200, + best_stored_nonce: 100, + }), + )), + } + } + + fn run_test(test: impl FnOnce()) { + sp_io::TestExternalities::new(Default::default()).execute_with(test) + } + + fn run_validate(call: RuntimeCall) -> TransactionValidity { + let extension: TestExtension = RefundBridgedParachainMessages(PhantomData); + extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + } + + fn run_pre_dispatch( + call: RuntimeCall, + ) -> Result>, TransactionValidityError> { + let extension: TestExtension = RefundBridgedParachainMessages(PhantomData); + extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + } + + fn dispatch_info() -> DispatchInfo { + DispatchInfo { + weight: Weight::from_parts( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, + 0, + ), + class: frame_support::dispatch::DispatchClass::Normal, + pays_fee: frame_support::dispatch::Pays::Yes, + } + } + + fn post_dispatch_info() -> PostDispatchInfo { + PostDispatchInfo { actual_weight: None, pays_fee: frame_support::dispatch::Pays::Yes } + } + + fn run_post_dispatch( + pre_dispatch_data: Option>, + dispatch_result: DispatchResult, + ) { + let post_dispatch_result = TestExtension::post_dispatch( + Some(pre_dispatch_data), + &dispatch_info(), + &post_dispatch_info(), + 1024, + &dispatch_result, + ); + assert_eq!(post_dispatch_result, Ok(())); + } + + fn expected_reward() -> ThisChainBalance { + pallet_transaction_payment::Pallet::::compute_actual_fee( + 1024, + &dispatch_info(), + &post_dispatch_info(), + Zero::zero(), + ) + } + + #[test] + fn validate_boosts_priority_of_message_delivery_transactons() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + let priority_of_100_messages_delivery = + run_validate(message_delivery_call(200)).unwrap().priority; + let priority_of_200_messages_delivery = + run_validate(message_delivery_call(300)).unwrap().priority; + assert!( + priority_of_200_messages_delivery > priority_of_100_messages_delivery, + "Invalid priorities: {} for 200 messages vs {} for 100 messages", + priority_of_200_messages_delivery, + priority_of_100_messages_delivery, + ); + + let priority_of_100_messages_confirmation = + run_validate(message_confirmation_call(200)).unwrap().priority; + let priority_of_200_messages_confirmation = + run_validate(message_confirmation_call(300)).unwrap().priority; + assert_eq!( + priority_of_100_messages_confirmation, + priority_of_200_messages_confirmation + ); + }); + } + + #[test] + fn validate_does_not_boost_priority_of_message_delivery_transactons_with_too_many_messages() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + let priority_of_max_messages_delivery = run_validate(message_delivery_call( + 100 + MaxUnconfirmedMessagesAtInboundLane::get(), + )) + .unwrap() + .priority; + let priority_of_more_than_max_messages_delivery = run_validate(message_delivery_call( + 100 + MaxUnconfirmedMessagesAtInboundLane::get() + 1, + )) + .unwrap() + .priority; + + assert!( + priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, + "Invalid priorities: {} for MAX messages vs {} for MAX+1 messages", + priority_of_max_messages_delivery, + priority_of_more_than_max_messages_delivery, + ); + }); + } + + #[test] + fn validate_allows_non_obsolete_transactions() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + fn run_validate_ignore_priority(call: RuntimeCall) -> TransactionValidity { + run_validate(call).map(|mut tx| { + tx.priority = 0; + tx + }) + } + + assert_eq!( + run_validate_ignore_priority(message_delivery_call(200)), + Ok(ValidTransaction::default()), + ); + assert_eq!( + run_validate_ignore_priority(message_confirmation_call(200)), + Ok(ValidTransaction::default()), + ); + + assert_eq!( + run_validate_ignore_priority(parachain_finality_and_delivery_batch_call(200, 200)), + Ok(ValidTransaction::default()), + ); + assert_eq!( + run_validate_ignore_priority(parachain_finality_and_confirmation_batch_call( + 200, 200 + )), + Ok(ValidTransaction::default()), + ); + + assert_eq!( + run_validate_ignore_priority(all_finality_and_delivery_batch_call(200, 200, 200)), + Ok(ValidTransaction::default()), + ); + assert_eq!( + run_validate_ignore_priority(all_finality_and_confirmation_batch_call( + 200, 200, 200 + )), + Ok(ValidTransaction::default()), + ); + }); + } + + #[test] + fn ext_rejects_batch_with_obsolete_relay_chain_header() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + assert_eq!( + run_pre_dispatch(all_finality_and_delivery_batch_call(100, 200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_validate(all_finality_and_delivery_batch_call(100, 200, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + }); + } + + #[test] + fn ext_rejects_batch_with_obsolete_parachain_head() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + assert_eq!( + run_pre_dispatch(all_finality_and_delivery_batch_call(101, 100, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_validate(all_finality_and_delivery_batch_call(101, 100, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_pre_dispatch(parachain_finality_and_delivery_batch_call(100, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_validate(parachain_finality_and_delivery_batch_call(100, 200)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + }); + } + + #[test] + fn ext_rejects_batch_with_obsolete_messages() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + assert_eq!( + run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_validate(all_finality_and_delivery_batch_call(200, 200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_validate(all_finality_and_confirmation_batch_call(200, 200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_validate(parachain_finality_and_delivery_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_validate(parachain_finality_and_confirmation_batch_call(200, 100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + }); + } + + #[test] + fn pre_dispatch_parses_batch_with_relay_chain_and_parachain_headers() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + assert_eq!( + run_pre_dispatch(all_finality_and_delivery_batch_call(200, 200, 200)), + Ok(Some(all_finality_pre_dispatch_data())), + ); + assert_eq!( + run_pre_dispatch(all_finality_and_confirmation_batch_call(200, 200, 200)), + Ok(Some(all_finality_confirmation_pre_dispatch_data())), + ); + }); + } + + #[test] + fn pre_dispatch_parses_batch_with_parachain_header() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + assert_eq!( + run_pre_dispatch(parachain_finality_and_delivery_batch_call(200, 200)), + Ok(Some(parachain_finality_pre_dispatch_data())), + ); + assert_eq!( + run_pre_dispatch(parachain_finality_and_confirmation_batch_call(200, 200)), + Ok(Some(parachain_finality_confirmation_pre_dispatch_data())), + ); + }); + } + + #[test] + fn pre_dispatch_fails_to_parse_batch_with_multiple_parachain_headers() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + let call = RuntimeCall::Utility(UtilityCall::batch_all { + calls: vec![ + RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { + at_relay_block: (100, RelayBlockHash::default()), + parachains: vec![ + (ParaId(TestParachain::get()), [1u8; 32].into()), + (ParaId(TestParachain::get() + 1), [1u8; 32].into()), + ], + parachain_heads_proof: ParaHeadsProof(vec![]), + }), + message_delivery_call(200), + ], + }); + + assert_eq!(run_pre_dispatch(call), Ok(None),); + }); + } + + #[test] + fn pre_dispatch_parses_message_transaction() { + run_test(|| { + initialize_environment(100, 100, Default::default(), 100); + + assert_eq!( + run_pre_dispatch(message_delivery_call(200)), + Ok(Some(delivery_pre_dispatch_data())), + ); + assert_eq!( + run_pre_dispatch(message_confirmation_call(200)), + Ok(Some(confirmation_pre_dispatch_data())), + ); + }); + } + + #[test] + fn post_dispatch_ignores_unknown_transaction() { + run_test(|| { + assert_storage_noop!(run_post_dispatch(None, Ok(()))); + }); + } + + #[test] + fn post_dispatch_ignores_failed_transaction() { + run_test(|| { + assert_storage_noop!(run_post_dispatch( + Some(all_finality_pre_dispatch_data()), + Err(DispatchError::BadOrigin) + )); + }); + } + + #[test] + fn post_dispatch_ignores_transaction_that_has_not_updated_relay_chain_state() { + run_test(|| { + initialize_environment(100, 200, Default::default(), 200); + + assert_storage_noop!(run_post_dispatch(Some(all_finality_pre_dispatch_data()), Ok(()))); + }); + } + + #[test] + fn post_dispatch_ignores_transaction_that_has_not_updated_parachain_state() { + run_test(|| { + initialize_environment(200, 100, Default::default(), 200); + + assert_storage_noop!(run_post_dispatch(Some(all_finality_pre_dispatch_data()), Ok(()))); + assert_storage_noop!(run_post_dispatch( + Some(parachain_finality_pre_dispatch_data()), + Ok(()) + )); + }); + } + + #[test] + fn post_dispatch_ignores_transaction_that_has_not_delivered_any_messages() { + run_test(|| { + initialize_environment(200, 200, Default::default(), 100); + + assert_storage_noop!(run_post_dispatch(Some(all_finality_pre_dispatch_data()), Ok(()))); + assert_storage_noop!(run_post_dispatch( + Some(parachain_finality_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch(Some(delivery_pre_dispatch_data()), Ok(()))); + + assert_storage_noop!(run_post_dispatch( + Some(all_finality_confirmation_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch( + Some(parachain_finality_confirmation_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch(Some(confirmation_pre_dispatch_data()), Ok(()))); + }); + } + + #[test] + fn post_dispatch_ignores_transaction_that_has_not_delivered_all_messages() { + run_test(|| { + initialize_environment(200, 200, Default::default(), 150); + + assert_storage_noop!(run_post_dispatch(Some(all_finality_pre_dispatch_data()), Ok(()))); + assert_storage_noop!(run_post_dispatch( + Some(parachain_finality_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch(Some(delivery_pre_dispatch_data()), Ok(()))); + + assert_storage_noop!(run_post_dispatch( + Some(all_finality_confirmation_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch( + Some(parachain_finality_confirmation_pre_dispatch_data()), + Ok(()) + )); + assert_storage_noop!(run_post_dispatch(Some(confirmation_pre_dispatch_data()), Ok(()))); + }); + } + + #[test] + fn post_dispatch_refunds_relayer_in_all_finality_batch_with_extra_weight() { + run_test(|| { + initialize_environment(200, 200, [1u8; 32].into(), 200); + + let mut dispatch_info = dispatch_info(); + dispatch_info.weight = Weight::from_parts( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND * 2, + 0, + ); + + // without any size/weight refund: we expect regular reward + let pre_dispatch_data = all_finality_pre_dispatch_data(); + let regular_reward = expected_reward(); + run_post_dispatch(Some(pre_dispatch_data), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgProofsRewardsAccount::get() + ), + Some(regular_reward), + ); + + // now repeat the same with size+weight refund: we expect smaller reward + let mut pre_dispatch_data = all_finality_pre_dispatch_data(); + match pre_dispatch_data.call_info { + CallInfo::AllFinalityAndMsgs(ref mut info, ..) => { + info.extra_weight.set_ref_time( + frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, + ); + info.extra_size = 32; + }, + _ => unreachable!(), + } + run_post_dispatch(Some(pre_dispatch_data), Ok(())); + let reward_after_two_calls = RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgProofsRewardsAccount::get(), + ) + .unwrap(); + assert!( + reward_after_two_calls < 2 * regular_reward, + "{} must be < 2 * {}", + reward_after_two_calls, + 2 * regular_reward, + ); + }); + } + + #[test] + fn post_dispatch_refunds_relayer_in_all_finality_batch() { + run_test(|| { + initialize_environment(200, 200, [1u8; 32].into(), 200); + + run_post_dispatch(Some(all_finality_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + + run_post_dispatch(Some(all_finality_confirmation_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgDeliveryProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + }); + } + + #[test] + fn post_dispatch_refunds_relayer_in_parachain_finality_batch() { + run_test(|| { + initialize_environment(200, 200, [1u8; 32].into(), 200); + + run_post_dispatch(Some(parachain_finality_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + + run_post_dispatch(Some(parachain_finality_confirmation_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgDeliveryProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + }); + } + + #[test] + fn post_dispatch_refunds_relayer_in_message_transaction() { + run_test(|| { + initialize_environment(200, 200, Default::default(), 200); + + run_post_dispatch(Some(delivery_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + + run_post_dispatch(Some(confirmation_pre_dispatch_data()), Ok(())); + assert_eq!( + RelayersPallet::::relayer_reward( + relayer_account_at_this_chain(), + MsgDeliveryProofsRewardsAccount::get() + ), + Some(expected_reward()), + ); + }); + } +} diff --git a/ci.Dockerfile b/ci.Dockerfile new file mode 100644 index 00000000000..b419f6be54d --- /dev/null +++ b/ci.Dockerfile @@ -0,0 +1,53 @@ +# This file is a "runtime" part from a builder-pattern in Dockerfile, it's used in CI. +# The only different part is that the compilation happens externally, +# so COPY has a different source. +FROM docker.io/library/ubuntu:20.04 + +# show backtraces +ENV RUST_BACKTRACE 1 +ENV DEBIAN_FRONTEND=noninteractive + +RUN set -eux; \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + curl ca-certificates libssl-dev && \ + update-ca-certificates && \ + groupadd -g 1000 user && \ + useradd -u 1000 -g user -s /bin/sh -m user && \ + # apt clean up + apt-get autoremove -y && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# switch to non-root user +USER user + +WORKDIR /home/user + +ARG PROJECT=substrate-relay + +COPY --chown=user:user ./${PROJECT} ./ +COPY --chown=user:user ./bridge-entrypoint.sh ./ + +# check if executable works in this container +RUN ./${PROJECT} --version + +ENV PROJECT=$PROJECT +ENTRYPOINT ["/home/user/bridge-entrypoint.sh"] + +# metadata +ARG VCS_REF=master +ARG BUILD_DATE="" +ARG VERSION="" + +LABEL org.opencontainers.image.title="${PROJECT}" \ + org.opencontainers.image.description="${PROJECT} - component of Parity Bridges Common" \ + org.opencontainers.image.source="https://github.com/paritytech/parity-bridges-common/blob/${VCS_REF}/ci.Dockerfile" \ + org.opencontainers.image.url="https://github.com/paritytech/parity-bridges-common/blob/${VCS_REF}/ci.Dockerfile" \ + org.opencontainers.image.documentation="https://github.com/paritytech/parity-bridges-common/blob/${VCS_REF}/README.md" \ + org.opencontainers.image.created="${BUILD_DATE}" \ + org.opencontainers.image.version="${VERSION}" \ + org.opencontainers.image.revision="${VCS_REF}" \ + org.opencontainers.image.authors="devops-team@parity.io" \ + org.opencontainers.image.vendor="Parity Technologies" \ + org.opencontainers.image.licenses="GPL-3.0 License" diff --git a/deny.toml b/deny.toml new file mode 100644 index 00000000000..264a37bd989 --- /dev/null +++ b/deny.toml @@ -0,0 +1,202 @@ +# This template contains all of the possible sections and their default values + +# Note that all fields that take a lint level have these possible values: +# * deny - An error will be produced and the check will fail +# * warn - A warning will be produced, but the check will not fail +# * allow - No warning or error will be produced, though in some cases a note +# will be + +# The values provided in this template are the default values that will be used +# when any section or field is not specified in your own configuration + +# If 1 or more target triples (and optionally, target_features) are specified, +# only the specified targets will be checked when running `cargo deny check`. +# This means, if a particular package is only ever used as a target specific +# dependency, such as, for example, the `nix` crate only being used via the +# `target_family = "unix"` configuration, that only having windows targets in +# this list would mean the nix crate, as well as any of its exclusive +# dependencies not shared by any other crates, would be ignored, as the target +# list here is effectively saying which targets you are building for. +targets = [ + # The triple can be any string, but only the target triples built in to + # rustc (as of 1.40) can be checked against actual config expressions + #{ triple = "x86_64-unknown-linux-musl" }, + # You can also specify which target_features you promise are enabled for a + # particular target. target_features are currently not validated against + # the actual valid features supported by the target architecture. + #{ triple = "wasm32-unknown-unknown", features = ["atomics"] }, +] + +# This section is considered when running `cargo deny check advisories` +# More documentation for the advisories section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html +[advisories] +# The path where the advisory database is cloned/fetched into +db-path = "~/.cargo/advisory-db" +# The url of the advisory database to use +db-urls = ["https://github.com/rustsec/advisory-db"] +# The lint level for security vulnerabilities +vulnerability = "deny" +# The lint level for unmaintained crates +unmaintained = "warn" +# The lint level for crates that have been yanked from their source registry +yanked = "warn" +# The lint level for crates with security notices. Note that as of +# 2019-12-17 there are no security notice advisories in +# https://github.com/rustsec/advisory-db +notice = "warn" +# A list of advisory IDs to ignore. Note that ignored advisories will still +# output a note when they are encountered. +ignore = [ + # time (origin: Substrate RPC + benchmarking crates) + "RUSTSEC-2020-0071", + # ansi_term (The maintainer has adviced that this crate is deprecated and will not receive any maintenance. + # Once other crates will move to some alternative, we'll do that too) + "RUSTSEC-2021-0139", + # deprecated parity-wasm (origin: Substrate) + "RUSTSEC-2022-0061", + # atty (origin: Substrate, clap) + "RUSTSEC-2021-0145", + # wasmtime (origin: Substrate) + "RUSTSEC-2022-0076", +] +# Threshold for security vulnerabilities, any vulnerability with a CVSS score +# lower than the range specified will be ignored. Note that ignored advisories +# will still output a note when they are encountered. +# * None - CVSS Score 0.0 +# * Low - CVSS Score 0.1 - 3.9 +# * Medium - CVSS Score 4.0 - 6.9 +# * High - CVSS Score 7.0 - 8.9 +# * Critical - CVSS Score 9.0 - 10.0 +#severity-threshold = + +# This section is considered when running `cargo deny check licenses` +# More documentation for the licenses section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html +[licenses] +# The lint level for crates which do not have a detectable license +unlicensed = "allow" +# List of explictly allowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. +allow = [ + "BlueOak-1.0.0" +] +# List of explictly disallowed licenses +# See https://spdx.org/licenses/ for list of possible licenses +# [possible values: any SPDX 3.7 short identifier (+ optional exception)]. +deny = [ + #"Nokia", +] +# Lint level for licenses considered copyleft +copyleft = "allow" +# Blanket approval or denial for OSI-approved or FSF Free/Libre licenses +# * both - The license will be approved if it is both OSI-approved *AND* FSF +# * either - The license will be approved if it is either OSI-approved *OR* FSF +# * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF +# * fsf-only - The license will be approved if is FSF *AND NOT* OSI-approved +# * neither - This predicate is ignored and the default lint level is used +allow-osi-fsf-free = "either" +# Lint level used when no other predicates are matched +# 1. License isn't in the allow or deny lists +# 2. License isn't copyleft +# 3. License isn't OSI/FSF, or allow-osi-fsf-free = "neither" +default = "deny" +# The confidence threshold for detecting a license from license text. +# The higher the value, the more closely the license text must be to the +# canonical license text of a valid SPDX license file. +# [possible values: any between 0.0 and 1.0]. +confidence-threshold = 0.9 +# 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 = ["Zlib"], name = "adler32", version = "*" }, +] + +# Some crates don't have (easily) machine readable licensing information, +# adding a clarification entry for it allows you to manually specify the +# licensing information +[[licenses.clarify]] +# The name of the crate the clarification applies to +name = "ring" +# THe optional version constraint for the crate +#version = "*" +# The SPDX expression for the license requirements of the crate +expression = "OpenSSL" +# One or more files in the crate's source used as the "source of truth" for +# the license expression. If the contents match, the clarification will be used +# when running the license check, otherwise the clarification will be ignored +# 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 } +] + +[[licenses.clarify]] +name = "webpki" +expression = "ISC" +license-files = [{ path = "LICENSE", hash = 0x001c7e6c }] + +[licenses.private] +# If true, ignores workspace crates that aren't published, or are only +# published to private registries +ignore = false +# One or more private registries that you might publish crates to, if a crate +# is only published to private registries, and ignore is true, the crate will +# not have its license(s) checked +registries = [ + #"https://sekretz.com/registry +] + +# This section is considered when running `cargo deny check bans`. +# More documentation about the 'bans' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html +[bans] +# Lint level for when multiple versions of the same crate are detected +multiple-versions = "warn" +# The graph highlighting used when creating dotgraphs for crates +# with multiple versions +# * lowest-version - The path to the lowest versioned duplicate is highlighted +# * simplest-path - The path to the version with the fewest edges is highlighted +# * all - Both lowest-version and simplest-path are used +highlight = "lowest-version" +# List of crates that are allowed. Use with care! +allow = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# List of crates to deny +deny = [ + { name = "parity-util-mem", version = "<0.6" } + # Each entry the name of a crate and a version range. If version is + # not specified, all versions will be matched. +] +# Certain crates/versions that will be skipped when doing duplicate detection. +skip = [ + #{ name = "ansi_term", version = "=0.11.0" }, +] +# Similarly to `skip` allows you to skip certain crates during duplicate +# detection. Unlike skip, it also includes the entire tree of transitive +# dependencies starting at the specified crate, up to a certain depth, which is +# by default infinite +skip-tree = [ + #{ name = "ansi_term", version = "=0.11.0", depth = 20 }, +] + +# This section is considered when running `cargo deny check sources`. +# More documentation about the 'sources' section can be found here: +# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html +[sources] +# Lint level for what to happen when a crate from a crate registry that is not +# in the allow list is encountered +unknown-registry = "deny" +# Lint level for what to happen when a crate from a git repository that is not +# in the allow list is encountered +unknown-git = "allow" +# List of URLs for allowed crate registries. Defaults to the crates.io index +# if not specified. If it is specified but empty, no registries are allowed. +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +# List of URLs for allowed Git repositories +allow-git = [] diff --git a/deployments/README.md b/deployments/README.md new file mode 100644 index 00000000000..e478f7df84a --- /dev/null +++ b/deployments/README.md @@ -0,0 +1,270 @@ +# Bridge Deployments + +## Requirements + +Make sure to install `docker` and `docker-compose` to be able to run and test bridge deployments. If +for whatever reason you can't or don't want to use Docker, you can find some scripts for running the +bridge [here](./local-scripts/). + +## Networks + +One of the building blocks we use for our deployments are _networks_. A network is a collection of +homogenous blockchain nodes. We have Docker Compose files for each network that we want to bridge. +Each of the compose files found in the `./networks` folder is able to independently spin up a +network like so: + +```bash +docker-compose -f ./networks/rialto.yml up +``` + +After running this command we would have a network of several nodes producing blocks. + +## Bridges + +A _bridge_ is a way for several _networks_ to connect to one another. Bridge deployments have their +own Docker Compose files which can be found in the `./bridges` folder. These Compose files typically +contain bridge relayers, which are services external to blockchain nodes, and other components such +as testing infrastructure, or user interfaces. + +Unlike the network Compose files, these *cannot* be deployed on their own. They must be combined +with different networks. + +In general, we can deploy the bridge using `docker-compose up` in the following way: + +```bash +docker-compose -f .yml \ + -f .yml \ + -f .yml \ + -f .yml up +``` + +If you want to see how the Compose commands are actually run, check out the source code of the +[`./run.sh`](./run.sh). + +One thing worth noting is that we have a _monitoring_ Compose file. This adds support for Prometheus +and Grafana. We cover these in more details in the [Monitoring](#monitoring) section. At the moment +the monitoring Compose file is _not_ optional, and must be included for bridge deployments. + +### Running and Updating Deployments + +We currently support three bridge deployments +1. Rialto Substrate to Millau Substrate +2. Rialto Parachain Substrate to Millau Substrate +2. Westend Substrate to Millau Substrate (only finality bridge) + +These bridges can be deployed using our [`./run.sh`](./run.sh) script. + +The first argument it takes is the name of the bridge you want to run. Right now we only support three +bridges: `rialto-millau`, `rialto-parachain-millau` and `westend-millau`. + +```bash +./run.sh rialto-millau +``` + +If you add a second `update` argument to the script it will pull the latest images from Docker Hub +and restart the deployment. + +```bash +./run.sh rialto-millau update +``` + +You can also bring down a deployment using the script with the `stop` argument. + +```bash +./run.sh rialto-millau stop +``` + +### Adding Deployments + +We need two main things when adding a new deployment. First, the new network which we want to +bridge. A compose file for the network should be added in the `/networks/` folder. Secondly we'll +need a new bridge Compose file in `./bridges/`. This should configure the bridge relayer nodes +correctly for the two networks, and add any additional components needed for the deployment. If you +want you can also add support in the `./run.sh` script for the new deployment. While recommended it's +not strictly required. + +## General Notes + +Rialto authorities are named: `Alice`, `Bob`, `Charlie`, `Dave`, `Eve`. +Millau authorities are named: `Alice`, `Bob`, `Charlie`, `Dave`, `Eve`. +RialtoParachain authorities are named: `Alice`, `Bob`. + +`Sudo` is a sudo account on all chains. + +Both authorities and following accounts have enough funds (for test purposes) on corresponding Substrate chains: + +- on Rialto: `Ferdie`. +- on Millau: `Ferdie`. +- on RialtoParachain: `Charlie`, `Dave`, `Eve`, `Ferdie`. + +Names of accounts on Substrate (Rialto and Millau) chains may be prefixed with `//` and used as +seeds for the `sr25519` keys. This seed may also be used in the signer argument in Substrate relays. +Example: + +```bash +./substrate-relay relay-headers rialto-to-millau \ + --source-host rialto-node-alice \ + --source-port 9944 \ + --target-host millau-node-alice \ + --target-port 9944 \ + --source-signer //Ferdie \ + --prometheus-host=0.0.0.0 +``` + +Some accounts are used by bridge components. Using these accounts to sign other transactions +is not recommended, because this may lead to nonces conflict. + +Following accounts are used when `rialto-millau` bridge is running: + +- Millau's `Rialto.HeadersAndMessagesRelay1` signs complex headers+messages relay transactions on Millau chain; +- Rialto's `Millau.HeadersAndMessagesRelay1` signs complex headers+messages relay transactions on Rialto chain; +- Millau's `Rialto.MessagesSender` signs Millau transactions which contain messages for Rialto; +- Rialto's `Millau.MessagesSender` signs Rialto transactions which contain messages for Millau; +- Millau's `Rialto.OutboundMessagesRelay.Lane00000001` signs relay transactions with message delivery confirmations (lane 00000001) from Rialto to Millau; +- Rialto's `Millau.InboundMessagesRelay.Lane00000001` signs relay transactions with messages (lane 00000001) from Millau to Rialto; +- Millau's `Millau.OutboundMessagesRelay.Lane00000001` signs relay transactions with messages (lane 00000001) from Rialto to Millau; +- Rialto's `Rialto.InboundMessagesRelay.Lane00000001` signs relay transactions with message delivery confirmations (lane 00000001) from Millau to Rialto; +- Millau's `Rialto.MessagesOwner` signs relay transactions with updated Rialto -> Millau conversion rate; +- Rialto's `Millau.MessagesOwner` signs relay transactions with updated Millau -> Rialto conversion rate. + +Following accounts are used when `westend-millau` bridge is running: + +- Millau's `Westend.GrandpaOwner` is signing with-Westend GRANDPA pallet initialization transaction. +- Millau's `Westend.HeadersRelay1` and `Westend.HeadersRelay2` are signing transactions with new Westend headers. +- Millau's `Westend.WestmintHeaders1` and `Westend.WestmintHeaders2` is signing transactions with new Westming headers. + +Following accounts are used when `rialto-parachain-millau` bridge is running: + +- RialtoParachain's `Millau.MessagesSender` signs RialtoParachain transactions which contain messages for Millau; +- Millau's `RialtoParachain.MessagesSender` signs Millau transactions which contain messages for RialtoParachain; +- Millau's `RialtoParachain.HeadersAndMessagesRelay` signs complex headers+parachains+messages relay transactions on Millau chain; +- RialtoParachain's `Millau.HeadersAndMessagesRelay` signs complex headers+messages relay transactions on RialtoParachain chain. + +### Docker Usage + +When the network is running you can query logs from individual nodes using: + +```bash +docker logs rialto_millau-node-charlie_1 -f +``` + +You may use the [dump-logs.sh](../scripts/dump-logs.sh) to dump logs of most of running containers. + +To kill all leftover containers and start the network from scratch next time: +```bash +docker ps -a --format "{{.ID}}" | xargs docker rm # This removes all containers! +``` + +### Docker Compose Usage + +If you're not familiar with how to use `docker-compose` here are some useful commands you'll need +when interacting with the bridge deployments: + +```bash +docker-compose pull # Get the latest images from the Docker Hub +docker-compose build # This is going to build images +docker-compose up # Start all the nodes +docker-compose up -d # Start the nodes in detached mode. +docker-compose down # Stop the network. +``` + +Note that you'll also need to add the appropriate `-f` arguments that were mentioned in the +[Bridges](#bridges) section. You can read more about using multiple Compose files +[here](https://docs.docker.com/compose/extends/#multiple-compose-files). One thing worth noting is +that the _order_ the compose files are specified in matters. A different order will result in a +different configuration. + +You can sanity check the final config like so: + +```bash +docker-compose -f docker-compose.yml -f docker-compose.override.yml config > docker-compose.merged.yml +``` + +## Docker and Git Deployment + +It is also possible to avoid using images from the Docker Hub and instead build +containers from Git. There are two ways to build the images this way. + +### Git Repo + +If you have cloned the bridges repo you can build local Docker images by running the following +command at the top level of the repo: + +```bash +docker build . -t local/ --build-arg=PROJECT= +``` + +This will build a local image of a particular component with a tag of +`local/`. This tag can be used in Docker Compose files. + +You can configure the build using Docker +[build arguments](https://docs.docker.com/engine/reference/commandline/build/#set-build-time-variables---build-arg). +Here are the arguments currently supported: + - `PROJECT`: Project to build withing bridges repo. Can be one of: + - `rialto-bridge-node` + - `millau-bridge-node` + - `rialto-parachain-collator` + - `substrate-relay` + +You may use the [build-containers.sh](../scripts/build-containers.sh) script to build all available +containers. + +### GitHub Actions + +We have a nightly job which runs and publishes Docker images for the different nodes and relayers to +the [ParityTech Docker Hub](https://hub.docker.com/u/paritytech) organization. These images are used +for our ephemeral (temporary) test networks. Additionally, any time a tag in the form of `v*` is +pushed to GitHub the publishing job is run. This will build all the components (nodes, relayers) and +publish them. + +With images built using either method, all you have to do to use them in a deployment is change the +`image` field in the existing Docker Compose files to point to the tag of the image you want to use. + +### Monitoring + +[Prometheus](https://prometheus.io/) is used by the bridge relay to monitor information such as system +resource use, and block data (e.g the best blocks it knows about). In order to visualize this data +a [Grafana](https://grafana.com/) dashboard can be used. + +As part of the Rialto `docker-compose` setup we spin up a Prometheus server and Grafana dashboard. The +Prometheus server connects to the Prometheus data endpoint exposed by the bridge relay. The Grafana +dashboard uses the Prometheus server as its data source. + +The default port for the bridge relay's Prometheus data is `9616`. The host and port can be +configured though the `--prometheus-host` and `--prometheus-port` flags. The Prometheus server's +dashboard can be accessed at `http://localhost:9090`. The Grafana dashboard can be accessed at +`http://localhost:3000`. Note that the default log-in credentials for Grafana are `admin:admin`. + +### Environment Variables + +Here is an example `.env` file which is used for production deployments and network updates. For +security reasons it is not kept as part of version control. When deploying a network this +file should be correctly populated and kept in the appropriate [`bridges`](`./bridges`) deployment +folder. + +The `UI_SUBSTRATE_PROVIDER` variable lets you define the url of the Substrate node that the user +interface will connect to. `UI_ETHEREUM_PROVIDER` is used only as a guidance for users to connect +Metamask to the right Ethereum network. `UI_EXPECTED_ETHEREUM_NETWORK_ID` is used by +the user interface as a fail safe to prevent users from connecting their Metamask extension to an +unexpected network. + +```bash +GRAFANA_ADMIN_PASS=admin_pass +GRAFANA_SERVER_ROOT_URL=%(protocol)s://%(domain)s:%(http_port)s/ +GRAFANA_SERVER_DOMAIN=server.domain.io +MATRIX_ACCESS_TOKEN="access-token" +WITH_PROXY=1 # Optional +UI_SUBSTRATE_PROVIDER=ws://localhost:9944 +UI_ETHEREUM_PROVIDER=http://localhost:8545 +UI_EXPECTED_ETHEREUM_NETWORK_ID=105 +``` + +### UI + +Use [wss://wss.rialto.brucke.link](https://polkadot.js.org/apps/) as a custom endpoint for +[https://polkadot.js.org/apps/](https://polkadot.js.org/apps/). + +## Scripts + +There are some bash scripts in `scripts` folder that allow testing `Relay` +without running the entire network within docker. Use if needed for development. diff --git a/deployments/bridges/common/generate_messages.sh b/deployments/bridges/common/generate_messages.sh new file mode 100755 index 00000000000..0987ff8987e --- /dev/null +++ b/deployments/bridges/common/generate_messages.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# Script for generating messages from a source chain to a target chain. +# Prerequisites: mounting the common folder in the docker container (Adding the following volume entry): +# - ./bridges/common:/common +# It can be used by executing `source /common/generate_messages.sh` in a different script, +# after setting the following variables: +# SOURCE_CHAIN +# TARGET_CHAIN +# MAX_SUBMIT_DELAY_S +# SEND_MESSAGE - the command that is executed to send a message +# SECONDARY_EXTRA_ARGS - optional, for example "--use-xcm-pallet" +# EXTRA_ARGS - for example "--use-xcm-pallet" +# REGULAR_PAYLOAD +# MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE + +SECONDARY_EXTRA_ARGS=${SECONDARY_EXTRA_ARGS:-""} + +trap "echo Exiting... TERM; exit $?" TERM + +# Sleep a bit between messages +rand_sleep() { + SUBMIT_DELAY_S=`shuf -i 0-$MAX_SUBMIT_DELAY_S -n 1` + echo "Sleeping $SUBMIT_DELAY_S seconds..." + sleep $SUBMIT_DELAY_S & wait $! + NOW=`date "+%Y-%m-%d %H:%M:%S"` + echo "Woke up at $NOW" +} + +# start sending large messages immediately +LARGE_MESSAGES_TIME=0 +# start sending message packs in a hour +BUNCH_OF_MESSAGES_TIME=3600 + +while true +do + rand_sleep + + # send regular message + echo "Sending Message from $SOURCE_CHAIN to $TARGET_CHAIN" + $SEND_MESSAGE $EXTRA_ARGS raw $REGULAR_PAYLOAD + + # every other hour we're sending 3 large (size, weight, size+weight) messages + if [ $SECONDS -ge $LARGE_MESSAGES_TIME ]; then + LARGE_MESSAGES_TIME=$((SECONDS + 7200)) + + rand_sleep + echo "Sending Maximal Size Message from $SOURCE_CHAIN to $TARGET_CHAIN" + $SEND_MESSAGE \ + sized max + fi + + # every other hour we're sending a bunch of small messages + if [ $SECONDS -ge $BUNCH_OF_MESSAGES_TIME ]; then + BUNCH_OF_MESSAGES_TIME=$((SECONDS + 7200)) + + for i in $(seq 0 $MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE); + do + $SEND_MESSAGE \ + $EXTRA_ARGS \ + raw $REGULAR_PAYLOAD + done + + fi +done diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-messages-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-messages-dashboard.json new file mode 100644 index 00000000000..af8749325de --- /dev/null +++ b/deployments/bridges/rialto-millau/dashboard/grafana/relay-millau-to-rialto-messages-dashboard.json @@ -0,0 +1,1153 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_Rialto_MessageLane_00000000_best_target_block_number", + "instant": false, + "interval": "", + "legendFormat": "At Rialto", + "refId": "A" + }, + { + "expr": "Millau_to_Rialto_MessageLane_00000000_best_target_at_source_block_number", + "instant": false, + "interval": "", + "legendFormat": "At Millau", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Rialto headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_Rialto_MessageLane_00000000_best_source_block_number", + "interval": "", + "legendFormat": "At Millau", + "refId": "A" + }, + { + "expr": "Millau_to_Rialto_MessageLane_00000000_best_source_at_target_block_number", + "interval": "", + "legendFormat": "At Rialto", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Millau headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Millau -> Rialto messages are not detected by relay", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Rialto\", \"type\", \"source_latest_generated\"), \"type\", \"Latest Rialto message received by Millau\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + }, + { + "expr": "increase(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[10m]) OR on() vector(0)", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes (Millau -> Rialto, 00000000)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Rialto to Millau\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest Rialto message received by Millau\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "7m", + "frequency": "1m", + "handler": 1, + "name": "Messages from Millau to Rialto are not being delivered", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 20 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Undelivered messages at Rialto", + "refId": "A" + }, + { + "expr": "increase(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[5m]) OR on() vector(0)", + "interval": "", + "legendFormat": "Millau Messages delivered to Rialto in last 5m", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Too many unconfirmed messages (Millau -> Rialto)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 20 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "legendFormat": "Unconfirmed messages at Millau", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Rewards are not being confirmed (Millau -> Rialto messages)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 20 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m])) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_confirmed\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Rialto", + "refId": "A" + }, + { + "expr": "(scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) > bool min_over_time(Millau_to_Rialto_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau->Rialto (zero if messages are not being delivered to Rialto)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Reward lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 16, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "avg_over_time(process_cpu_usage_percentage{instance='relay-millau-rialto:9616'}[1m])", + "instant": true, + "interval": "", + "legendFormat": "1 CPU = 100", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Relay process CPU usage (1 CPU = 100)", + "type": "gauge" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 38 + }, + "hiddenSeries": false, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "system_average_load{instance='relay-millau-rialto:9616'}", + "interval": "", + "legendFormat": "Average system load in last {{over}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "System load average", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 38 + }, + "hiddenSeries": false, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_memory_usage_bytes{instance='relay-millau-rialto:9616'} / 1024 / 1024", + "interval": "", + "legendFormat": "Process memory, MB", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory used by relay process", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Millau to Rialto Message Sync Dashboard", + "uid": "relay-millau-to-rialto-messages", + "version": 1 +} diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-messages-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-messages-dashboard.json new file mode 100644 index 00000000000..efee749c5c1 --- /dev/null +++ b/deployments/bridges/rialto-millau/dashboard/grafana/relay-rialto-to-millau-messages-dashboard.json @@ -0,0 +1,1145 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 4, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Rialto_to_Millau_MessageLane_00000000_best_target_block_number", + "instant": false, + "interval": "", + "legendFormat": "At Millau", + "refId": "A" + }, + { + "expr": "Rialto_to_Millau_MessageLane_00000000_best_target_at_source_block_number", + "instant": false, + "interval": "", + "legendFormat": "At Rialto", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Millau headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Rialto_to_Millau_MessageLane_00000000_best_source_block_number", + "interval": "", + "legendFormat": "At Rialto", + "refId": "A" + }, + { + "expr": "Rialto_to_Millau_MessageLane_00000000_best_source_at_target_block_number", + "interval": "", + "legendFormat": "At Millau", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Rialto headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Rialto -> Millau messages are not detected by relay", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Millau\", \"type\", \"source_latest_generated\"), \"type\", \"Latest message received by Rialto\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + }, + { + "expr": "increase(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[10m]) OR on() vector(0)", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes (Rialto -> Millau, 00000000)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Millau to Rialto\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest message received by Rialto\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "7m", + "frequency": "1m", + "handler": 1, + "name": "Messages from Rialto to Millau are not being delivered", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 20 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Undelivered messages at Millau", + "refId": "A" + }, + { + "expr": "increase(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[5m]) OR on() vector(0)", + "interval": "", + "legendFormat": "Rialto Messages delivered to Millau in last 5m", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Too many unconfirmed messages (Rialto -> Millau)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 20 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "legendFormat": "Unconfirmed messages at Rialto", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Rewards are not being confirmed (Rialto -> Millau messages)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 20 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m])) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_confirmed\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau", + "refId": "A" + }, + { + "expr": "(scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]) > bool min_over_time(Rialto_to_Millau_MessageLane_00000000_lane_state_nonces{type=\"target_latest_received\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau (zero if messages are not being delivered to Millau)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Reward lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 38 + }, + "id": 16, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "avg_over_time(process_cpu_usage_percentage{instance='relay-millau-rialto:9616'}[1m])", + "instant": true, + "interval": "", + "legendFormat": "1 CPU = 100", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Relay process CPU usage (1 CPU = 100)", + "type": "gauge" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 38 + }, + "hiddenSeries": false, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "system_average_load{instance='relay-millau-rialto:9616'}", + "interval": "", + "legendFormat": "Average system load in last {{over}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "System load average", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 38 + }, + "hiddenSeries": false, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_memory_usage_bytes{instance='relay-millau-rialto:9616'} / 1024 / 1024", + "interval": "", + "legendFormat": "Process memory, MB", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory used by relay process", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rialto to Millau Message Sync Dashboard", + "uid": "relay-rialto-to-millau-messages", + "version": 2 +} diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json new file mode 100644 index 00000000000..4f134914f70 --- /dev/null +++ b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json @@ -0,0 +1,635 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "At-Rialto relay balances are too low", + "noDataState": "ok", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "at_Rialto_relay_MillauHeaders_balance", + "interval": "", + "legendFormat": "With-Millau headers relay account balance", + "refId": "A" + }, + { + "expr": "at_Rialto_relay_MillauMessages_balance", + "interval": "", + "legendFormat": "With-Millau messages relay account balance", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1000, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rialto relay balances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "At-Millau relay balances are too low", + "noDataState": "ok", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "at_Millau_relay_RialtoHeaders_balance{instance=\"relay-millau-rialto:9616\"}", + "interval": "", + "legendFormat": "With-Rialto headers relay account balance", + "refId": "A" + }, + { + "expr": "at_Millau_relay_RialtoMessages_balance", + "interval": "", + "legendFormat": "With-Rialto messages relay account balance", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1000, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Millau relay balances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Whether with-Rialto-grandpa-pallet and Rialto itself are on different forks alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Rialto_to_Millau_MessageLane_00000000_is_source_and_source_at_target_using_different_forks OR on() vector(0)", + "interval": "", + "legendFormat": "On different forks?", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Whether with-Rialto-grandpa-pallet and Rialto itself are on different forks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Whether with-Rialto-grandpa-pallet and Rialto itself are on different forks alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_Rialto_MessageLane_00000000_is_source_and_source_at_target_using_different_forks OR on() vector(0)", + "interval": "", + "legendFormat": "On different forks?", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Whether with-Millau-grandpa-pallet and Millau itself are on different forks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 32, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Rialto+Millau maintenance dashboard", + "uid": "7AuyrjlMz", + "version": 1 +} diff --git a/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml b/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml new file mode 100644 index 00000000000..75c3e0c2aa9 --- /dev/null +++ b/deployments/bridges/rialto-millau/dashboard/prometheus/targets.yml @@ -0,0 +1,2 @@ +- targets: + - relay-millau-rialto:9616 diff --git a/deployments/bridges/rialto-millau/docker-compose.yml b/deployments/bridges/rialto-millau/docker-compose.yml new file mode 100644 index 00000000000..5d15a0398b1 --- /dev/null +++ b/deployments/bridges/rialto-millau/docker-compose.yml @@ -0,0 +1,88 @@ +# Exposed ports: 10016, 10116, 10216, 10316, 10416, 10516, 10716 + +version: '3.5' +services: + # We provide overrides for these particular nodes since they are public facing + # nodes which we use to connect from things like Polkadot JS Apps. + rialto-node-charlie: + environment: + VIRTUAL_HOST: wss.rialto.brucke.link + VIRTUAL_PORT: 9944 + LETSENCRYPT_HOST: wss.rialto.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + + millau-node-charlie: + environment: + VIRTUAL_HOST: wss.millau.brucke.link + VIRTUAL_PORT: 9944 + LETSENCRYPT_HOST: wss.millau.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + + relay-millau-rialto: &sub-bridge-relay + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-millau-rialto-entrypoint.sh + volumes: + - ./bridges/common:/common + - ./bridges/rialto-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + GLOBAL_DEPLOYMENTS: $GLOBAL_DEPLOYMENTS + ports: + - "10016:9616" + depends_on: &all-nodes + - millau-node-alice + - millau-node-bob + - millau-node-charlie + - millau-node-dave + - millau-node-eve + - rialto-node-alice + - rialto-node-bob + - rialto-node-charlie + - rialto-node-dave + - rialto-node-eve + + relay-messages-millau-to-rialto-generator: + <<: *sub-bridge-relay + environment: + RUST_LOG: bridge=trace + entrypoint: /entrypoints/relay-messages-to-rialto-generator-entrypoint.sh + ports: + - "10216:9616" + depends_on: + - relay-millau-rialto + + relay-messages-millau-to-rialto-resubmitter: + <<: *sub-bridge-relay + environment: + RUST_LOG: bridge=trace + entrypoint: /entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh + ports: + - "10316:9616" + depends_on: + - relay-messages-millau-to-rialto-generator + + relay-messages-rialto-to-millau-generator: + <<: *sub-bridge-relay + environment: + RUST_LOG: bridge=trace + entrypoint: /entrypoints/relay-messages-to-millau-generator-entrypoint.sh + ports: + - "10516:9616" + depends_on: + - relay-millau-rialto + + # Note: These are being overridden from the top level `monitoring` compose file. + grafana-dashboard: + environment: + VIRTUAL_HOST: grafana.millau.brucke.link,grafana.rialto.brucke.link + VIRTUAL_PORT: 3000 + LETSENCRYPT_HOST: grafana.millau.brucke.link,grafana.rialto.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + volumes: + - ./bridges/rialto-millau/dashboard/grafana:/etc/grafana/dashboards/rialto-millau:ro + - ./networks/dashboard/grafana/beefy-dashboard.json:/etc/grafana/dashboards/beefy.json + + prometheus-metrics: + volumes: + - ./bridges/rialto-millau/dashboard/prometheus/targets.yml:/etc/prometheus/targets-rialto-millau.yml + depends_on: *all-nodes diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh new file mode 100755 index 00000000000..3a55cc782ca --- /dev/null +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -xeu + +sleep 15 + +MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} + +/home/user/substrate-relay relay-messages millau-to-rialto \ + --lane $MESSAGE_LANE \ + --source-host millau-node-bob \ + --source-port 9944 \ + --source-signer //Rialto.OutboundMessagesRelay.Lane00000001 \ + --target-host rialto-node-bob \ + --target-port 9944 \ + --target-signer //Millau.InboundMessagesRelay.Lane00000001 \ + --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh new file mode 100755 index 00000000000..145cd20100d --- /dev/null +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -xeu + +sleep 15 + +MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} + +/home/user/substrate-relay relay-messages rialto-to-millau \ + --lane $MESSAGE_LANE \ + --source-host rialto-node-bob \ + --source-port 9944 \ + --source-signer //Millau.OutboundMessagesRelay.Lane00000001 \ + --target-host millau-node-bob \ + --target-port 9944 \ + --target-signer //Rialto.InboundMessagesRelay.Lane00000001 \ + --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh new file mode 100755 index 00000000000..a36538ea515 --- /dev/null +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# THIS SCRIPT IS NOT INTENDED FOR USE IN PRODUCTION ENVIRONMENT +# +# This scripts periodically calls the Substrate relay binary to generate messages. These messages +# are sent from the Rialto network to the Millau network. + +set -eu + +# Max delay before submitting transactions (s) +MAX_SUBMIT_DELAY_S=${MSG_EXCHANGE_GEN_MAX_SUBMIT_DELAY_S:-30} +MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE=1024 + +SHARED_CMD="/home/user/substrate-relay send-message rialto-to-millau" +SHARED_HOST="--source-host rialto-node-bob --source-port 9944" +SOURCE_SIGNER="--source-signer //Millau.MessagesSender" + +SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $SOURCE_SIGNER" + +SOURCE_CHAIN="Rialto" +TARGET_CHAIN="Millau" +EXTRA_ARGS="" +# It is the encoded `xcm::VersionedXcm::V3(prepare_outbound_xcm_message(MillauNetwork::get())` +# from the `xcm_messages_to_millau_are_sent_using_bridge_exporter` test in the `rialto-runtime` +REGULAR_PAYLOAD="030426030109030419a8" + +source /common/generate_messages.sh diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh new file mode 100755 index 00000000000..dacb5615229 --- /dev/null +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# THIS SCRIPT IS NOT INTENDED FOR USE IN PRODUCTION ENVIRONMENT +# +# This scripts periodically calls the Substrate relay binary to generate messages. These messages +# are sent from the Millau network to the Rialto network. + +set -eu + +# Max delay before submitting transactions (s) +MAX_SUBMIT_DELAY_S=${MSG_EXCHANGE_GEN_MAX_SUBMIT_DELAY_S:-30} +MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE=128 + +SHARED_CMD=" /home/user/substrate-relay send-message millau-to-rialto" +SHARED_HOST="--source-host millau-node-bob --source-port 9944" +SOURCE_SIGNER="--source-signer //Rialto.MessagesSender" + +SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $SOURCE_SIGNER" + +SOURCE_CHAIN="Millau" +TARGET_CHAIN="Rialto" +EXTRA_ARGS="" +# It is the encoded `xcm::VersionedXcm::V3(prepare_outbound_xcm_message(RialtoNetwork::get())` +# from the `xcm_messages_to_rialto_are_sent_using_bridge_exporter` test in the `millau-runtime` +REGULAR_PAYLOAD="030426020109020419a8" + +source /common/generate_messages.sh diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh new file mode 100755 index 00000000000..bd9bf800ad4 --- /dev/null +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -xeu + +sleep 15 + +# //Rialto.MessagesSender is signing Millau -> Rialto message-send transactions, which are causing problems. +# +# When large message is being sent from Millau to Rialto AND other transactions are +# blocking it from being mined, we'll see something like this in logs: +# +# Millau transaction priority with tip=0: 17800827994. Target priority: +# 526186677695 +# +# So since fee multiplier in Millau is `1` and `WeightToFee` is `IdentityFee`, then +# we need tip around `526186677695 - 17800827994 = 508_385_849_701`. Let's round it +# up to `1_000_000_000_000`. + +/home/user/substrate-relay resubmit-transactions millau \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer //Rialto.MessagesSender \ + --stalled-blocks 5 \ + --tip-limit 1000000000000 \ + --tip-step 1000000000 \ + make-it-best-transaction diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh new file mode 100755 index 00000000000..a1306984bca --- /dev/null +++ b/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh @@ -0,0 +1,37 @@ +#!/bin/bash +set -xeu + +sleep 15 + +/home/user/substrate-relay init-bridge millau-to-rialto \ + --source-host millau-node-alice \ + --source-port 9944 \ + --target-host rialto-node-alice \ + --target-port 9944 \ + --target-signer //Sudo + +/home/user/substrate-relay init-bridge rialto-to-millau \ + --source-host rialto-node-alice \ + --source-port 9944 \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer //Sudo + +# Give chain a little bit of time to process initialization transaction +sleep 6 + +RIALTO_NODE_CONNECTION_PARAMS=$([ -z ${GLOBAL_DEPLOYMENTS} ] && \ + echo "--rialto-host rialto-node-alice --rialto-port 9944" \ + || \ + echo "--rialto-host wss.rialto.brucke.link --rialto-port 443 --rialto-secure" ) + +/home/user/substrate-relay relay-headers-and-messages millau-rialto \ + --millau-host millau-node-alice \ + --millau-port 9944 \ + --millau-signer //Rialto.HeadersAndMessagesRelay \ + --millau-transactions-mortality=64 \ + $RIALTO_NODE_CONNECTION_PARAMS \ + --rialto-signer //Millau.HeadersAndMessagesRelay \ + --rialto-transactions-mortality=64 \ + --lane=00000000 \ + --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-millau-to-rialto-parachain-messages-dashboard.json b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-millau-to-rialto-parachain-messages-dashboard.json new file mode 100644 index 00000000000..b20348cc513 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-millau-to-rialto-parachain-messages-dashboard.json @@ -0,0 +1,910 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_best_target_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "At RialtoParachain", + "refId": "A" + }, + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_best_target_at_source_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "At Millau", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized RialtoParachain headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_best_source_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "At Millau", + "refId": "A" + }, + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_best_source_at_target_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "At RialtoParachain", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Millau headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Millau -> RialtoParachain messages are not detected by relay", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from RialtoParachain\", \"type\", \"source_latest_generated\"), \"type\", \"Latest RialtoParachain message received by Millau\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + }, + { + "expr": "increase(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_generated\"}[10m]) OR on() vector(0)", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes (Millau -> RialtoParachain, 00000000)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by RialtoParachain to Millau\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest RialtoParachain message received by Millau\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "7m", + "frequency": "1m", + "handler": 1, + "name": "Messages from Millau to RialtoParachain are not being delivered", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 20 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Undelivered messages at RialtoParachain", + "refId": "A" + }, + { + "expr": "increase(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[5m]) OR on() vector(0)", + "interval": "", + "legendFormat": "Millau Messages delivered to RialtoParachain in last 5m", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Too many unconfirmed messages (Millau -> RialtoParachain)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 20 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "legendFormat": "Unconfirmed messages at Millau", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Rewards are not being confirmed (Millau -> RialtoParachain messages)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 20 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m])) - scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_confirmed\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at RialtoParachain", + "refId": "A" + }, + { + "expr": "(scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]) > bool min_over_time(Millau_to_RialtoParachain_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau->RaltoParachain (zero if messages are not being delivered to RialtoParachain)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Reward lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Millau to RialtoParachain Message Sync Dashboard", + "uid": "C61e-797z", + "version": 1 +} diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-rialto-parachain-to-millau-messages-dashboard.json b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-rialto-parachain-to-millau-messages-dashboard.json new file mode 100644 index 00000000000..064436145de --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/relay-rialto-parachain-to-millau-messages-dashboard.json @@ -0,0 +1,908 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_best_target_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "At Millau", + "refId": "A" + }, + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_best_target_at_source_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "At RialtoParachain", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized Millau headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_best_source_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "At RialtoParachain", + "refId": "A" + }, + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_best_source_at_target_block_number{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "At Millau", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Best finalized RialtoParachain headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "RialtoParachain -> Millau messages are not detected by relay", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from Millau\", \"type\", \"source_latest_generated\"), \"type\", \"Latest Millau message received by RialtoParachain\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + }, + { + "expr": "increase(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_generated\"}[10m]) OR on() vector(0)", + "hide": true, + "interval": "", + "legendFormat": "Messages generated in last 5 minutes (RialtoParachain -> Millau, 00000000)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "label_replace(label_replace(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest message confirmed by Millau to RialtoParachain\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest Millau message received by RialtoParachain\", \"type\", \"target_latest_received\")", + "interval": "", + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "sum" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "7m", + "frequency": "1m", + "handler": 1, + "name": "Messages from RialtoParachain to Millau are not being delivered", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 20 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_generated\"}[2m])) - scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "Undelivered messages at Millau", + "refId": "A" + }, + { + "expr": "increase(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[5m]) OR on() vector(0)", + "interval": "", + "legendFormat": "RialtoParachain Messages delivered to Millau in last 5m", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Delivery race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Too many unconfirmed messages (RialtoParachain -> Millau)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 20 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "legendFormat": "Unconfirmed messages at RialtoParachain", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Confirmations race lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "20m", + "frequency": "1m", + "handler": 1, + "name": "Rewards are not being confirmed (RialtoParachain -> Millau messages)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 20 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m])) - scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_confirmed\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau", + "refId": "A" + }, + { + "expr": "(scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]) > bool min_over_time(RialtoParachain_to_Millau_MessageLane_00000000_lane_state_nonces{instance=\"relay-millau-rialto-parachain-1:9616\",type=\"target_latest_received\"}[2m]))", + "interval": "", + "legendFormat": "Unconfirmed rewards at Millau (zero if messages are not being delivered to Millau)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 10 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Reward lags (00000000)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "RialtoParachain to Millau Message Sync Dashboard", + "uid": "-l61a7r7k", + "version": 1 +} diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json new file mode 100644 index 00000000000..ca22a6dadd0 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/dashboard/grafana/rialto-parachain-millau-maintenance-dashboard.json @@ -0,0 +1,627 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "At-Rialto relay balances are too low", + "noDataState": "ok", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "at_RialtoParachain_relay_MillauMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "instant": false, + "interval": "", + "legendFormat": "With-Millau relay account balance", + "refId": "A" + }, + { + "exemplar": true, + "expr": "at_RialtoParachain_relay_MillauMessages_reward_for_msgs_from_Millau_on_lane_00000000{instance=\"relay-millau-rialto-parachain-1:9616\"} + at_RialtoParachain_relay_MillauMessages_reward_for_msgs_to_Millau_on_lane_00000000{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "hide": false, + "instant": false, + "interval": "", + "legendFormat": "With-Millau relay account reward", + "refId": "B" + }, + { + "exemplar": true, + "expr": "at_RialtoParachain_relay_MillauMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"} + at_RialtoParachain_relay_MillauMessages_reward_for_msgs_from_Millau_on_lane_00000000{instance=\"relay-millau-rialto-parachain-1:9616\"} + at_RialtoParachain_relay_MillauMessages_reward_for_msgs_to_Millau_on_lane_00000000{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "hide": false, + "interval": "", + "legendFormat": "With-Millau relay account total balance (balance + reward)", + "refId": "C" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1000, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RialtoParachain relay balances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1000 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "At-Millau relay balances are too low", + "noDataState": "ok", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "at_Millau_relay_RialtoParachainMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "interval": "", + "legendFormat": "With-Rialto relay account balance", + "refId": "A" + }, + { + "exemplar": true, + "expr": "at_Millau_relay_RialtoParachainMessages_reward_for_msgs_from_RialtoParachain_on_lane_00000000{instance=\"relay-millau-rialto-parachain-1:9616\"} + at_Millau_relay_RialtoParachainMessages_reward_for_msgs_to_RialtoParachain_on_lane_00000000{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "hide": false, + "interval": "", + "legendFormat": "With-Rialto relay account reward", + "refId": "B" + }, + { + "exemplar": true, + "expr": "at_Millau_relay_RialtoParachainMessages_balance{instance=\"relay-millau-rialto-parachain-1:9616\"} + at_Millau_relay_RialtoParachainMessages_reward_for_msgs_from_RialtoParachain_on_lane_00000000{instance=\"relay-millau-rialto-parachain-1:9616\"} + at_Millau_relay_RialtoParachainMessages_reward_for_msgs_to_RialtoParachain_on_lane_00000000{instance=\"relay-millau-rialto-parachain-1:9616\"}", + "hide": false, + "interval": "", + "legendFormat": "With-Rialto relay account total balance (balance + reward)", + "refId": "C" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1000, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Millau relay balances", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Whether with-RialtoParachain-parachains-pallet and Rialto itself are on different forks alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "RialtoParachain_to_Millau_MessageLane_00000000_is_source_and_source_at_target_using_different_forks{instance=\"relay-millau-rialto-parachain-1:9616\"} OR on() vector(0)", + "instant": false, + "interval": "", + "legendFormat": "On different forks?", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Whether with-RialtoParachain-parachains-pallet and RialtoParachain itself are on different forks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Whether with-Millau-grandpa-pallet and Millau itself are on different forks", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "hiddenSeries": false, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Millau_to_RialtoParachain_MessageLane_00000000_is_source_and_source_at_target_using_different_forks{instance=\"relay-millau-rialto-parachain-1:9616\"} OR on() vector(0)", + "interval": "", + "legendFormat": "On different forks?", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Whether with-Millau-grandpa-pallet and Millau itself are on different forks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 32, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "RialtoParachain+Millau maintenance dashboard", + "uid": "WALc3ajnk", + "version": 1 +} diff --git a/deployments/bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml b/deployments/bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml new file mode 100644 index 00000000000..ba683e3479a --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml @@ -0,0 +1,3 @@ +- targets: + - relay-millau-rialto-parachain-1:9616 + - relay-millau-rialto-parachain-2:9616 diff --git a/deployments/bridges/rialto-parachain-millau/docker-compose.yml b/deployments/bridges/rialto-parachain-millau/docker-compose.yml new file mode 100644 index 00000000000..a62bda52eb3 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/docker-compose.yml @@ -0,0 +1,90 @@ +# Exposed ports: 10816, 10916, 11016, 11017, 11018 + +version: '3.5' +services: + # We provide overrides for these particular nodes since they are public facing + # nodes which we use to connect from things like Polkadot JS Apps. + rialto-parachain-collator-charlie: + environment: + VIRTUAL_HOST: wss.rialto-parachain.brucke.link + VIRTUAL_PORT: 9944 + LETSENCRYPT_HOST: wss.rialto-parachain.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + + millau-node-charlie: + environment: + VIRTUAL_HOST: wss.millau.brucke.link + VIRTUAL_PORT: 9944 + LETSENCRYPT_HOST: wss.millau.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + + relay-millau-rialto-parachain-1: &sub-bridge-relay + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-millau-rialto-parachain-entrypoint.sh + volumes: + - ./bridges/common:/common + - ./bridges/rialto-parachain-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + ports: + - "10816:9616" + depends_on: &all-nodes + - millau-node-alice + - millau-node-bob + - millau-node-charlie + - millau-node-dave + - millau-node-eve + - rialto-parachain-collator-alice + - rialto-parachain-collator-bob + - rialto-parachain-collator-charlie + + relay-millau-rialto-parachain-2: + <<: *sub-bridge-relay + environment: + RUST_LOG: rpc=trace,bridge=trace + EXT_MILLAU_RELAY_ACCOUNT: //RialtoParachain.HeadersAndMessagesRelay2 + EXT_MILLAU_RELAY_ACCOUNT_HEADERS_OVERRIDE: //RialtoParachain.RialtoHeadersRelay2 + EXT_RIALTO_PARACHAIN_RELAY_ACCOUNT: //Millau.HeadersAndMessagesRelay2 + ports: + - "10916:9616" + relay-messages-millau-to-rialto-parachain-generator: + <<: *sub-bridge-relay + ports: + - "11016:9616" + entrypoint: /entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh + depends_on: + - relay-millau-rialto-parachain-1 + + relay-messages-rialto-parachain-to-millau-generator: + <<: *sub-bridge-relay + entrypoint: /entrypoints/relay-messages-to-millau-generator-entrypoint.sh + ports: + - "11017:9616" + depends_on: + - relay-millau-rialto-parachain-1 + + relay-messages-millau-to-rialto-parachain-resubmitter: + <<: *sub-bridge-relay + environment: + RUST_LOG: bridge=trace + entrypoint: /entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh + ports: + - "11018:9616" + depends_on: + - relay-messages-millau-to-rialto-parachain-generator + + # Note: These are being overridden from the top level `monitoring` compose file. + grafana-dashboard: + environment: + VIRTUAL_HOST: grafana.millau.brucke.link,grafana.rialto.brucke.link + VIRTUAL_PORT: 3000 + LETSENCRYPT_HOST: grafana.millau.brucke.link,grafana.rialto.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + volumes: + - ./bridges/rialto-parachain-millau/dashboard/grafana:/etc/grafana/dashboards/rialto-parachain-millau:ro + - ./networks/dashboard/grafana/beefy-dashboard.json:/etc/grafana/dashboards/beefy.json + + prometheus-metrics: + volumes: + - ./bridges/rialto-parachain-millau/dashboard/prometheus/targets.yml:/etc/prometheus/targets-rialto-parachain-millau.yml + depends_on: *all-nodes diff --git a/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh new file mode 100755 index 00000000000..c09116a1614 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# THIS SCRIPT IS NOT INTENDED FOR USE IN PRODUCTION ENVIRONMENT +# +# This scripts periodically calls the Substrate relay binary to generate messages. These messages +# are sent from the Rialto network to the Millau network. + +set -eu + +# Max delay before submitting transactions (s) +MAX_SUBMIT_DELAY_S=${MSG_EXCHANGE_GEN_MAX_SUBMIT_DELAY_S:-30} +MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} +MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE=1024 + +SHARED_CMD="/home/user/substrate-relay send-message rialto-parachain-to-millau" +SHARED_HOST="--source-host rialto-parachain-collator-bob --source-port 9944" +SOURCE_SIGNER="--source-signer //Millau.MessagesSender" + +SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $SOURCE_SIGNER" + +SOURCE_CHAIN="RialtoParachain" +TARGET_CHAIN="Millau" +EXTRA_ARGS="" +# It is the encoded `xcm::VersionedXcm::V3(prepare_outbound_xcm_message(MillauNetwork::get())` +# from the `xcm_messages_to_millau_are_sent_using_bridge_exporter` test in the `rialto-parachain-runtime` +REGULAR_PAYLOAD="030426030109030419a8" + +source /common/generate_messages.sh diff --git a/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh new file mode 100755 index 00000000000..dbf14ef18bc --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-generator-entrypoint.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# THIS SCRIPT IS NOT INTENDED FOR USE IN PRODUCTION ENVIRONMENT +# +# This scripts periodically calls the Substrate relay binary to generate messages. These messages +# are sent from the Millau network to the Rialto network. + +set -eu + +# Max delay before submitting transactions (s) +MAX_SUBMIT_DELAY_S=${MSG_EXCHANGE_GEN_MAX_SUBMIT_DELAY_S:-30} +MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE=1024 + +SHARED_CMD=" /home/user/substrate-relay send-message millau-to-rialto-parachain" +SHARED_HOST="--source-host millau-node-bob --source-port 9944" +SOURCE_SIGNER="--source-signer //RialtoParachain.MessagesSender" + +SEND_MESSAGE="$SHARED_CMD $SHARED_HOST $SOURCE_SIGNER" + +SOURCE_CHAIN="Millau" +TARGET_CHAIN="RialtoParachain" +EXTRA_ARGS="" +# It is the encoded `xcm::VersionedXcm::V3(prepare_outbound_xcm_message(RialtoParachainNetwork::get())` +# from the `xcm_messages_to_rialto_parachain_are_sent_using_bridge_exporter` test in the `millau-runtime` +REGULAR_PAYLOAD="030426040109040419a8" + +source /common/generate_messages.sh diff --git a/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh new file mode 100755 index 00000000000..4653ae396c6 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-messages-to-rialto-parachain-resubmitter-entrypoint.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -xeu + +sleep 15 + +# //RialtoParachain.MessagesSender is signing Millau -> RialtoParachain message-send transactions, which are causing problems. +# +# When large message is being sent from Millau to RialtoParachain AND other transactions are +# blocking it from being mined, we'll see something like this in logs: +# +# Millau transaction priority with tip=0: 17800827994. Target priority: +# 526186677695 +# +# So since fee multiplier in Millau is `1` and `WeightToFee` is `IdentityFee`, then +# we need tip around `526186677695 - 17800827994 = 508_385_849_701`. Let's round it +# up to `1_000_000_000_000`. + +exec /home/user/substrate-relay resubmit-transactions millau \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer //RialtoParachain.MessagesSender \ + --stalled-blocks 7 \ + --tip-limit 1000000000000 \ + --tip-step 1000000000 \ + make-it-best-transaction diff --git a/deployments/bridges/rialto-parachain-millau/entrypoints/relay-millau-rialto-parachain-entrypoint.sh b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-millau-rialto-parachain-entrypoint.sh new file mode 100755 index 00000000000..7685f5f5ec2 --- /dev/null +++ b/deployments/bridges/rialto-parachain-millau/entrypoints/relay-millau-rialto-parachain-entrypoint.sh @@ -0,0 +1,39 @@ +#!/bin/bash +set -xeu + +sleep 15 + +MILLAU_RELAY_ACCOUNT=${EXT_MILLAU_RELAY_ACCOUNT:-//RialtoParachain.HeadersAndMessagesRelay1} +MILLAU_RELAY_ACCOUNT_HEADERS_OVERRIDE=${EXT_MILLAU_RELAY_ACCOUNT_HEADERS_OVERRIDE:-//RialtoParachain.RialtoHeadersRelay1} +RIALTO_PARACHAIN_RELAY_ACCOUNT=${EXT_RIALTO_PARACHAIN_RELAY_ACCOUNT:-//Millau.HeadersAndMessagesRelay1} + +/home/user/substrate-relay init-bridge millau-to-rialto-parachain \ + --source-host millau-node-alice \ + --source-port 9944 \ + --target-host rialto-parachain-collator-alice \ + --target-port 9944 \ + --target-signer //Sudo + +/home/user/substrate-relay init-bridge rialto-to-millau \ + --source-host rialto-node-alice \ + --source-port 9944 \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer //Sudo + +# Give chain a little bit of time to process initialization transaction +sleep 6 + +exec /home/user/substrate-relay relay-headers-and-messages millau-rialto-parachain \ + --millau-host millau-node-alice \ + --millau-port 9944 \ + --millau-signer $MILLAU_RELAY_ACCOUNT \ + --millau-transactions-mortality=64 \ + --rialto-parachain-host rialto-parachain-collator-charlie \ + --rialto-parachain-port 9944 \ + --rialto-parachain-signer $RIALTO_PARACHAIN_RELAY_ACCOUNT \ + --rialto-parachain-transactions-mortality=64 \ + --rialto-host rialto-node-alice \ + --rialto-port 9944 \ + --lane=00000000 \ + --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/rococo-wococo/README.md b/deployments/bridges/rococo-wococo/README.md new file mode 100644 index 00000000000..1c2985a3357 --- /dev/null +++ b/deployments/bridges/rococo-wococo/README.md @@ -0,0 +1,10 @@ +# Rococo Bridge Hub <> Wococo Bridge Hub deployments + +This folder contains some information and useful stuff from our other test deployment - between Rococo and Wococo +bridge hubs. The bridge overview and other helpful information can be found in +[this readme](https://github.com/paritytech/cumulus/tree/bridge-hub-rococo-wococo/parachains/runtimes/bridge-hubs). + +## Grafana Alerts and Dashboards + +JSON model for Grafana alerts and dashobards that we use, may be found in the [dasboard/grafana](./dashboard/grafana/) +folder. diff --git a/deployments/bridges/rococo-wococo/dashboard/grafana/bridges-alerts.json b/deployments/bridges/rococo-wococo/dashboard/grafana/bridges-alerts.json new file mode 100644 index 00000000000..6432f79deaf --- /dev/null +++ b/deployments/bridges/rococo-wococo/dashboard/grafana/bridges-alerts.json @@ -0,0 +1,1994 @@ +{ + "Bridges": [ + { + "name": "Bridges", + "interval": "1m", + "rules": [ + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "12", + "summary": "Messages from RococoBridgeHub to WococoBridgeHub (00000001) are either not delivered, or are delivered with lags" + }, + "grafana_alert": { + "id": 51, + "orgId": 1, + "title": "RococoBridgeHub -> WococoBridgeHub delivery lags (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_generated\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Undelivered messages", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 90, + "uid": "r41otJp4k", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "zqjpgXxnk", + "__panelId__": "14", + "summary": "Messages from WococoBridgeHub to RococoBridgeHub (00000001) are either not delivered, or are delivered with lags" + }, + "grafana_alert": { + "id": 55, + "orgId": 1, + "title": "WococoBridgeHub -> RococoBridgeHub delivery lags (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_generated\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Undelivered messages", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 88, + "uid": "wqmPtJpVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "14", + "summary": "Messages from RococoBridgeHub to WococoBridgeHub (00000001) are either not confirmed, or are confirmed with lags" + }, + "grafana_alert": { + "id": 56, + "orgId": 1, + "title": "RococoBridgeHub -> WococoBridgeHub confirmation lags (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(RococoBridgeHub_to_WococoBridgeHub_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(RococoBridgeHub_to_WococoBridgeHub_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Unconfirmed messages", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 84, + "uid": "z4h3pJtVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "zqjpgXxnk", + "__panelId__": "16", + "summary": "Messages from WococoBridgeHub to RococoBridgeHub (00000001) are either not confirmed, or are confirmed with lags" + }, + "grafana_alert": { + "id": 57, + "orgId": 1, + "title": "WococoBridgeHub -> RococoBridgeHub confirmation lags (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Unconfirmed messages", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 50 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 83, + "uid": "Kj_z21t4k", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "zqjpgXxnk", + "__panelId__": "18", + "summary": "Rewards for messages from WococoBridgeHub to RococoBridgeHub (00000001) are either not confirmed, or are confirmed with lags" + }, + "grafana_alert": { + "id": 58, + "orgId": 1, + "title": "WococoBridgeHub -> RococoBridgeHub reward lags (00000001)", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Unconfirmed rewards", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "(scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0) > bool min_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "hide": true, + "interval": "", + "intervalMs": 30000, + "legendFormat": "__auto", + "maxDataPoints": 43200, + "range": true, + "refId": "B" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 78, + "uid": "hw_a21pVk", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "15", + "summary": "Rewards for messages from RococoBridgeHub to WococoBridgeHub (00000001) are either not confirmed, or are confirmed with lags" + }, + "grafana_alert": { + "id": 59, + "orgId": 1, + "title": "RococoBridgeHub -> WococoBridgeHub reward lags (00000001)", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Unconfirmed rewards", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "(scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0) > bool min_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "hide": true, + "interval": "", + "intervalMs": 30000, + "legendFormat": "__auto", + "maxDataPoints": 43200, + "range": true, + "refId": "B" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 77, + "uid": "daN62Jt4z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "2", + "summary": "Best BridgeHubRococo header at BridgeHubWococo (00000001) doesn't match the same header at BridgeHubRococo" + }, + "grafana_alert": { + "id": 60, + "orgId": 1, + "title": "BridgeHubRococo header mismatch (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 74, + "uid": "BzBDb1pVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "3", + "summary": "Best BridgeHubWococo header at BridgeHubRococo (00000001) doesn't match the same header at BridgeHubWococo" + }, + "grafana_alert": { + "id": 61, + "orgId": 1, + "title": "BridgeHubWococo header mismatch (00000001)", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 73, + "uid": "1W6lb1p4z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "5", + "summary": "With-WococoBridgeHub messages relay balance at RococoBridgeHub (00000001) is too low" + }, + "grafana_alert": { + "id": 62, + "orgId": 1, + "title": "With-WococoBridgeHub messages relay balance at RococoBridgeHub (00000001) is too low", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "last_over_time(at_BridgeHubRococo_relay_BridgeHubWococoMessages_balance{domain=\"parity-testnet\"}[1h])", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Messages Relay Balance", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 72, + "uid": "Y5Dm-1tVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "6", + "summary": "With-RococoBridgeHub messages relay balance at WococoBridgeHub (00000001) is too low" + }, + "grafana_alert": { + "id": 63, + "orgId": 1, + "title": "With-RococoBridgeHub messages relay balance at WococoBridgeHub (00000001) is too low", + "condition": "B", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "last_over_time(at_BridgeHubWococo_relay_BridgeHubRococoMessages_balance{domain=\"parity-testnet\"}[1h])", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Messages Relay Balance", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 300, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 10 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "B", + "type": "classic_conditions" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 71, + "uid": "yUl4a1tVz", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "5m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "6", + "summary": "Less than 500 Rococo headers have been synced to WococoBridgeHub in last 120 minutes. Relay is not running?" + }, + "grafana_alert": { + "id": 65, + "orgId": 1, + "title": "Rococo -> WococoBridgeHub finality sync lags (00000001)", + "condition": "D", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "max(increase(Rococo_to_BridgeHubWococo_Sync_best_source_at_target_block_number{domain=\"parity-testnet\"}[120m]))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "At Rococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "last", + "refId": "C", + "type": "reduce" + } + }, + { + "refId": "D", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 500 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "D" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "C", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "D", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 40, + "uid": "R6GKwNA4z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "5m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "zqjpgXxnk", + "__panelId__": "2", + "summary": "Less than 500 Wococo headers have been synced to RococoBridgeHub in last 120 minutes. Relay is not running?" + }, + "grafana_alert": { + "id": 66, + "orgId": 1, + "title": "Wococo -> RococoBridgeHub finality sync lags (00000001)", + "condition": "D", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "max(increase(Wococo_to_BridgeHubRococo_Sync_best_source_at_target_block_number{domain=\"parity-testnet\"}[120m]))", + "interval": "", + "intervalMs": 30000, + "legendFormat": "At Wococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "last", + "refId": "C", + "type": "reduce" + } + }, + { + "refId": "D", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 500 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "D" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "C", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "D", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 38, + "uid": "rAM1QHAVk", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "0s", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "11", + "summary": "The RococoBridgeHub <> WococoBridgeHub relay (00000001) has been aborted by version guard - i.e. one of chains has been upgraded and relay wasn't redeployed" + }, + "grafana_alert": { + "id": 67, + "orgId": 1, + "title": "Version guard has aborted RococoBridgeHub <> WococoBridgeHub relay (00000001)", + "condition": "B", + "data": [ + { + "refId": "B", + "queryType": "range", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "P03E52D76DFE188C3", + "model": { + "datasource": { + "type": "loki", + "uid": "P03E52D76DFE188C3" + }, + "editorMode": "code", + "expr": "count_over_time({container=\"bridges-common-relay\"} |= `Aborting relay` [1m])", + "hide": false, + "intervalMs": 1000, + "legendFormat": "Aborts per minute", + "maxDataPoints": 43200, + "queryType": "range", + "refId": "B" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "max", + "refId": "C", + "type": "reduce" + } + }, + { + "refId": "D", + "queryType": "", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "D" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "C", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "D", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 37, + "uid": "TwWPeN04z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "12", + "summary": "Best Rococo header at BridgeHubWococo (00000001) doesn't match the same header at Rococo" + }, + "grafana_alert": { + "id": 69, + "orgId": 1, + "title": "Rococo headers mismatch", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Rococo_to_BridgeHubWococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "last", + "refId": "B", + "type": "reduce" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 32, + "uid": "08-5gv04k", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "10m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "13", + "summary": "Best Wococo header at BridgeHubRococo (00000001) doesn't match the same header at Wococo" + }, + "grafana_alert": { + "id": 70, + "orgId": 1, + "title": "Wococo headers mismatch", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Wococo_to_BridgeHubRococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "interval": "", + "intervalMs": 30000, + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "last", + "refId": "B", + "type": "reduce" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 31, + "uid": "Esj2gD0Vk", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "5m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "tkgc6_bnk", + "__panelId__": "9", + "summary": "Test messages from RococoBridgeHub to WococoBridgeHub are not generated. Our cronjob has died?" + }, + "grafana_alert": { + "id": 73, + "orgId": 1, + "title": "Test messages from RococoBridgeHub to WococoBridgeHub are not generated.", + "condition": "D", + "data": [ + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 21600, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "increase(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\", type=~\"source_latest_generated\"}[24h])", + "hide": true, + "interval": "", + "intervalMs": 30000, + "legendFormat": "Messages generated in last 24h", + "maxDataPoints": 43200, + "range": true, + "refId": "B" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "max", + "refId": "C", + "type": "reduce" + } + }, + { + "refId": "D", + "queryType": "", + "relativeTimeRange": { + "from": 600, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "D" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "C", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "D", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 3, + "uid": "ry1K5SB4k", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + }, + { + "expr": "", + "for": "5m", + "labels": { + "matrix_room": "XyVkmRJgIkjcvIBPsP" + }, + "annotations": { + "__dashboardUid__": "UFsgbJtVz", + "__panelId__": "16", + "summary": "RococoBridgeHub <> WococoBridgeHub relay (00000001) node is down" + }, + "grafana_alert": { + "id": 74, + "orgId": 1, + "title": "RococoBridgeHub <> WococoBridgeHub relay (00000001) node is down", + "condition": "C", + "data": [ + { + "refId": "A", + "queryType": "", + "relativeTimeRange": { + "from": 900, + "to": 0 + }, + "datasourceUid": "PC96415006F908B67", + "model": { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "up{domain=\"parity-testnet\",container=\"bridges-common-relay\"}", + "instant": false, + "interval": "", + "intervalMs": 30000, + "legendFormat": "Is relay running", + "maxDataPoints": 43200, + "range": true, + "refId": "A" + } + }, + { + "refId": "B", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "B" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "A", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "reducer": "max", + "refId": "B", + "type": "reduce" + } + }, + { + "refId": "C", + "queryType": "", + "relativeTimeRange": { + "from": 0, + "to": 0 + }, + "datasourceUid": "-100", + "model": { + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "datasource": { + "type": "__expr__", + "uid": "-100" + }, + "expression": "B", + "hide": false, + "intervalMs": 1000, + "maxDataPoints": 43200, + "refId": "C", + "type": "threshold" + } + } + ], + "updated": "2023-03-29T05:39:46Z", + "intervalSeconds": 60, + "version": 1, + "uid": "9YAdEUB4z", + "namespace_uid": "eblDiw17z", + "namespace_id": 140, + "rule_group": "Bridges", + "no_data_state": "OK", + "exec_err_state": "OK" + } + } + ] + } + ] + } diff --git a/deployments/bridges/rococo-wococo/dashboard/grafana/relay-rococo-to-wococo-messages-dashboard.json b/deployments/bridges/rococo-wococo/dashboard/grafana/relay-rococo-to-wococo-messages-dashboard.json new file mode 100644 index 00000000000..d1ecba2acfd --- /dev/null +++ b/deployments/bridges/rococo-wococo/dashboard/grafana/relay-rococo-to-wococo-messages-dashboard.json @@ -0,0 +1,941 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 141, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Rococo_to_BridgeHubWococo_Sync_best_source_block_number{domain=\"parity-testnet\"}", + "legendFormat": "At Rococo", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Rococo_to_BridgeHubWococo_Sync_best_source_at_target_block_number{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "At BridgeHubWococo", + "range": true, + "refId": "B" + } + ], + "title": "Best finalized Rococo headers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Wococo_to_BridgeHubRococo_Sync_best_source_block_number{domain=\"parity-testnet\"}", + "legendFormat": "At Wococo", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Wococo_to_BridgeHubRococo_Sync_best_source_at_target_block_number{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "At BridgeHubRococo", + "range": true, + "refId": "B" + } + ], + "title": "Best finalized Wococo headers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": true, + "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_best_source_block_number{domain=\"parity-testnet\"}", + "interval": "", + "legendFormat": "At RococoBridgeHub", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_best_source_at_target_block_number{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "At WococoBridgeHub", + "range": true, + "refId": "B" + } + ], + "title": "Best finalized RococoBridgeHub headers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": true, + "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_best_target_block_number{domain=\"parity-testnet\"}", + "interval": "", + "legendFormat": "At WococoBridgeHub", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_best_target_at_source_block_number{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "At RococoBridgeHub", + "range": true, + "refId": "B" + } + ], + "title": "Best finalized WococoBridgeHub headers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "label_replace(label_replace(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\", type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from BridgeHubRococo\", \"type\", \"source_latest_generated\"), \"type\", \"Latest BridgeHubRococo message received by BridgeHubWococo\", \"type\", \"target_latest_received\")", + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + } + ], + "title": "Delivery race (00000001)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "label_replace(label_replace(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest delivery confirmation from BridgeHubWococo to BridgeHubRococo\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest BridgeHubRococo message received by BridgeHubWococo\", \"type\", \"target_latest_received\")", + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + } + ], + "title": "Confirmations race (00000001)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_generated\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "legendFormat": "Undelivered messages", + "range": true, + "refId": "A" + } + ], + "title": "Delivery race lags (00000001)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(RococoBridgeHub_to_WococoBridgeHub_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(RococoBridgeHub_to_WococoBridgeHub_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "legendFormat": "Unconfirmed messages", + "range": true, + "refId": "A" + } + ], + "title": "Confirmations race lags (00000001)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 16 + }, + "id": 15, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))", + "legendFormat": "Unconfirmed rewards", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "(scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0) > bool min_over_time(BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Reward lags (00000001)", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "BridgeHubRococo to BridgeHubWococo (00000001)", + "uid": "tkgc6_bnk", + "version": 42, + "weekStart": "" + } \ No newline at end of file diff --git a/deployments/bridges/rococo-wococo/dashboard/grafana/relay-wococo-to-rococo-messages-dashboard.json b/deployments/bridges/rococo-wococo/dashboard/grafana/relay-wococo-to-rococo-messages-dashboard.json new file mode 100644 index 00000000000..be33f0dcecc --- /dev/null +++ b/deployments/bridges/rococo-wococo/dashboard/grafana/relay-wococo-to-rococo-messages-dashboard.json @@ -0,0 +1,941 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 142, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Wococo_to_BridgeHubRococo_Sync_best_source_block_number{domain=\"parity-testnet\"}", + "legendFormat": "At Wococo", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Wococo_to_BridgeHubRococo_Sync_best_source_at_target_block_number{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "At BridgeHubRococo", + "range": true, + "refId": "B" + } + ], + "title": "Best finalized Wococo headers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Rococo_to_BridgeHubWococo_Sync_best_source_block_number{domain=\"parity-testnet\"}", + "legendFormat": "At Rococo", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Rococo_to_BridgeHubWococo_Sync_best_source_at_target_block_number{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "At WococoBridgeHub", + "range": true, + "refId": "B" + } + ], + "title": "Best finalized Rococo headers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": true, + "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_best_source_block_number{domain=\"parity-testnet\"}", + "interval": "", + "legendFormat": "At WococoBridgeHub", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_best_source_at_target_block_number{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "At RococoBridgeHub", + "range": true, + "refId": "B" + } + ], + "title": "Best finalized WococoBridgeHub headers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": true, + "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_best_target_block_number{domain=\"parity-testnet\"}", + "interval": "", + "legendFormat": "At RococoBridgeHub", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_best_target_at_source_block_number{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "At WococoBridgeHub", + "range": true, + "refId": "B" + } + ], + "title": "Best finalized RococoBridgeHub headers", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "label_replace(label_replace(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=~\"source_latest_generated|target_latest_received\"}, \"type\", \"Latest message sent from BridgeHubWococo\", \"type\", \"source_latest_generated\"), \"type\", \"Latest BridgeHubWococo message received by BridgeHubRococo\", \"type\", \"target_latest_received\")", + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + } + ], + "title": "Delivery race (00000001)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "label_replace(label_replace(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=~\"source_latest_confirmed|target_latest_received\"}, \"type\", \"Latest delivery confirmation from BridgeHubRococo to BridgeHubWococo\", \"type\", \"source_latest_confirmed\"), \"type\", \"Latest BridgeHubWococo message received by BridgeHubRococo\", \"type\", \"target_latest_received\")", + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + } + ], + "title": "Confirmations race (00000001)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 16 + }, + "id": 14, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_generated\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "legendFormat": "Undelivered messages", + "range": true, + "refId": "A" + } + ], + "title": "Delivery race lags (00000001)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 16 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0))", + "legendFormat": "Unconfirmed messages", + "range": true, + "refId": "A" + } + ], + "title": "Confirmations race lags (00000001)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 16 + }, + "id": 18, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))", + "legendFormat": "Unconfirmed rewards", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "(scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"source_latest_confirmed\"}[2m]) OR on() vector(0)) - scalar(max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_confirmed\"}[2m]) OR on() vector(0))) * (max_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0) > bool min_over_time(BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_lane_state_nonces{domain=\"parity-testnet\",type=\"target_latest_received\"}[2m]) OR on() vector(0))", + "hide": true, + "legendFormat": "__auto", + "range": true, + "refId": "B" + } + ], + "title": "Reward lags (00000001)", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "BridgeHubWococo to BridgeHubRococo (00000001)", + "uid": "zqjpgXxnk", + "version": 30, + "weekStart": "" + } \ No newline at end of file diff --git a/deployments/bridges/rococo-wococo/dashboard/grafana/rococo-wococo-maintenance-dashboard.json b/deployments/bridges/rococo-wococo/dashboard/grafana/rococo-wococo-maintenance-dashboard.json new file mode 100644 index 00000000000..6158c3e73a9 --- /dev/null +++ b/deployments/bridges/rococo-wococo/dashboard/grafana/rococo-wococo-maintenance-dashboard.json @@ -0,0 +1,1031 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 284, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 5, + "x": 0, + "y": 0 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "name" + }, + "pluginVersion": "9.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "substrate_relay_build_info{domain=\"parity-testnet\"}", + "instant": true, + "legendFormat": "{{commit}}", + "range": false, + "refId": "A" + } + ], + "title": "Relay build commit", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 5, + "y": 0 + }, + "id": 9, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^1\\.0\\.1$/", + "values": false + }, + "text": {}, + "textMode": "name" + }, + "pluginVersion": "9.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "substrate_relay_build_info{domain=\"parity-testnet\"}", + "instant": true, + "legendFormat": "{{version}}", + "range": false, + "refId": "A" + } + ], + "title": "Relay build version", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { + "color": "red", + "index": 1, + "text": "No" + }, + "1": { + "color": "green", + "index": 0, + "text": "Yes" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 4, + "x": 9, + "y": 0 + }, + "id": 15, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "9.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "up{domain=\"parity-testnet\",container=\"bridges-common-relay\"}", + "instant": false, + "legendFormat": "Is relay running", + "range": true, + "refId": "A" + } + ], + "title": "Is relay running?", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 5, + "x": 13, + "y": 0 + }, + "id": 16, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.3.1", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "exemplar": false, + "expr": "up{domain=\"parity-testnet\",container=\"bridges-common-relay\"}", + "instant": false, + "legendFormat": "Is relay running", + "range": true, + "refId": "A" + } + ], + "title": "Is relay running? (for alert)", + "type": "timeseries" + }, + { + "datasource": { + "type": "loki", + "uid": "P03E52D76DFE188C3" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 18, + "x": 0, + "y": 5 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "loki", + "uid": "P03E52D76DFE188C3" + }, + "editorMode": "code", + "expr": "count_over_time({container=\"bridges-common-relay\"} |~ `(?i)(warn|error|fail)` [1m])", + "legendFormat": "Errors per minute", + "queryType": "range", + "refId": "A" + } + ], + "title": "Relay errors/warnings per minute", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 0, + "y": 14 + }, + "id": 12, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Rococo_to_BridgeHubWococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "range": true, + "refId": "A" + } + ], + "title": "Rococo headers mismatch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 9, + "y": 14 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "Wococo_to_BridgeHubRococo_Sync_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "range": true, + "refId": "A" + } + ], + "title": "Wococo headers mismatch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 0, + "y": 21 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubRococo_to_BridgeHubWococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "range": true, + "refId": "A" + } + ], + "title": "BridgeHubRococo headers mismatch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 9, + "x": 9, + "y": 21 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "BridgeHubWococo_to_BridgeHubRococo_MessageLane_00000001_is_source_and_source_at_target_using_different_forks{domain=\"parity-testnet\"}", + "legendFormat": "Best BridgeHubRococo header at BridgeHubWococo doesn't match the same header of BridgeHubRococo", + "range": true, + "refId": "A" + } + ], + "title": "BridgeHubWococo headers mismatch", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 0, + "y": 28 + }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "at_BridgeHubRococo_relay_BridgeHubWococoMessages_balance{domain=\"parity-testnet\"}", + "legendFormat": "Messages Relay Balance", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "at_BridgeHubRococo_relay_WococoHeaders_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"} + at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "Pending reward", + "range": true, + "refId": "B" + } + ], + "title": "Relay balances at RococoBridgeHub", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 9, + "y": 28 + }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "at_BridgeHubWococo_relay_BridgeHubRococoMessages_balance{domain=\"parity-testnet\"}", + "legendFormat": "Messages Relay Balance", + "range": true, + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "PC96415006F908B67" + }, + "editorMode": "code", + "expr": "at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_from_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"} + at_BridgeHubRococo_relay_BridgeHubWococoMessages_reward_for_msgs_to_BridgeHubWococo_on_lane_00000001{domain=\"parity-testnet\"}", + "hide": false, + "legendFormat": "Pending reward", + "range": true, + "refId": "B" + } + ], + "title": "Relay balances at WococoBridgeHub", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "BridgeHubRococo <> BridgeHubWococo maintenance (00000001)", + "uid": "UFsgbJtVz", + "version": 26, + "weekStart": "" +} diff --git a/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-headers-dashboard.json b/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-headers-dashboard.json new file mode 100644 index 00000000000..8f740d2ba5e --- /dev/null +++ b/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-headers-dashboard.json @@ -0,0 +1,781 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 32 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "60m", + "frequency": "5m", + "handler": 1, + "message": "", + "name": "Synced Header Difference is Over 32 (Westend to Millau)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "Shows how many headers behind the target chain is from the source chain.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max(Westend_to_Millau_Sync_best_source_block_number) - max(Westend_to_Millau_Sync_best_source_at_target_block_number)", + "format": "table", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 5 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Difference Between Source and Target Headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 32 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "2m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "60m", + "frequency": "5m", + "handler": 1, + "name": "No New Headers (Westend to Millau)", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "How many headers has the relay synced from the source node in the last 2 mins?", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "max_over_time(Westend_to_Millau_Sync_best_source_block_number[10m])-min_over_time(Westend_to_Millau_Sync_best_source_block_number[10m])", + "interval": "", + "legendFormat": "Number of new Headers on Westend (Last 10 Mins)", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 5 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Headers Synced on Millau (Last 2 Mins)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 2, + "interval": "5s", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "Westend_to_Millau_Sync_best_source_block_number", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Best Known Westend Header at Westend", + "refId": "A" + }, + { + "expr": "Westend_to_Millau_Sync_best_source_at_target_block_number", + "format": "time_series", + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Best Known Westend Header at Millau", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Best Blocks according to Relay", + "type": "stat" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 8 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "system_average_load{instance='relay-headers-westend-to-millau-1:9616'}", + "interval": "", + "legendFormat": "Average system load in last {{over}}", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": null + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average System Load", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 8 + }, + "id": 12, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "avg_over_time(process_cpu_usage_percentage{instance='relay-headers-westend-to-millau-1:9616'}[1m])", + "instant": true, + "interval": "", + "legendFormat": "1 CPU = 100", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Relay Process CPU Usage ", + "type": "gauge" + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Whether with-Westend-grandpa-pallet and Westend itself are on different forks alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Westend_to_Millau_Sync_is_source_and_source_at_target_using_different_forks", + "interval": "", + "legendFormat": "On different forks?", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Whether with-Westend-grandpa-pallet and Westend itself are on different forks", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_memory_usage_bytes{instance='relay-headers-westend-to-millau-1:9616'} / 1024 / 1024", + "interval": "", + "legendFormat": "Process memory, MB", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage for Relay Process", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Westend to Millau Header Sync Dashboard", + "uid": "relay-westend-to-millau-headers", + "version": 1 +} diff --git a/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-parachains-dashboard.json b/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-parachains-dashboard.json new file mode 100644 index 00000000000..31a7cca5229 --- /dev/null +++ b/deployments/bridges/westend-millau/dashboard/grafana/relay-westend-to-millau-parachains-dashboard.json @@ -0,0 +1,200 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 9, + "links": [], + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 32 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Too many Westmint headers are missing at Millau", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "Westend_to_Millau_Parachains_1000_best_parachain_block_number_at_source", + "interval": "", + "legendFormat": "At Westend", + "refId": "A" + }, + { + "expr": "Westend_to_Millau_Parachains_1000_best_parachain_block_number_at_target", + "interval": "", + "legendFormat": "At Millau", + "refId": "B" + }, + { + "expr": "Westend_to_Millau_Parachains_1000_best_parachain_block_number_at_source - Westend_to_Millau_Parachains_1000_best_parachain_block_number_at_target", + "hide": true, + "interval": "", + "legendFormat": "Missing Westmint headers at Millau", + "refId": "C" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 32 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Westmint headers", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Westend parachains at Millau", + "uid": "vUMhOlq7k", + "version": 1 + } + \ No newline at end of file diff --git a/deployments/bridges/westend-millau/dashboard/prometheus/targets.yml b/deployments/bridges/westend-millau/dashboard/prometheus/targets.yml new file mode 100644 index 00000000000..aed2d494582 --- /dev/null +++ b/deployments/bridges/westend-millau/dashboard/prometheus/targets.yml @@ -0,0 +1,3 @@ +- targets: + - relay-headers-westend-to-millau-1:9616 + - relay-parachains-westend-to-millau-1:9616 \ No newline at end of file diff --git a/deployments/bridges/westend-millau/docker-compose.yml b/deployments/bridges/westend-millau/docker-compose.yml new file mode 100644 index 00000000000..dfb6ebb0c64 --- /dev/null +++ b/deployments/bridges/westend-millau/docker-compose.yml @@ -0,0 +1,72 @@ +# Exposed ports: 10616, 10617, 10618, 10619 + +version: '3.5' +services: + relay-headers-westend-to-millau-1: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-headers-westend-to-millau-entrypoint.sh + volumes: + - ./bridges/westend-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + ports: + - "10616:9616" + depends_on: + - millau-node-alice + + relay-headers-westend-to-millau-2: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-headers-westend-to-millau-entrypoint.sh + volumes: + - ./bridges/westend-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + EXT_RELAY_ACCOUNT: //Westend.HeadersRelay2 + ports: + - "10617:9616" + depends_on: + - millau-node-alice + + relay-parachains-westend-to-millau-1: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-parachains-westend-to-millau-entrypoint.sh + volumes: + - ./bridges/westend-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + ports: + - "10618:9616" + depends_on: + - millau-node-alice + + relay-parachains-westend-to-millau-2: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/relay-parachains-westend-to-millau-entrypoint.sh + volumes: + - ./bridges/westend-millau/entrypoints:/entrypoints + environment: + RUST_LOG: rpc=trace,bridge=trace + EXT_RELAY_ACCOUNT: //Westend.WestmintHeaders2 + ports: + - "10619:9616" + depends_on: + - millau-node-alice + + # Note: These are being overridden from the top level `monitoring` compose file. + grafana-dashboard: + environment: + VIRTUAL_HOST: grafana.millau.brucke.link,grafana.rialto.brucke.link + VIRTUAL_PORT: 3000 + LETSENCRYPT_HOST: grafana.millau.brucke.link,grafana.rialto.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + volumes: + - ./bridges/westend-millau/dashboard/grafana:/etc/grafana/dashboards/westend-millau:ro + + prometheus-metrics: + volumes: + - ./bridges/westend-millau/dashboard/prometheus/targets.yml:/etc/prometheus/targets-westend-millau.yml + depends_on: + - relay-headers-westend-to-millau-1 + - relay-headers-westend-to-millau-2 + - relay-parachains-westend-to-millau-1 + - relay-parachains-westend-to-millau-2 diff --git a/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh b/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh new file mode 100755 index 00000000000..8548e9f5a41 --- /dev/null +++ b/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -xeu + +sleep 15 + +RELAY_ACCOUNT=${EXT_RELAY_ACCOUNT:-//Westend.HeadersRelay1} + +/home/user/substrate-relay init-bridge westend-to-millau \ + --source-host westend-rpc.polkadot.io \ + --source-port 443 \ + --source-secure \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer //Westend.GrandpaOwner + +# Give chain a little bit of time to process initialization transaction +sleep 6 +/home/user/substrate-relay relay-headers westend-to-millau \ + --source-host westend-rpc.polkadot.io \ + --source-port 443 \ + --source-secure \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer $RELAY_ACCOUNT \ + --target-transactions-mortality=4\ + --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/westend-millau/entrypoints/relay-parachains-westend-to-millau-entrypoint.sh b/deployments/bridges/westend-millau/entrypoints/relay-parachains-westend-to-millau-entrypoint.sh new file mode 100755 index 00000000000..fc7ccb3584f --- /dev/null +++ b/deployments/bridges/westend-millau/entrypoints/relay-parachains-westend-to-millau-entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -xeu + +sleep 15 + +RELAY_ACCOUNT=${EXT_RELAY_ACCOUNT:-//Westend.WestmintHeaders1} + +/home/user/substrate-relay relay-parachains westend-to-millau \ + --source-host westend-rpc.polkadot.io \ + --source-port 443 \ + --source-secure \ + --target-host millau-node-alice \ + --target-port 9944 \ + --target-signer $RELAY_ACCOUNT \ + --target-transactions-mortality=4\ + --prometheus-host=0.0.0.0 diff --git a/deployments/local-scripts/bridge-entrypoint.sh b/deployments/local-scripts/bridge-entrypoint.sh new file mode 100755 index 00000000000..5c1b6e90ec2 --- /dev/null +++ b/deployments/local-scripts/bridge-entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -xeu + +# This will allow us to run whichever binary the user wanted +# with arguments passed through `docker run` +# e.g `docker run -it rialto-bridge-node-dev --dev --tmp` +/home/user/$PROJECT $@ diff --git a/deployments/local-scripts/relay-messages-millau-to-rialto.sh b/deployments/local-scripts/relay-messages-millau-to-rialto.sh new file mode 100755 index 00000000000..d420dc56c26 --- /dev/null +++ b/deployments/local-scripts/relay-messages-millau-to-rialto.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# A script for relaying Millau messages to the Rialto chain. +# +# Will not work unless both the Rialto and Millau are running (see `run-rialto-node.sh` +# and `run-millau-node.sh). +set -xeu + +MILLAU_PORT="${MILLAU_PORT:-9945}" +RIALTO_PORT="${RIALTO_PORT:-9944}" + +RUST_LOG=bridge=debug \ +./target/debug/substrate-relay relay-messages millau-to-rialto \ + --lane 00000000 \ + --source-host localhost \ + --source-port $MILLAU_PORT \ + --source-signer //Bob \ + --target-host localhost \ + --target-port $RIALTO_PORT \ + --target-signer //Bob \ + --prometheus-host=0.0.0.0 diff --git a/deployments/local-scripts/relay-messages-rialto-to-millau.sh b/deployments/local-scripts/relay-messages-rialto-to-millau.sh new file mode 100755 index 00000000000..0cd73c00454 --- /dev/null +++ b/deployments/local-scripts/relay-messages-rialto-to-millau.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# A script for relaying Rialto messages to the Millau chain. +# +# Will not work unless both the Rialto and Millau are running (see `run-rialto-node.sh` +# and `run-millau-node.sh). +set -xeu + +MILLAU_PORT="${MILLAU_PORT:-9945}" +RIALTO_PORT="${RIALTO_PORT:-9944}" + +RUST_LOG=bridge=debug \ +./target/debug/substrate-relay relay-messages rialto-to-millau \ + --lane 00000000 \ + --source-host localhost \ + --source-port $RIALTO_PORT \ + --source-signer //Bob \ + --target-host localhost \ + --target-port $MILLAU_PORT \ + --target-signer //Bob \ + --prometheus-host=0.0.0.0 diff --git a/deployments/local-scripts/relay-millau-to-rialto.sh b/deployments/local-scripts/relay-millau-to-rialto.sh new file mode 100755 index 00000000000..4758173f72f --- /dev/null +++ b/deployments/local-scripts/relay-millau-to-rialto.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# A script for relaying Millau headers to the Rialto chain. +# +# Will not work unless both the Rialto and Millau are running (see `run-rialto-node.sh` +# and `run-millau-node.sh). + +MILLAU_PORT="${MILLAU_PORT:-9945}" +RIALTO_PORT="${RIALTO_PORT:-9944}" + +RUST_LOG=bridge=debug \ +./target/debug/substrate-relay init-bridge millau-to-rialto \ + --source-host localhost \ + --source-port $MILLAU_PORT \ + --target-host localhost \ + --target-port $RIALTO_PORT \ + --target-signer //Sudo \ + --source-version-mode Bundle \ + --target-version-mode Bundle + +sleep 5 +RUST_LOG=bridge=debug \ +./target/debug/substrate-relay relay-headers millau-to-rialto \ + --source-host localhost \ + --source-port $MILLAU_PORT \ + --target-host localhost \ + --target-port $RIALTO_PORT \ + --target-signer //Alice \ + --prometheus-host=0.0.0.0 diff --git a/deployments/local-scripts/relay-rialto-to-millau.sh b/deployments/local-scripts/relay-rialto-to-millau.sh new file mode 100755 index 00000000000..5fd27840214 --- /dev/null +++ b/deployments/local-scripts/relay-rialto-to-millau.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# A script for relaying Rialto headers to the Millau chain. +# +# Will not work unless both the Rialto and Millau are running (see `run-rialto-node.sh` +# and `run-millau-node.sh). + +MILLAU_PORT="${MILLAU_PORT:-9945}" +RIALTO_PORT="${RIALTO_PORT:-9944}" + +RUST_LOG=bridge=debug \ +./target/debug/substrate-relay init-bridge rialto-to-millau \ + --target-host localhost \ + --target-port $MILLAU_PORT \ + --source-host localhost \ + --source-port $RIALTO_PORT \ + --target-signer //Sudo \ + +sleep 5 +RUST_LOG=bridge=debug \ +./target/debug/substrate-relay relay-headers rialto-to-millau \ + --target-host localhost \ + --target-port $MILLAU_PORT \ + --source-host localhost \ + --source-port $RIALTO_PORT \ + --target-signer //Alice \ + --prometheus-host=0.0.0.0 diff --git a/deployments/local-scripts/run-millau-node.sh b/deployments/local-scripts/run-millau-node.sh new file mode 100755 index 00000000000..916f876c536 --- /dev/null +++ b/deployments/local-scripts/run-millau-node.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Run a development instance of the Millau Substrate bridge node. +# To override the default port just export MILLAU_PORT=9945 + +MILLAU_PORT="${MILLAU_PORT:-9945}" + +RUST_LOG=runtime=trace \ +./target/debug/millau-bridge-node --dev --tmp \ + --rpc-cors=all --unsafe-rpc-external --unsafe-ws-external \ + --port 33044 --rpc-port 9934 --ws-port $MILLAU_PORT \ diff --git a/deployments/local-scripts/run-rialto-node.sh b/deployments/local-scripts/run-rialto-node.sh new file mode 100755 index 00000000000..e7987e2af36 --- /dev/null +++ b/deployments/local-scripts/run-rialto-node.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Run a development instance of the Rialto Substrate bridge node. +# To override the default port just export RIALTO_PORT=9944 + +RIALTO_PORT="${RIALTO_PORT:-9944}" + +RUST_LOG=runtime=trace \ + ./target/debug/rialto-bridge-node --dev --tmp \ + --rpc-cors=all --unsafe-rpc-external --unsafe-ws-external \ + --port 33033 --rpc-port 9933 --ws-port $RIALTO_PORT \ diff --git a/deployments/local-scripts/run-westend-node.sh b/deployments/local-scripts/run-westend-node.sh new file mode 100755 index 00000000000..1bb490fc1a8 --- /dev/null +++ b/deployments/local-scripts/run-westend-node.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Run a development instance of the Westend Substrate bridge node. +# To override the default port just export WESTEND_PORT=9945 +# +# Note: This script will not work out of the box with the bridges +# repo since it relies on a Polkadot binary. + +WESTEND_PORT="${WESTEND_PORT:-9944}" + +RUST_LOG=runtime=trace,runtime::bridge=trace \ +./target/debug/polkadot --chain=westend-dev --alice --tmp \ + --rpc-cors=all --unsafe-rpc-external --unsafe-ws-external \ + --port 33033 --rpc-port 9933 --ws-port $WESTEND_PORT \ diff --git a/deployments/monitoring/GrafanaMatrix.Dockerfile b/deployments/monitoring/GrafanaMatrix.Dockerfile new file mode 100644 index 00000000000..be1c80d4059 --- /dev/null +++ b/deployments/monitoring/GrafanaMatrix.Dockerfile @@ -0,0 +1,15 @@ +FROM ruby:alpine3.13 + +RUN apk add --no-cache git + +ENV APP_HOME /app +ENV RACK_ENV production +RUN mkdir $APP_HOME +WORKDIR $APP_HOME + +RUN git clone https://github.com/ananace/ruby-grafana-matrix.git $APP_HOME +RUN bundle install --without development + +RUN mkdir /config && touch /config/config.yml && ln -s /config/config.yml ./config.yml + +CMD ["bundle", "exec", "rackup", "-p4567"] diff --git a/deployments/monitoring/disabled.yml b/deployments/monitoring/disabled.yml new file mode 100644 index 00000000000..a0b4ed3aad0 --- /dev/null +++ b/deployments/monitoring/disabled.yml @@ -0,0 +1,15 @@ +# A disabled version of monitoring. +# +# We replace each service with a no-op container. We can't simply not include this file, +# cause the bridge-specific compose files might have overrides. +version: '3.5' +services: + prometheus-metrics: + image: alpine + + grafana-dashboard: + image: alpine + + grafana-matrix-notifier: + image: alpine + diff --git a/deployments/monitoring/docker-compose.yml b/deployments/monitoring/docker-compose.yml new file mode 100644 index 00000000000..4f7d958da4a --- /dev/null +++ b/deployments/monitoring/docker-compose.yml @@ -0,0 +1,36 @@ +version: '3.5' +services: + prometheus-metrics: + image: prom/prometheus:v2.38.0 + volumes: + - ./monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml + ports: + - "9090:9090" + + grafana-dashboard: + image: grafana/grafana:8.2.6 + environment: + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASS:-admin} + GF_SERVER_ROOT_URL: ${GRAFANA_SERVER_ROOT_URL} + GF_SERVER_DOMAIN: ${GRAFANA_SERVER_DOMAIN} + volumes: + - ./monitoring/grafana/provisioning/:/etc/grafana/provisioning/:ro + - ./monitoring/grafana/dashboards/:/etc/grafana/dashboards/common:ro + ports: + - "3000:3000" + depends_on: + - prometheus-metrics + # SIGTERM won't work because of our custom entrypoint. Should be ok to use SIGKILL. + stop_signal: SIGKILL + entrypoint: sh -c "${NO_GRAFANA_STARTUP_DELAY:-echo 'sleeping for 10m' && sleep 600} && /run.sh" + + grafana-matrix-notifier: + build: + context: . + dockerfile: ./monitoring/GrafanaMatrix.Dockerfile + volumes: + - ./monitoring/grafana-matrix:/config + ports: + - "4567:4567" + depends_on: + - grafana-dashboard diff --git a/deployments/monitoring/grafana-matrix/config.yml b/deployments/monitoring/grafana-matrix/config.yml new file mode 100644 index 00000000000..123cf76a80b --- /dev/null +++ b/deployments/monitoring/grafana-matrix/config.yml @@ -0,0 +1,47 @@ +--- +# Webhook server configuration +# Or use the launch options `-o '::' -p 4567` + +# Set up your HS connections +matrix: +- name: matrix-parity-io + url: https://matrix.parity.io + # Create a user - log that user in using a post request + # curl -XPOST -d '{"type": "m.login.password", + # "user":"grafana", + # "password":"dummy-password"}' + # "https://my-matrix-server/_matrix/client/r0/login" + # Fill that access token in here + access_token: "" + #device_id: # Optional + +# The default message type for messages, should be either m.text or m.notice, +# defaults to m.text +msgtype: m.text + +# Set up notification ingress rules +rules: +- name: bridge # Name of the rule + room: "#bridges-rialto-millau-alerts:matrix.parity.io" # Room or ID + matrix: matrix-parity-io # The Matrix HS to use - defaults to first one + msgtype: m.notice + # The following values are optional: + image: true # Attach image to the notification? + embed_image: true # Upload and embed the image into the message? + #templates: + # Templates to use when rendering the notification, available placeholders: + # %TEMPLATES% - lib/grafana_matrix/templates + # $ - Environment variables + #html: "%TEMPLATES%/html.erb" # Path to HTML template + #plain: "%TEMPLATES%/plain.erb" # Path to plaintext template + #auth: + #user: example + #pass: any HTTP encodable string +#- name: other-hq +# room: "#hq:private.matrix.org +# matrix: matrix-priv + +# To use the webhook, you need to configure it into Grafana as: +# +# Url: http://:/hook?rule= +# Http Method: POST diff --git a/deployments/monitoring/grafana/dashboards/nodes.json b/deployments/monitoring/grafana/dashboards/nodes.json new file mode 100644 index 00000000000..db14c3cf1fa --- /dev/null +++ b/deployments/monitoring/grafana/dashboards/nodes.json @@ -0,0 +1,200 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "description": "Running nodes", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "15m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "min" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "3m", + "frequency": "1m", + "handler": 1, + "name": "Nodes are not running", + "noDataState": "alerting", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "interval": null, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "maxDataPoints": null, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "up", + "format": "time_series", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Running nodes", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:111", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:112", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "", + "schemaVersion": 32, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Running nodes", + "uid": "DHl-xSW4z", + "version": 1 +} diff --git a/deployments/monitoring/grafana/provisioning/dashboards/grafana-dashboard.yaml b/deployments/monitoring/grafana/provisioning/dashboards/grafana-dashboard.yaml new file mode 100644 index 00000000000..d14ed2637d5 --- /dev/null +++ b/deployments/monitoring/grafana/provisioning/dashboards/grafana-dashboard.yaml @@ -0,0 +1,6 @@ +- name: 'default' + orgId: 1 + folder: '' + type: file + options: + path: '/etc/grafana/dashboards' \ No newline at end of file diff --git a/deployments/monitoring/grafana/provisioning/datasources/grafana-datasource.yaml b/deployments/monitoring/grafana/provisioning/datasources/grafana-datasource.yaml new file mode 100644 index 00000000000..b85cf06e2bd --- /dev/null +++ b/deployments/monitoring/grafana/provisioning/datasources/grafana-datasource.yaml @@ -0,0 +1,16 @@ +# list of datasources to insert/update depending +# whats available in the database +datasources: + # name of the datasource. Required +- name: Prometheus + # datasource type. Required + type: prometheus + # access mode. direct or proxy. Required + access: proxy + # org id. will default to orgId 1 if not specified + orgId: 1 + # url + url: http://prometheus-metrics:9090 + # mark as default datasource. Max one per org + isDefault: true + version: 1 diff --git a/deployments/monitoring/grafana/provisioning/notifiers/grafana-notifier.yaml b/deployments/monitoring/grafana/provisioning/notifiers/grafana-notifier.yaml new file mode 100644 index 00000000000..4eb6ea3863e --- /dev/null +++ b/deployments/monitoring/grafana/provisioning/notifiers/grafana-notifier.yaml @@ -0,0 +1,15 @@ +notifiers: + - name: Matrix + type: webhook + uid: notifier1 + is_default: true + send_reminder: true + frequency: 1h + disable_resolve_message: false + settings: + url: http://grafana-matrix-notifier:4567/hook?rule=bridge + http_method: POST + +delete_notifiers: + - name: Matrix + uid: notifier1 diff --git a/deployments/monitoring/prometheus/prometheus.yml b/deployments/monitoring/prometheus/prometheus.yml new file mode 100644 index 00000000000..7092bd27314 --- /dev/null +++ b/deployments/monitoring/prometheus/prometheus.yml @@ -0,0 +1,7 @@ +global: + scrape_interval: 15s +scrape_configs: + - job_name: dummy + file_sd_configs: + - files: + - /etc/prometheus/targets-*.yml diff --git a/deployments/networks/dashboard/grafana/beefy-dashboard.json b/deployments/networks/dashboard/grafana/beefy-dashboard.json new file mode 100644 index 00000000000..2e1e177641a --- /dev/null +++ b/deployments/networks/dashboard/grafana/beefy-dashboard.json @@ -0,0 +1,500 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "D", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Beefy best blocks not advancing", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 14, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "substrate_beefy_best_block{chain=\"rialto_local\"}", + "interval": "", + "legendFormat": "", + "refId": "A" + }, + { + "exemplar": true, + "expr": "substrate_beefy_best_block{chain=\"millau_local\"}", + "hide": false, + "interval": "", + "legendFormat": "", + "refId": "B" + }, + { + "exemplar": true, + "expr": "increase(substrate_beefy_best_block{chain=\"millau_local\"}[5m])", + "hide": true, + "interval": "", + "legendFormat": "Millau Best Beefy blocks count in last 5 minutes", + "refId": "C" + }, + { + "exemplar": true, + "expr": "increase(substrate_beefy_best_block{chain=\"rialto_local\"}[5m])", + "hide": true, + "interval": "", + "legendFormat": "Rialto Best Beefy blocks count in last 5 minutes", + "refId": "D" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Beefy Best block", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Beefy Lagging Sessions alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 14, + "w": 6, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "substrate_beefy_lagging_sessions{chain=\"rialto_local\"}", + "interval": "", + "legendFormat": "", + "refId": "A" + }, + { + "exemplar": true, + "expr": "substrate_beefy_lagging_sessions{chain=\"millau_local\"}", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0, + "visible": true + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Beefy Lagging Sessions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 12, + "w": 18, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.2.6", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "substrate_beefy_votes_sent{chain=\"rialto_local\"}", + "interval": "", + "legendFormat": "", + "refId": "A" + }, + { + "exemplar": true, + "expr": "substrate_beefy_votes_sent{chain=\"millau_local\"}", + "interval": "", + "legendFormat": "", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Beefy Votes Sent", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 32, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Beefy", + "uid": "j6cRDRh7z", + "version": 1 +} diff --git a/deployments/networks/dashboard/prometheus/millau-targets.yml b/deployments/networks/dashboard/prometheus/millau-targets.yml new file mode 100644 index 00000000000..5890c8fb3fd --- /dev/null +++ b/deployments/networks/dashboard/prometheus/millau-targets.yml @@ -0,0 +1,6 @@ +- targets: + - millau-node-alice:9615 + - millau-node-bob:9615 + - millau-node-charlie:9615 + - millau-node-dave:9615 + - millau-node-eve:9615 diff --git a/deployments/networks/dashboard/prometheus/rialto-targets.yml b/deployments/networks/dashboard/prometheus/rialto-targets.yml new file mode 100644 index 00000000000..0c89926e8c3 --- /dev/null +++ b/deployments/networks/dashboard/prometheus/rialto-targets.yml @@ -0,0 +1,6 @@ +- targets: + - rialto-node-alice:9615 + - rialto-node-bob:9615 + - rialto-node-charlie:9615 + - rialto-node-dave:9615 + - rialto-node-eve:9615 diff --git a/deployments/networks/entrypoints/rialto-chainspec-exporter-entrypoint.sh b/deployments/networks/entrypoints/rialto-chainspec-exporter-entrypoint.sh new file mode 100755 index 00000000000..eac2a80de87 --- /dev/null +++ b/deployments/networks/entrypoints/rialto-chainspec-exporter-entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -xeu + +trap "echo Exiting... TERM; exit $?" TERM + +/home/user/rialto-bridge-node build-spec \ + --chain local \ + --raw \ + --disable-default-bootnode \ + > /rialto-share/rialto-relaychain-spec-raw.json + +# we're using local driver + tmpfs for shared `/rialto-share` volume, which is populated +# by the container running this script. If this script ends, the volume will be detached +# and our chain spec will be lost when it'll go online again. Hence the never-ending +# script which keeps volume online until container is stopped. +tail -f /dev/null & wait $! diff --git a/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh b/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh new file mode 100755 index 00000000000..1c33dd00841 --- /dev/null +++ b/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -xeu + +sleep 15 + +exec /home/user/substrate-relay register-parachain rialto-parachain \ + --parachain-host rialto-parachain-collator-alice \ + --parachain-port 9944 \ + --relaychain-host rialto-node-alice \ + --relaychain-port 9944 \ + --relaychain-signer //Sudo diff --git a/deployments/networks/millau.yml b/deployments/networks/millau.yml new file mode 100644 index 00000000000..d91c5d83286 --- /dev/null +++ b/deployments/networks/millau.yml @@ -0,0 +1,113 @@ +# Compose file for quickly spinning up a local instance of the Millau Substrate network. +# +# Note that the Millau network is only used for testing, so the configuration settings you see here +# are *not* recommended for a production environment. +# +# For example, do *not* keep your `node-key` in version control, and unless you're _really_ sure you +# want to provide public access to your nodes do *not* publicly expose RPC methods. +version: '3.5' +services: + millau-node-alice: &millau-bridge-node + image: ${MILLAU_BRIDGE_NODE_IMAGE:-paritytech/millau-bridge-node} + entrypoint: + - /home/user/millau-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/millau-node-bob/tcp/30333/p2p/12D3KooWM5LFR5ne4yTQ4sBSXJ75M4bDo2MAhAW2GhL3i8fe5aRb + - --alice + - --node-key=0f900c89f4e626f4a217302ab8c7d213737d00627115f318ad6fb169717ac8e0 + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + environment: + RUST_LOG: runtime=trace,rpc=debug,txpool=trace,runtime::bridge=trace,sc_basic_authorship=trace,beefy=trace,xcm=trace + ports: + - "19933:9933" + - "19944:9944" + - "19615:9615" + + millau-node-bob: + <<: *millau-bridge-node + entrypoint: + - /home/user/millau-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/millau-node-alice/tcp/30333/p2p/12D3KooWFqiV73ipQ1jpfVmCfLqBCp8G9PLH3zPkY9EhmdrSGA4H + - --bob + - --node-key=db383639ff2905d79f8e936fd5dc4416ef46b514b2f83823ec3c42753d7557bb + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + ports: + - "20033:9933" + - "20044:9944" + - "20015:9615" + + millau-node-charlie: + <<: *millau-bridge-node + entrypoint: + - /home/user/millau-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/millau-node-alice/tcp/30333/p2p/12D3KooWFqiV73ipQ1jpfVmCfLqBCp8G9PLH3zPkY9EhmdrSGA4H + - --charlie + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + ports: + - "20133:9933" + - "20144:9944" + - "20115:9615" + + millau-node-dave: + <<: *millau-bridge-node + entrypoint: + - /home/user/millau-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/millau-node-alice/tcp/30333/p2p/12D3KooWFqiV73ipQ1jpfVmCfLqBCp8G9PLH3zPkY9EhmdrSGA4H + - --dave + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + ports: + - "20233:9933" + - "20244:9944" + - "20215:9615" + + millau-node-eve: + <<: *millau-bridge-node + entrypoint: + - /home/user/millau-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/millau-node-alice/tcp/30333/p2p/12D3KooWFqiV73ipQ1jpfVmCfLqBCp8G9PLH3zPkY9EhmdrSGA4H + - --eve + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + ports: + - "20333:9933" + - "20344:9944" + - "20315:9615" + + # Note: These are being overridden from the top level `monitoring` compose file. + prometheus-metrics: + volumes: + - ./networks/dashboard/prometheus/millau-targets.yml:/etc/prometheus/targets-millau-nodes.yml + depends_on: + - millau-node-alice + - millau-node-bob + - millau-node-charlie + - millau-node-dave + - millau-node-eve diff --git a/deployments/networks/rialto-parachain.yml b/deployments/networks/rialto-parachain.yml new file mode 100644 index 00000000000..89724183148 --- /dev/null +++ b/deployments/networks/rialto-parachain.yml @@ -0,0 +1,90 @@ +# Compose file for quickly spinning up a local instance of the Rialto Parachain network. +# +# Since Rialto Parachain is unusable without Rialto, this file depends on some Rialto +# network nodes. +version: '3.5' +services: + rialto-parachain-collator-alice: &rialto-parachain-collator + image: ${RIALTO_PARACHAIN_COLLATOR_IMAGE:-paritytech/rialto-parachain-collator} + entrypoint: > + /home/user/rialto-parachain-collator + --alice + --collator + --force-authoring + --parachain-id 2000 + --rpc-port 9933 + --ws-port 9944 + --rpc-cors=all + --unsafe-rpc-external + --unsafe-ws-external + -- + --execution wasm + --chain /rialto-share/rialto-relaychain-spec-raw.json + --rpc-port 9934 + --ws-port 9945 + volumes: + - rialto-share:/rialto-share:z + environment: + RUST_LOG: runtime=trace,rpc=trace,txpool=trace,parachain=trace,parity_ws=trace,sc_basic_authorship=trace,xcm=trace + depends_on: + - rialto-chainspec-exporter + ports: + - "20433:9933" + - "20444:9944" + + rialto-parachain-collator-bob: + <<: *rialto-parachain-collator + entrypoint: > + /home/user/rialto-parachain-collator + --bob + --collator + --force-authoring + --parachain-id 2000 + --rpc-port 9933 + --ws-port 9944 + --rpc-cors=all + --unsafe-rpc-external + --unsafe-ws-external + -- + --execution wasm + --chain /rialto-share/rialto-relaychain-spec-raw.json + --rpc-port 9934 + --ws-port 9945 + ports: + - "20533:9933" + - "20544:9944" + + rialto-parachain-collator-charlie: + <<: *rialto-parachain-collator + entrypoint: > + /home/user/rialto-parachain-collator + --charlie + --collator + --force-authoring + --parachain-id 2000 + --rpc-port 9933 + --ws-port 9944 + --rpc-cors=all + --unsafe-rpc-external + --unsafe-ws-external + -- + --execution wasm + --chain /rialto-share/rialto-relaychain-spec-raw.json + --rpc-port 9934 + --ws-port 9945 + ports: + - "20633:9933" + - "20644:9944" + + rialto-parachain-registrar: + image: ${SUBSTRATE_RELAY_IMAGE:-paritytech/substrate-relay} + entrypoint: /entrypoints/rialto-parachain-registrar-entrypoint.sh + volumes: + - ./networks/entrypoints:/entrypoints + - rialto-share:/rialto-share:z + environment: + RUST_LOG: bridge=trace + depends_on: + - rialto-node-alice + - rialto-parachain-collator-alice + diff --git a/deployments/networks/rialto.yml b/deployments/networks/rialto.yml new file mode 100644 index 00000000000..fab85b89c04 --- /dev/null +++ b/deployments/networks/rialto.yml @@ -0,0 +1,130 @@ +# Compose file for quickly spinning up a local instance of the Rialto Substrate network. +# +# Note that the Rialto network is only used for testing, so the configuration settings you see here +# are *not* recommended for a production environment. +# +# For example, do *not* keep your `node-key` in version control, and unless you're _really_ sure you +# want to provide public access to your nodes do *not* publicly expose RPC methods. +version: '3.5' +services: + rialto-node-alice: &rialto-bridge-node + image: ${RIALTO_BRIDGE_NODE_IMAGE:-paritytech/rialto-bridge-node} + entrypoint: + - /home/user/rialto-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/rialto-node-bob/tcp/30333/p2p/12D3KooWSEpHJj29HEzgPFcRYVc5X3sEuP3KgiUoqJNCet51NiMX + - --alice + - --node-key=79cf382988364291a7968ae7825c01f68c50d679796a8983237d07fe0ccf363b + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + environment: + RUST_LOG: runtime=trace,rpc=debug,txpool=trace,runtime::bridge=trace,beefy=trace,xcm=trace + ports: + - "9933:9933" + - "9944:9944" + - "9915:9615" + + rialto-node-bob: + <<: *rialto-bridge-node + entrypoint: + - /home/user/rialto-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/rialto-node-alice/tcp/30333/p2p/12D3KooWMF6JvV319a7kJn5pqkKbhR3fcM2cvK5vCbYZHeQhYzFE + - --bob + - --node-key=4f9d0146dd9b7b3bf5a8089e3880023d1df92057f89e96e07bb4d8c2ead75bbd + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + ports: + - "10033:9933" + - "10044:9944" + - "10015:9615" + + rialto-node-charlie: + <<: *rialto-bridge-node + entrypoint: + - /home/user/rialto-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/rialto-node-alice/tcp/30333/p2p/12D3KooWMF6JvV319a7kJn5pqkKbhR3fcM2cvK5vCbYZHeQhYzFE + - --charlie + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + ports: + - "10133:9933" + - "10144:9944" + - "10115:9615" + + rialto-node-dave: + <<: *rialto-bridge-node + entrypoint: + - /home/user/rialto-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/rialto-node-alice/tcp/30333/p2p/12D3KooWMF6JvV319a7kJn5pqkKbhR3fcM2cvK5vCbYZHeQhYzFE + - --dave + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + ports: + - "10233:9933" + - "10244:9944" + - "10215:9615" + + rialto-node-eve: + <<: *rialto-bridge-node + entrypoint: + - /home/user/rialto-bridge-node + - --execution=Native + - --chain=local + - --bootnodes=/dns4/rialto-node-alice/tcp/30333/p2p/12D3KooWMF6JvV319a7kJn5pqkKbhR3fcM2cvK5vCbYZHeQhYzFE + - --eve + - --rpc-cors=all + - --enable-offchain-indexing=true + - --unsafe-rpc-external + - --unsafe-ws-external + - --prometheus-external + ports: + - "10333:9933" + - "10344:9944" + - "10315:9615" + + rialto-chainspec-exporter: + image: ${RIALTO_BRIDGE_NODE_IMAGE:-paritytech/rialto-bridge-node} + entrypoint: /entrypoints/rialto-chainspec-exporter-entrypoint.sh + volumes: + - ./networks/entrypoints:/entrypoints + - rialto-share:/rialto-share:z + + # Note: These are being overridden from the top level `monitoring` compose file. + prometheus-metrics: + volumes: + - ./networks/dashboard/prometheus/rialto-targets.yml:/etc/prometheus/targets-rialto-nodes.yml + depends_on: + - rialto-node-alice + - rialto-node-bob + - rialto-node-charlie + - rialto-node-dave + - rialto-node-eve + +# we're using `/rialto-share` to expose Rialto chain spec to those who are interested. Right +# now it is Rialto Parachain collator nodes. Local + tmpfs combination allows sharing writable +# in-memory volumes, which are dropped when containers are stopped. +volumes: + rialto-share: + driver: local + driver_opts: + type: "tmpfs" + device: "tmpfs" diff --git a/deployments/reverse-proxy/README.md b/deployments/reverse-proxy/README.md new file mode 100644 index 00000000000..ded81f80a1b --- /dev/null +++ b/deployments/reverse-proxy/README.md @@ -0,0 +1,15 @@ +# nginx-proxy + +This is a nginx reverse proxy configuration with Let's encrypt companion. +Main purpose is to be able to use `https://polkadot.js.org/apps` to connect to +a running network. + +## How to? + +In current directory: +```bash +docker-compose up -d +``` + +Then start `rialto` network with the same command (one folder up). `nginx` should +pick up new containers being created and automatically create a proxy setup for `Charlie`. diff --git a/deployments/reverse-proxy/docker-compose.yml b/deployments/reverse-proxy/docker-compose.yml new file mode 100644 index 00000000000..ee49e96afdd --- /dev/null +++ b/deployments/reverse-proxy/docker-compose.yml @@ -0,0 +1,45 @@ +version: '2' +services: + nginx-proxy: + image: jwilder/nginx-proxy + container_name: nginx-proxy + networks: + - nginx-proxy + - deployments_default + ports: + - "80:80" + - "443:443" + volumes: + - conf:/etc/nginx/conf.d + - vhost:/etc/nginx/vhost.d + - html:/usr/share/nginx/html + - dhparam:/etc/nginx/dhparam + - certs:/etc/nginx/certs:ro + - /var/run/docker.sock:/tmp/docker.sock:ro + - acme:/etc/acme.sh + + letsencrypt: + image: jrcs/letsencrypt-nginx-proxy-companion + container_name: nginx-proxy-le + networks: + - nginx-proxy + volumes_from: + - nginx-proxy + volumes: + - certs:/etc/nginx/certs:rw + - /var/run/docker.sock:/var/run/docker.sock:ro + - acme:/etc/acme.sh + +volumes: + conf: + vhost: + html: + dhparam: + certs: + acme: + +networks: + nginx-proxy: + driver: bridge + deployments_default: + external: true diff --git a/deployments/run.sh b/deployments/run.sh new file mode 100755 index 00000000000..a2a1900c1f0 --- /dev/null +++ b/deployments/run.sh @@ -0,0 +1,217 @@ +#!/bin/bash + +# Script used for running and updating bridge deployments. +# +# To deploy a network you can run this script with the name of the bridge (or multiple bridges) you want to run. +# +# `./run.sh westend-millau rialto-millau` +# +# To update a deployment to use the latest images available from the Docker Hub add the `update` +# argument after the bridge name. +# +# `./run.sh rialto-millau update` +# +# Once you've stopped having fun with your deployment you can take it down with: +# +# `./run.sh rialto-millau stop` +# +# Stopping the bridge will also bring down all networks that it uses. So if you have started multiple bridges +# that are using the same network (like Millau in rialto-millau and westend-millau bridges), then stopping one +# of these bridges will cause the other bridge to break. + +set -xeu + +# Since the Compose commands are using relative paths we need to `cd` into the `deployments` folder. +cd "$( dirname "${BASH_SOURCE[0]}" )" + +function show_help () { + set +x + echo " " + echo Error: $1 + echo " " + echo "Usage:" + echo " ./run.sh rialto-millau [stop|update] Run Rialto <> Millau Networks & Bridge" + echo " ./run.sh rialto-parachain-millau [stop|update] Run RialtoParachain <> Millau Networks & Bridge" + echo " ./run.sh westend-millau [stop|update] Run Westend -> Millau Networks & Bridge" + echo " ./run.sh everything|all [stop|update] Run all available Networks & Bridges" + echo " " + echo "Options:" + echo " --no-monitoring Disable monitoring" + echo " --no-ui Disable UI" + echo " --local Use prebuilt local images when starting relay and nodes" + echo " --local-substrate-relay Use prebuilt local/substrate-realy image when starting relay" + echo " --local-rialto Use prebuilt local/rialto-bridge-node image when starting nodes" + echo " --local-rialto-parachain Use prebuilt local/rialto-parachain-collator image when starting nodes" + echo " --local-millau Use prebuilt local/millau-bridge-node image when starting nodes" + echo " --no-grafana-startup-delay Start Grafana without any delay (you may see some false alerts during startup)" + echo " " + echo "You can start multiple bridges at once by passing several bridge names:" + echo " ./run.sh rialto-millau rialto-parachain-millau westend-millau [stop|update]" + exit 1 +} + +RIALTO=' -f ./networks/rialto.yml' +RIALTO_PARACHAIN=' -f ./networks/rialto-parachain.yml' +MILLAU=' -f ./networks/millau.yml' + +RIALTO_MILLAU='rialto-millau' +RIALTO_PARACHAIN_MILLAU='rialto-parachain-millau' +WESTEND_MILLAU='westend-millau' + +MONITORING=' -f ./monitoring/docker-compose.yml' +UI=' -f ./ui/docker-compose.yml' + +BRIDGES=() +NETWORKS='' +SUB_COMMAND='start' +for i in "$@" +do + case $i in + --no-monitoring) + MONITORING=" -f ./monitoring/disabled.yml" + shift + continue + ;; + --no-ui) + UI="" + shift + continue + ;; + --local) + export SUBSTRATE_RELAY_IMAGE=local/substrate-relay + export RIALTO_BRIDGE_NODE_IMAGE=local/rialto-bridge-node + export RIALTO_PARACHAIN_COLLATOR_IMAGE=local/rialto-parachain-collator + export MILLAU_BRIDGE_NODE_IMAGE=local/millau-bridge-node + export IMMEDIATE_ + shift + continue + ;; + --local-substrate-relay) + export SUBSTRATE_RELAY_IMAGE=local/substrate-relay + shift + continue + ;; + --local-rialto) + export RIALTO_BRIDGE_NODE_IMAGE=local/rialto-bridge-node + shift + continue + ;; + --local-rialto-parachain) + export RIALTO_PARACHAIN_COLLATOR_IMAGE=local/rialto-parachain-collator + shift + continue + ;; + --local-millau) + export MILLAU_BRIDGE_NODE_IMAGE=local/millau-bridge-node + shift + continue + ;; + --no-grafana-startup-delay) + export NO_GRAFANA_STARTUP_DELAY="echo 'No Grafana startup delay'" + shift + continue + ;; + everything|all) + BRIDGES=(${RIALTO_MILLAU:-} ${RIALTO_PARACHAIN_MILLAU:-} ${WESTEND_MILLAU:-}) + NETWORKS="${RIALTO:-} ${RIALTO_PARACHAIN:-} ${MILLAU:-}" + unset RIALTO RIALTO_PARACHAIN MILLAU RIALTO_MILLAU RIALTO_PARACHAIN_MILLAU WESTEND_MILLAU + shift + ;; + rialto-millau) + BRIDGES+=(${RIALTO_MILLAU:-}) + NETWORKS+="${RIALTO:-} ${MILLAU:-}" + unset RIALTO MILLAU RIALTO_MILLAU + shift + ;; + rialto-parachain-millau) + BRIDGES+=(${RIALTO_PARACHAIN_MILLAU:-}) + NETWORKS+="${RIALTO:-} ${RIALTO_PARACHAIN:-} ${MILLAU:-}" + unset RIALTO RIALTO_PARACHAIN MILLAU RIALTO_PARACHAIN_MILLAU + shift + ;; + westend-millau) + BRIDGES+=(${WESTEND_MILLAU:-}) + NETWORKS+=${MILLAU:-} + unset MILLAU WESTEND_MILLAU + shift + ;; + start|stop|update) + SUB_COMMAND=$i + shift + ;; + *) + show_help "Unknown option: $i" + ;; + esac +done + +if [ ${#BRIDGES[@]} -eq 0 ]; then + show_help "Missing bridge name." +fi + +COMPOSE_FILES=$NETWORKS$MONITORING$UI + +# Compose looks for .env files in the the current directory by default, we don't want that +COMPOSE_ARGS="--project-directory ." +# Path to env file that we want to use. Compose only accepts single `--env-file` argument, +# so we'll be using the last .env file we'll found. +COMPOSE_ENV_FILE='' + +for BRIDGE in "${BRIDGES[@]}" +do + BRIDGE_PATH="./bridges/$BRIDGE" + BRIDGE=" -f $BRIDGE_PATH/docker-compose.yml" + COMPOSE_FILES=$BRIDGE$COMPOSE_FILES + + # Remember .env file to use in docker-compose call + if [[ -f "$BRIDGE_PATH/.env" ]]; then + COMPOSE_ENV_FILE=" --env-file $BRIDGE_PATH/.env" + fi + + # Read and source variables from .env file so we can use them here + grep -e MATRIX_ACCESS_TOKEN -e WITH_PROXY $BRIDGE_PATH/.env > .env2 && . ./.env2 && rm .env2 + if [ ! -z ${MATRIX_ACCESS_TOKEN+x} ]; then + sed -i "s/access_token.*/access_token: \"$MATRIX_ACCESS_TOKEN\"/" ./monitoring/grafana-matrix/config.yml + fi +done + +# Final COMPOSE_ARGS +COMPOSE_ARGS="$COMPOSE_ARGS $COMPOSE_ENV_FILE" + +# Check the sub-command, perhaps we just mean to stop the network instead of starting it. +if [ "$SUB_COMMAND" == "stop" ]; then + + if [ ! -z ${WITH_PROXY+x} ]; then + cd ./reverse-proxy + docker-compose down + cd - + fi + + docker-compose $COMPOSE_ARGS $COMPOSE_FILES down + + exit 0 +fi + +# See if we want to update the docker images before starting the network. +if [ "$SUB_COMMAND" == "update" ]; then + + # Stop the proxy cause otherwise the network can't be stopped + if [ ! -z ${WITH_PROXY+x} ]; then + cd ./reverse-proxy + docker-compose down + cd - + fi + + + docker-compose $COMPOSE_ARGS $COMPOSE_FILES pull + docker-compose $COMPOSE_ARGS $COMPOSE_FILES down + docker-compose $COMPOSE_ARGS $COMPOSE_FILES build +fi + +docker-compose $COMPOSE_ARGS $COMPOSE_FILES up -d + +# Start the proxy if needed +if [ ! -z ${WITH_PROXY+x} ]; then + cd ./reverse-proxy + docker-compose up -d +fi diff --git a/deployments/types-millau.json b/deployments/types-millau.json new file mode 100644 index 00000000000..88b67f70b05 --- /dev/null +++ b/deployments/types-millau.json @@ -0,0 +1,191 @@ +{ + "--1": "Millau Types", + "MillauAddress": "AccountId", + "MillauLookupSource": "AccountId", + "MillauBalance": "u64", + "MillauBlockHash": "H512", + "MillauBlockNumber": "u64", + "MillauHeader": { + "parent_Hash": "MillauBlockHash", + "number": "Compact", + "state_root": "MillauBlockHash", + "extrinsics_root": "MillauBlockHash", + "digest": "MillauDigest" + }, + "MillauDigest": { + "logs": "Vec" + }, + "MillauDigestItem": { + "_enum": { + "Other": "Vec", + "AuthoritiesChange": "Vec", + "ChangesTrieRoot": "MillauBlockHash", + "SealV0": "SealV0", + "Consensus": "Consensus", + "Seal": "Seal", + "PreRuntime": "PreRuntime" + } + }, + "--2": "Rialto Types", + "RialtoAddress": "MultiAddress", + "RialtoLookupSource": "MultiAddress", + "RialtoBalance": "u128", + "RialtoBlockHash": "H256", + "RialtoBlockNumber": "u32", + "RialtoHeader": { + "parent_Hash": "RialtoBlockHash", + "number": "Compact", + "state_root": "RialtoBlockHash", + "extrinsics_root": "RialtoBlockHash", + "digest": "RialtoDigest" + }, + "RialtoDigest": { + "logs": "Vec" + }, + "RialtoDigestItem": { + "_enum": { + "Other": "Vec", + "AuthoritiesChange": "Vec", + "ChangesTrieRoot": "RialtoBlockHash", + "SealV0": "SealV0", + "Consensus": "Consensus", + "Seal": "Seal", + "PreRuntime": "PreRuntime" + } + }, + "--3": "Common types", + "AccountSigner": "MultiSigner", + "SpecVersion": "u32", + "RelayerId": "AccountId", + "SourceAccountId": "AccountId", + "ImportedHeader": { + "header": "BridgedHeader", + "requires_justification": "bool", + "is_finalized": "bool", + "signal_hash": "Option" + }, + "AuthoritySet": { + "authorities": "AuthorityList", + "set_id": "SetId" + }, + "Id": "[u8; 4]", + "ChainId": "Id", + "LaneId": "Id", + "MessageNonce": "u64", + "BridgeMessageId": "(Id, u64)", + "MessageKey": { + "lane_id": "LaneId", + "nonce:": "MessageNonce" + }, + "InboundRelayer": "AccountId", + "InboundLaneData": { + "relayers": "Vec", + "last_confirmed_nonce": "MessageNonce" + }, + "UnrewardedRelayer": { + "relayer": "RelayerId", + "messages": "DeliveredMessages" + }, + "DeliveredMessages": { + "begin": "MessageNonce", + "end": "MessageNonce" + }, + "OutboundLaneData": { + "oldest_unpruned_nonce": "MessageNonce", + "latest_received_nonce": "MessageNonce", + "latest_generated_nonce": "MessageNonce" + }, + "MessageData": { + "payload": "MessagePayload", + "fee": "Fee" + }, + "MessagePayload": "Vec", + "BridgedOpaqueCall": "Vec", + "OutboundMessageFee": "Fee", + "OutboundPayload": { + "spec_version": "SpecVersion", + "weight": "Weight", + "origin": "CallOrigin", + "dispatch_fee_payment": "DispatchFeePayment", + "call": "BridgedOpaqueCall" + }, + "CallOrigin": { + "_enum": { + "SourceRoot": "()", + "TargetAccount": "(SourceAccountId, MultiSigner, MultiSignature)", + "SourceAccount": "SourceAccountId" + } + }, + "DispatchFeePayment": { + "_enum": { + "AtSourceChain": "()", + "AtTargetChain": "()" + } + }, + "MultiSigner": { + "_enum": { + "Ed25519": "H256", + "Sr25519": "H256", + "Ecdsa": "[u8;33]" + } + }, + "MessagesProofOf": { + "bridged_header_hash": "BridgedBlockHash", + "storage_proof": "Vec", + "lane": "LaneId", + "nonces_start": "MessageNonce", + "nonces_end": "MessageNonce" + }, + "StorageProofItem": "Vec", + "MessagesDeliveryProofOf": { + "bridged_header_hash": "BridgedBlockHash", + "storage_proof": "Vec", + "lane": "LaneId" + }, + "UnrewardedRelayersState": { + "unrewarded_relayer_entries": "MessageNonce", + "messages_in_oldest_entry": "MessageNonce", + "total_messages": "MessageNonce" + }, + "AncestryProof": "()", + "MessageFeeData": { + "lane_id": "LaneId", + "payload": "OutboundPayload" + }, + "Precommit": { + "target_hash": "BridgedBlockHash", + "target_number": "BridgedBlockNumber" + }, + "AuthoritySignature": "[u8;64]", + "AuthorityId": "[u8;32]", + "SignedPrecommit": { + "precommit": "Precommit", + "signature": "AuthoritySignature", + "id": "AuthorityId" + }, + "Commit": { + "target_hash": "BridgedBlockHash", + "target_number": "BridgedBlockNumber", + "precommits": "Vec" + }, + "GrandpaJustification": { + "round": "u64", + "commit": "Commit", + "votes_ancestries": "Vec" + }, + "Address": "MillauAddress", + "LookupSource": "MillauLookupSource", + "Fee": "MillauBalance", + "Balance": "MillauBalance", + "Hash": "MillauBlockHash", + "BlockHash": "MillauBlockHash", + "BlockNumber": "MillauBlockNumber", + "BridgedBlockHash": "RialtoBlockHash", + "BridgedBlockNumber": "RialtoBlockNumber", + "BridgedHeader": "RialtoHeader", + "Parameter": { + "_enum": { + "MillauToRialtoConversionRate": "u128" + } + } +} diff --git a/deployments/types-rialto.json b/deployments/types-rialto.json new file mode 100644 index 00000000000..02ceaf676d6 --- /dev/null +++ b/deployments/types-rialto.json @@ -0,0 +1,191 @@ +{ + "--1": "Millau Types", + "MillauAddress": "AccountId", + "MillauLookupSource": "AccountId", + "MillauBalance": "u64", + "MillauBlockHash": "H512", + "MillauBlockNumber": "u64", + "MillauHeader": { + "parent_Hash": "MillauBlockHash", + "number": "Compact", + "state_root": "MillauBlockHash", + "extrinsics_root": "MillauBlockHash", + "digest": "MillauDigest" + }, + "MillauDigest": { + "logs": "Vec" + }, + "MillauDigestItem": { + "_enum": { + "Other": "Vec", + "AuthoritiesChange": "Vec", + "ChangesTrieRoot": "MillauBlockHash", + "SealV0": "SealV0", + "Consensus": "Consensus", + "Seal": "Seal", + "PreRuntime": "PreRuntime" + } + }, + "--2": "Rialto Types", + "RialtoAddress": "MultiAddress", + "RialtoLookupSource": "MultiAddress", + "RialtoBalance": "u128", + "RialtoBlockHash": "H256", + "RialtoBlockNumber": "u32", + "RialtoHeader": { + "parent_Hash": "RialtoBlockHash", + "number": "Compact", + "state_root": "RialtoBlockHash", + "extrinsics_root": "RialtoBlockHash", + "digest": "RialtoDigest" + }, + "RialtoDigest": { + "logs": "Vec" + }, + "RialtoDigestItem": { + "_enum": { + "Other": "Vec", + "AuthoritiesChange": "Vec", + "ChangesTrieRoot": "RialtoBlockHash", + "SealV0": "SealV0", + "Consensus": "Consensus", + "Seal": "Seal", + "PreRuntime": "PreRuntime" + } + }, + "--3": "Common types", + "AccountSigner": "MultiSigner", + "SpecVersion": "u32", + "RelayerId": "AccountId", + "SourceAccountId": "AccountId", + "ImportedHeader": { + "header": "BridgedHeader", + "requires_justification": "bool", + "is_finalized": "bool", + "signal_hash": "Option" + }, + "AuthoritySet": { + "authorities": "AuthorityList", + "set_id": "SetId" + }, + "Id": "[u8; 4]", + "ChainId": "Id", + "LaneId": "Id", + "MessageNonce": "u64", + "BridgeMessageId": "(Id, u64)", + "MessageKey": { + "lane_id": "LaneId", + "nonce:": "MessageNonce" + }, + "InboundRelayer": "AccountId", + "InboundLaneData": { + "relayers": "Vec", + "last_confirmed_nonce": "MessageNonce" + }, + "UnrewardedRelayer": { + "relayer": "RelayerId", + "messages": "DeliveredMessages" + }, + "DeliveredMessages": { + "begin": "MessageNonce", + "end": "MessageNonce" + }, + "OutboundLaneData": { + "oldest_unpruned_nonce": "MessageNonce", + "latest_received_nonce": "MessageNonce", + "latest_generated_nonce": "MessageNonce" + }, + "MessageData": { + "payload": "MessagePayload", + "fee": "Fee" + }, + "MessagePayload": "Vec", + "BridgedOpaqueCall": "Vec", + "OutboundMessageFee": "Fee", + "OutboundPayload": { + "spec_version": "SpecVersion", + "weight": "Weight", + "origin": "CallOrigin", + "dispatch_fee_payment": "DispatchFeePayment", + "call": "BridgedOpaqueCall" + }, + "CallOrigin": { + "_enum": { + "SourceRoot": "()", + "TargetAccount": "(SourceAccountId, MultiSigner, MultiSignature)", + "SourceAccount": "SourceAccountId" + } + }, + "DispatchFeePayment": { + "_enum": { + "AtSourceChain": "()", + "AtTargetChain": "()" + } + }, + "MultiSigner": { + "_enum": { + "Ed25519": "H256", + "Sr25519": "H256", + "Ecdsa": "[u8;33]" + } + }, + "MessagesProofOf": { + "bridged_header_hash": "BridgedBlockHash", + "storage_proof": "Vec", + "lane": "LaneId", + "nonces_start": "MessageNonce", + "nonces_end": "MessageNonce" + }, + "StorageProofItem": "Vec", + "MessagesDeliveryProofOf": { + "bridged_header_hash": "BridgedBlockHash", + "storage_proof": "Vec", + "lane": "LaneId" + }, + "UnrewardedRelayersState": { + "unrewarded_relayer_entries": "MessageNonce", + "messages_in_oldest_entry": "MessageNonce", + "total_messages": "MessageNonce" + }, + "AncestryProof": "()", + "MessageFeeData": { + "lane_id": "LaneId", + "payload": "OutboundPayload" + }, + "Precommit": { + "target_hash": "BridgedBlockHash", + "target_number": "BridgedBlockNumber" + }, + "AuthoritySignature": "[u8;64]", + "AuthorityId": "[u8;32]", + "SignedPrecommit": { + "precommit": "Precommit", + "signature": "AuthoritySignature", + "id": "AuthorityId" + }, + "Commit": { + "target_hash": "BridgedBlockHash", + "target_number": "BridgedBlockNumber", + "precommits": "Vec" + }, + "GrandpaJustification": { + "round": "u64", + "commit": "Commit", + "votes_ancestries": "Vec" + }, + "Address": "RialtoAddress", + "LookupSource": "RialtoLookupSource", + "Fee": "RialtoBalance", + "Balance": "RialtoBalance", + "BlockHash": "RialtoBlockHash", + "BlockNumber": "RialtoBlockNumber", + "BridgedBlockHash": "MillauBlockHash", + "BridgedBlockNumber": "MillauBlockNumber", + "BridgedHeader": "MillauHeader", + "Parameter": { + "_enum": { + "RialtoToMillauConversionRate": "u128" + } + }, + "ValidationCodeHash": "H256" +} diff --git a/deployments/types/build.sh b/deployments/types/build.sh new file mode 100755 index 00000000000..be96459a6da --- /dev/null +++ b/deployments/types/build.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# The script generates JSON type definition files in `./deployment` directory to be used for +# JS clients. +# +# It works by creating definitions for each side of the different bridge pairs we support +# (Rialto<>Millau at the moment). +# +# To avoid duplication each bridge pair has a JSON file with common definitions, as well as a +# general JSON file with common definitions regardless of the bridge pair. These files are then +# merged with chain-specific type definitions. + +set -eux + +# Make sure we are in the right dir. +cd $(dirname $(realpath $0)) + +# Create types for our supported bridge pairs (Rialto<>Millau) +jq -s '.[0] * .[1] * .[2]' rialto-millau.json common.json rialto.json > ../types-rialto.json +jq -s '.[0] * .[1] * .[2]' rialto-millau.json common.json millau.json > ../types-millau.json diff --git a/deployments/types/common.json b/deployments/types/common.json new file mode 100644 index 00000000000..7247e546bec --- /dev/null +++ b/deployments/types/common.json @@ -0,0 +1,123 @@ +{ + "--3": "Common types", + "AccountSigner": "MultiSigner", + "SpecVersion": "u32", + "RelayerId": "AccountId", + "SourceAccountId": "AccountId", + "ImportedHeader": { + "header": "BridgedHeader", + "requires_justification": "bool", + "is_finalized": "bool", + "signal_hash": "Option" + }, + "AuthoritySet": { + "authorities": "AuthorityList", + "set_id": "SetId" + }, + "Id": "[u8; 4]", + "ChainId": "Id", + "LaneId": "Id", + "MessageNonce": "u64", + "BridgeMessageId": "(Id, u64)", + "MessageKey": { + "lane_id": "LaneId", + "nonce:": "MessageNonce" + }, + "InboundRelayer": "AccountId", + "InboundLaneData": { + "relayers": "Vec", + "last_confirmed_nonce": "MessageNonce" + }, + "UnrewardedRelayer": { + "relayer": "RelayerId", + "messages": "DeliveredMessages" + }, + "DeliveredMessages": { + "begin": "MessageNonce", + "end": "MessageNonce" + }, + "OutboundLaneData": { + "oldest_unpruned_nonce": "MessageNonce", + "latest_received_nonce": "MessageNonce", + "latest_generated_nonce": "MessageNonce" + + }, + "MessageData": { + "payload": "MessagePayload", + "fee": "Fee" + }, + "MessagePayload": "Vec", + "BridgedOpaqueCall": "Vec", + "OutboundMessageFee": "Fee", + "OutboundPayload": { + "spec_version": "SpecVersion", + "weight": "Weight", + "origin": "CallOrigin", + "dispatch_fee_payment": "DispatchFeePayment", + "call": "BridgedOpaqueCall" + }, + "CallOrigin": { + "_enum": { + "SourceRoot": "()", + "TargetAccount": "(SourceAccountId, MultiSigner, MultiSignature)", + "SourceAccount": "SourceAccountId" + } + }, + "DispatchFeePayment": { + "_enum": { + "AtSourceChain": "()", + "AtTargetChain": "()" + } + }, + "MultiSigner": { + "_enum": { + "Ed25519": "H256", + "Sr25519": "H256", + "Ecdsa": "[u8;33]" + } + }, + "MessagesProofOf": { + "bridged_header_hash": "BridgedBlockHash", + "storage_proof": "Vec", + "lane": "LaneId", + "nonces_start": "MessageNonce", + "nonces_end": "MessageNonce" + }, + "StorageProofItem": "Vec", + "MessagesDeliveryProofOf": { + "bridged_header_hash": "BridgedBlockHash", + "storage_proof": "Vec", + "lane": "LaneId" + }, + "UnrewardedRelayersState": { + "unrewarded_relayer_entries": "MessageNonce", + "messages_in_oldest_entry": "MessageNonce", + "total_messages": "MessageNonce" + }, + "AncestryProof": "()", + "MessageFeeData": { + "lane_id": "LaneId", + "payload": "OutboundPayload" + }, + "Precommit": { + "target_hash": "BridgedBlockHash", + "target_number": "BridgedBlockNumber" + }, + "AuthoritySignature": "[u8;64]", + "AuthorityId": "[u8;32]", + "SignedPrecommit": { + "precommit": "Precommit", + "signature": "AuthoritySignature", + "id": "AuthorityId" + }, + "Commit": { + "target_hash": "BridgedBlockHash", + "target_number": "BridgedBlockNumber", + "precommits": "Vec" + }, + "GrandpaJustification": { + "round": "u64", + "commit": "Commit", + "votes_ancestries": "Vec" + } +} diff --git a/deployments/types/millau.json b/deployments/types/millau.json new file mode 100644 index 00000000000..589d5619df4 --- /dev/null +++ b/deployments/types/millau.json @@ -0,0 +1,17 @@ +{ + "Address": "MillauAddress", + "LookupSource": "MillauLookupSource", + "Fee": "MillauBalance", + "Balance": "MillauBalance", + "Hash": "MillauBlockHash", + "BlockHash": "MillauBlockHash", + "BlockNumber": "MillauBlockNumber", + "BridgedBlockHash": "RialtoBlockHash", + "BridgedBlockNumber": "RialtoBlockNumber", + "BridgedHeader": "RialtoHeader", + "Parameter": { + "_enum": { + "MillauToRialtoConversionRate": "u128" + } + } +} diff --git a/deployments/types/rialto-millau.json b/deployments/types/rialto-millau.json new file mode 100644 index 00000000000..971cf666d47 --- /dev/null +++ b/deployments/types/rialto-millau.json @@ -0,0 +1,56 @@ +{ + "--1": "Millau Types", + "MillauAddress": "AccountId", + "MillauLookupSource": "AccountId", + "MillauBalance": "u64", + "MillauBlockHash": "H512", + "MillauBlockNumber": "u64", + "MillauHeader": { + "parent_Hash": "MillauBlockHash", + "number": "Compact", + "state_root": "MillauBlockHash", + "extrinsics_root": "MillauBlockHash", + "digest": "MillauDigest" + }, + "MillauDigest": { + "logs": "Vec" + }, + "MillauDigestItem": { + "_enum": { + "Other": "Vec", + "AuthoritiesChange": "Vec", + "ChangesTrieRoot": "MillauBlockHash", + "SealV0": "SealV0", + "Consensus": "Consensus", + "Seal": "Seal", + "PreRuntime": "PreRuntime" + } + }, + "--2": "Rialto Types", + "RialtoAddress": "MultiAddress", + "RialtoLookupSource": "MultiAddress", + "RialtoBalance": "u128", + "RialtoBlockHash": "H256", + "RialtoBlockNumber": "u32", + "RialtoHeader": { + "parent_Hash": "RialtoBlockHash", + "number": "Compact", + "state_root": "RialtoBlockHash", + "extrinsics_root": "RialtoBlockHash", + "digest": "RialtoDigest" + }, + "RialtoDigest": { + "logs": "Vec" + }, + "RialtoDigestItem": { + "_enum": { + "Other": "Vec", + "AuthoritiesChange": "Vec", + "ChangesTrieRoot": "RialtoBlockHash", + "SealV0": "SealV0", + "Consensus": "Consensus", + "Seal": "Seal", + "PreRuntime": "PreRuntime" + } + } +} diff --git a/deployments/types/rialto.json b/deployments/types/rialto.json new file mode 100644 index 00000000000..77c30b7cc2d --- /dev/null +++ b/deployments/types/rialto.json @@ -0,0 +1,17 @@ +{ + "Address": "RialtoAddress", + "LookupSource": "RialtoLookupSource", + "Fee": "RialtoBalance", + "Balance": "RialtoBalance", + "BlockHash": "RialtoBlockHash", + "BlockNumber": "RialtoBlockNumber", + "BridgedBlockHash": "MillauBlockHash", + "BridgedBlockNumber": "MillauBlockNumber", + "BridgedHeader": "MillauHeader", + "Parameter": { + "_enum": { + "RialtoToMillauConversionRate": "u128" + } + }, + "ValidationCodeHash": "H256" +} diff --git a/deployments/ui/README.md b/deployments/ui/README.md new file mode 100644 index 00000000000..ad946fc699b --- /dev/null +++ b/deployments/ui/README.md @@ -0,0 +1,23 @@ +# bridges-ui + +This is a Bridges UI docker configuration file. The source of the Bridges UI code +can be found in [the repository](https://github.com/paritytech/parity-bridges-ui). +The CI should create and publish a docker image that is used by this configuration +file, so that the code is always using the latest version. +The UI is configured to point to local Rialto and Millau nodes to retrieve the require +data. + +This image can be used together with `nginx-proxy` to expose the UI externally. See +`VIRTUAL_*` and `LETSENCRYPT_*` environment variables. + +After start the UI is available at `http://localhost:8080` + +## How to? + +In current directory: +```bash +docker-compose up -d +``` + +Then start `rialto` & `millau` networks with the same command (one folder up) or +run the full setup by using `../run.sh` script. diff --git a/deployments/ui/docker-compose.yml b/deployments/ui/docker-compose.yml new file mode 100644 index 00000000000..2d400609c44 --- /dev/null +++ b/deployments/ui/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3.5' +services: + bridges-ui: + image: paritytech/parity-bridges-ui + environment: + VIRTUAL_HOST: ui.brucke.link + VIRTUAL_PORT: 80 + LETSENCRYPT_HOST: ui.brucke.link + LETSENCRYPT_EMAIL: admin@parity.io + CHAIN_1_SUBSTRATE_PROVIDER: ${UI_CHAIN_1:-ws://localhost:9944} + CHAIN_2_SUBSTRATE_PROVIDER: ${UI_CHAIN_2:-ws://localhost:19944} + stop_signal: SIGKILL + ports: + - "8080:80" diff --git a/docs/complex-relay.html b/docs/complex-relay.html new file mode 100644 index 00000000000..21524bfd049 --- /dev/null +++ b/docs/complex-relay.html @@ -0,0 +1,85 @@ + + + + + + Complex Relay + + +

Complex Relay

+

+ Both Source Chain and Target Chains have Bridge Messages pallets deployed. They also have required + finality pallets deployed - we don't care about finality type here - they can be either Bridge GRANDPA, + or Bridge Parachains finality pallets, or any combination of those.
+

+

+ There are 4-6 relayer subprocesses inside the Complex Relayer. They include two message relayers, + serving the lane in both directions and 2-4 Complex Relayers (depending on the finality type of Source + and Target Chains).
+

+

+ The following diagram shows the way the complex relayer serves the lane in single direction. Everything + below may be applied to the opposite direction if you'll swap the Source and Target Chains. +

+
+ sequenceDiagram + participant Source Chain + participant Complex Relayer + participant Target Chain + + Note right of Source Chain: Finalized: 480, Target Finalized: 50, Sent Messages: 42, Confirmed Messages: 42 + Note left of Target Chain: Finalized: 60, Source Finalized: 420, Received Messages: 42 + + Source Chain ->> Source Chain: someone Sends Message 43 + Source Chain ->> Source Chain: Import and Finalize Block 481 + + Source Chain ->> Complex Relayer: notes new outbound message 43 at Source Chain Block 481 + Note right of Complex Relayer: can't deliver message 43, Source Chain Block 481 is not relayed + Complex Relayer ->> Complex Relayer: asks on-demand Finality Relayer to relay Source Chain Block 481 + + Source Chain ->> Complex Relayer: Read Finality Proof of Block 481 + Complex Relayer ->> Target Chain: Submit Finality Proof of Block 481 + Target Chain ->> Target Chain: Import and Finalize Block 61 + Note left of Target Chain: Finalized: 61, Source Finalized: 481, Received Messages: 42 + + Source Chain ->> Complex Relayer: Read Proof of Message 43 at Block 481 + Complex Relayer ->> Target Chain: Submit Proof of Message 43 at Block 481 + Target Chain ->> Target Chain: Import and Finalize Block 62 + Note left of Target Chain: Finalized: 62, Source Finalized: 481, Received Messages: { rewarded: 42, messages-relayer-account: [43] } + + Target Chain ->> Complex Relayer: notes new unrewarded relayer at Target Chain Block 62 + Note right of Complex Relayer: can't relay delivery confirmations because Target Chain Block 62 is not relayed + Complex Relayer ->> Complex Relayer: asks on-demand Finality Relayer to relay Target Chain Block 62 + + Target Chain ->> Complex Relayer: Read Finality Proof of Block 62 + Complex Relayer ->> Source Chain: Submit Finality Proof of Block 62 + Source Chain ->> Source Chain: Import and Finalize Block 482 + Note right of Source Chain: Finalized: 482, Target Finalized: 62, Confirmed Messages: 42 + + Target Chain ->> Complex Relayer: Read Proof of Message 43 Delivery at Block 62 + Complex Relayer ->> Source Chain: Submit Proof of Message 43 Delivery at Block 612 + Source Chain ->> Source Chain: rewards messages-relayer-account for delivering message [43] + Source Chain ->> Source Chain: prune delivered message 43 from runtime storage + Note right of Source Chain: Finalized: 482, Target Finalized: 61, Confirmed Messages: 43 + + Source Chain ->> Source Chain: someone Sends Message 44 + Source Chain ->> Source Chain: Import and Finalize Block 483 + + Source Chain ->> Complex Relayer: notes new outbound message 44 at Source Chain Block 483 and new confirmed message 43 + Note right of Complex Relayer: can't deliver message 44, Source Chain Block 483 is not relayed + Complex Relayer ->> Complex Relayer: asks on-demand Finality Relayer to relay Source Chain Block 483 + + Source Chain ->> Complex Relayer: Read Finality Proof of Block 483 + Complex Relayer ->> Target Chain: Submit Finality Proof of Block 483 + Target Chain ->> Target Chain: Import and Finalize Block 63 + Note left of Target Chain: Finalized: 63, Source Finalized: 483, Received Messages: { rewarded: 42, messages-relayer-account: [43] } + + Source Chain ->> Complex Relayer: Read Proof of Message 44 and Proof of Message 43 reward at Block 483 + Complex Relayer ->> Target Chain: Submit Proof of Message 44 and Proof of Message 43 reward at Block 483 + Target Chain ->> Target Chain: Import and Finalize Block 64 + Note left of Target Chain: Finalized: 64, Source Finalized: 483, Received Messages: { rewarded: 43, messages-relayer-account: [44] }--> +
+ + + + diff --git a/docs/dockerhub-bridges-common-relay.README.md b/docs/dockerhub-bridges-common-relay.README.md new file mode 100644 index 00000000000..d199227c9c6 --- /dev/null +++ b/docs/dockerhub-bridges-common-relay.README.md @@ -0,0 +1 @@ +# bridges-common-relay diff --git a/docs/dockerhub-millau-bridge-node.README.md b/docs/dockerhub-millau-bridge-node.README.md new file mode 100644 index 00000000000..481ad46b7c6 --- /dev/null +++ b/docs/dockerhub-millau-bridge-node.README.md @@ -0,0 +1 @@ +# millau-bridge-node diff --git a/docs/dockerhub-rialto-bridge-node.README.md b/docs/dockerhub-rialto-bridge-node.README.md new file mode 100644 index 00000000000..2393e6f8129 --- /dev/null +++ b/docs/dockerhub-rialto-bridge-node.README.md @@ -0,0 +1 @@ +# rialto-bridge-node diff --git a/docs/dockerhub-rialto-parachain-collator.README.md b/docs/dockerhub-rialto-parachain-collator.README.md new file mode 100644 index 00000000000..a09f6b1561b --- /dev/null +++ b/docs/dockerhub-rialto-parachain-collator.README.md @@ -0,0 +1 @@ +# rialto-parachain-collator diff --git a/docs/dockerhub-substrate-relay.README.md b/docs/dockerhub-substrate-relay.README.md new file mode 100644 index 00000000000..1a9f22c425c --- /dev/null +++ b/docs/dockerhub-substrate-relay.README.md @@ -0,0 +1 @@ +# substrate-relay diff --git a/docs/grandpa-finality-relay.html b/docs/grandpa-finality-relay.html new file mode 100644 index 00000000000..4136621b1a4 --- /dev/null +++ b/docs/grandpa-finality-relay.html @@ -0,0 +1,47 @@ + + + + + + GRANDPA Finality Relay + + +

GRANDPA Finality Relay

+

+ Source Chain is running GRANDPA Finality Gadget. Bridge GRANDPA finality pallet is deployed at + Target Chain runtime. Relayer is configured to relay Source Chain finality to Target Chain. +

+
+ sequenceDiagram + participant Source Chain + participant Relayer + participant Target Chain + Note left of Source Chain: Best: 500, Finalized: 480, Authorities Set Index: 42 + Note right of Target Chain: Uninitialized + + Source Chain ->> Relayer: Read Initialization Data + Relayer ->> Target Chain: Initialize Bridge GRANDPA Finality Pallet + Note right of Target Chain: Finalized: 480, Authorities Set Index: 42 + + Source Chain ->> Source Chain: Import Block 501 + Source Chain ->> Source Chain: Import Block 502 + Source Chain ->> Source Chain: Finalize Block 495 + Source Chain ->> Relayer: Read Finality Proof of Block 495 + Relayer ->> Target Chain: Finality Proof of Block 495 + Note right of Target Chain: Finalized: 495, Authorities Set Index: 42 + + Source Chain ->> Source Chain: Import Block 503 that changes Authorities Set to 43 + Source Chain ->> Source Chain: Finalize Block 500 + Note left of Relayer: Relayer Misses Finality Notification for Block 500 + + Source Chain ->> Source Chain: Import Block 504 + Source Chain ->> Source Chain: Finalize Mandatory Block 503 + Source Chain ->> Source Chain: Finalize Block 504 + Source Chain ->> Relayer: Read Finality Proof of Mandatory Block 503 + Relayer ->> Target Chain: Finality Proof of Block 503 + Note right of Target Chain: Finalized: 503, Authorities Set Index: 43 +
+ + + + diff --git a/docs/high-level-overview.md b/docs/high-level-overview.md new file mode 100644 index 00000000000..449224124af --- /dev/null +++ b/docs/high-level-overview.md @@ -0,0 +1,181 @@ +# 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). + +## 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. + +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. + +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. + +### 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. + +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). + +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. + +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). +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. + +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 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. + +Many things are abstracted by the pallet: +- the message itself may mean anything, the pallet doesn't care about its content; +- the message dispatch happens during delivery, but it is decoupled from the pallet code; +- 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. + +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. + +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. + +### 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. + +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. + +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. + +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. + +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/). + +### 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. + +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. + +More: [Complex Relay Sequence Diagram](./complex-relay.html), [code](../relays/bin-substrate/src/cli/relay_headers_and_messages/). diff --git a/docs/messages-relay.html b/docs/messages-relay.html new file mode 100644 index 00000000000..c4dab9901e0 --- /dev/null +++ b/docs/messages-relay.html @@ -0,0 +1,78 @@ + + + + + + Messages Relay + + +

Messages Relay

+

+ Both Source Chain and Target Chains have Bridge Messages pallets deployed. They also have required + finality pallets deployed - we don't care about finality type here - they can be either Bridge GRANDPA, + or Bridge Parachains finality pallets, or any combination of those. +

+

+ Finality Relayer represents two actual relayers - one relays Source Chain Finality to Target Chain. + And another one relays Target Chain Finality to Source Chain. +

+
+ sequenceDiagram + participant Source Chain + participant Finality Relayer + participant Messages Relayer + participant Target Chain + + Note right of Source Chain: Finalized: 480, Target Finalized: 50, Sent Messages: 42, Confirmed Messages: 42 + Note left of Target Chain: Finalized: 60, Source Finalized: 420, Received Messages: 42 + + Source Chain ->> Source Chain: someone Sends Message 43 + Source Chain ->> Source Chain: Import and Finalize Block 481 + + Source Chain ->> Messages Relayer: notes new outbound message 43 at Source Chain Block 481 + Note right of Messages Relayer: can't deliver message 43, Source Chain Block 481 is not relayed + + Source Chain ->> Finality Relayer: Read Finality Proof of Block 481 + Finality Relayer ->> Target Chain: Submit Finality Proof of Block 481 + Target Chain ->> Target Chain: Import and Finalize Block 61 + Note left of Target Chain: Finalized: 61, Source Finalized: 481, Received Messages: 42 + + Source Chain ->> Messages Relayer: Read Proof of Message 43 at Block 481 + Messages Relayer ->> Target Chain: Submit Proof of Message 43 at Block 481 + Target Chain ->> Target Chain: Import and Finalize Block 62 + Note left of Target Chain: Finalized: 62, Source Finalized: 481, Received Messages: { rewarded: 42, messages-relayer-account: [43] } + + Target Chain ->> Messages Relayer: notes new unrewarded relayer at Target Chain Block 62 + Note right of Messages Relayer: can't relay delivery confirmations because Target Chain Block 62 is not relayed + + Target Chain ->> Finality Relayer: Read Finality Proof of Block 62 + Finality Relayer ->> Source Chain: Submit Finality Proof of Block 62 + Source Chain ->> Source Chain: Import and Finalize Block 482 + Note right of Source Chain: Finalized: 482, Target Finalized: 62, Confirmed Messages: 42 + + Target Chain ->> Messages Relayer: Read Proof of Message 43 Delivery at Block 62 + Messages Relayer ->> Source Chain: Submit Proof of Message 43 Delivery at Block 612 + Source Chain ->> Source Chain: rewards messages-relayer-account for delivering message [43] + Source Chain ->> Source Chain: prune delivered message 43 from runtime storage + Note right of Source Chain: Finalized: 482, Target Finalized: 61, Confirmed Messages: 43 + + Source Chain ->> Source Chain: someone Sends Message 44 + Source Chain ->> Source Chain: Import and Finalize Block 483 + + Source Chain ->> Messages Relayer: notes new outbound message 44 at Source Chain Block 483 and new confirmed message 43 + Note right of Messages Relayer: can't deliver message 44, Source Chain Block 483 is not relayed + + Source Chain ->> Finality Relayer: Read Finality Proof of Block 483 + Finality Relayer ->> Target Chain: Submit Finality Proof of Block 483 + Target Chain ->> Target Chain: Import and Finalize Block 63 + Note left of Target Chain: Finalized: 63, Source Finalized: 483, Received Messages: { rewarded: 42, messages-relayer-account: [43] } + + Source Chain ->> Messages Relayer: Read Proof of Message 44 and Proof of Message 43 reward at Block 483 + Messages Relayer ->> Target Chain: Submit Proof of Message 44 and Proof of Message 43 reward at Block 483 + Target Chain ->> Target Chain: Import and Finalize Block 64 + Note left of Target Chain: Finalized: 64, Source Finalized: 483, Received Messages: { rewarded: 43, messages-relayer-account: [44] } +
+ + + + diff --git a/docs/parachains-finality-relay.html b/docs/parachains-finality-relay.html new file mode 100644 index 00000000000..4fc1392b87d --- /dev/null +++ b/docs/parachains-finality-relay.html @@ -0,0 +1,55 @@ + + + + + + Parachains Finality Relay + + +

Parachains Finality Relay

+

+ Source Relay Chain is running GRANDPA Finality Gadget. Source Parachain is a parachain of the Source + Relay Chain. Bridge GRANDPA finality pallet is deployed at Target Chain runtime and is "connected" + to the Source Relay Chain. Bridge Parachains finality pallet is deployed at Target Chain and is + configured to track the Source Parachain. GRANDPA Relayer is configured to relay Source Relay Chain + finality to Target Chain. Parachains Relayer is configured to relay Source Parachain headers finality + to Target Chain. +

+
+ sequenceDiagram + participant Source Parachain + participant Source Relay Chain + participant GRANDPA Relayer + participant Parachains Relayer + participant Target Chain + + Note left of Source Parachain: Best: 125 + Note left of Source Relay Chain: Finalized: 500, Best Parachain at Finalized: 120 + Note right of Target Chain: Best Relay: 480, Best Parachain: 110 + + Source Parachain ->> Source Parachain: Import Block 126 + Source Parachain ->> Source Relay Chain: Receives the Parachain block 126 + + Source Relay Chain ->> Source Relay Chain: Import block 501 + Source Relay Chain ->> Source Relay Chain: Finalize block 501 + Note left of Source Relay Chain: Finalized: 501, Best Parachain at Finalized: 126 + + Source Relay Chain ->> Parachains Relayer: notes new Source Parachain Block 126 + Note left of Parachains Relayer: can't relay Source Parachain Block 126, because it requires at least Source Relay Block 501 at Target Chain + + Source Relay Chain ->> Source Relay Chain: Import block 502 + Source Relay Chain ->> Source Relay Chain: Finalize block 502 + + Source Relay Chain ->> GRANDPA Relayer: read GRANDPA Finality Proof of Block 502 + GRANDPA Relayer ->> Target Chain: submit GRANDPA Finality Proof of Block 502 + Note right of Target Chain: Best Relay: 502, Best Parachain: 110 + + Target Chain ->> Parachains Relayer: notes finalized Source Relay Block 502 at Target Chain + Source Relay Chain ->> Parachains Relayer: read Parachain Finality Proof at Relay Block 502 + Parachains Relayer ->> Target Chain: submit Parachain Finality Proof at Relay Block 502 + Note right of Target Chain: Best Relay: 502, Best Parachain: 126 +
+ + + + diff --git a/docs/polkadot-kusama-bridge-overview.md b/docs/polkadot-kusama-bridge-overview.md new file mode 100644 index 00000000000..9f407b6ba00 --- /dev/null +++ b/docs/polkadot-kusama-bridge-overview.md @@ -0,0 +1,132 @@ +# 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. + +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. + +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. + +## 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. + +Our first planned bridge will connect the Polkadot' Statemint and Kusama' Statemine. Bridge between those two +parachains would allow Statemint accounts to hold wrapped KSM tokens and Statemine 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. + +## Running Relayers + +We are planning to run our own complex relayer for the lane 00000000. The relayer will relay Kusama/Polkadot GRANDPA +justifications to the bridge hubs at the other side. It'll also relay finalized Kusama Bridge Hub and Polkadot Bridge +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. + +### Compensating the Cost of Message Delivery Transactions + +One part of our rewarding scheme is that the cost of message delivery, for honest relayer, is zero. The honest relayer +is the relayer, which is following our rules: + +- we do not reward relayers for submitting GRANDPA finality transactions. The only exception is submitting mandatory + headers (headers which are changing the GRANDPA authorities set) - the cost of such transaction is zero. The relayer + will pay the full cost for submitting all other headers; + +- we do not reward relayers for submitting parachain finality transactions. The relayer will pay the full cost for + submitting parachain finality transactions; + +- 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; + +- 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. + +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. + +*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. + +### 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.; + +- 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. + +Bridged Parachains will have sovereign accounts at bridge hubs. For example, the Statemine (Kusama Parachain) will +have an account at the Polkadot Bridge Hub. The Statemint (Polkadot Parachain) 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. +Statemine will only reward relayers that are delivering messages from Statemine. The Statemine sovereign account +is not used to cover rewards of bridging with some other Polkadot Parachain. + +### Multiple Relayers and Rewards + +Our goal is to incentivize running honest relayers. But we have no relayers sets, so at any time anyone may submit +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. + +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 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. diff --git a/docs/polkadot-kusama-bridge.html b/docs/polkadot-kusama-bridge.html new file mode 100644 index 00000000000..dcbae0e7b17 --- /dev/null +++ b/docs/polkadot-kusama-bridge.html @@ -0,0 +1,67 @@ + + + + + + Polkadot <> Kusama Bridge + + +

Polkadot <> Kusama Bridge

+

+ Our bridge connects two parachains - Kusama Bridge Hub and Polkadot Bridge Hub. Messages that + are sent over bridge have XCM format and we are using existing architecture to dispatch them. + Since both Polkadot, Kusama and their parachains already have means to exchange XCM messages + within the same consensus system (HRMP, VMP, ...), it means that we are able to connect all those + chains with our bridge. +

+

+ In our architecture, the lane that is used to relay messages over the bridge is determined by + the XCM source and destinations. So e.g. bridge between Statemint and Statemine (and opposite direction) + will use the lane 00000000, bridge between some other Polkadot Parachain and some other Kusama Parachain + will use the lane 00000001 and so on. +

+
+ flowchart LR + subgraph Polkadot Consensus + polkadot(((Polkadot))) + statemint(((Statemint))) + polkadot_bh(((Polkadot Bridge Hub))) + + polkadot---statemint + polkadot---polkadot_bh + + statemint-->|Send Message Using HRMP|polkadot_bh + + polkadot_bh-->|Send Message Using HRMP|statemint + statemint-->|Dispatch the Message|statemint + end + subgraph Kusama Consensus + kusama_bh(((Kusama Bridge Hub))) + statemine(((Statemine))) + kusama(((Kusama))) + + kusama---statemine + kusama---kusama_bh + + kusama_bh-->|Send Message Using HRMP|statemine + statemine-->|Dispatch the Message|statemine + + statemine-->|Send Message Using HRMP|kusama_bh + end + + polkadot_bh<===>|Message is relayed to the Bridged Chain using lane 00000000|kusama_bh + + linkStyle 2 stroke:red + linkStyle 7 stroke:red + linkStyle 8 stroke:red + + linkStyle 3 stroke:green + linkStyle 4 stroke:green + linkStyle 9 stroke:green +
+ + + \ No newline at end of file diff --git a/fuzz/storage-proof/Cargo.lock b/fuzz/storage-proof/Cargo.lock new file mode 100644 index 00000000000..6eba720c493 --- /dev/null +++ b/fuzz/storage-proof/Cargo.lock @@ -0,0 +1,2796 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.7", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" + +[[package]] +name = "arbitrary" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-trait" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" +dependencies = [ + "digest 0.10.3", +] + +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" +dependencies = [ + "arrayvec 0.4.12", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bp-runtime" +version = "0.1.0" +dependencies = [ + "frame-support", + "frame-system", + "hash-db", + "impl-trait-for-tuples", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", + "trie-db 0.24.0", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byte-slice-cast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c5fdd0166095e1d463fc6cc01aa8ce547ad77a4e84d42eb6762b084e28067e" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "winapi", +] + +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" +dependencies = [ + "generic-array 0.14.4", + "rand_core 0.6.1", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ccfd8c0ee4cce11e45b3fd6f9d5e69e0cc62912aa6a0cb1bf4617b0eba5a12f" +dependencies = [ + "generic-array 0.14.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.4", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434e1720189a637d44fe464f4df1e6eb900b4835255b14354497c78af37d9bb8" +dependencies = [ + "byteorder", + "digest 0.8.1", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f627126b946c25a4638eec0ea634fc52506dea98db118aae985118ce7c3d723f" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "der" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +dependencies = [ + "const-oid", +] + +[[package]] +name = "derive_more" +version = "0.99.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dyn-clonable" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +dependencies = [ + "dyn-clonable-impl", + "dyn-clone", +] + +[[package]] +name = "dyn-clonable-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dyn-clone" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" + +[[package]] +name = "ecdsa" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c66a534cbb46ab4ea03477eae19d5c22c01da8258030280b7bd9d8433fb6ef" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.0.2", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "elliptic-curve" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "ff", + "generic-array 0.14.4", + "group", + "rand_core 0.6.1", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "environmental" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b91989ae21441195d7d9b9993a2f9295c7e1a8c96255d8b729accddc124797" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "ff" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +dependencies = [ + "rand_core 0.6.1", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand 0.8.2", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "frame-metadata" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "frame-support" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "bitflags", + "frame-metadata", + "frame-support-procedural", + "impl-trait-for-tuples", + "k256", + "log", + "once_cell", + "parity-scale-codec", + "paste", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic", + "sp-core", + "sp-core-hashing-proc-macro", + "sp-inherents", + "sp-io", + "sp-runtime", + "sp-staking", + "sp-state-machine", + "sp-std", + "sp-tracing", + "tt-call", +] + +[[package]] +name = "frame-support-procedural" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "Inflector", + "frame-support-procedural-tools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-support-procedural-tools" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "frame-support-procedural-tools-derive", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-support-procedural-tools-derive" +version = "3.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frame-system" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "frame-support", + "log", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", + "sp-version", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "group" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +dependencies = [ + "ff", + "rand_core 0.6.1", + "subtle", +] + +[[package]] +name = "hash-db" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.4", + "hmac 0.8.1", +] + +[[package]] +name = "honggfuzz" +version = "0.5.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea09577d948a98a5f59b7c891e274c4fb35ad52f67782b3d0cb53b9c05301f1" +dependencies = [ + "arbitrary", + "lazy_static", + "memmap", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-serde" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47ca4d2b6931707a55fce5cf66aff80e2178c8b63bbb4ecb5695cbc870ddf6f" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" +dependencies = [ + "libc", + "windows-sys 0.42.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes", + "rustix", + "windows-sys 0.42.0", +] + +[[package]] +name = "itoa" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "js-sys" +version = "0.3.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sec1", +] + +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "libsecp256k1" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.2", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "memory-db" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6566c70c1016f525ced45d7b7f97730a2bafb037c788211d0c186ef5b2189f0a" +dependencies = [ + "hash-db", + "hashbrown", + "parity-util-mem", +] + +[[package]] +name = "memory_units" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d96e3f3c0b6325d8ccd83c33b28acb183edcb6c67938ba104ec546854b0882" + +[[package]] +name = "merlin" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafe4179722c2894288ee77a9f044f02811c86af699344c498b0840c698a2465" +dependencies = [ + "arrayvec 0.4.12", + "itoa 0.4.7", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi 0.1.18", + "libc", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parity-scale-codec" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ab01d0f889e957861bc65888d5ccbe82c158d0270136ba46820d43837cdf72" +dependencies = [ + "arrayvec 0.7.2", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parity-util-mem" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c32561d248d352148124f036cac253a644685a21dc9fea383eb4907d7bd35a8f" +dependencies = [ + "cfg-if", + "hashbrown", + "impl-trait-for-tuples", + "parity-util-mem-derive", + "parking_lot", + "primitive-types", + "winapi", +] + +[[package]] +name = "parity-util-mem-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" +dependencies = [ + "proc-macro2", + "syn", + "synstructure", +] + +[[package]] +name = "parity-wasm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5e13c266502aadf83426d87d81a0f5d1ef45b8027f5a471c360abfe4bfae92" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.36.1", +] + +[[package]] +name = "paste" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc" + +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac 0.8.0", +] + +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +dependencies = [ + "crypto-mac 0.11.1", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "primitive-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18519b42a40024d661e1714153e9ad0c3de27cd495760ceb09710920f1098b1e" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.1", + "rand_hc 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.1", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core 0.6.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +dependencies = [ + "byteorder", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "rfc6979" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" +dependencies = [ + "crypto-bigint", + "hmac 0.11.0", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.42.0", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scale-info" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c46be926081c9f4dd5dd9b6f1d3e3229f2360bc6502dd8836f84a93b7c75e99a" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e334bb10a245e28e5fd755cabcafd96cfcd167c99ae63a46924ca8d8703a3c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "schnorrkel" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "curve25519-dalek 2.1.2", + "getrandom 0.1.16", + "merlin", + "rand 0.7.3", + "rand_core 0.5.1", + "sha2 0.8.2", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sec1" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" +dependencies = [ + "der", + "generic-array 0.14.4", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c42e6f1735c5f00f51e43e28d6634141f2bcad10931b2609ddd74a86d751260" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957da2573cde917463ece3570eab4a0b3f19de6f1646cde62e6fd3868f566036" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa 1.0.2", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + +[[package]] +name = "sha3" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" +dependencies = [ + "digest 0.10.3", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signature" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.1", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "sp-application-crypto" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "sp-arithmetic" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-debug-derive", + "sp-std", + "static_assertions", +] + +[[package]] +name = "sp-core" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "base58", + "bitflags", + "blake2-rfc", + "byteorder", + "dyn-clonable", + "ed25519-dalek", + "futures", + "hash-db", + "hash256-std-hasher", + "hex", + "impl-serde", + "lazy_static", + "libsecp256k1", + "log", + "merlin", + "num-traits", + "parity-scale-codec", + "parity-util-mem", + "parking_lot", + "primitive-types", + "rand 0.7.3", + "regex", + "scale-info", + "schnorrkel", + "secp256k1", + "secrecy", + "serde", + "sp-core-hashing", + "sp-debug-derive", + "sp-externalities", + "sp-runtime-interface", + "sp-std", + "sp-storage", + "ss58-registry", + "substrate-bip39", + "thiserror", + "tiny-bip39", + "wasmi", + "zeroize", +] + +[[package]] +name = "sp-core-hashing" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "blake2", + "byteorder", + "digest 0.10.3", + "sha2 0.10.2", + "sha3", + "sp-std", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing-proc-macro" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "proc-macro2", + "quote", + "sp-core-hashing", + "syn", +] + +[[package]] +name = "sp-debug-derive" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-externalities" +version = "0.12.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-std", + "sp-storage", +] + +[[package]] +name = "sp-inherents" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "async-trait", + "impl-trait-for-tuples", + "parity-scale-codec", + "sp-core", + "sp-runtime", + "sp-std", + "thiserror", +] + +[[package]] +name = "sp-io" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "futures", + "hash-db", + "libsecp256k1", + "log", + "parity-scale-codec", + "parking_lot", + "secp256k1", + "sp-core", + "sp-externalities", + "sp-keystore", + "sp-runtime-interface", + "sp-state-machine", + "sp-std", + "sp-tracing", + "sp-trie", + "sp-wasm-interface", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-keystore" +version = "0.12.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "async-trait", + "futures", + "merlin", + "parity-scale-codec", + "parking_lot", + "schnorrkel", + "sp-core", + "sp-externalities", + "thiserror", +] + +[[package]] +name = "sp-panic-handler" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "backtrace", + "lazy_static", + "regex", +] + +[[package]] +name = "sp-runtime" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "parity-util-mem", + "paste", + "rand 0.7.3", + "scale-info", + "serde", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-std", +] + +[[package]] +name = "sp-runtime-interface" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "impl-trait-for-tuples", + "parity-scale-codec", + "primitive-types", + "sp-externalities", + "sp-runtime-interface-proc-macro", + "sp-std", + "sp-storage", + "sp-tracing", + "sp-wasm-interface", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-staking" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "parity-scale-codec", + "scale-info", + "sp-runtime", + "sp-std", +] + +[[package]] +name = "sp-state-machine" +version = "0.12.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "hash-db", + "log", + "num-traits", + "parity-scale-codec", + "parking_lot", + "rand 0.7.3", + "smallvec", + "sp-core", + "sp-externalities", + "sp-panic-handler", + "sp-std", + "sp-trie", + "thiserror", + "tracing", + "trie-root", +] + +[[package]] +name = "sp-std" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" + +[[package]] +name = "sp-storage" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive", + "sp-std", +] + +[[package]] +name = "sp-tracing" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "parity-scale-codec", + "sp-std", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sp-trie" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "hash-db", + "memory-db", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-std", + "thiserror", + "trie-db 0.23.1", + "trie-root", +] + +[[package]] +name = "sp-version" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-core-hashing-proc-macro", + "sp-runtime", + "sp-std", + "sp-version-proc-macro", + "thiserror", +] + +[[package]] +name = "sp-version-proc-macro" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "parity-scale-codec", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sp-wasm-interface" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?branch=master#367dab0d4bd7fd7b6c222dd15c753169c057dd42" +dependencies = [ + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std", + "wasmi", +] + +[[package]] +name = "ss58-registry" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ef98aedad3dc52e10995e7ed15f1279e11d4da35795f5dac7305742d0feb66" +dependencies = [ + "Inflector", + "num-format", + "proc-macro2", + "quote", + "serde", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "storage-proof-fuzzer" +version = "0.1.0" +dependencies = [ + "bp-runtime", + "env_logger", + "honggfuzz", + "log", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-std", + "sp-trie", +] + +[[package]] +name = "substrate-bip39" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +dependencies = [ + "hmac 0.11.0", + "pbkdf2 0.8.0", + "schnorrkel", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "subtle" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tiny-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac 0.8.1", + "once_cell", + "pbkdf2 0.4.0", + "rand 0.7.3", + "rustc-hash", + "sha2 0.9.9", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinyvec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "trie-db" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32d034c0d3db64b43c31de38e945f15b40cd4ca6d2dcfc26d4798ce8de4ab83" +dependencies = [ + "hash-db", + "hashbrown", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-db" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004e1e8f92535694b4cb1444dc5a8073ecf0815e3357f729638b9f8fc4062908" +dependencies = [ + "hash-db", + "hashbrown", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-root" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" +dependencies = [ + "hash-db", +] + +[[package]] +name = "tt-call" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "digest 0.10.3", + "rand 0.8.2", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "uint" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11fe9a9348741cf134085ad57c249508345fe16411b3d7fb4ff2da2f1d6382e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "unicode-normalization" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" + +[[package]] +name = "wasmi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca00c5147c319a8ec91ec1a0edbec31e566ce2c9cc93b3f9bb86a9efd0eb795d" +dependencies = [ + "downcast-rs", + "libc", + "memory_units", + "num-rational", + "num-traits", + "parity-wasm", + "wasmi-validation", +] + +[[package]] +name = "wasmi-validation" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "165343ecd6c018fc09ebcae280752702c9a2ef3e6f8d02f1cfcbdb53ef6d7937" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.42.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "wyz" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20b578acffd8516a6c3f2a1bdefc1ec37e547bb4e0fb8b6b01a4cafc886b4442" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/fuzz/storage-proof/Cargo.toml b/fuzz/storage-proof/Cargo.toml new file mode 100644 index 00000000000..61d0e63a878 --- /dev/null +++ b/fuzz/storage-proof/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "storage-proof-fuzzer" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 + +[dependencies] +honggfuzz = "0.5.54" +log = "0.4.0" +env_logger = "0.10.0" + +# Bridge Dependencies + +bp-runtime = { path = "../../primitives/runtime" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/fuzz/storage-proof/README.md b/fuzz/storage-proof/README.md new file mode 100644 index 00000000000..1eeec7562a9 --- /dev/null +++ b/fuzz/storage-proof/README.md @@ -0,0 +1,34 @@ +# Storage Proof Fuzzer + +## How to run? + +Install dependencies: +``` +$ sudo apt install build-essential binutils-dev libunwind-dev +``` +or on nix: +``` +$ nix-shell -p honggfuzz +``` + +Install `cargo hfuzz` plugin: +``` +$ cargo install honggfuzz +``` + +Run: +``` +$ cargo hfuzz run storage-proof-fuzzer +``` + +Use `HFUZZ_RUN_ARGS` to customize execution: +``` +# 1 second of timeout +# use 12 fuzzing thread +# be verbose +# stop after 1000000 fuzzing iteration +# exit upon crash +HFUZZ_RUN_ARGS="-t 1 -n 12 -v -N 1000000 --exit_upon_crash" cargo hfuzz run example +``` + +More details in the [official documentation](https://docs.rs/honggfuzz/0.5.52/honggfuzz/#about-honggfuzz). diff --git a/fuzz/storage-proof/src/main.rs b/fuzz/storage-proof/src/main.rs new file mode 100644 index 00000000000..9ceda58d163 --- /dev/null +++ b/fuzz/storage-proof/src/main.rs @@ -0,0 +1,78 @@ +// Copyright 2019-2021 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 . + +//! Storage Proof Checker fuzzer. + +#![warn(missing_docs)] + +use honggfuzz::fuzz; +// Logic for checking Substrate storage proofs. + +use sp_core::{Blake2Hasher, H256}; +use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; +use sp_std::vec::Vec; +use std::collections::HashMap; + +fn craft_known_storage_proof( + input_vec: Vec<(Vec, Vec)>, +) -> (H256, bp_runtime::RawStorageProof) { + let storage_proof_vec = + vec![(None, input_vec.iter().map(|x| (x.0.clone(), Some(x.1.clone()))).collect())]; + log::info!("Storage proof vec {:?}", storage_proof_vec); + let state_version = sp_runtime::StateVersion::default(); + let backend = >::from((storage_proof_vec, state_version)); + let root = backend.storage_root(std::iter::empty(), state_version).0; + let vector_element_proof = + prove_read(backend, input_vec.iter().map(|x| x.0.as_slice())).unwrap(); + (root, vector_element_proof.iter_nodes().cloned().collect()) +} + +fn transform_into_unique(input_vec: Vec<(Vec, Vec)>) -> Vec<(Vec, Vec)> { + let mut output_hashmap = HashMap::new(); + let mut output_vec = Vec::new(); + for key_value_pair in input_vec { + output_hashmap.insert(key_value_pair.0, key_value_pair.1); //Only 1 value per key + } + for (key, val) in output_hashmap.iter() { + output_vec.push((key.clone(), val.clone())); + } + output_vec +} + +fn run_fuzzer() { + fuzz!(|input_vec: Vec<(Vec, Vec)>| { + if input_vec.is_empty() { + return + } + let unique_input_vec = transform_into_unique(input_vec); + let (root, craft_known_storage_proof) = craft_known_storage_proof(unique_input_vec.clone()); + let mut checker = + >::new(root, craft_known_storage_proof) + .expect("Valid proof passed; qed"); + for key_value_pair in unique_input_vec { + log::info!("Reading value for pair {:?}", key_value_pair); + assert_eq!(checker.read_value(&key_value_pair.0), Ok(Some(key_value_pair.1.clone()))); + } + }) +} + +fn main() { + env_logger::init(); + + loop { + run_fuzzer(); + } +} diff --git a/modules/beefy/Cargo.toml b/modules/beefy/Cargo.toml new file mode 100644 index 00000000000..8aff2c169b4 --- /dev/null +++ b/modules/beefy/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "pallet-bridge-beefy" +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.0.0", default-features = false } +log = { version = "0.4.14", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true } + +# Bridge Dependencies + +bp-beefy = { path = "../../primitives/beefy", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +sp-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "master" } +mmr-lib = { package = "ckb-merkle-mountain-range", version = "0.3.2" } +pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master" } +rand = "0.8" +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } +bp-test-utils = { path = "../../primitives/test-utils" } + +[features] +default = ["std"] +std = [ + "bp-beefy/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "serde", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/beefy/src/lib.rs b/modules/beefy/src/lib.rs new file mode 100644 index 00000000000..79795dd0770 --- /dev/null +++ b/modules/beefy/src/lib.rs @@ -0,0 +1,648 @@ +// Copyright 2021 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 . + +//! BEEFY bridge pallet. +//! +//! This pallet is an on-chain BEEFY light client for Substrate-based chains that are using the +//! following pallets bundle: `pallet-mmr`, `pallet-beefy` and `pallet-beefy-mmr`. +//! +//! The pallet is able to verify MMR leaf proofs and BEEFY commitments, so it has access +//! to the following data of the bridged chain: +//! +//! - header hashes +//! - changes of BEEFY authorities +//! - extra data of MMR leafs +//! +//! Given the header hash, other pallets are able to verify header-based proofs +//! (e.g. storage proofs, transaction inclusion proofs, etc.). + +#![cfg_attr(not(feature = "std"), no_std)] + +use bp_beefy::{ChainWithBeefy, InitializationData}; +use sp_std::{boxed::Box, prelude::*}; + +// Re-export in crate namespace for `construct_runtime!` +pub use pallet::*; + +mod utils; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod mock_chain; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-beefy"; + +/// Configured bridged chain. +pub type BridgedChain = >::BridgedChain; +/// Block number, used by configured bridged chain. +pub type BridgedBlockNumber = bp_runtime::BlockNumberOf>; +/// Block hash, used by configured bridged chain. +pub type BridgedBlockHash = bp_runtime::HashOf>; + +/// Pallet initialization data. +pub type InitializationDataOf = + InitializationData, bp_beefy::MmrHashOf>>; +/// BEEFY commitment hasher, used by configured bridged chain. +pub type BridgedBeefyCommitmentHasher = bp_beefy::BeefyCommitmentHasher>; +/// BEEFY validator id, used by configured bridged chain. +pub type BridgedBeefyAuthorityId = bp_beefy::BeefyAuthorityIdOf>; +/// BEEFY validator set, used by configured bridged chain. +pub type BridgedBeefyAuthoritySet = bp_beefy::BeefyAuthoritySetOf>; +/// BEEFY authority set, used by configured bridged chain. +pub type BridgedBeefyAuthoritySetInfo = bp_beefy::BeefyAuthoritySetInfoOf>; +/// BEEFY signed commitment, used by configured bridged chain. +pub type BridgedBeefySignedCommitment = bp_beefy::BeefySignedCommitmentOf>; +/// MMR hashing algorithm, used by configured bridged chain. +pub type BridgedMmrHashing = bp_beefy::MmrHashingOf>; +/// MMR hashing output type of `BridgedMmrHashing`. +pub type BridgedMmrHash = bp_beefy::MmrHashOf>; +/// The type of the MMR leaf extra data used by the configured bridged chain. +pub type BridgedBeefyMmrLeafExtra = bp_beefy::BeefyMmrLeafExtraOf>; +/// BEEFY MMR proof type used by the pallet +pub type BridgedMmrProof = bp_beefy::MmrProofOf>; +/// MMR leaf type, used by configured bridged chain. +pub type BridgedBeefyMmrLeaf = bp_beefy::BeefyMmrLeafOf>; +/// Imported commitment data, stored by the pallet. +pub type ImportedCommitment = bp_beefy::ImportedCommitment< + BridgedBlockNumber, + BridgedBlockHash, + BridgedMmrHash, +>; + +/// Some high level info about the imported commitments. +#[derive(codec::Encode, codec::Decode, scale_info::TypeInfo)] +pub struct ImportedCommitmentsInfoData { + /// Best known block number, provided in a BEEFY commitment. However this is not + /// the best proven block. The best proven block is this block's parent. + best_block_number: BlockNumber, + /// The head of the `ImportedBlockNumbers` ring buffer. + next_block_number_index: u32, +} + +#[frame_support::pallet(dev_mode)] +pub mod pallet { + use super::*; + use bp_runtime::{BasicOperatingMode, OwnedBridgeModule}; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The upper bound on the number of requests allowed by the pallet. + /// + /// A request refers to an action which writes a header to storage. + /// + /// Once this bound is reached the pallet will reject all commitments + /// until the request count has decreased. + #[pallet::constant] + type MaxRequests: Get; + + /// Maximal number of imported commitments to keep in the storage. + /// + /// The setting is there to prevent growing the on-chain state indefinitely. Note + /// the setting does not relate to block numbers - we will simply keep as much items + /// in the storage, so it doesn't guarantee any fixed timeframe for imported commitments. + #[pallet::constant] + type CommitmentsToKeep: Get; + + /// The chain we are bridging to here. + type BridgedChain: ChainWithBeefy; + } + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + fn on_initialize(_n: T::BlockNumber) -> frame_support::weights::Weight { + >::mutate(|count| *count = count.saturating_sub(1)); + + Weight::from_parts(0, 0) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + } + + impl, I: 'static> OwnedBridgeModule for Pallet { + const LOG_TARGET: &'static str = LOG_TARGET; + type OwnerStorage = PalletOwner; + type OperatingMode = BasicOperatingMode; + type OperatingModeStorage = PalletOperatingMode; + } + + #[pallet::call] + impl, I: 'static> Pallet + where + BridgedMmrHashing: 'static + Send + Sync, + { + /// Initialize pallet with BEEFY authority set and best known finalized block number. + #[pallet::call_index(0)] + #[pallet::weight((T::DbWeight::get().reads_writes(2, 3), DispatchClass::Operational))] + pub fn initialize( + origin: OriginFor, + init_data: InitializationDataOf, + ) -> DispatchResult { + Self::ensure_owner_or_root(origin)?; + + let is_initialized = >::exists(); + ensure!(!is_initialized, >::AlreadyInitialized); + + log::info!(target: LOG_TARGET, "Initializing bridge BEEFY pallet: {:?}", init_data); + Ok(initialize::(init_data)?) + } + + /// Change `PalletOwner`. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(1)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { + >::set_owner(origin, new_owner) + } + + /// Halt or resume all pallet operations. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(2)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_operating_mode( + origin: OriginFor, + operating_mode: BasicOperatingMode, + ) -> DispatchResult { + >::set_operating_mode(origin, operating_mode) + } + + /// Submit a commitment generated by BEEFY authority set. + /// + /// It will use the underlying storage pallet to fetch information about the current + /// authority set and best finalized block number in order to verify that the commitment + /// is valid. + /// + /// If successful in verification, it will update the underlying storage with the data + /// provided in the newly submitted commitment. + #[pallet::call_index(3)] + #[pallet::weight(0)] + pub fn submit_commitment( + origin: OriginFor, + commitment: BridgedBeefySignedCommitment, + validator_set: BridgedBeefyAuthoritySet, + mmr_leaf: Box>, + mmr_proof: BridgedMmrProof, + ) -> DispatchResult + where + BridgedBeefySignedCommitment: Clone, + { + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; + ensure_signed(origin)?; + + ensure!(Self::request_count() < T::MaxRequests::get(), >::TooManyRequests); + + // Ensure that the commitment is for a better block. + let commitments_info = + ImportedCommitmentsInfo::::get().ok_or(Error::::NotInitialized)?; + ensure!( + commitment.commitment.block_number > commitments_info.best_block_number, + Error::::OldCommitment + ); + + // Verify commitment and mmr leaf. + let current_authority_set_info = CurrentAuthoritySetInfo::::get(); + let mmr_root = utils::verify_commitment::( + &commitment, + ¤t_authority_set_info, + &validator_set, + )?; + utils::verify_beefy_mmr_leaf::(&mmr_leaf, mmr_proof, mmr_root)?; + + // Update request count. + RequestCount::::mutate(|count| *count += 1); + // Update authority set if needed. + if mmr_leaf.beefy_next_authority_set.id > current_authority_set_info.id { + CurrentAuthoritySetInfo::::put(mmr_leaf.beefy_next_authority_set); + } + + // Import commitment. + let block_number_index = commitments_info.next_block_number_index; + let to_prune = ImportedBlockNumbers::::try_get(block_number_index); + ImportedCommitments::::insert( + commitment.commitment.block_number, + ImportedCommitment:: { + parent_number_and_hash: mmr_leaf.parent_number_and_hash, + mmr_root, + }, + ); + ImportedBlockNumbers::::insert( + block_number_index, + commitment.commitment.block_number, + ); + ImportedCommitmentsInfo::::put(ImportedCommitmentsInfoData { + best_block_number: commitment.commitment.block_number, + next_block_number_index: (block_number_index + 1) % T::CommitmentsToKeep::get(), + }); + if let Ok(old_block_number) = to_prune { + log::debug!( + target: LOG_TARGET, + "Pruning commitment for old block: {:?}.", + old_block_number + ); + ImportedCommitments::::remove(old_block_number); + } + + log::info!( + target: LOG_TARGET, + "Successfully imported commitment for block {:?}", + commitment.commitment.block_number, + ); + + Ok(()) + } + } + + /// The current number of requests which have written to storage. + /// + /// If the `RequestCount` hits `MaxRequests`, no more calls will be allowed to the pallet until + /// the request capacity is increased. + /// + /// The `RequestCount` is decreased by one at the beginning of every block. This is to ensure + /// that the pallet can always make progress. + #[pallet::storage] + #[pallet::getter(fn request_count)] + pub type RequestCount, I: 'static = ()> = StorageValue<_, u32, ValueQuery>; + + /// High level info about the imported commitments. + /// + /// Contains the following info: + /// - best known block number of the bridged chain, finalized by BEEFY + /// - the head of the `ImportedBlockNumbers` ring buffer + #[pallet::storage] + pub type ImportedCommitmentsInfo, I: 'static = ()> = + StorageValue<_, ImportedCommitmentsInfoData>>; + + /// A ring buffer containing the block numbers of the commitments that we have imported, + /// ordered by the insertion time. + #[pallet::storage] + pub(super) type ImportedBlockNumbers, I: 'static = ()> = + StorageMap<_, Identity, u32, BridgedBlockNumber>; + + /// All the commitments that we have imported and haven't been pruned yet. + #[pallet::storage] + pub type ImportedCommitments, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, BridgedBlockNumber, ImportedCommitment>; + + /// The current BEEFY authority set at the bridged chain. + #[pallet::storage] + pub type CurrentAuthoritySetInfo, I: 'static = ()> = + StorageValue<_, BridgedBeefyAuthoritySetInfo, ValueQuery>; + + /// Optional pallet owner. + /// + /// Pallet owner has the right to halt all pallet operations and then resume it. If it is + /// `None`, then there are no direct ways to halt/resume pallet operations, but other + /// runtime methods may still be used to do that (i.e. `democracy::referendum` to update halt + /// flag directly or calling `halt_operations`). + #[pallet::storage] + pub type PalletOwner, I: 'static = ()> = + StorageValue<_, T::AccountId, OptionQuery>; + + /// The current operating mode of the pallet. + /// + /// Depending on the mode either all, or no transactions will be allowed. + #[pallet::storage] + pub type PalletOperatingMode, I: 'static = ()> = + StorageValue<_, BasicOperatingMode, ValueQuery>; + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + /// Optional module owner account. + pub owner: Option, + /// Optional module initialization data. + pub init_data: Option>, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { owner: None, init_data: None } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + if let Some(ref owner) = self.owner { + >::put(owner); + } + + if let Some(init_data) = self.init_data.clone() { + initialize::(init_data) + .expect("invalid initialization data of BEEFY bridge pallet"); + } else { + // Since the bridge hasn't been initialized we shouldn't allow anyone to perform + // transactions. + >::put(BasicOperatingMode::Halted); + } + } + } + + #[pallet::error] + pub enum Error { + /// The pallet has not been initialized yet. + NotInitialized, + /// The pallet has already been initialized. + AlreadyInitialized, + /// Invalid initial authority set. + InvalidInitialAuthoritySet, + /// There are too many requests for the current window to handle. + TooManyRequests, + /// The imported commitment is older than the best commitment known to the pallet. + OldCommitment, + /// The commitment is signed by unknown validator set. + InvalidCommitmentValidatorSetId, + /// The id of the provided validator set is invalid. + InvalidValidatorSetId, + /// The number of signatures in the commitment is invalid. + InvalidCommitmentSignaturesLen, + /// The number of validator ids provided is invalid. + InvalidValidatorSetLen, + /// There aren't enough correct signatures in the commitment to finalize the block. + NotEnoughCorrectSignatures, + /// MMR root is missing from the commitment. + MmrRootMissingFromCommitment, + /// MMR proof verification has failed. + MmrProofVerificationFailed, + /// The validators are not matching the merkle tree root of the authority set. + InvalidValidatorSetRoot, + /// Error generated by the `OwnedBridgeModule` trait. + BridgeModule(bp_runtime::OwnedBridgeModuleError), + } + + /// Initialize pallet with given parameters. + pub(super) fn initialize, I: 'static>( + init_data: InitializationDataOf, + ) -> Result<(), Error> { + if init_data.authority_set.len == 0 { + return Err(Error::::InvalidInitialAuthoritySet) + } + CurrentAuthoritySetInfo::::put(init_data.authority_set); + + >::put(init_data.operating_mode); + ImportedCommitmentsInfo::::put(ImportedCommitmentsInfoData { + best_block_number: init_data.best_block_number, + next_block_number_index: 0, + }); + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_runtime::{BasicOperatingMode, OwnedBridgeModuleError}; + use bp_test_utils::generate_owned_bridge_module_tests; + use frame_support::{assert_noop, assert_ok, traits::Get}; + use mock::*; + use mock_chain::*; + use sp_consensus_beefy::mmr::BeefyAuthoritySet; + use sp_runtime::DispatchError; + + fn next_block() { + use frame_support::traits::OnInitialize; + + let current_number = frame_system::Pallet::::block_number(); + frame_system::Pallet::::set_block_number(current_number + 1); + let _ = Pallet::::on_initialize(current_number); + } + + fn import_header_chain(headers: Vec) { + for header in headers { + if header.commitment.is_some() { + assert_ok!(import_commitment(header)); + } + } + } + + #[test] + fn fails_to_initialize_if_already_initialized() { + run_test_with_initialize(32, || { + assert_noop!( + Pallet::::initialize( + RuntimeOrigin::root(), + InitializationData { + operating_mode: BasicOperatingMode::Normal, + best_block_number: 0, + authority_set: BeefyAuthoritySet { id: 0, len: 1, root: [0u8; 32].into() } + } + ), + Error::::AlreadyInitialized, + ); + }); + } + + #[test] + fn fails_to_initialize_if_authority_set_is_empty() { + run_test(|| { + assert_noop!( + Pallet::::initialize( + RuntimeOrigin::root(), + InitializationData { + operating_mode: BasicOperatingMode::Normal, + best_block_number: 0, + authority_set: BeefyAuthoritySet { id: 0, len: 0, root: [0u8; 32].into() } + } + ), + Error::::InvalidInitialAuthoritySet, + ); + }); + } + + #[test] + fn fails_to_import_commitment_if_halted() { + run_test_with_initialize(1, || { + assert_ok!(Pallet::::set_operating_mode( + RuntimeOrigin::root(), + BasicOperatingMode::Halted + )); + assert_noop!( + import_commitment(ChainBuilder::new(1).append_finalized_header().to_header()), + Error::::BridgeModule(OwnedBridgeModuleError::Halted), + ); + }) + } + + #[test] + fn fails_to_import_commitment_if_too_many_requests() { + run_test_with_initialize(1, || { + let max_requests = <::MaxRequests as Get>::get() as u64; + let mut chain = ChainBuilder::new(1); + for _ in 0..max_requests + 2 { + chain = chain.append_finalized_header(); + } + + // import `max_request` headers + for i in 0..max_requests { + assert_ok!(import_commitment(chain.header(i + 1))); + } + + // try to import next header: it fails because we are no longer accepting commitments + assert_noop!( + import_commitment(chain.header(max_requests + 1)), + Error::::TooManyRequests, + ); + + // when next block is "started", we allow import of next header + next_block(); + assert_ok!(import_commitment(chain.header(max_requests + 1))); + + // but we can't import two headers until next block and so on + assert_noop!( + import_commitment(chain.header(max_requests + 2)), + Error::::TooManyRequests, + ); + }) + } + + #[test] + fn fails_to_import_commitment_if_not_initialized() { + run_test(|| { + assert_noop!( + import_commitment(ChainBuilder::new(1).append_finalized_header().to_header()), + Error::::NotInitialized, + ); + }) + } + + #[test] + fn submit_commitment_works_with_long_chain_with_handoffs() { + run_test_with_initialize(3, || { + let chain = ChainBuilder::new(3) + .append_finalized_header() + .append_default_headers(16) // 2..17 + .append_finalized_header() // 18 + .append_default_headers(16) // 19..34 + .append_handoff_header(9) // 35 + .append_default_headers(8) // 36..43 + .append_finalized_header() // 44 + .append_default_headers(8) // 45..52 + .append_handoff_header(17) // 53 + .append_default_headers(4) // 54..57 + .append_finalized_header() // 58 + .append_default_headers(4); // 59..63 + import_header_chain(chain.to_chain()); + + assert_eq!( + ImportedCommitmentsInfo::::get().unwrap().best_block_number, + 58 + ); + assert_eq!(CurrentAuthoritySetInfo::::get().id, 2); + assert_eq!(CurrentAuthoritySetInfo::::get().len, 17); + + let imported_commitment = ImportedCommitments::::get(58).unwrap(); + assert_eq!( + imported_commitment, + bp_beefy::ImportedCommitment { + parent_number_and_hash: (57, chain.header(57).header.hash()), + mmr_root: chain.header(58).mmr_root, + }, + ); + }) + } + + #[test] + fn commitment_pruning_works() { + run_test_with_initialize(3, || { + let commitments_to_keep = >::CommitmentsToKeep::get(); + let commitments_to_import: Vec = ChainBuilder::new(3) + .append_finalized_headers(commitments_to_keep as usize + 2) + .to_chain(); + + // import exactly `CommitmentsToKeep` commitments + for index in 0..commitments_to_keep { + next_block(); + import_commitment(commitments_to_import[index as usize].clone()) + .expect("must succeed"); + assert_eq!( + ImportedCommitmentsInfo::::get().unwrap().next_block_number_index, + (index + 1) % commitments_to_keep + ); + } + + // ensure that all commitments are in the storage + assert_eq!( + ImportedCommitmentsInfo::::get().unwrap().best_block_number, + commitments_to_keep as TestBridgedBlockNumber + ); + assert_eq!( + ImportedCommitmentsInfo::::get().unwrap().next_block_number_index, + 0 + ); + for index in 0..commitments_to_keep { + assert!(ImportedCommitments::::get( + index as TestBridgedBlockNumber + 1 + ) + .is_some()); + assert_eq!( + ImportedBlockNumbers::::get(index), + Some(index + 1).map(Into::into) + ); + } + + // import next commitment + next_block(); + import_commitment(commitments_to_import[commitments_to_keep as usize].clone()) + .expect("must succeed"); + assert_eq!( + ImportedCommitmentsInfo::::get().unwrap().next_block_number_index, + 1 + ); + assert!(ImportedCommitments::::get( + commitments_to_keep as TestBridgedBlockNumber + 1 + ) + .is_some()); + assert_eq!( + ImportedBlockNumbers::::get(0), + Some(commitments_to_keep + 1).map(Into::into) + ); + // the side effect of the import is that the commitment#1 is pruned + assert!(ImportedCommitments::::get(1).is_none()); + + // import next commitment + next_block(); + import_commitment(commitments_to_import[commitments_to_keep as usize + 1].clone()) + .expect("must succeed"); + assert_eq!( + ImportedCommitmentsInfo::::get().unwrap().next_block_number_index, + 2 + ); + assert!(ImportedCommitments::::get( + commitments_to_keep as TestBridgedBlockNumber + 2 + ) + .is_some()); + assert_eq!( + ImportedBlockNumbers::::get(1), + Some(commitments_to_keep + 2).map(Into::into) + ); + // the side effect of the import is that the commitment#2 is pruned + assert!(ImportedCommitments::::get(1).is_none()); + assert!(ImportedCommitments::::get(2).is_none()); + }); + } + + generate_owned_bridge_module_tests!(BasicOperatingMode::Normal, BasicOperatingMode::Halted); +} diff --git a/modules/beefy/src/mock.rs b/modules/beefy/src/mock.rs new file mode 100644 index 00000000000..1ffccc5dfbc --- /dev/null +++ b/modules/beefy/src/mock.rs @@ -0,0 +1,224 @@ +// Copyright 2019-2021 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 . + +use crate as beefy; +use crate::{ + utils::get_authorities_mmr_root, BridgedBeefyAuthoritySet, BridgedBeefyAuthoritySetInfo, + BridgedBeefyCommitmentHasher, BridgedBeefyMmrLeafExtra, BridgedBeefySignedCommitment, + BridgedMmrHash, BridgedMmrHashing, BridgedMmrProof, +}; + +use bp_beefy::{BeefyValidatorSignatureOf, ChainWithBeefy, Commitment, MmrDataOrHash}; +use bp_runtime::{BasicOperatingMode, Chain}; +use codec::Encode; +use frame_support::{construct_runtime, parameter_types, traits::ConstU64, weights::Weight}; +use sp_core::{sr25519::Signature, Pair}; +use sp_runtime::{ + testing::{Header, H256}, + traits::{BlakeTwo256, Hash, IdentityLookup}, + Perbill, +}; + +pub use sp_consensus_beefy::crypto::{AuthorityId as BeefyId, Pair as BeefyPair}; +use sp_core::crypto::Wraps; +use sp_runtime::traits::Keccak256; + +pub type TestAccountId = u64; +pub type TestBridgedBlockNumber = u64; +pub type TestBridgedBlockHash = H256; +pub type TestBridgedHeader = Header; +pub type TestBridgedAuthoritySetInfo = BridgedBeefyAuthoritySetInfo; +pub type TestBridgedValidatorSet = BridgedBeefyAuthoritySet; +pub type TestBridgedCommitment = BridgedBeefySignedCommitment; +pub type TestBridgedValidatorSignature = BeefyValidatorSignatureOf; +pub type TestBridgedCommitmentHasher = BridgedBeefyCommitmentHasher; +pub type TestBridgedMmrHashing = BridgedMmrHashing; +pub type TestBridgedMmrHash = BridgedMmrHash; +pub type TestBridgedBeefyMmrLeafExtra = BridgedBeefyMmrLeafExtra; +pub type TestBridgedMmrProof = BridgedMmrProof; +pub type TestBridgedRawMmrLeaf = sp_consensus_beefy::mmr::MmrLeaf< + TestBridgedBlockNumber, + TestBridgedBlockHash, + TestBridgedMmrHash, + TestBridgedBeefyMmrLeafExtra, +>; +pub type TestBridgedMmrNode = MmrDataOrHash; + +type TestBlock = frame_system::mocking::MockBlock; +type TestUncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +construct_runtime! { + pub enum TestRuntime where + Block = TestBlock, + NodeBlock = TestBlock, + UncheckedExtrinsic = TestUncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Beefy: beefy::{Pallet}, + } +} + +parameter_types! { + pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 0); + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); +} + +impl frame_system::Config for TestRuntime { + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = TestAccountId; + type Lookup = IdentityLookup; + type Header = Header; + type 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 = frame_support::traits::ConstU32<16>; +} + +impl beefy::Config for TestRuntime { + type MaxRequests = frame_support::traits::ConstU32<16>; + type BridgedChain = TestBridgedChain; + type CommitmentsToKeep = frame_support::traits::ConstU32<16>; +} + +#[derive(Debug)] +pub struct TestBridgedChain; + +impl Chain for TestBridgedChain { + type BlockNumber = TestBridgedBlockNumber; + type Hash = H256; + type Hasher = BlakeTwo256; + type Header = ::Header; + + type AccountId = TestAccountId; + type Balance = u64; + type Index = u64; + type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +impl ChainWithBeefy for TestBridgedChain { + type CommitmentHasher = Keccak256; + type MmrHashing = Keccak256; + type MmrHash = ::Output; + type BeefyMmrLeafExtra = (); + type AuthorityId = BeefyId; + type AuthorityIdToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum; +} + +/// Run test within test runtime. +pub fn run_test(test: impl FnOnce() -> T) -> T { + sp_io::TestExternalities::new(Default::default()).execute_with(test) +} + +/// Initialize pallet and run test. +pub fn run_test_with_initialize(initial_validators_count: u32, test: impl FnOnce() -> T) -> T { + run_test(|| { + let validators = validator_ids(0, initial_validators_count); + let authority_set = authority_set_info(0, &validators); + + crate::Pallet::::initialize( + RuntimeOrigin::root(), + bp_beefy::InitializationData { + operating_mode: BasicOperatingMode::Normal, + best_block_number: 0, + authority_set, + }, + ) + .expect("initialization data is correct"); + + test() + }) +} + +/// Import given commitment. +pub fn import_commitment( + header: crate::mock_chain::HeaderAndCommitment, +) -> sp_runtime::DispatchResult { + crate::Pallet::::submit_commitment( + RuntimeOrigin::signed(1), + header + .commitment + .expect("thou shall not call import_commitment on header without commitment"), + header.validator_set, + Box::new(header.leaf), + header.leaf_proof, + ) +} + +pub fn validator_pairs(index: u32, count: u32) -> Vec { + (index..index + count) + .map(|index| { + let mut seed = [1u8; 32]; + seed[0..8].copy_from_slice(&(index as u64).encode()); + BeefyPair::from_seed(&seed) + }) + .collect() +} + +/// Return identifiers of validators, starting at given index. +pub fn validator_ids(index: u32, count: u32) -> Vec { + validator_pairs(index, count).into_iter().map(|pair| pair.public()).collect() +} + +pub fn authority_set_info(id: u64, validators: &Vec) -> TestBridgedAuthoritySetInfo { + let merkle_root = get_authorities_mmr_root::(validators.iter()); + + TestBridgedAuthoritySetInfo { id, len: validators.len() as u32, root: merkle_root } +} + +/// Sign BEEFY commitment. +pub fn sign_commitment( + commitment: Commitment, + validator_pairs: &[BeefyPair], + signature_count: usize, +) -> TestBridgedCommitment { + let total_validators = validator_pairs.len(); + let random_validators = + rand::seq::index::sample(&mut rand::thread_rng(), total_validators, signature_count); + + let commitment_hash = TestBridgedCommitmentHasher::hash(&commitment.encode()); + let mut signatures = vec![None; total_validators]; + for validator_idx in random_validators.iter() { + let validator = &validator_pairs[validator_idx]; + signatures[validator_idx] = + Some(validator.as_inner_ref().sign_prehashed(commitment_hash.as_fixed_bytes()).into()); + } + + TestBridgedCommitment { commitment, signatures } +} diff --git a/modules/beefy/src/mock_chain.rs b/modules/beefy/src/mock_chain.rs new file mode 100644 index 00000000000..c736aed0742 --- /dev/null +++ b/modules/beefy/src/mock_chain.rs @@ -0,0 +1,299 @@ +// Copyright 2019-2021 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 . + +//! Utilities to build bridged chain and BEEFY+MMR structures. + +use crate::{ + mock::{ + sign_commitment, validator_pairs, BeefyPair, TestBridgedBlockNumber, TestBridgedCommitment, + TestBridgedHeader, TestBridgedMmrHash, TestBridgedMmrHashing, TestBridgedMmrNode, + TestBridgedMmrProof, TestBridgedRawMmrLeaf, TestBridgedValidatorSet, + TestBridgedValidatorSignature, TestRuntime, + }, + utils::get_authorities_mmr_root, +}; + +use bp_beefy::{BeefyPayload, Commitment, ValidatorSetId, MMR_ROOT_PAYLOAD_ID}; +use codec::Encode; +use pallet_mmr::NodeIndex; +use rand::Rng; +use sp_consensus_beefy::mmr::{BeefyNextAuthoritySet, MmrLeafVersion}; +use sp_core::Pair; +use sp_runtime::traits::{Hash, Header as HeaderT}; +use std::collections::HashMap; + +#[derive(Debug, Clone)] +pub struct HeaderAndCommitment { + pub header: TestBridgedHeader, + pub commitment: Option, + pub validator_set: TestBridgedValidatorSet, + pub leaf: TestBridgedRawMmrLeaf, + pub leaf_proof: TestBridgedMmrProof, + pub mmr_root: TestBridgedMmrHash, +} + +impl HeaderAndCommitment { + pub fn customize_signatures( + &mut self, + f: impl FnOnce(&mut Vec>), + ) { + if let Some(commitment) = &mut self.commitment { + f(&mut commitment.signatures); + } + } + + pub fn customize_commitment( + &mut self, + f: impl FnOnce(&mut Commitment), + validator_pairs: &[BeefyPair], + signature_count: usize, + ) { + if let Some(mut commitment) = self.commitment.take() { + f(&mut commitment.commitment); + self.commitment = + Some(sign_commitment(commitment.commitment, validator_pairs, signature_count)); + } + } +} + +pub struct ChainBuilder { + headers: Vec, + validator_set_id: ValidatorSetId, + validator_keys: Vec, + mmr: mmr_lib::MMR, +} + +struct BridgedMmrStorage { + nodes: HashMap, +} + +impl mmr_lib::MMRStore for BridgedMmrStorage { + fn get_elem(&self, pos: NodeIndex) -> mmr_lib::Result> { + Ok(self.nodes.get(&pos).cloned()) + } + + fn append(&mut self, pos: NodeIndex, elems: Vec) -> mmr_lib::Result<()> { + for (i, elem) in elems.into_iter().enumerate() { + self.nodes.insert(pos + i as NodeIndex, elem); + } + Ok(()) + } +} + +impl ChainBuilder { + /// Creates new chain builder with given validator set size. + pub fn new(initial_validators_count: u32) -> Self { + ChainBuilder { + headers: Vec::new(), + validator_set_id: 0, + validator_keys: validator_pairs(0, initial_validators_count), + mmr: mmr_lib::MMR::new(0, BridgedMmrStorage { nodes: HashMap::new() }), + } + } + + /// Get header with given number. + pub fn header(&self, number: TestBridgedBlockNumber) -> HeaderAndCommitment { + self.headers[number as usize - 1].clone() + } + + /// Returns single built header. + pub fn to_header(&self) -> HeaderAndCommitment { + assert_eq!(self.headers.len(), 1); + self.headers[0].clone() + } + + /// Returns built chain. + pub fn to_chain(&self) -> Vec { + self.headers.clone() + } + + /// Appends header, that has been finalized by BEEFY (so it has a linked signed commitment). + pub fn append_finalized_header(self) -> Self { + let next_validator_set_id = self.validator_set_id; + let next_validator_keys = self.validator_keys.clone(); + HeaderBuilder::with_chain(self, next_validator_set_id, next_validator_keys).finalize() + } + + /// Append multiple finalized headers at once. + pub fn append_finalized_headers(mut self, count: usize) -> Self { + for _ in 0..count { + self = self.append_finalized_header(); + } + self + } + + /// Appends header, that enacts new validator set. + /// + /// Such headers are explicitly finalized by BEEFY. + pub fn append_handoff_header(self, next_validators_len: u32) -> Self { + let new_validator_set_id = self.validator_set_id + 1; + let new_validator_pairs = + validator_pairs(rand::thread_rng().gen::() % (u32::MAX / 2), next_validators_len); + + HeaderBuilder::with_chain(self, new_validator_set_id, new_validator_pairs).finalize() + } + + /// Append several default header without commitment. + pub fn append_default_headers(mut self, count: usize) -> Self { + for _ in 0..count { + let next_validator_set_id = self.validator_set_id; + let next_validator_keys = self.validator_keys.clone(); + self = + HeaderBuilder::with_chain(self, next_validator_set_id, next_validator_keys).build() + } + self + } +} + +/// Custom header builder. +pub struct HeaderBuilder { + chain: ChainBuilder, + header: TestBridgedHeader, + leaf: TestBridgedRawMmrLeaf, + leaf_proof: Option, + next_validator_set_id: ValidatorSetId, + next_validator_keys: Vec, +} + +impl HeaderBuilder { + fn with_chain( + chain: ChainBuilder, + next_validator_set_id: ValidatorSetId, + next_validator_keys: Vec, + ) -> Self { + // we're starting with header#1, since header#0 is always finalized + let header_number = chain.headers.len() as TestBridgedBlockNumber + 1; + let header = TestBridgedHeader::new( + header_number, + Default::default(), + Default::default(), + chain.headers.last().map(|h| h.header.hash()).unwrap_or_default(), + Default::default(), + ); + + let next_validators = + next_validator_keys.iter().map(|pair| pair.public()).collect::>(); + let next_validators_mmr_root = + get_authorities_mmr_root::(next_validators.iter()); + let leaf = sp_consensus_beefy::mmr::MmrLeaf { + version: MmrLeafVersion::new(1, 0), + parent_number_and_hash: (header.number().saturating_sub(1), *header.parent_hash()), + beefy_next_authority_set: BeefyNextAuthoritySet { + id: next_validator_set_id, + len: next_validators.len() as u32, + root: next_validators_mmr_root, + }, + leaf_extra: (), + }; + + HeaderBuilder { + chain, + header, + leaf, + leaf_proof: None, + next_validator_keys, + next_validator_set_id, + } + } + + /// Customize generated proof of header MMR leaf. + /// + /// Can only be called once. + pub fn customize_proof( + mut self, + f: impl FnOnce(TestBridgedMmrProof) -> TestBridgedMmrProof, + ) -> Self { + assert!(self.leaf_proof.is_none()); + + let leaf_hash = TestBridgedMmrHashing::hash(&self.leaf.encode()); + let node = TestBridgedMmrNode::Hash(leaf_hash); + let leaf_position = self.chain.mmr.push(node).unwrap(); + + let proof = self.chain.mmr.gen_proof(vec![leaf_position]).unwrap(); + // genesis has no leaf => leaf index is header number minus 1 + let leaf_index = *self.header.number() - 1; + let leaf_count = *self.header.number(); + self.leaf_proof = Some(f(TestBridgedMmrProof { + leaf_indices: vec![leaf_index], + leaf_count, + items: proof.proof_items().iter().map(|i| i.hash()).collect(), + })); + + self + } + + /// Build header without commitment. + pub fn build(mut self) -> ChainBuilder { + if self.leaf_proof.is_none() { + self = self.customize_proof(|proof| proof); + } + + let validators = + self.chain.validator_keys.iter().map(|pair| pair.public()).collect::>(); + self.chain.headers.push(HeaderAndCommitment { + header: self.header, + commitment: None, + validator_set: TestBridgedValidatorSet::new(validators, self.chain.validator_set_id) + .unwrap(), + leaf: self.leaf, + leaf_proof: self.leaf_proof.expect("guaranteed by the customize_proof call above; qed"), + mmr_root: self.chain.mmr.get_root().unwrap().hash(), + }); + + self.chain.validator_set_id = self.next_validator_set_id; + self.chain.validator_keys = self.next_validator_keys; + + self.chain + } + + /// Build header with commitment. + pub fn finalize(self) -> ChainBuilder { + let validator_count = self.chain.validator_keys.len(); + let current_validator_set_id = self.chain.validator_set_id; + let current_validator_set_keys = self.chain.validator_keys.clone(); + let mut chain = self.build(); + + let last_header = chain.headers.last_mut().expect("added by append_header; qed"); + last_header.commitment = Some(sign_commitment( + Commitment { + payload: BeefyPayload::from_single_entry( + MMR_ROOT_PAYLOAD_ID, + chain.mmr.get_root().unwrap().hash().encode(), + ), + block_number: *last_header.header.number(), + validator_set_id: current_validator_set_id, + }, + ¤t_validator_set_keys, + validator_count * 2 / 3 + 1, + )); + + chain + } +} + +/// Default Merging & Hashing behavior for MMR. +pub struct BridgedMmrHashMerge; + +impl mmr_lib::Merge for BridgedMmrHashMerge { + type Item = TestBridgedMmrNode; + + fn merge(left: &Self::Item, right: &Self::Item) -> Self::Item { + let mut concat = left.hash().as_ref().to_vec(); + concat.extend_from_slice(right.hash().as_ref()); + + TestBridgedMmrNode::Hash(TestBridgedMmrHashing::hash(&concat)) + } +} diff --git a/modules/beefy/src/utils.rs b/modules/beefy/src/utils.rs new file mode 100644 index 00000000000..45e14ecbfe0 --- /dev/null +++ b/modules/beefy/src/utils.rs @@ -0,0 +1,361 @@ +use crate::{ + BridgedBeefyAuthorityId, BridgedBeefyAuthoritySet, BridgedBeefyAuthoritySetInfo, + BridgedBeefyMmrLeaf, BridgedBeefySignedCommitment, BridgedChain, BridgedMmrHash, + BridgedMmrHashing, BridgedMmrProof, Config, Error, LOG_TARGET, +}; +use bp_beefy::{merkle_root, verify_mmr_leaves_proof, BeefyAuthorityId, MmrDataOrHash}; +use codec::Encode; +use frame_support::ensure; +use sp_runtime::traits::{Convert, Hash}; +use sp_std::{vec, vec::Vec}; + +type BridgedMmrDataOrHash = MmrDataOrHash, BridgedBeefyMmrLeaf>; +/// A way to encode validator id to the BEEFY merkle tree leaf. +type BridgedBeefyAuthorityIdToMerkleLeaf = + bp_beefy::BeefyAuthorityIdToMerkleLeafOf>; + +/// Get the MMR root for a collection of validators. +pub(crate) fn get_authorities_mmr_root< + 'a, + T: Config, + I: 'static, + V: Iterator>, +>( + authorities: V, +) -> BridgedMmrHash { + let merkle_leafs = authorities + .cloned() + .map(BridgedBeefyAuthorityIdToMerkleLeaf::::convert) + .collect::>(); + merkle_root::, _>(merkle_leafs) +} + +fn verify_authority_set, I: 'static>( + authority_set_info: &BridgedBeefyAuthoritySetInfo, + authority_set: &BridgedBeefyAuthoritySet, +) -> Result<(), Error> { + ensure!(authority_set.id() == authority_set_info.id, Error::::InvalidValidatorSetId); + ensure!( + authority_set.len() == authority_set_info.len as usize, + Error::::InvalidValidatorSetLen + ); + + // Ensure that the authority set that signed the commitment is the expected one. + let root = get_authorities_mmr_root::(authority_set.validators().iter()); + ensure!(root == authority_set_info.root, Error::::InvalidValidatorSetRoot); + + Ok(()) +} + +/// Number of correct signatures, required from given validators set to accept signed +/// commitment. +/// +/// We're using 'conservative' approach here, where signatures of `2/3+1` validators are +/// required.. +pub(crate) fn signatures_required(validators_len: usize) -> usize { + validators_len - validators_len.saturating_sub(1) / 3 +} + +fn verify_signatures, I: 'static>( + commitment: &BridgedBeefySignedCommitment, + authority_set: &BridgedBeefyAuthoritySet, +) -> Result<(), Error> { + ensure!( + commitment.signatures.len() == authority_set.len(), + Error::::InvalidCommitmentSignaturesLen + ); + + // Ensure that the commitment was signed by enough authorities. + let msg = commitment.commitment.encode(); + let mut missing_signatures = signatures_required(authority_set.len()); + for (idx, (authority, maybe_sig)) in + authority_set.validators().iter().zip(commitment.signatures.iter()).enumerate() + { + if let Some(sig) = maybe_sig { + if authority.verify(sig, &msg) { + missing_signatures = missing_signatures.saturating_sub(1); + if missing_signatures == 0 { + break + } + } else { + log::debug!( + target: LOG_TARGET, + "Signed commitment contains incorrect signature of validator {} ({:?}): {:?}", + idx, + authority, + sig, + ); + } + } + } + ensure!(missing_signatures == 0, Error::::NotEnoughCorrectSignatures); + + Ok(()) +} + +/// Extract MMR root from commitment payload. +fn extract_mmr_root, I: 'static>( + commitment: &BridgedBeefySignedCommitment, +) -> Result, Error> { + commitment + .commitment + .payload + .get_decoded(&bp_beefy::MMR_ROOT_PAYLOAD_ID) + .ok_or(Error::MmrRootMissingFromCommitment) +} + +pub(crate) fn verify_commitment, I: 'static>( + commitment: &BridgedBeefySignedCommitment, + authority_set_info: &BridgedBeefyAuthoritySetInfo, + authority_set: &BridgedBeefyAuthoritySet, +) -> Result, Error> { + // Ensure that the commitment is signed by the best known BEEFY validator set. + ensure!( + commitment.commitment.validator_set_id == authority_set_info.id, + Error::::InvalidCommitmentValidatorSetId + ); + ensure!( + commitment.signatures.len() == authority_set_info.len as usize, + Error::::InvalidCommitmentSignaturesLen + ); + + verify_authority_set(authority_set_info, authority_set)?; + verify_signatures(commitment, authority_set)?; + + extract_mmr_root(commitment) +} + +/// Verify MMR proof of given leaf. +pub(crate) fn verify_beefy_mmr_leaf, I: 'static>( + mmr_leaf: &BridgedBeefyMmrLeaf, + mmr_proof: BridgedMmrProof, + mmr_root: BridgedMmrHash, +) -> Result<(), Error> { + let mmr_proof_leaf_count = mmr_proof.leaf_count; + let mmr_proof_length = mmr_proof.items.len(); + + // Verify the mmr proof for the provided leaf. + let mmr_leaf_hash = BridgedMmrHashing::::hash(&mmr_leaf.encode()); + verify_mmr_leaves_proof( + mmr_root, + vec![BridgedMmrDataOrHash::::Hash(mmr_leaf_hash)], + mmr_proof, + ) + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "MMR proof of leaf {:?} (root: {:?}, leaf count: {}, len: {}) \ + verification has failed with error: {:?}", + mmr_leaf_hash, + mmr_root, + mmr_proof_leaf_count, + mmr_proof_length, + e, + ); + + Error::::MmrProofVerificationFailed + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{mock::*, mock_chain::*, *}; + use bp_beefy::{BeefyPayload, MMR_ROOT_PAYLOAD_ID}; + use frame_support::{assert_noop, assert_ok}; + use sp_consensus_beefy::ValidatorSet; + + #[test] + fn submit_commitment_checks_metadata() { + run_test_with_initialize(8, || { + // Fails if `commitment.commitment.validator_set_id` differs. + let mut header = ChainBuilder::new(8).append_finalized_header().to_header(); + header.customize_commitment( + |commitment| { + commitment.validator_set_id += 1; + }, + &validator_pairs(0, 8), + 6, + ); + assert_noop!( + import_commitment(header), + Error::::InvalidCommitmentValidatorSetId, + ); + + // Fails if `commitment.signatures.len()` differs. + let mut header = ChainBuilder::new(8).append_finalized_header().to_header(); + header.customize_signatures(|signatures| { + signatures.pop(); + }); + assert_noop!( + import_commitment(header), + Error::::InvalidCommitmentSignaturesLen, + ); + }); + } + + #[test] + fn submit_commitment_checks_validator_set() { + run_test_with_initialize(8, || { + // Fails if `ValidatorSet::id` differs. + let mut header = ChainBuilder::new(8).append_finalized_header().to_header(); + header.validator_set = ValidatorSet::new(validator_ids(0, 8), 1).unwrap(); + assert_noop!( + import_commitment(header), + Error::::InvalidValidatorSetId, + ); + + // Fails if `ValidatorSet::len()` differs. + let mut header = ChainBuilder::new(8).append_finalized_header().to_header(); + header.validator_set = ValidatorSet::new(validator_ids(0, 5), 0).unwrap(); + assert_noop!( + import_commitment(header), + Error::::InvalidValidatorSetLen, + ); + + // Fails if the validators differ. + let mut header = ChainBuilder::new(8).append_finalized_header().to_header(); + header.validator_set = ValidatorSet::new(validator_ids(3, 8), 0).unwrap(); + assert_noop!( + import_commitment(header), + Error::::InvalidValidatorSetRoot, + ); + }); + } + + #[test] + fn submit_commitment_checks_signatures() { + run_test_with_initialize(20, || { + // Fails when there aren't enough signatures. + let mut header = ChainBuilder::new(20).append_finalized_header().to_header(); + header.customize_signatures(|signatures| { + let first_signature_idx = signatures.iter().position(Option::is_some).unwrap(); + signatures[first_signature_idx] = None; + }); + assert_noop!( + import_commitment(header), + Error::::NotEnoughCorrectSignatures, + ); + + // Fails when there aren't enough correct signatures. + let mut header = ChainBuilder::new(20).append_finalized_header().to_header(); + header.customize_signatures(|signatures| { + let first_signature_idx = signatures.iter().position(Option::is_some).unwrap(); + let last_signature_idx = signatures.len() - + signatures.iter().rev().position(Option::is_some).unwrap() - + 1; + signatures[first_signature_idx] = signatures[last_signature_idx].clone(); + }); + assert_noop!( + import_commitment(header), + Error::::NotEnoughCorrectSignatures, + ); + + // Returns Ok(()) when there are enough signatures, even if some are incorrect. + let mut header = ChainBuilder::new(20).append_finalized_header().to_header(); + header.customize_signatures(|signatures| { + let first_signature_idx = signatures.iter().position(Option::is_some).unwrap(); + let first_missing_signature_idx = + signatures.iter().position(Option::is_none).unwrap(); + signatures[first_missing_signature_idx] = signatures[first_signature_idx].clone(); + }); + assert_ok!(import_commitment(header)); + }); + } + + #[test] + fn submit_commitment_checks_mmr_proof() { + run_test_with_initialize(1, || { + let validators = validator_pairs(0, 1); + + // Fails if leaf is not for parent. + let mut header = ChainBuilder::new(1).append_finalized_header().to_header(); + header.leaf.parent_number_and_hash.0 += 1; + assert_noop!( + import_commitment(header), + Error::::MmrProofVerificationFailed, + ); + + // Fails if mmr proof is incorrect. + let mut header = ChainBuilder::new(1).append_finalized_header().to_header(); + header.leaf_proof.leaf_indices[0] += 1; + assert_noop!( + import_commitment(header), + Error::::MmrProofVerificationFailed, + ); + + // Fails if mmr root is incorrect. + let mut header = ChainBuilder::new(1).append_finalized_header().to_header(); + // Replace MMR root with zeroes. + header.customize_commitment( + |commitment| { + commitment.payload = + BeefyPayload::from_single_entry(MMR_ROOT_PAYLOAD_ID, [0u8; 32].encode()); + }, + &validators, + 1, + ); + assert_noop!( + import_commitment(header), + Error::::MmrProofVerificationFailed, + ); + }); + } + + #[test] + fn submit_commitment_extracts_mmr_root() { + run_test_with_initialize(1, || { + let validators = validator_pairs(0, 1); + + // Fails if there is no mmr root in the payload. + let mut header = ChainBuilder::new(1).append_finalized_header().to_header(); + // Remove MMR root from the payload. + header.customize_commitment( + |commitment| { + commitment.payload = BeefyPayload::from_single_entry(*b"xy", vec![]); + }, + &validators, + 1, + ); + assert_noop!( + import_commitment(header), + Error::::MmrRootMissingFromCommitment, + ); + + // Fails if mmr root can't be decoded. + let mut header = ChainBuilder::new(1).append_finalized_header().to_header(); + // MMR root is a 32-byte array and we have replaced it with single byte + header.customize_commitment( + |commitment| { + commitment.payload = + BeefyPayload::from_single_entry(MMR_ROOT_PAYLOAD_ID, vec![42]); + }, + &validators, + 1, + ); + assert_noop!( + import_commitment(header), + Error::::MmrRootMissingFromCommitment, + ); + }); + } + + #[test] + fn submit_commitment_stores_valid_data() { + run_test_with_initialize(20, || { + let header = ChainBuilder::new(20).append_handoff_header(30).to_header(); + assert_ok!(import_commitment(header.clone())); + + assert_eq!(ImportedCommitmentsInfo::::get().unwrap().best_block_number, 1); + assert_eq!(CurrentAuthoritySetInfo::::get().id, 1); + assert_eq!(CurrentAuthoritySetInfo::::get().len, 30); + assert_eq!( + ImportedCommitments::::get(1).unwrap(), + bp_beefy::ImportedCommitment { + parent_number_and_hash: (0, [0; 32].into()), + mmr_root: header.mmr_root, + }, + ); + }); + } +} diff --git a/modules/grandpa/Cargo.toml b/modules/grandpa/Cargo.toml new file mode 100644 index 00000000000..07d2593b914 --- /dev/null +++ b/modules/grandpa/Cargo.toml @@ -0,0 +1,63 @@ +[package] +name = "pallet-bridge-grandpa" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false } +finality-grandpa = { version = "0.16.2", default-features = false } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +# Bridge Dependencies + +bp-runtime = { path = "../../primitives/runtime", default-features = false } +bp-header-chain = { path = "../../primitives/header-chain", default-features = false } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +# Optional Benchmarking Dependencies +bp-test-utils = { path = "../../primitives/test-utils", default-features = false, optional = true } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } + +[dev-dependencies] +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-runtime/std", + "bp-test-utils/std", + "codec/std", + "finality-grandpa/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "log/std", + "scale-info/std", + "sp-consensus-grandpa/std", + "sp-runtime/std", + "sp-std/std", + "sp-trie/std", +] +runtime-benchmarks = [ + "bp-test-utils", + "frame-benchmarking/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/grandpa/README.md b/modules/grandpa/README.md new file mode 100644 index 00000000000..27b4d2389c4 --- /dev/null +++ b/modules/grandpa/README.md @@ -0,0 +1,101 @@ +# Bridge GRANDPA Pallet + +The bridge GRANDPA pallet is a light client for the GRANDPA finality gadget, running at the bridged chain. +It may import headers and their GRANDPA finality proofs (justifications) of the bridged chain. Imported +headers then may be used to verify storage proofs by other pallets. This makes the bridge GRANDPA pallet +a basic pallet of all bridges with Substrate-based chains. It is used by all bridge types (bridge between +standalone chains, between parachains and any combination of those) and is used by other bridge pallets. +It is used by the parachains light client (bridge parachains pallet) and by messages pallet. + +## A Brief Introduction into GRANDPA Finality + +You can find detailed information on GRANDPA, by exploring its [repository](https://github.com/paritytech/finality-grandpa). +Here is the minimal reqiuired GRANDPA information to understand how pallet works. + +Any Substrate chain may use different block authorship algorithms (like BABE or Aura) to determine block producers and +generate blocks. This has nothing common with finality, though - the task of block authorship is to coordinate +blocks generation. Any block may be reverted (if there's a fork) if it is not finalized. The finality solution +for (standalone) Substrate-based chains is the GRANDPA finality gadget. If some block is finalized by the gadget, it +can't be reverted. + +In GRANDPA, there are validators, identified by their public keys. They select some generated block and produce +signatures on this block hash. If there are enough (more than `2 / 3 * N`, where `N` is number of validators) +signatures, then the block is considered finalized. The set of signatures for the block is called justification. +Anyone who knows the public keys of validators is able to verify GRANDPA justification and that it is generated +for provided header. + +There are two main things in GRANDPA that help building light clients: + +- there's no need to import all headers of the bridged chain. Light client may import finalized headers or just + some of finalized headders that it consider useful. While the validators set stays the same, the client may + import any header that is finalized by this set; + +- when validators set changes, the GRANDPA gadget adds next set to the header. So light client doesn't need to + verify storage proofs when this happens - it only needs to look at the header and see if it changes the set. + Once set is changed, all following justifications are generated by the new set. Header that is changing the + set is called "mandatory" in the pallet. As the name says, the light client need to import all such headers + to be able to operate properly. + +## Pallet Operations + +The main entrypoint of the pallet is the `submit_finality_proof` call. It has two arguments - the finalized +headers and associated GRANDPA justification. The call simply verifies the justification using current +validators set and checks if header is better than the previous best header. If both checks are passed, the +header (only its useful fields) is inserted into the runtime storage and may be used by other pallets to verify +storage proofs. + +The submitter pays regular fee for submitting all headers, except for the mandatory header. Since it is +required for the pallet operations, submitting such header is free. So if you're ok with session-length +lags (meaning that there's exactly 1 mandatory header per session), the cost of pallet calls is zero. + +When the pallet sees mandatory header, it updates the validators set with the set from the header. All +following justifications (until next mandatory header) must be generated by this new set. + +## Pallet Initialization + +As the previous section states, there are two things that are mandatory for pallet operations: best finalized +header and the current validators set. Without it the pallet can't import any headers. But how to provide +initial values for these fields? There are two options. + +First option, while it is easier, doesn't work in all cases. It is to start chain with initial header and +validators set specified in the chain specification. This won't work, however, if we want to add bridge +to already started chain. + +For the latter case we have the `initialize` call. It accepts the initial header and initial validators set. +The call may be called by the governance, root or by the pallet owner (if it is set). + +## Non-Essential Functionality + +There may be a special account in every runtime where the bridge GRANDPA 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 set_operating_mode()`: the module owner (or sudo account) may call this function to stop all + module operations. After this call, all finality proofs will be rejected until further `set_operating_mode` call'. + This call may be used when something extraordinary happens with the bridge; + +- `fn initialize()`: module owner may call this function to initialize the bridge. + +If pallet owner is not defined, the governance may be used to make those calls. + +## Signed Extension to Reject Obsolete Headers + +It'd be better for anyone (for chain and for submitters) to reject all transactions that are submitting +already known headers to the pallet. This way, we leave block space to other useful transactions and +we don't charge concurrent submitters for their honest actions. + +To deal with that, we have a [signed extension](./src/call_ext) that may be added to the runtime. +It does exactly what is required - rejects all transactions with already known headers. The submitter +pays nothing for such transactions - they're simply removed from the transaction pool, when the block +is built. + +You may also take a look at the [`generate_bridge_reject_obsolete_headers_and_messages`](../../bin/runtime-common/src/lib.rs) +macro that bundles several similar signed extensions in a single one. + +## GRANDPA Finality Relay + +We have an offchain actor, who is watching for GRANDPA justifications and submits them to the bridged chain. +It is the finality relay - you may look at the [crate level documentation and the code](../../relays/finality/). diff --git a/modules/grandpa/src/benchmarking.rs b/modules/grandpa/src/benchmarking.rs new file mode 100644 index 00000000000..aa222d6e4de --- /dev/null +++ b/modules/grandpa/src/benchmarking.rs @@ -0,0 +1,141 @@ +// Copyright 2019-2021 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 . + +//! Benchmarks for the GRANDPA Pallet. +//! +//! The main dispatchable for the GRANDPA pallet is `submit_finality_proof`, so these benchmarks are +//! based around that. There are to main factors which affect finality proof verification: +//! +//! 1. The number of `votes-ancestries` in the justification +//! 2. The number of `pre-commits` in the justification +//! +//! Vote ancestries are the headers between (`finality_target`, `head_of_chain`], where +//! `header_of_chain` is a descendant of `finality_target`. +//! +//! Pre-commits are messages which are signed by validators at the head of the chain they think is +//! the best. +//! +//! Consider the following: +//! +//! / B <- C' +//! A <- B <- C +//! +//! The common ancestor of both forks is block A, so this is what GRANDPA will finalize. In order to +//! verify this we will have vote ancestries of `[B, C, B', C']` and pre-commits `[C, C']`. +//! +//! Note that the worst case scenario here would be a justification where each validator has it's +//! own fork which is `SESSION_LENGTH` blocks long. + +use crate::*; + +use bp_header_chain::justification::required_justification_precommits; +use bp_runtime::BasicOperatingMode; +use bp_test_utils::{ + accounts, make_justification_for_header, JustificationGeneratorParams, TEST_GRANDPA_ROUND, + TEST_GRANDPA_SET_ID, +}; +use frame_benchmarking::{benchmarks_instance_pallet, whitelisted_caller}; +use frame_system::RawOrigin; +use sp_consensus_grandpa::AuthorityId; +use sp_runtime::traits::{One, Zero}; +use sp_std::vec::Vec; + +/// The maximum number of vote ancestries to include in a justification. +/// +/// In practice this would be limited by the session length (number of blocks a single authority set +/// can produce) of a given chain. +const MAX_VOTE_ANCESTRIES: u32 = 1000; + +// `1..MAX_VOTE_ANCESTRIES` is too large && benchmarks are running for almost 40m (steps=50, +// repeat=20) on a decent laptop, which is too much. Since we're building linear function here, +// let's just select some limited subrange for benchmarking. +const MAX_VOTE_ANCESTRIES_RANGE_BEGIN: u32 = MAX_VOTE_ANCESTRIES / 20; +const MAX_VOTE_ANCESTRIES_RANGE_END: u32 = + MAX_VOTE_ANCESTRIES_RANGE_BEGIN + MAX_VOTE_ANCESTRIES_RANGE_BEGIN; + +// the same with validators - if there are too much validators, let's run benchmarks on subrange +fn precommits_range_end, I: 'static>() -> u32 { + let max_bridged_authorities = T::BridgedChain::MAX_AUTHORITIES_COUNT; + if max_bridged_authorities > 128 { + sp_std::cmp::max(128, max_bridged_authorities / 5) + } else { + max_bridged_authorities + }; + required_justification_precommits(max_bridged_authorities) +} + +/// Prepare header and its justification to submit using `submit_finality_proof`. +fn prepare_benchmark_data, I: 'static>( + precommits: u32, + ancestors: u32, +) -> (BridgedHeader, GrandpaJustification>) { + // going from precommits to total authorities count + let total_authorities_count = (3 * precommits - 1) / 2; + + let authority_list = accounts(total_authorities_count as u16) + .iter() + .map(|id| (AuthorityId::from(*id), 1)) + .collect::>(); + + let genesis_header: BridgedHeader = bp_test_utils::test_header(Zero::zero()); + let genesis_hash = genesis_header.hash(); + let init_data = InitializationData { + header: Box::new(genesis_header), + authority_list, + set_id: TEST_GRANDPA_SET_ID, + operating_mode: BasicOperatingMode::Normal, + }; + + bootstrap_bridge::(init_data); + assert!(>::contains_key(genesis_hash)); + + let header: BridgedHeader = bp_test_utils::test_header(One::one()); + let params = JustificationGeneratorParams { + header: header.clone(), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: accounts(precommits as u16).iter().map(|k| (*k, 1)).collect::>(), + ancestors, + forks: 1, + }; + let justification = make_justification_for_header(params); + (header, justification) +} + +benchmarks_instance_pallet! { + // This is the "gold standard" benchmark for this extrinsic, and it's what should be used to + // annotate the weight in the pallet. + submit_finality_proof { + let p in 1 .. precommits_range_end::(); + let v in MAX_VOTE_ANCESTRIES_RANGE_BEGIN..MAX_VOTE_ANCESTRIES_RANGE_END; + let caller: T::AccountId = whitelisted_caller(); + let (header, justification) = prepare_benchmark_data::(p, v); + }: submit_finality_proof(RawOrigin::Signed(caller), Box::new(header), justification) + verify { + let genesis_header: BridgedHeader = bp_test_utils::test_header(Zero::zero()); + let header: BridgedHeader = bp_test_utils::test_header(One::one()); + let expected_hash = header.hash(); + + // check that the header#1 has been inserted + assert_eq!(>::get().unwrap().1, expected_hash); + assert!(>::contains_key(expected_hash)); + + // check that the header#0 has been pruned + assert!(!>::contains_key(genesis_header.hash())); + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) +} diff --git a/modules/grandpa/src/call_ext.rs b/modules/grandpa/src/call_ext.rs new file mode 100644 index 00000000000..b57aebb1ac1 --- /dev/null +++ b/modules/grandpa/src/call_ext.rs @@ -0,0 +1,311 @@ +// Copyright 2021 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 . + +use crate::{weights::WeightInfo, BridgedBlockNumber, BridgedHeader, Config, Error, Pallet}; +use bp_header_chain::{justification::GrandpaJustification, ChainWithGrandpa}; +use bp_runtime::BlockNumberOf; +use codec::Encode; +use frame_support::{dispatch::CallableCallFor, traits::IsSubType, weights::Weight, RuntimeDebug}; +use sp_runtime::{ + traits::{Header, Zero}, + transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, + SaturatedConversion, +}; + +/// Info about a `SubmitParachainHeads` call which tries to update a single parachain. +#[derive(Copy, Clone, PartialEq, RuntimeDebug)] +pub struct SubmitFinalityProofInfo { + /// Number of the finality target. + pub block_number: N, + /// Extra weight that we assume is included in the call. + /// + /// We have some assumptions about headers and justifications of the bridged chain. + /// We know that if our assumptions are correct, then the call must not have the + /// weight above some limit. The fee paid for weight above that limit, is never refunded. + pub extra_weight: Weight, + /// Extra size (in bytes) that we assume are included in the call. + /// + /// We have some assumptions about headers and justifications of the bridged chain. + /// We know that if our assumptions are correct, then the call must not have the + /// weight above some limit. The fee paid for bytes above that limit, is never refunded. + pub extra_size: u32, +} + +impl SubmitFinalityProofInfo { + /// Returns `true` if call size/weight is below our estimations for regular calls. + pub fn fits_limits(&self) -> bool { + self.extra_weight.is_zero() && self.extra_size.is_zero() + } +} + +/// Helper struct that provides methods for working with the `SubmitFinalityProof` call. +pub struct SubmitFinalityProofHelper, I: 'static> { + _phantom_data: sp_std::marker::PhantomData<(T, I)>, +} + +impl, I: 'static> SubmitFinalityProofHelper { + /// Check that the GRANDPA head provided by the `SubmitFinalityProof` is better than the best + /// one we know. + pub fn check_obsolete( + finality_target: BlockNumberOf, + ) -> Result<(), Error> { + let best_finalized = crate::BestFinalized::::get().ok_or_else(|| { + log::trace!( + target: crate::LOG_TARGET, + "Cannot finalize header {:?} because pallet is not yet initialized", + finality_target, + ); + >::NotInitialized + })?; + + if best_finalized.number() >= finality_target { + log::trace!( + target: crate::LOG_TARGET, + "Cannot finalize obsolete header: bundled {:?}, best {:?}", + finality_target, + best_finalized, + ); + + return Err(Error::::OldHeader) + } + + Ok(()) + } + + /// Check if the `SubmitFinalityProof` was successfully executed. + pub fn was_successful(finality_target: BlockNumberOf) -> bool { + match crate::BestFinalized::::get() { + Some(best_finalized) => best_finalized.number() == finality_target, + None => false, + } + } +} + +/// Trait representing a call that is a sub type of this pallet's call. +pub trait CallSubType, I: 'static>: + IsSubType, T>> +{ + /// Extract finality proof info from a runtime call. + fn submit_finality_proof_info( + &self, + ) -> Option>> { + if let Some(crate::Call::::submit_finality_proof { finality_target, justification }) = + self.is_sub_type() + { + return Some(submit_finality_proof_info_from_args::( + finality_target, + justification, + )) + } + + None + } + + /// Validate Grandpa headers in order to avoid "mining" transactions that provide outdated + /// bridged chain headers. Without this validation, even honest relayers may lose their funds + /// if there are multiple relays running and submitting the same information. + fn check_obsolete_submit_finality_proof(&self) -> TransactionValidity + where + Self: Sized, + { + let finality_target = match self.submit_finality_proof_info() { + Some(finality_proof) => finality_proof, + _ => return Ok(ValidTransaction::default()), + }; + + match SubmitFinalityProofHelper::::check_obsolete(finality_target.block_number) { + Ok(_) => Ok(ValidTransaction::default()), + Err(Error::::OldHeader) => InvalidTransaction::Stale.into(), + Err(_) => InvalidTransaction::Call.into(), + } + } +} + +impl, I: 'static> CallSubType for T::RuntimeCall where + T::RuntimeCall: IsSubType, T>> +{ +} + +/// Extract finality proof info from the submitted header and justification. +pub(crate) fn submit_finality_proof_info_from_args, I: 'static>( + finality_target: &BridgedHeader, + justification: &GrandpaJustification>, +) -> SubmitFinalityProofInfo> { + let block_number = *finality_target.number(); + + // the `submit_finality_proof` call will reject justifications with invalid, duplicate, + // unknown and extra signatures. It'll also reject justifications with less than necessary + // signatures. So we do not care about extra weight because of additional signatures here. + let precommits_len = justification.commit.precommits.len().saturated_into(); + let required_precommits = precommits_len; + + // We do care about extra weight because of more-than-expected headers in the votes + // ancestries. But we have problems computing extra weight for additional headers (weight of + // additional header is too small, so that our benchmarks aren't detecting that). So if there + // are more than expected headers in votes ancestries, we will treat the whole call weight + // as an extra weight. + let votes_ancestries_len = justification.votes_ancestries.len().saturated_into(); + let extra_weight = + if votes_ancestries_len > T::BridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY { + T::WeightInfo::submit_finality_proof(precommits_len, votes_ancestries_len) + } else { + Weight::zero() + }; + + // we can estimate extra call size easily, without any additional significant overhead + let actual_call_size: u32 = finality_target + .encoded_size() + .saturating_add(justification.encoded_size()) + .saturated_into(); + let max_expected_call_size = max_expected_call_size::(required_precommits); + let extra_size = actual_call_size.saturating_sub(max_expected_call_size); + + SubmitFinalityProofInfo { block_number, extra_weight, extra_size } +} + +/// Returns maximal expected size of `submit_finality_proof` call arguments. +fn max_expected_call_size, I: 'static>(required_precommits: u32) -> u32 { + let max_expected_justification_size = + GrandpaJustification::max_reasonable_size::(required_precommits); + + // call arguments are header and justification + T::BridgedChain::MAX_HEADER_SIZE.saturating_add(max_expected_justification_size) +} + +#[cfg(test)] +mod tests { + use crate::{ + call_ext::CallSubType, + mock::{run_test, test_header, RuntimeCall, TestBridgedChain, TestNumber, TestRuntime}, + BestFinalized, Config, WeightInfo, + }; + use bp_header_chain::ChainWithGrandpa; + use bp_runtime::HeaderId; + use bp_test_utils::{ + make_default_justification, make_justification_for_header, JustificationGeneratorParams, + }; + use frame_support::weights::Weight; + use sp_runtime::{testing::DigestItem, traits::Header as _, SaturatedConversion}; + + fn validate_block_submit(num: TestNumber) -> bool { + let bridge_grandpa_call = crate::Call::::submit_finality_proof { + finality_target: Box::new(test_header(num)), + justification: make_default_justification(&test_header(num)), + }; + RuntimeCall::check_obsolete_submit_finality_proof(&RuntimeCall::Grandpa( + bridge_grandpa_call, + )) + .is_ok() + } + + fn sync_to_header_10() { + let header10_hash = sp_core::H256::default(); + BestFinalized::::put(HeaderId(10, header10_hash)); + } + + #[test] + fn extension_rejects_obsolete_header() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#5 => tx is + // rejected + sync_to_header_10(); + assert!(!validate_block_submit(5)); + }); + } + + #[test] + fn extension_rejects_same_header() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#10 => tx is + // rejected + sync_to_header_10(); + assert!(!validate_block_submit(10)); + }); + } + + #[test] + fn extension_accepts_new_header() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#15 => tx is + // accepted + sync_to_header_10(); + assert!(validate_block_submit(15)); + }); + } + + #[test] + fn extension_returns_correct_extra_size_if_call_arguments_are_too_large() { + // when call arguments are below our limit => no refund + let small_finality_target = test_header(1); + let justification_params = JustificationGeneratorParams { + header: small_finality_target.clone(), + ..Default::default() + }; + let small_justification = make_justification_for_header(justification_params); + let small_call = RuntimeCall::Grandpa(crate::Call::submit_finality_proof { + finality_target: Box::new(small_finality_target), + justification: small_justification, + }); + assert_eq!(small_call.submit_finality_proof_info().unwrap().extra_size, 0); + + // when call arguments are too large => partial refund + let mut large_finality_target = test_header(1); + large_finality_target + .digest_mut() + .push(DigestItem::Other(vec![42u8; 1024 * 1024])); + let justification_params = JustificationGeneratorParams { + header: large_finality_target.clone(), + ..Default::default() + }; + let large_justification = make_justification_for_header(justification_params); + let large_call = RuntimeCall::Grandpa(crate::Call::submit_finality_proof { + finality_target: Box::new(large_finality_target), + justification: large_justification, + }); + assert_ne!(large_call.submit_finality_proof_info().unwrap().extra_size, 0); + } + + #[test] + fn extension_returns_correct_extra_weight_if_there_are_too_many_headers_in_votes_ancestry() { + let finality_target = test_header(1); + let mut justification_params = JustificationGeneratorParams { + header: finality_target.clone(), + ancestors: TestBridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY, + ..Default::default() + }; + + // when there are `REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY` headers => no refund + let justification = make_justification_for_header(justification_params.clone()); + let call = RuntimeCall::Grandpa(crate::Call::submit_finality_proof { + finality_target: Box::new(finality_target.clone()), + justification, + }); + assert_eq!(call.submit_finality_proof_info().unwrap().extra_weight, Weight::zero()); + + // when there are `REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY + 1` headers => full refund + justification_params.ancestors += 1; + let justification = make_justification_for_header(justification_params); + let call_weight = ::WeightInfo::submit_finality_proof( + justification.commit.precommits.len().saturated_into(), + justification.votes_ancestries.len().saturated_into(), + ); + let call = RuntimeCall::Grandpa(crate::Call::submit_finality_proof { + finality_target: Box::new(finality_target), + justification, + }); + assert_eq!(call.submit_finality_proof_info().unwrap().extra_weight, call_weight); + } +} diff --git a/modules/grandpa/src/lib.rs b/modules/grandpa/src/lib.rs new file mode 100644 index 00000000000..9d38c9723d7 --- /dev/null +++ b/modules/grandpa/src/lib.rs @@ -0,0 +1,1423 @@ +// Copyright 2021 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 . + +//! Substrate GRANDPA Pallet +//! +//! This pallet is an on-chain GRANDPA light client for Substrate based chains. +//! +//! This pallet achieves this by trustlessly verifying GRANDPA finality proofs on-chain. Once +//! verified, finalized headers are stored in the pallet, thereby creating a sparse header chain. +//! This sparse header chain can be used as a source of truth for other higher-level applications. +//! +//! The pallet is responsible for tracking GRANDPA validator set hand-offs. We only import headers +//! with justifications signed by the current validator set we know of. The header is inspected for +//! a `ScheduledChanges` digest item, which is then used to update to next validator set. +//! +//! Since this pallet only tracks finalized headers it does not deal with forks. Forks can only +//! occur if the GRANDPA validator set on the bridged chain is either colluding or there is a severe +//! bug causing resulting in an equivocation. Such events are outside the scope of this pallet. +//! Shall the fork occur on the bridged chain governance intervention will be required to +//! re-initialize the bridge and track the right fork. + +#![cfg_attr(not(feature = "std"), no_std)] +// Runtime-generated enums +#![allow(clippy::large_enum_variant)] + +pub use storage_types::StoredAuthoritySet; + +use bp_header_chain::{ + justification::GrandpaJustification, ChainWithGrandpa, HeaderChain, InitializationData, + StoredHeaderData, StoredHeaderDataBuilder, +}; +use bp_runtime::{BlockNumberOf, HashOf, HasherOf, HeaderId, HeaderOf, OwnedBridgeModule}; +use finality_grandpa::voter_set::VoterSet; +use frame_support::{dispatch::PostDispatchInfo, ensure}; +use sp_consensus_grandpa::{ConsensusLog, GRANDPA_ENGINE_ID}; +use sp_runtime::{ + traits::{Header as HeaderT, Zero}, + SaturatedConversion, +}; +use sp_std::{boxed::Box, convert::TryInto}; + +mod call_ext; +#[cfg(test)] +mod mock; +mod storage_types; + +/// Module, containing weights for this pallet. +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +// Re-export in crate namespace for `construct_runtime!` +pub use call_ext::*; +pub use pallet::*; +pub use weights::WeightInfo; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-grandpa"; + +/// Bridged chain from the pallet configuration. +pub type BridgedChain = >::BridgedChain; +/// Block number of the bridged chain. +pub type BridgedBlockNumber = BlockNumberOf<>::BridgedChain>; +/// Block hash of the bridged chain. +pub type BridgedBlockHash = HashOf<>::BridgedChain>; +/// Block id of the bridged chain. +pub type BridgedBlockId = HeaderId, BridgedBlockNumber>; +/// Hasher of the bridged chain. +pub type BridgedBlockHasher = HasherOf<>::BridgedChain>; +/// Header of the bridged chain. +pub type BridgedHeader = HeaderOf<>::BridgedChain>; +/// Header data of the bridged chain that is stored at this chain by this pallet. +pub type BridgedStoredHeaderData = + StoredHeaderData, BridgedBlockHash>; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use bp_runtime::BasicOperatingMode; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + + /// The chain we are bridging to here. + type BridgedChain: ChainWithGrandpa; + + /// Maximal number of "free" mandatory header transactions per block. + /// + /// To be able to track the bridged chain, the pallet requires all headers that are + /// changing GRANDPA authorities set at the bridged chain (we call them mandatory). + /// So it is a common good deed to submit mandatory headers to the pallet. However, if the + /// bridged chain gets compromised, its validators may generate as many mandatory headers + /// as they want. And they may fill the whole block (at this chain) for free. This constants + /// limits number of calls that we may refund in a single block. All calls above this + /// limit are accepted, but are not refunded. + #[pallet::constant] + type MaxFreeMandatoryHeadersPerBlock: Get; + + /// Maximal number of finalized headers to keep in the storage. + /// + /// The setting is there to prevent growing the on-chain state indefinitely. Note + /// the setting does not relate to block numbers - we will simply keep as much items + /// in the storage, so it doesn't guarantee any fixed timeframe for finality headers. + /// + /// Incautious change of this constant may lead to orphan entries in the runtime storage. + #[pallet::constant] + type HeadersToKeep: Get; + + /// Weights gathered through benchmarking. + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + fn on_initialize(_n: BlockNumberFor) -> Weight { + FreeMandatoryHeadersRemaining::::put(T::MaxFreeMandatoryHeadersPerBlock::get()); + Weight::zero() + } + + fn on_finalize(_n: BlockNumberFor) { + FreeMandatoryHeadersRemaining::::kill(); + } + } + + impl, I: 'static> OwnedBridgeModule for Pallet { + const LOG_TARGET: &'static str = LOG_TARGET; + type OwnerStorage = PalletOwner; + type OperatingMode = BasicOperatingMode; + type OperatingModeStorage = PalletOperatingMode; + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Verify a target header is finalized according to the given finality proof. + /// + /// It will use the underlying storage pallet to fetch information about the current + /// authorities and best finalized header in order to verify that the header is finalized. + /// + /// If successful in verification, it will write the target header to the underlying storage + /// pallet. + /// + /// The call fails if: + /// + /// - the pallet is halted; + /// + /// - the pallet knows better header than the `finality_target`; + /// + /// - verification is not optimized or invalid; + /// + /// - header contains forced authorities set change or change with non-zero delay. + #[pallet::call_index(0)] + #[pallet::weight(::submit_finality_proof( + justification.commit.precommits.len().saturated_into(), + justification.votes_ancestries.len().saturated_into(), + ))] + pub fn submit_finality_proof( + _origin: OriginFor, + finality_target: Box>, + justification: GrandpaJustification>, + ) -> DispatchResultWithPostInfo { + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; + + let (hash, number) = (finality_target.hash(), *finality_target.number()); + log::trace!( + target: LOG_TARGET, + "Going to try and finalize header {:?}", + finality_target + ); + + SubmitFinalityProofHelper::::check_obsolete(number)?; + + let authority_set = >::get(); + let unused_proof_size = authority_set.unused_proof_size(); + let set_id = authority_set.set_id; + verify_justification::(&justification, hash, number, authority_set.into())?; + + let is_authorities_change_enacted = + try_enact_authority_change::(&finality_target, set_id)?; + let may_refund_call_fee = is_authorities_change_enacted && + // if we have seen too many mandatory headers in this block, we don't want to refund + Self::free_mandatory_headers_remaining() > 0 && + // if arguments out of expected bounds, we don't want to refund + submit_finality_proof_info_from_args::(&finality_target, &justification) + .fits_limits(); + if may_refund_call_fee { + FreeMandatoryHeadersRemaining::::mutate(|count| { + *count = count.saturating_sub(1) + }); + } + insert_header::(*finality_target, hash); + log::info!( + target: LOG_TARGET, + "Successfully imported finalized header with hash {:?}!", + hash + ); + + // mandatory header is a header that changes authorities set. The pallet can't go + // further without importing this header. So every bridge MUST import mandatory headers. + // + // We don't want to charge extra costs for mandatory operations. So relayer is not + // paying fee for mandatory headers import transactions. + // + // If size/weight of the call is exceeds our estimated limits, the relayer still needs + // to pay for the transaction. + let pays_fee = if may_refund_call_fee { Pays::No } else { Pays::Yes }; + + // the proof size component of the call weight assumes that there are + // `MaxBridgedAuthorities` in the `CurrentAuthoritySet` (we use `MaxEncodedLen` + // estimation). But if their number is lower, then we may "refund" some `proof_size`, + // making proof smaller and leaving block space to other useful transactions + let pre_dispatch_weight = T::WeightInfo::submit_finality_proof( + justification.commit.precommits.len().saturated_into(), + justification.votes_ancestries.len().saturated_into(), + ); + let actual_weight = pre_dispatch_weight + .set_proof_size(pre_dispatch_weight.proof_size().saturating_sub(unused_proof_size)); + + Self::deposit_event(Event::UpdatedBestFinalizedHeader { number, hash }); + + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee }) + } + + /// Bootstrap the bridge pallet with an initial header and authority set from which to sync. + /// + /// The initial configuration provided does not need to be the genesis header of the bridged + /// chain, it can be any arbitrary header. You can also provide the next scheduled set + /// change if it is already know. + /// + /// This function is only allowed to be called from a trusted origin and writes to storage + /// with practically no checks in terms of the validity of the data. It is important that + /// you ensure that valid data is being passed in. + #[pallet::call_index(1)] + #[pallet::weight((T::DbWeight::get().reads_writes(2, 5), DispatchClass::Operational))] + pub fn initialize( + origin: OriginFor, + init_data: super::InitializationData>, + ) -> DispatchResultWithPostInfo { + Self::ensure_owner_or_root(origin)?; + + let init_allowed = !>::exists(); + ensure!(init_allowed, >::AlreadyInitialized); + initialize_bridge::(init_data.clone())?; + + log::info!( + target: LOG_TARGET, + "Pallet has been initialized with the following parameters: {:?}", + init_data + ); + + Ok(().into()) + } + + /// Change `PalletOwner`. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(2)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { + >::set_owner(origin, new_owner) + } + + /// Halt or resume all pallet operations. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(3)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_operating_mode( + origin: OriginFor, + operating_mode: BasicOperatingMode, + ) -> DispatchResult { + >::set_operating_mode(origin, operating_mode) + } + } + + /// Number mandatory headers that we may accept in the current block for free (returning + /// `Pays::No`). + /// + /// If the `FreeMandatoryHeadersRemaining` hits zero, all following mandatory headers in the + /// current block are accepted with fee (`Pays::Yes` is returned). + /// + /// The `FreeMandatoryHeadersRemaining` is an ephemeral value that is set to + /// `MaxFreeMandatoryHeadersPerBlock` at each block initialization and is killed on block + /// finalization. So it never ends up in the storage trie. + #[pallet::storage] + #[pallet::whitelist_storage] + #[pallet::getter(fn free_mandatory_headers_remaining)] + pub(super) type FreeMandatoryHeadersRemaining, I: 'static = ()> = + StorageValue<_, u32, ValueQuery>; + + /// Hash of the header used to bootstrap the pallet. + #[pallet::storage] + pub(super) type InitialHash, I: 'static = ()> = + StorageValue<_, BridgedBlockHash, ValueQuery>; + + /// Hash of the best finalized header. + #[pallet::storage] + #[pallet::getter(fn best_finalized)] + pub type BestFinalized, I: 'static = ()> = + StorageValue<_, BridgedBlockId, OptionQuery>; + + /// A ring buffer of imported hashes. Ordered by the insertion time. + #[pallet::storage] + pub(super) type ImportedHashes, I: 'static = ()> = StorageMap< + Hasher = Identity, + Key = u32, + Value = BridgedBlockHash, + QueryKind = OptionQuery, + OnEmpty = GetDefault, + MaxValues = MaybeHeadersToKeep, + >; + + /// Current ring buffer position. + #[pallet::storage] + pub(super) type ImportedHashesPointer, I: 'static = ()> = + StorageValue<_, u32, ValueQuery>; + + /// Relevant fields of imported headers. + #[pallet::storage] + pub type ImportedHeaders, I: 'static = ()> = StorageMap< + Hasher = Identity, + Key = BridgedBlockHash, + Value = BridgedStoredHeaderData, + QueryKind = OptionQuery, + OnEmpty = GetDefault, + MaxValues = MaybeHeadersToKeep, + >; + + /// The current GRANDPA Authority set. + #[pallet::storage] + pub type CurrentAuthoritySet, I: 'static = ()> = + StorageValue<_, StoredAuthoritySet, ValueQuery>; + + /// Optional pallet owner. + /// + /// Pallet owner has a right to halt all pallet operations and then resume it. If it is + /// `None`, then there are no direct ways to halt/resume pallet operations, but other + /// runtime methods may still be used to do that (i.e. democracy::referendum to update halt + /// flag directly or call the `halt_operations`). + #[pallet::storage] + pub type PalletOwner, I: 'static = ()> = + StorageValue<_, T::AccountId, OptionQuery>; + + /// The current operating mode of the pallet. + /// + /// Depending on the mode either all, or no transactions will be allowed. + #[pallet::storage] + pub type PalletOperatingMode, I: 'static = ()> = + StorageValue<_, BasicOperatingMode, ValueQuery>; + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + /// Optional module owner account. + pub owner: Option, + /// Optional module initialization data. + pub init_data: Option>>, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { owner: None, init_data: None } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + if let Some(ref owner) = self.owner { + >::put(owner); + } + + if let Some(init_data) = self.init_data.clone() { + initialize_bridge::(init_data).expect("genesis config is correct; qed"); + } else { + // Since the bridge hasn't been initialized we shouldn't allow anyone to perform + // transactions. + >::put(BasicOperatingMode::Halted); + } + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// Best finalized chain header has been updated to the header with given number and hash. + UpdatedBestFinalizedHeader { + number: BridgedBlockNumber, + hash: BridgedBlockHash, + }, + } + + #[pallet::error] + pub enum Error { + /// The given justification is invalid for the given header. + InvalidJustification, + /// The authority set from the underlying header chain is invalid. + InvalidAuthoritySet, + /// The header being imported is older than the best finalized header known to the pallet. + OldHeader, + /// The scheduled authority set change found in the header is unsupported by the pallet. + /// + /// This is the case for non-standard (e.g forced) authority set changes. + UnsupportedScheduledChange, + /// The pallet is not yet initialized. + NotInitialized, + /// The pallet has already been initialized. + AlreadyInitialized, + /// Too many authorities in the set. + TooManyAuthoritiesInSet, + /// Error generated by the `OwnedBridgeModule` trait. + BridgeModule(bp_runtime::OwnedBridgeModuleError), + } + + /// Check the given header for a GRANDPA scheduled authority set change. If a change + /// is found it will be enacted immediately. + /// + /// This function does not support forced changes, or scheduled changes with delays + /// since these types of changes are indicative of abnormal behavior from GRANDPA. + /// + /// Returned value will indicate if a change was enacted or not. + pub(crate) fn try_enact_authority_change, I: 'static>( + header: &BridgedHeader, + current_set_id: sp_consensus_grandpa::SetId, + ) -> Result { + let mut change_enacted = false; + + // We don't support forced changes - at that point governance intervention is required. + ensure!( + super::find_forced_change(header).is_none(), + >::UnsupportedScheduledChange + ); + + if let Some(change) = super::find_scheduled_change(header) { + // GRANDPA only includes a `delay` for forced changes, so this isn't valid. + ensure!(change.delay == Zero::zero(), >::UnsupportedScheduledChange); + + // TODO [#788]: Stop manually increasing the `set_id` here. + let next_authorities = StoredAuthoritySet:: { + authorities: change + .next_authorities + .try_into() + .map_err(|_| Error::::TooManyAuthoritiesInSet)?, + set_id: current_set_id + 1, + }; + + // Since our header schedules a change and we know the delay is 0, it must also enact + // the change. + >::put(&next_authorities); + change_enacted = true; + + log::info!( + target: LOG_TARGET, + "Transitioned from authority set {} to {}! New authorities are: {:?}", + current_set_id, + current_set_id + 1, + next_authorities, + ); + }; + + Ok(change_enacted) + } + + /// Verify a GRANDPA justification (finality proof) for a given header. + /// + /// Will use the GRANDPA current authorities known to the pallet. + /// + /// If successful it returns the decoded GRANDPA justification so we can refund any weight which + /// was overcharged in the initial call. + pub(crate) fn verify_justification, I: 'static>( + justification: &GrandpaJustification>, + hash: BridgedBlockHash, + number: BridgedBlockNumber, + authority_set: bp_header_chain::AuthoritySet, + ) -> Result<(), sp_runtime::DispatchError> { + use bp_header_chain::justification::verify_justification; + + let voter_set = + VoterSet::new(authority_set.authorities).ok_or(>::InvalidAuthoritySet)?; + let set_id = authority_set.set_id; + + Ok(verify_justification::>( + (hash, number), + set_id, + &voter_set, + justification, + ) + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "Received invalid justification for {:?}: {:?}", + hash, + e, + ); + >::InvalidJustification + })?) + } + + /// Import a previously verified header to the storage. + /// + /// Note this function solely takes care of updating the storage and pruning old entries, + /// but does not verify the validity of such import. + pub(crate) fn insert_header, I: 'static>( + header: BridgedHeader, + hash: BridgedBlockHash, + ) { + let index = >::get(); + let pruning = >::try_get(index); + >::put(HeaderId(*header.number(), hash)); + >::insert(hash, header.build()); + >::insert(index, hash); + + // Update ring buffer pointer and remove old header. + >::put((index + 1) % T::HeadersToKeep::get()); + if let Ok(hash) = pruning { + log::debug!(target: LOG_TARGET, "Pruning old header: {:?}.", hash); + >::remove(hash); + } + } + + /// Since this writes to storage with no real checks this should only be used in functions that + /// were called by a trusted origin. + pub(crate) fn initialize_bridge, I: 'static>( + init_params: super::InitializationData>, + ) -> Result<(), Error> { + let super::InitializationData { header, authority_list, set_id, operating_mode } = + init_params; + let authority_set_length = authority_list.len(); + let authority_set = StoredAuthoritySet::::try_new(authority_list, set_id) + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "Failed to initialize bridge. Number of authorities in the set {} is larger than the configured value {}", + authority_set_length, + T::BridgedChain::MAX_AUTHORITIES_COUNT, + ); + + e + })?; + let initial_hash = header.hash(); + + >::put(initial_hash); + >::put(0); + insert_header::(*header, initial_hash); + + >::put(authority_set); + + >::put(operating_mode); + + Ok(()) + } + + /// Adapter for using `Config::HeadersToKeep` as `MaxValues` bound in our storage maps. + pub struct MaybeHeadersToKeep(PhantomData<(T, I)>); + + // this implementation is required to use the struct as `MaxValues` + impl, I: 'static> Get> for MaybeHeadersToKeep { + fn get() -> Option { + Some(T::HeadersToKeep::get()) + } + } + + /// Initialize pallet so that it is ready for inserting new header. + /// + /// The function makes sure that the new insertion will cause the pruning of some old header. + /// + /// Returns parent header for the new header. + #[cfg(feature = "runtime-benchmarks")] + pub(crate) fn bootstrap_bridge, I: 'static>( + init_params: super::InitializationData>, + ) -> BridgedHeader { + let start_header = init_params.header.clone(); + initialize_bridge::(init_params).expect("benchmarks are correct"); + + // the most obvious way to cause pruning during next insertion would be to insert + // `HeadersToKeep` headers. But it'll make our benchmarks slow. So we will just play with + // our pruning ring-buffer. + assert_eq!(ImportedHashesPointer::::get(), 1); + ImportedHashesPointer::::put(0); + + *start_header + } +} + +impl, I: 'static> Pallet { + /// Get the best finalized block number. + pub fn best_finalized_number() -> Option> { + BestFinalized::::get().map(|id| id.number()) + } +} + +/// Bridge GRANDPA pallet as header chain. +pub type GrandpaChainHeaders = Pallet; + +impl, I: 'static> HeaderChain> for GrandpaChainHeaders { + fn finalized_header_state_root( + header_hash: HashOf>, + ) -> Option>> { + ImportedHeaders::::get(header_hash).map(|h| h.state_root) + } +} + +pub(crate) fn find_scheduled_change( + header: &H, +) -> Option> { + use sp_runtime::generic::OpaqueDigestItemId; + + let id = OpaqueDigestItemId::Consensus(&GRANDPA_ENGINE_ID); + + let filter_log = |log: ConsensusLog| match log { + ConsensusLog::ScheduledChange(change) => Some(change), + _ => None, + }; + + // find the first consensus digest with the right ID which converts to + // the right kind of consensus log. + header.digest().convert_first(|l| l.try_to(id).and_then(filter_log)) +} + +/// Checks the given header for a consensus digest signaling a **forced** scheduled change and +/// extracts it. +pub(crate) fn find_forced_change( + header: &H, +) -> Option<(H::Number, sp_consensus_grandpa::ScheduledChange)> { + use sp_runtime::generic::OpaqueDigestItemId; + + let id = OpaqueDigestItemId::Consensus(&GRANDPA_ENGINE_ID); + + let filter_log = |log: ConsensusLog| match log { + ConsensusLog::ForcedChange(delay, change) => Some((delay, change)), + _ => None, + }; + + // find the first consensus digest with the right ID which converts to + // the right kind of consensus log. + header.digest().convert_first(|l| l.try_to(id).and_then(filter_log)) +} + +/// (Re)initialize bridge with given header for using it in `pallet-bridge-messages` benchmarks. +#[cfg(feature = "runtime-benchmarks")] +pub fn initialize_for_benchmarks, I: 'static>(header: BridgedHeader) { + initialize_bridge::(InitializationData { + header: Box::new(header), + authority_list: sp_std::vec::Vec::new(), /* we don't verify any proofs in external + * benchmarks */ + set_id: 0, + operating_mode: bp_runtime::BasicOperatingMode::Normal, + }) + .expect("only used from benchmarks; benchmarks are correct; qed"); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ + run_test, test_header, RuntimeEvent as TestEvent, RuntimeOrigin, System, TestBridgedChain, + TestHeader, TestNumber, TestRuntime, MAX_BRIDGED_AUTHORITIES, + }; + use bp_header_chain::BridgeGrandpaCall; + use bp_runtime::BasicOperatingMode; + use bp_test_utils::{ + authority_list, generate_owned_bridge_module_tests, make_default_justification, + make_justification_for_header, JustificationGeneratorParams, ALICE, BOB, + }; + use codec::Encode; + use frame_support::{ + assert_err, assert_noop, assert_ok, + dispatch::{Pays, PostDispatchInfo}, + storage::generator::StorageValue, + }; + use frame_system::{EventRecord, Phase}; + use sp_core::Get; + use sp_runtime::{Digest, DigestItem, DispatchError}; + + fn initialize_substrate_bridge() { + System::set_block_number(1); + System::reset_events(); + + assert_ok!(init_with_origin(RuntimeOrigin::root())); + } + + fn init_with_origin( + origin: RuntimeOrigin, + ) -> Result< + InitializationData, + sp_runtime::DispatchErrorWithPostInfo, + > { + let genesis = test_header(0); + + let init_data = InitializationData { + header: Box::new(genesis), + authority_list: authority_list(), + set_id: 1, + operating_mode: BasicOperatingMode::Normal, + }; + + Pallet::::initialize(origin, init_data.clone()).map(|_| init_data) + } + + fn submit_finality_proof(header: u8) -> frame_support::dispatch::DispatchResultWithPostInfo { + let header = test_header(header.into()); + let justification = make_default_justification(&header); + + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ) + } + + fn submit_finality_proof_with_set_id( + header: u8, + set_id: u64, + ) -> frame_support::dispatch::DispatchResultWithPostInfo { + let header = test_header(header.into()); + let justification = make_justification_for_header(JustificationGeneratorParams { + header: header.clone(), + set_id, + ..Default::default() + }); + + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ) + } + + fn submit_mandatory_finality_proof( + number: u8, + set_id: u64, + ) -> frame_support::dispatch::DispatchResultWithPostInfo { + let mut header = test_header(number.into()); + // to ease tests that are using `submit_mandatory_finality_proof`, we'll be using the + // same set for all sessions + let consensus_log = + ConsensusLog::::ScheduledChange(sp_consensus_grandpa::ScheduledChange { + next_authorities: authority_list(), + delay: 0, + }); + header.digest = + Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] }; + let justification = make_justification_for_header(JustificationGeneratorParams { + header: header.clone(), + set_id, + ..Default::default() + }); + + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ) + } + + fn next_block() { + use frame_support::traits::OnInitialize; + + let current_number = frame_system::Pallet::::block_number(); + frame_system::Pallet::::set_block_number(current_number + 1); + let _ = Pallet::::on_initialize(current_number); + } + + fn change_log(delay: u64) -> Digest { + let consensus_log = + ConsensusLog::::ScheduledChange(sp_consensus_grandpa::ScheduledChange { + next_authorities: vec![(ALICE.into(), 1), (BOB.into(), 1)], + delay, + }); + + Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] } + } + + fn forced_change_log(delay: u64) -> Digest { + let consensus_log = ConsensusLog::::ForcedChange( + delay, + sp_consensus_grandpa::ScheduledChange { + next_authorities: vec![(ALICE.into(), 1), (BOB.into(), 1)], + delay, + }, + ); + + Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] } + } + + fn many_authorities_log() -> Digest { + let consensus_log = + ConsensusLog::::ScheduledChange(sp_consensus_grandpa::ScheduledChange { + next_authorities: std::iter::repeat((ALICE.into(), 1)) + .take(MAX_BRIDGED_AUTHORITIES as usize + 1) + .collect(), + delay: 0, + }); + + Digest { logs: vec![DigestItem::Consensus(GRANDPA_ENGINE_ID, consensus_log.encode())] } + } + + #[test] + fn init_root_or_owner_origin_can_initialize_pallet() { + run_test(|| { + assert_noop!(init_with_origin(RuntimeOrigin::signed(1)), DispatchError::BadOrigin); + assert_ok!(init_with_origin(RuntimeOrigin::root())); + + // Reset storage so we can initialize the pallet again + BestFinalized::::kill(); + PalletOwner::::put(2); + assert_ok!(init_with_origin(RuntimeOrigin::signed(2))); + }) + } + + #[test] + fn init_storage_entries_are_correctly_initialized() { + run_test(|| { + assert_eq!(BestFinalized::::get(), None,); + assert_eq!(Pallet::::best_finalized(), None); + + let init_data = init_with_origin(RuntimeOrigin::root()).unwrap(); + + assert!(>::contains_key(init_data.header.hash())); + assert_eq!(BestFinalized::::get().unwrap().1, init_data.header.hash()); + assert_eq!( + CurrentAuthoritySet::::get().authorities, + init_data.authority_list + ); + assert_eq!(PalletOperatingMode::::get(), BasicOperatingMode::Normal); + }) + } + + #[test] + fn init_can_only_initialize_pallet_once() { + run_test(|| { + initialize_substrate_bridge(); + assert_noop!( + init_with_origin(RuntimeOrigin::root()), + >::AlreadyInitialized + ); + }) + } + + #[test] + fn init_fails_if_there_are_too_many_authorities_in_the_set() { + run_test(|| { + let genesis = test_header(0); + let init_data = InitializationData { + header: Box::new(genesis), + authority_list: std::iter::repeat(authority_list().remove(0)) + .take(MAX_BRIDGED_AUTHORITIES as usize + 1) + .collect(), + set_id: 1, + operating_mode: BasicOperatingMode::Normal, + }; + + assert_noop!( + Pallet::::initialize(RuntimeOrigin::root(), init_data), + Error::::TooManyAuthoritiesInSet, + ); + }); + } + + #[test] + fn pallet_rejects_transactions_if_halted() { + run_test(|| { + initialize_substrate_bridge(); + + assert_ok!(Pallet::::set_operating_mode( + RuntimeOrigin::root(), + BasicOperatingMode::Halted + )); + assert_noop!( + submit_finality_proof(1), + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted) + ); + + assert_ok!(Pallet::::set_operating_mode( + RuntimeOrigin::root(), + BasicOperatingMode::Normal + )); + assert_ok!(submit_finality_proof(1)); + }) + } + + #[test] + fn pallet_rejects_header_if_not_initialized_yet() { + run_test(|| { + assert_noop!(submit_finality_proof(1), Error::::NotInitialized); + }); + } + + #[test] + fn succesfully_imports_header_with_valid_finality() { + run_test(|| { + initialize_substrate_bridge(); + + let header_number = 1; + let header = test_header(header_number.into()); + let justification = make_default_justification(&header); + + let pre_dispatch_weight = ::WeightInfo::submit_finality_proof( + justification.commit.precommits.len().try_into().unwrap_or(u32::MAX), + justification.votes_ancestries.len().try_into().unwrap_or(u32::MAX), + ); + + let result = submit_finality_proof(header_number); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::Yes); + // our test config assumes 2048 max authorities and we are just using couple + let pre_dispatch_proof_size = pre_dispatch_weight.proof_size(); + let actual_proof_size = result.unwrap().actual_weight.unwrap().proof_size(); + assert!(actual_proof_size > 0); + assert!( + actual_proof_size < pre_dispatch_proof_size, + "Actual proof size {actual_proof_size} must be less than the pre-dispatch {pre_dispatch_proof_size}", + ); + + let header = test_header(1); + assert_eq!(>::get().unwrap().1, header.hash()); + assert!(>::contains_key(header.hash())); + + assert_eq!( + System::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Grandpa(Event::UpdatedBestFinalizedHeader { + number: *header.number(), + hash: header.hash(), + }), + topics: vec![], + }], + ); + }) + } + + #[test] + fn rejects_justification_that_skips_authority_set_transition() { + run_test(|| { + initialize_substrate_bridge(); + + let header = test_header(1); + + let params = + JustificationGeneratorParams:: { set_id: 2, ..Default::default() }; + let justification = make_justification_for_header(params); + + assert_err!( + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ), + >::InvalidJustification + ); + }) + } + + #[test] + fn does_not_import_header_with_invalid_finality_proof() { + run_test(|| { + initialize_substrate_bridge(); + + let header = test_header(1); + let mut justification = make_default_justification(&header); + justification.round = 42; + + assert_err!( + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ), + >::InvalidJustification + ); + }) + } + + #[test] + fn disallows_invalid_authority_set() { + run_test(|| { + let genesis = test_header(0); + + let invalid_authority_list = vec![(ALICE.into(), u64::MAX), (BOB.into(), u64::MAX)]; + let init_data = InitializationData { + header: Box::new(genesis), + authority_list: invalid_authority_list, + set_id: 1, + operating_mode: BasicOperatingMode::Normal, + }; + + assert_ok!(Pallet::::initialize(RuntimeOrigin::root(), init_data)); + + let header = test_header(1); + let justification = make_default_justification(&header); + + assert_err!( + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ), + >::InvalidAuthoritySet + ); + }) + } + + #[test] + fn importing_header_ensures_that_chain_is_extended() { + run_test(|| { + initialize_substrate_bridge(); + + assert_ok!(submit_finality_proof(4)); + assert_err!(submit_finality_proof(3), Error::::OldHeader); + assert_ok!(submit_finality_proof(5)); + }) + } + + #[test] + fn importing_header_enacts_new_authority_set() { + run_test(|| { + initialize_substrate_bridge(); + + let next_set_id = 2; + let next_authorities = vec![(ALICE.into(), 1), (BOB.into(), 1)]; + + // Need to update the header digest to indicate that our header signals an authority set + // change. The change will be enacted when we import our header. + let mut header = test_header(2); + header.digest = change_log(0); + + // Create a valid justification for the header + let justification = make_default_justification(&header); + + // Let's import our test header + let result = Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header.clone()), + justification, + ); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::No); + + // Make sure that our header is the best finalized + assert_eq!(>::get().unwrap().1, header.hash()); + assert!(>::contains_key(header.hash())); + + // Make sure that the authority set actually changed upon importing our header + assert_eq!( + >::get(), + StoredAuthoritySet::::try_new(next_authorities, next_set_id) + .unwrap(), + ); + }) + } + + #[test] + fn relayer_pays_tx_fee_when_submitting_huge_mandatory_header() { + run_test(|| { + initialize_substrate_bridge(); + + // let's prepare a huge authorities change header, which is definitely above size limits + let mut header = test_header(2); + header.digest = change_log(0); + header.digest.push(DigestItem::Other(vec![42u8; 1024 * 1024])); + let justification = make_default_justification(&header); + + // without large digest item ^^^ the relayer would have paid zero transaction fee + // (`Pays::No`) + let result = Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header.clone()), + justification, + ); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::Yes); + + // Make sure that our header is the best finalized + assert_eq!(>::get().unwrap().1, header.hash()); + assert!(>::contains_key(header.hash())); + }) + } + + #[test] + fn relayer_pays_tx_fee_when_submitting_justification_with_long_ancestry_votes() { + run_test(|| { + initialize_substrate_bridge(); + + // let's prepare a huge authorities change header, which is definitely above weight + // limits + let mut header = test_header(2); + header.digest = change_log(0); + let justification = make_justification_for_header(JustificationGeneratorParams { + header: header.clone(), + ancestors: TestBridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY + 1, + ..Default::default() + }); + + // without many headers in votes ancestries ^^^ the relayer would have paid zero + // transaction fee (`Pays::No`) + let result = Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header.clone()), + justification, + ); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, frame_support::dispatch::Pays::Yes); + + // Make sure that our header is the best finalized + assert_eq!(>::get().unwrap().1, header.hash()); + assert!(>::contains_key(header.hash())); + }) + } + + #[test] + fn importing_header_rejects_header_with_scheduled_change_delay() { + run_test(|| { + initialize_substrate_bridge(); + + // Need to update the header digest to indicate that our header signals an authority set + // change. However, the change doesn't happen until the next block. + let mut header = test_header(2); + header.digest = change_log(1); + + // Create a valid justification for the header + let justification = make_default_justification(&header); + + // Should not be allowed to import this header + assert_err!( + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification + ), + >::UnsupportedScheduledChange + ); + }) + } + + #[test] + fn importing_header_rejects_header_with_forced_changes() { + run_test(|| { + initialize_substrate_bridge(); + + // Need to update the header digest to indicate that it signals a forced authority set + // change. + let mut header = test_header(2); + header.digest = forced_change_log(0); + + // Create a valid justification for the header + let justification = make_default_justification(&header); + + // Should not be allowed to import this header + assert_err!( + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification + ), + >::UnsupportedScheduledChange + ); + }) + } + + #[test] + fn importing_header_rejects_header_with_too_many_authorities() { + run_test(|| { + initialize_substrate_bridge(); + + // Need to update the header digest to indicate that our header signals an authority set + // change. However, the change doesn't happen until the next block. + let mut header = test_header(2); + header.digest = many_authorities_log(); + + // Create a valid justification for the header + let justification = make_default_justification(&header); + + // Should not be allowed to import this header + assert_err!( + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification + ), + >::TooManyAuthoritiesInSet + ); + }); + } + + #[test] + fn parse_finalized_storage_proof_rejects_proof_on_unknown_header() { + run_test(|| { + assert_noop!( + Pallet::::parse_finalized_storage_proof( + Default::default(), + vec![], + |_| (), + ), + bp_header_chain::HeaderChainError::UnknownHeader, + ); + }); + } + + #[test] + fn parse_finalized_storage_accepts_valid_proof() { + run_test(|| { + let (state_root, storage_proof) = bp_runtime::craft_valid_storage_proof(); + + let mut header = test_header(2); + header.set_state_root(state_root); + + let hash = header.hash(); + >::put(HeaderId(2, hash)); + >::insert(hash, header.build()); + + assert_ok!( + Pallet::::parse_finalized_storage_proof(hash, storage_proof, |_| (),), + (), + ); + }); + } + + #[test] + fn rate_limiter_disallows_free_imports_once_limit_is_hit_in_single_block() { + run_test(|| { + initialize_substrate_bridge(); + + let result = submit_mandatory_finality_proof(1, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(2, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(3, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + }) + } + + #[test] + fn rate_limiter_invalid_requests_do_not_count_towards_request_count() { + run_test(|| { + let submit_invalid_request = || { + let mut header = test_header(1); + header.digest = change_log(0); + let mut invalid_justification = make_default_justification(&header); + invalid_justification.round = 42; + + Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + invalid_justification, + ) + }; + + initialize_substrate_bridge(); + + for _ in 0..::MaxFreeMandatoryHeadersPerBlock::get() + 1 { + assert_err!(submit_invalid_request(), >::InvalidJustification); + } + + // Can still submit free mandatory headers afterwards + let result = submit_mandatory_finality_proof(1, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(2, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(3, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + }) + } + + #[test] + fn rate_limiter_allows_request_after_new_block_has_started() { + run_test(|| { + initialize_substrate_bridge(); + + let result = submit_mandatory_finality_proof(1, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(2, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(3, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + + next_block(); + + let result = submit_mandatory_finality_proof(4, 4); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(5, 5); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_mandatory_finality_proof(6, 6); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + }) + } + + #[test] + fn rate_limiter_ignores_non_mandatory_headers() { + run_test(|| { + initialize_substrate_bridge(); + + let result = submit_finality_proof(1); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + + let result = submit_mandatory_finality_proof(2, 1); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_finality_proof_with_set_id(3, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + + let result = submit_mandatory_finality_proof(4, 2); + assert_eq!(result.expect("call failed").pays_fee, Pays::No); + + let result = submit_finality_proof_with_set_id(5, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + + let result = submit_mandatory_finality_proof(6, 3); + assert_eq!(result.expect("call failed").pays_fee, Pays::Yes); + }) + } + + #[test] + fn should_prune_headers_over_headers_to_keep_parameter() { + run_test(|| { + initialize_substrate_bridge(); + assert_ok!(submit_finality_proof(1)); + let first_header_hash = Pallet::::best_finalized().unwrap().hash(); + next_block(); + + assert_ok!(submit_finality_proof(2)); + next_block(); + assert_ok!(submit_finality_proof(3)); + next_block(); + assert_ok!(submit_finality_proof(4)); + next_block(); + assert_ok!(submit_finality_proof(5)); + next_block(); + + assert_ok!(submit_finality_proof(6)); + + assert!( + !ImportedHeaders::::contains_key(first_header_hash), + "First header should be pruned.", + ); + }) + } + + #[test] + fn storage_keys_computed_properly() { + assert_eq!( + PalletOperatingMode::::storage_value_final_key().to_vec(), + bp_header_chain::storage_keys::pallet_operating_mode_key("Grandpa").0, + ); + + assert_eq!( + CurrentAuthoritySet::::storage_value_final_key().to_vec(), + bp_header_chain::storage_keys::current_authority_set_key("Grandpa").0, + ); + + assert_eq!( + BestFinalized::::storage_value_final_key().to_vec(), + bp_header_chain::storage_keys::best_finalized_key("Grandpa").0, + ); + } + + #[test] + fn test_bridge_grandpa_call_is_correctly_defined() { + let header = test_header(0); + let init_data = InitializationData { + header: Box::new(header.clone()), + authority_list: authority_list(), + set_id: 1, + operating_mode: BasicOperatingMode::Normal, + }; + let justification = make_default_justification(&header); + + let direct_initialize_call = + Call::::initialize { init_data: init_data.clone() }; + let indirect_initialize_call = BridgeGrandpaCall::::initialize { init_data }; + assert_eq!(direct_initialize_call.encode(), indirect_initialize_call.encode()); + + let direct_submit_finality_proof_call = Call::::submit_finality_proof { + finality_target: Box::new(header.clone()), + justification: justification.clone(), + }; + let indirect_submit_finality_proof_call = + BridgeGrandpaCall::::submit_finality_proof { + finality_target: Box::new(header), + justification, + }; + assert_eq!( + direct_submit_finality_proof_call.encode(), + indirect_submit_finality_proof_call.encode() + ); + } + + generate_owned_bridge_module_tests!(BasicOperatingMode::Normal, BasicOperatingMode::Halted); + + #[test] + fn maybe_headers_to_keep_returns_correct_value() { + assert_eq!(MaybeHeadersToKeep::::get(), Some(mock::HeadersToKeep::get())); + } +} diff --git a/modules/grandpa/src/mock.rs b/modules/grandpa/src/mock.rs new file mode 100644 index 00000000000..0ebbc0bccbb --- /dev/null +++ b/modules/grandpa/src/mock.rs @@ -0,0 +1,151 @@ +// Copyright 2019-2021 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 . + +// From construct_runtime macro +#![allow(clippy::from_over_into)] + +use bp_header_chain::ChainWithGrandpa; +use bp_runtime::Chain; +use frame_support::{ + construct_runtime, parameter_types, + traits::{ConstU32, ConstU64, Hooks}, + weights::Weight, +}; +use sp_core::sr25519::Signature; +use sp_runtime::{ + testing::{Header, H256}, + traits::{BlakeTwo256, IdentityLookup}, + Perbill, +}; + +pub type AccountId = u64; +pub type TestHeader = crate::BridgedHeader; +pub type TestNumber = crate::BridgedBlockNumber; + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +pub const MAX_BRIDGED_AUTHORITIES: u32 = 5; + +use crate as grandpa; + +construct_runtime! { + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Grandpa: grandpa::{Pallet, Call, Event}, + } +} + +parameter_types! { + pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 0); + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); +} + +impl frame_system::Config for TestRuntime { + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + 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 { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = TestBridgedChain; + type MaxFreeMandatoryHeadersPerBlock = MaxFreeMandatoryHeadersPerBlock; + type HeadersToKeep = HeadersToKeep; + type WeightInfo = (); +} + +#[derive(Debug)] +pub struct TestBridgedChain; + +impl Chain for TestBridgedChain { + type BlockNumber = ::BlockNumber; + type Hash = ::Hash; + type Hasher = ::Hashing; + type Header = ::Header; + + type AccountId = AccountId; + type Balance = u64; + type Index = u64; + type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +impl ChainWithGrandpa for TestBridgedChain { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; + const MAX_AUTHORITIES_COUNT: u32 = MAX_BRIDGED_AUTHORITIES; + const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + const MAX_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; +} + +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new(Default::default()) +} + +/// Return test within default test externalities context. +pub fn run_test(test: impl FnOnce() -> T) -> T { + new_test_ext().execute_with(|| { + let _ = Grandpa::on_initialize(0); + test() + }) +} + +/// Return test header with given number. +pub fn test_header(num: TestNumber) -> TestHeader { + // We wrap the call to avoid explicit type annotations in our tests + bp_test_utils::test_header(num) +} diff --git a/modules/grandpa/src/storage_types.rs b/modules/grandpa/src/storage_types.rs new file mode 100644 index 00000000000..70448286335 --- /dev/null +++ b/modules/grandpa/src/storage_types.rs @@ -0,0 +1,136 @@ +// Copyright 2022 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 . + +//! Wrappers for public types that are implementing `MaxEncodedLen` + +use crate::{Config, Error}; + +use bp_header_chain::{AuthoritySet, ChainWithGrandpa}; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{traits::Get, BoundedVec, RuntimeDebugNoBound}; +use scale_info::TypeInfo; +use sp_consensus_grandpa::{AuthorityId, AuthorityList, AuthorityWeight, SetId}; +use sp_std::marker::PhantomData; + +/// A bounded list of Grandpa authorities with associated weights. +pub type StoredAuthorityList = + BoundedVec<(AuthorityId, AuthorityWeight), MaxBridgedAuthorities>; + +/// Adapter for using `T::BridgedChain::MAX_BRIDGED_AUTHORITIES` in `BoundedVec`. +pub struct StoredAuthorityListLimit(PhantomData<(T, I)>); + +impl, I: 'static> Get for StoredAuthorityListLimit { + fn get() -> u32 { + T::BridgedChain::MAX_AUTHORITIES_COUNT + } +} + +/// A bounded GRANDPA Authority List and ID. +#[derive(Clone, Decode, Encode, Eq, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound)] +#[scale_info(skip_type_params(T, I))] +pub struct StoredAuthoritySet, I: 'static> { + /// List of GRANDPA authorities for the current round. + pub authorities: StoredAuthorityList>, + /// Monotonic identifier of the current GRANDPA authority set. + pub set_id: SetId, +} + +impl, I: 'static> StoredAuthoritySet { + /// Try to create a new bounded GRANDPA Authority Set from unbounded list. + /// + /// Returns error if number of authorities in the provided list is too large. + pub fn try_new(authorities: AuthorityList, set_id: SetId) -> Result> { + Ok(Self { + authorities: TryFrom::try_from(authorities) + .map_err(|_| Error::TooManyAuthoritiesInSet)?, + set_id, + }) + } + + /// Returns number of bytes that may be subtracted from the PoV component of + /// `submit_finality_proof` call, because the actual authorities set is smaller than the maximal + /// configured. + /// + /// Maximal authorities set size is configured by the `MaxBridgedAuthorities` constant from + /// the pallet configuration. The PoV of the call includes the size of maximal authorities + /// count. If the actual size is smaller, we may subtract extra bytes from this component. + pub fn unused_proof_size(&self) -> u64 { + // we can only safely estimate bytes that are occupied by the authority data itself. We have + // no means here to compute PoV bytes, occupied by extra trie nodes or extra bytes in the + // whole set encoding + let single_authority_max_encoded_len = + <(AuthorityId, AuthorityWeight)>::max_encoded_len() as u64; + let extra_authorities = + T::BridgedChain::MAX_AUTHORITIES_COUNT.saturating_sub(self.authorities.len() as _); + single_authority_max_encoded_len.saturating_mul(extra_authorities as u64) + } +} + +impl, I: 'static> PartialEq for StoredAuthoritySet { + fn eq(&self, other: &Self) -> bool { + self.set_id == other.set_id && self.authorities == other.authorities + } +} + +impl, I: 'static> Default for StoredAuthoritySet { + fn default() -> Self { + StoredAuthoritySet { authorities: BoundedVec::default(), set_id: 0 } + } +} + +impl, I: 'static> From> for AuthoritySet { + fn from(t: StoredAuthoritySet) -> Self { + AuthoritySet { authorities: t.authorities.into(), set_id: t.set_id } + } +} + +#[cfg(test)] +mod tests { + use crate::mock::{TestRuntime, MAX_BRIDGED_AUTHORITIES}; + use bp_test_utils::authority_list; + + type StoredAuthoritySet = super::StoredAuthoritySet; + + #[test] + fn unused_proof_size_works() { + let authority_entry = authority_list().pop().unwrap(); + + // when we have exactly `MaxBridgedAuthorities` authorities + assert_eq!( + StoredAuthoritySet::try_new( + vec![authority_entry.clone(); MAX_BRIDGED_AUTHORITIES as usize], + 0, + ) + .unwrap() + .unused_proof_size(), + 0, + ); + + // when we have less than `MaxBridgedAuthorities` authorities + assert_eq!( + StoredAuthoritySet::try_new( + vec![authority_entry; MAX_BRIDGED_AUTHORITIES as usize - 1], + 0, + ) + .unwrap() + .unused_proof_size(), + 40, + ); + + // and we can't have more than `MaxBridgedAuthorities` authorities in the bounded vec, so + // no test for this case + } +} diff --git a/modules/grandpa/src/weights.rs b/modules/grandpa/src/weights.rs new file mode 100644 index 00000000000..089aee8b569 --- /dev/null +++ b/modules/grandpa/src/weights.rs @@ -0,0 +1,167 @@ +// Copyright 2019-2021 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 . + +//! Autogenerated weights for pallet_bridge_grandpa +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/millau-bridge-node +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_bridge_grandpa +// --extrinsic=* +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --output=./modules/grandpa/src/weights.rs +// --template=./.maintain/millau-weight-template.hbs + +#![allow(clippy::all)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_bridge_grandpa. +pub trait WeightInfo { + fn submit_finality_proof(p: u32, v: u32) -> Weight; +} + +/// Weights for `pallet_bridge_grandpa` 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: BridgeRialtoGrandpa PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// added: 496, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa RequestCount (r:1 w:1) + /// + /// Proof: BridgeRialtoGrandpa RequestCount (max_values: Some(1), max_size: Some(4), added: 499, + /// mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa BestFinalized (r:1 w:1) + /// + /// Proof: BridgeRialtoGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: + /// 531, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa CurrentAuthoritySet (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(209), + /// added: 704, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHashesPointer (r:1 w:1) + /// + /// Proof: BridgeRialtoGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), + /// added: 499, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHashes (r:1 w:1) + /// + /// Proof: BridgeRialtoGrandpa ImportedHashes (max_values: Some(14400), max_size: Some(36), + /// added: 2016, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:0 w:2) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// The range of component `p` is `[1, 4]`. + /// + /// The range of component `v` is `[50, 100]`. + fn submit_finality_proof(p: u32, v: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `394 + p * (60 ±0)` + // Estimated: `4745` + // Minimum execution time: 228_072 nanoseconds. + Weight::from_parts(57_853_228, 4745) + // Standard Error: 149_421 + .saturating_add(Weight::from_parts(36_708_702, 0).saturating_mul(p.into())) + // Standard Error: 10_625 + .saturating_add(Weight::from_parts(1_469_032, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(6_u64)) + .saturating_add(T::DbWeight::get().writes(6_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: BridgeRialtoGrandpa PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// added: 496, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa RequestCount (r:1 w:1) + /// + /// Proof: BridgeRialtoGrandpa RequestCount (max_values: Some(1), max_size: Some(4), added: 499, + /// mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa BestFinalized (r:1 w:1) + /// + /// Proof: BridgeRialtoGrandpa BestFinalized (max_values: Some(1), max_size: Some(36), added: + /// 531, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa CurrentAuthoritySet (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa CurrentAuthoritySet (max_values: Some(1), max_size: Some(209), + /// added: 704, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHashesPointer (r:1 w:1) + /// + /// Proof: BridgeRialtoGrandpa ImportedHashesPointer (max_values: Some(1), max_size: Some(4), + /// added: 499, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHashes (r:1 w:1) + /// + /// Proof: BridgeRialtoGrandpa ImportedHashes (max_values: Some(14400), max_size: Some(36), + /// added: 2016, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:0 w:2) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// The range of component `p` is `[1, 4]`. + /// + /// The range of component `v` is `[50, 100]`. + fn submit_finality_proof(p: u32, v: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `394 + p * (60 ±0)` + // Estimated: `4745` + // Minimum execution time: 228_072 nanoseconds. + Weight::from_parts(57_853_228, 4745) + // Standard Error: 149_421 + .saturating_add(Weight::from_parts(36_708_702, 0).saturating_mul(p.into())) + // Standard Error: 10_625 + .saturating_add(Weight::from_parts(1_469_032, 0).saturating_mul(v.into())) + .saturating_add(RocksDbWeight::get().reads(6_u64)) + .saturating_add(RocksDbWeight::get().writes(6_u64)) + } +} diff --git a/modules/messages/Cargo.toml b/modules/messages/Cargo.toml new file mode 100644 index 00000000000..f733d62bf64 --- /dev/null +++ b/modules/messages/Cargo.toml @@ -0,0 +1,56 @@ +[package] +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" +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.17", default-features = false } +num-traits = { version = "0.2", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +# Bridge dependencies + +bp-messages = { path = "../../primitives/messages", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } + +# Substrate Dependencies + +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +bp-test-utils = { path = "../../primitives/test-utils" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = ["std"] +std = [ + "bp-messages/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "log/std", + "num-traits/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/messages/README.md b/modules/messages/README.md new file mode 100644 index 00000000000..b717db6ad62 --- /dev/null +++ b/modules/messages/README.md @@ -0,0 +1,242 @@ +# 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. + +## Contents + +- [Overview](#overview) +- [Message Workflow](#message-workflow) +- [Integrating Message Lane Module into Runtime](#integrating-messages-module-into-runtime) +- [Non-Essential Functionality](#non-essential-functionality) +- [Weights of Module Extrinsics](#weights-of-module-extrinsics) + +## 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). + +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. + +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 Statemint <> Statemine communications. Other lanes may be used to bridge +another 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 +`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. + +### 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 +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. + +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. + +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 +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. + +### 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. + +### 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::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. + +### 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. + +## 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: +- `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. + +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/). diff --git a/modules/messages/src/benchmarking.rs b/modules/messages/src/benchmarking.rs new file mode 100644 index 00000000000..aab8855a729 --- /dev/null +++ b/modules/messages/src/benchmarking.rs @@ -0,0 +1,460 @@ +// Copyright 2019-2021 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 . + +//! Messages pallet benchmarking. + +use crate::{ + inbound_lane::InboundLaneStorage, inbound_lane_storage, outbound_lane, + weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, Call, OutboundLanes, +}; + +use bp_messages::{ + source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, DeliveredMessages, + InboundLaneData, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer, + UnrewardedRelayersState, +}; +use bp_runtime::StorageProofSize; +use codec::Decode; +use frame_benchmarking::{account, benchmarks_instance_pallet}; +use frame_support::weights::Weight; +use frame_system::RawOrigin; +use sp_runtime::traits::TrailingZeroInput; +use sp_std::{ops::RangeInclusive, prelude::*}; + +const SEED: u32 = 0; + +/// Pallet we're benchmarking here. +pub struct Pallet, I: 'static = ()>(crate::Pallet); + +/// Benchmark-specific message proof parameters. +#[derive(Debug)] +pub struct MessageProofParams { + /// Id of the lane. + pub lane: LaneId, + /// Range of messages to include in the proof. + pub message_nonces: RangeInclusive, + /// If `Some`, the proof needs to include this outbound lane data. + pub outbound_lane_data: Option, + /// If `true`, the caller expects that the proof will contain correct messages that will + /// be successfully dispatched. This is only called from the "optional" + /// `receive_single_message_proof_with_dispatch` benchmark. If you don't need it, just + /// return `true` from the `is_message_successfully_dispatched`. + pub is_successful_dispatch_expected: bool, + /// Proof size requirements. + pub size: StorageProofSize, +} + +/// Benchmark-specific message delivery proof parameters. +#[derive(Debug)] +pub struct MessageDeliveryProofParams { + /// Id of the lane. + pub lane: LaneId, + /// The proof needs to include this inbound lane data. + pub inbound_lane_data: InboundLaneData, + /// Proof size requirements. + pub size: StorageProofSize, +} + +/// Trait that must be implemented by runtime. +pub trait Config: crate::Config { + /// Lane id to use in benchmarks. + /// + /// By default, lane 00000000 is used. + fn bench_lane_id() -> LaneId { + LaneId([0, 0, 0, 0]) + } + + /// Return id of relayer account at the bridged chain. + /// + /// By default, zero account is returned. + fn bridged_relayer_id() -> Self::InboundRelayer { + Self::InboundRelayer::decode(&mut TrailingZeroInput::zeroes()).unwrap() + } + + /// Create given account and give it enough balance for test purposes. Used to create + /// relayer account at the target chain. Is strictly necessary when your rewards scheme + /// assumes that the relayer account must exist. + /// + /// Does nothing by default. + fn endow_account(_account: &Self::AccountId) {} + + /// Prepare messages proof to receive by the module. + fn prepare_message_proof( + params: MessageProofParams, + ) -> (::MessagesProof, Weight); + /// Prepare messages delivery proof to receive by the module. + fn prepare_message_delivery_proof( + params: MessageDeliveryProofParams, + ) -> >::MessagesDeliveryProof; + + /// Returns true if message has been successfully dispatched or not. + fn is_message_successfully_dispatched(_nonce: MessageNonce) -> bool { + true + } + + /// Returns true if given relayer has been rewarded for some of its actions. + fn is_relayer_rewarded(relayer: &Self::AccountId) -> bool; +} + +benchmarks_instance_pallet! { + // + // Benchmarks that are used directly by the runtime calls weight formulae. + // + + // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: + // * proof does not include outbound lane state proof; + // * inbound lane already has state, so it needs to be read and decoded; + // * message is dispatched (reminder: dispatch weight should be minimal); + // * message requires all heavy checks done by dispatcher. + // + // This is base benchmark for all other message delivery benchmarks. + receive_single_message_proof { + let relayer_id_on_source = T::bridged_relayer_id(); + let relayer_id_on_target = account("relayer", 0, SEED); + T::endow_account(&relayer_id_on_target); + + // mark messages 1..=20 as delivered + receive_messages::(20); + + let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { + lane: T::bench_lane_id(), + message_nonces: 21..=21, + outbound_lane_data: None, + is_successful_dispatch_expected: false, + size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + }); + }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) + verify { + assert_eq!( + crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), + 21, + ); + } + + // Benchmark `receive_messages_proof` extrinsic with two minimal-weight messages and following conditions: + // * proof does not include outbound lane state proof; + // * inbound lane already has state, so it needs to be read and decoded; + // * message is dispatched (reminder: dispatch weight should be minimal); + // * message requires all heavy checks done by dispatcher. + // + // The weight of single message delivery could be approximated as + // `weight(receive_two_messages_proof) - weight(receive_single_message_proof)`. + // This won't be super-accurate if message has non-zero dispatch weight, but estimation should + // be close enough to real weight. + receive_two_messages_proof { + let relayer_id_on_source = T::bridged_relayer_id(); + let relayer_id_on_target = account("relayer", 0, SEED); + T::endow_account(&relayer_id_on_target); + + // mark messages 1..=20 as delivered + receive_messages::(20); + + let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { + lane: T::bench_lane_id(), + message_nonces: 21..=22, + outbound_lane_data: None, + is_successful_dispatch_expected: false, + size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + }); + }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 2, dispatch_weight) + verify { + assert_eq!( + crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), + 22, + ); + } + + // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: + // * proof includes outbound lane state proof; + // * inbound lane already has state, so it needs to be read and decoded; + // * message is successfully dispatched (reminder: dispatch weight should be minimal); + // * message requires all heavy checks done by dispatcher. + // + // The weight of outbound lane state delivery would be + // `weight(receive_single_message_proof_with_outbound_lane_state) - weight(receive_single_message_proof)`. + // This won't be super-accurate if message has non-zero dispatch weight, but estimation should + // be close enough to real weight. + receive_single_message_proof_with_outbound_lane_state { + let relayer_id_on_source = T::bridged_relayer_id(); + let relayer_id_on_target = account("relayer", 0, SEED); + T::endow_account(&relayer_id_on_target); + + // mark messages 1..=20 as delivered + receive_messages::(20); + + let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { + lane: T::bench_lane_id(), + message_nonces: 21..=21, + outbound_lane_data: Some(OutboundLaneData { + oldest_unpruned_nonce: 21, + latest_received_nonce: 20, + latest_generated_nonce: 21, + }), + is_successful_dispatch_expected: false, + size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH), + }); + }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) + verify { + let lane_state = crate::InboundLanes::::get(&T::bench_lane_id()); + assert_eq!(lane_state.last_delivered_nonce(), 21); + assert_eq!(lane_state.last_confirmed_nonce, 20); + } + + // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: + // * the proof has large leaf with total size of approximately 1KB; + // * proof does not include outbound lane state proof; + // * inbound lane already has state, so it needs to be read and decoded; + // * message is dispatched (reminder: dispatch weight should be minimal); + // * message requires all heavy checks done by dispatcher. + // + // With single KB of messages proof, the weight of the call is increased (roughly) by + // `(receive_single_message_proof_16KB - receive_single_message_proof_1_kb) / 15`. + receive_single_message_proof_1_kb { + let relayer_id_on_source = T::bridged_relayer_id(); + let relayer_id_on_target = account("relayer", 0, SEED); + T::endow_account(&relayer_id_on_target); + + // mark messages 1..=20 as delivered + receive_messages::(20); + + let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { + lane: T::bench_lane_id(), + message_nonces: 21..=21, + outbound_lane_data: None, + is_successful_dispatch_expected: false, + size: StorageProofSize::HasLargeLeaf(1024), + }); + }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) + verify { + assert_eq!( + crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), + 21, + ); + } + + // Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions: + // * the proof has large leaf with total size of approximately 16KB; + // * proof does not include outbound lane state proof; + // * inbound lane already has state, so it needs to be read and decoded; + // * message is dispatched (reminder: dispatch weight should be minimal); + // * message requires all heavy checks done by dispatcher. + // + // Size of proof grows because it contains extra trie nodes in it. + // + // With single KB of messages proof, the weight of the call is increased (roughly) by + // `(receive_single_message_proof_16KB - receive_single_message_proof) / 15`. + receive_single_message_proof_16_kb { + let relayer_id_on_source = T::bridged_relayer_id(); + let relayer_id_on_target = account("relayer", 0, SEED); + T::endow_account(&relayer_id_on_target); + + // mark messages 1..=20 as delivered + receive_messages::(20); + + let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { + lane: T::bench_lane_id(), + message_nonces: 21..=21, + outbound_lane_data: None, + is_successful_dispatch_expected: false, + size: StorageProofSize::HasLargeLeaf(16 * 1024), + }); + }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) + verify { + assert_eq!( + crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), + 21, + ); + } + + // Benchmark `receive_messages_delivery_proof` extrinsic with following conditions: + // * single relayer is rewarded for relaying single message; + // * relayer account does not exist (in practice it needs to exist in production environment). + // + // This is base benchmark for all other confirmations delivery benchmarks. + receive_delivery_proof_for_single_message { + let relayer_id: T::AccountId = account("relayer", 0, SEED); + + // send message that we're going to confirm + send_regular_message::(); + + let relayers_state = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }; + let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { + lane: T::bench_lane_id(), + inbound_lane_data: InboundLaneData { + relayers: vec![UnrewardedRelayer { + relayer: relayer_id.clone(), + messages: DeliveredMessages::new(1), + }].into_iter().collect(), + last_confirmed_nonce: 0, + }, + size: StorageProofSize::Minimal(0), + }); + }: receive_messages_delivery_proof(RawOrigin::Signed(relayer_id.clone()), proof, relayers_state) + verify { + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 1); + assert!(T::is_relayer_rewarded(&relayer_id)); + } + + // Benchmark `receive_messages_delivery_proof` extrinsic with following conditions: + // * single relayer is rewarded for relaying two messages; + // * relayer account does not exist (in practice it needs to exist in production environment). + // + // Additional weight for paying single-message reward to the same relayer could be computed + // as `weight(receive_delivery_proof_for_two_messages_by_single_relayer) + // - weight(receive_delivery_proof_for_single_message)`. + receive_delivery_proof_for_two_messages_by_single_relayer { + let relayer_id: T::AccountId = account("relayer", 0, SEED); + + // send message that we're going to confirm + send_regular_message::(); + send_regular_message::(); + + let relayers_state = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 2, + total_messages: 2, + last_delivered_nonce: 2, + }; + let mut delivered_messages = DeliveredMessages::new(1); + delivered_messages.note_dispatched_message(); + let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { + lane: T::bench_lane_id(), + inbound_lane_data: InboundLaneData { + relayers: vec![UnrewardedRelayer { + relayer: relayer_id.clone(), + messages: delivered_messages, + }].into_iter().collect(), + last_confirmed_nonce: 0, + }, + size: StorageProofSize::Minimal(0), + }); + }: receive_messages_delivery_proof(RawOrigin::Signed(relayer_id.clone()), proof, relayers_state) + verify { + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); + assert!(T::is_relayer_rewarded(&relayer_id)); + } + + // Benchmark `receive_messages_delivery_proof` extrinsic with following conditions: + // * two relayers are rewarded for relaying single message each; + // * relayer account does not exist (in practice it needs to exist in production environment). + // + // Additional weight for paying reward to the next relayer could be computed + // as `weight(receive_delivery_proof_for_two_messages_by_two_relayers) + // - weight(receive_delivery_proof_for_two_messages_by_single_relayer)`. + receive_delivery_proof_for_two_messages_by_two_relayers { + let relayer1_id: T::AccountId = account("relayer1", 1, SEED); + let relayer2_id: T::AccountId = account("relayer2", 2, SEED); + + // send message that we're going to confirm + send_regular_message::(); + send_regular_message::(); + + let relayers_state = UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + messages_in_oldest_entry: 1, + total_messages: 2, + last_delivered_nonce: 2, + }; + let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { + lane: T::bench_lane_id(), + inbound_lane_data: InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: relayer1_id.clone(), + messages: DeliveredMessages::new(1), + }, + UnrewardedRelayer { + relayer: relayer2_id.clone(), + messages: DeliveredMessages::new(2), + }, + ].into_iter().collect(), + last_confirmed_nonce: 0, + }, + size: StorageProofSize::Minimal(0), + }); + }: receive_messages_delivery_proof(RawOrigin::Signed(relayer1_id.clone()), proof, relayers_state) + verify { + assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); + assert!(T::is_relayer_rewarded(&relayer1_id)); + assert!(T::is_relayer_rewarded(&relayer2_id)); + } + + // + // Benchmarks that the runtime developers may use for proper pallet configuration. + // + + // This benchmark is optional and may be used when runtime developer need a way to compute + // message dispatch weight. In this case, he needs to provide messages that can go the whole + // dispatch + // + // Benchmark `receive_messages_proof` extrinsic with single message and following conditions: + // + // * proof does not include outbound lane state proof; + // * inbound lane already has state, so it needs to be read and decoded; + // * message is **SUCCESSFULLY** dispatched; + // * message requires all heavy checks done by dispatcher. + receive_single_message_proof_with_dispatch { + // maybe dispatch weight relies on the message size too? + let i in EXPECTED_DEFAULT_MESSAGE_LENGTH .. EXPECTED_DEFAULT_MESSAGE_LENGTH * 16; + + let relayer_id_on_source = T::bridged_relayer_id(); + let relayer_id_on_target = account("relayer", 0, SEED); + T::endow_account(&relayer_id_on_target); + + // mark messages 1..=20 as delivered + receive_messages::(20); + + let (proof, dispatch_weight) = T::prepare_message_proof(MessageProofParams { + lane: T::bench_lane_id(), + message_nonces: 21..=21, + outbound_lane_data: None, + is_successful_dispatch_expected: true, + size: StorageProofSize::Minimal(i), + }); + }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) + verify { + assert_eq!( + crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), + 21, + ); + assert!(T::is_message_successfully_dispatched(21)); + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) +} + +fn send_regular_message, I: 'static>() { + let mut outbound_lane = outbound_lane::(T::bench_lane_id()); + outbound_lane.send_message(vec![]); +} + +fn receive_messages, I: 'static>(nonce: MessageNonce) { + let mut inbound_lane_storage = inbound_lane_storage::(T::bench_lane_id()); + inbound_lane_storage.set_data(InboundLaneData { + relayers: vec![UnrewardedRelayer { + relayer: T::bridged_relayer_id(), + messages: DeliveredMessages::new(nonce), + }] + .into_iter() + .collect(), + last_confirmed_nonce: 0, + }); +} diff --git a/modules/messages/src/inbound_lane.rs b/modules/messages/src/inbound_lane.rs new file mode 100644 index 00000000000..3f64ab765b5 --- /dev/null +++ b/modules/messages/src/inbound_lane.rs @@ -0,0 +1,550 @@ +// Copyright 2019-2021 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 . + +//! Everything about incoming messages receival. + +use crate::Config; + +use bp_messages::{ + target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, + DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, OutboundLaneData, + ReceivalResult, UnrewardedRelayer, +}; +use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; +use frame_support::{traits::Get, RuntimeDebug}; +use scale_info::{Type, TypeInfo}; +use sp_std::prelude::PartialEq; + +/// Inbound lane storage. +pub trait InboundLaneStorage { + /// Id of relayer on source chain. + type Relayer: Clone + PartialEq; + + /// Lane id. + fn id(&self) -> LaneId; + /// Return maximal number of unrewarded relayer entries in inbound lane. + fn max_unrewarded_relayer_entries(&self) -> MessageNonce; + /// Return maximal number of unconfirmed messages in inbound lane. + fn max_unconfirmed_messages(&self) -> MessageNonce; + /// Get lane data from the storage. + fn data(&self) -> InboundLaneData; + /// Update lane data in the storage. + fn set_data(&mut self, data: InboundLaneData); +} + +/// Inbound lane data wrapper that implements `MaxEncodedLen`. +/// +/// We have already had `MaxEncodedLen`-like functionality before, but its usage has +/// been localized and we haven't been passing bounds (maximal count of unrewarded relayer entries, +/// maximal count of unconfirmed messages) everywhere. This wrapper allows us to avoid passing +/// these generic bounds all over the code. +/// +/// The encoding of this type matches encoding of the corresponding `MessageData`. +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)] +pub struct StoredInboundLaneData, I: 'static>(pub InboundLaneData); + +impl, I: 'static> sp_std::ops::Deref for StoredInboundLaneData { + type Target = InboundLaneData; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl, I: 'static> sp_std::ops::DerefMut for StoredInboundLaneData { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl, I: 'static> Default for StoredInboundLaneData { + fn default() -> Self { + StoredInboundLaneData(Default::default()) + } +} + +impl, I: 'static> From> + for InboundLaneData +{ + fn from(data: StoredInboundLaneData) -> Self { + data.0 + } +} + +impl, I: 'static> EncodeLike> + for InboundLaneData +{ +} + +impl, I: 'static> TypeInfo for StoredInboundLaneData { + type Identity = Self; + + fn type_info() -> Type { + InboundLaneData::::type_info() + } +} + +impl, I: 'static> MaxEncodedLen for StoredInboundLaneData { + fn max_encoded_len() -> usize { + InboundLaneData::::encoded_size_hint( + T::MaxUnrewardedRelayerEntriesAtInboundLane::get() as usize, + ) + .unwrap_or(usize::MAX) + } +} + +/// Inbound messages lane. +pub struct InboundLane { + storage: S, +} + +impl InboundLane { + /// Create new inbound lane backed by given storage. + pub fn new(storage: S) -> Self { + InboundLane { storage } + } + + /// Returns storage reference. + pub fn storage(&self) -> &S { + &self.storage + } + + /// Receive state of the corresponding outbound lane. + pub fn receive_state_update( + &mut self, + outbound_lane_data: OutboundLaneData, + ) -> Option { + let mut data = self.storage.data(); + let last_delivered_nonce = data.last_delivered_nonce(); + + if outbound_lane_data.latest_received_nonce > last_delivered_nonce { + // this is something that should never happen if proofs are correct + return None + } + if outbound_lane_data.latest_received_nonce <= data.last_confirmed_nonce { + return None + } + + let new_confirmed_nonce = outbound_lane_data.latest_received_nonce; + data.last_confirmed_nonce = new_confirmed_nonce; + // Firstly, remove all of the records where higher nonce <= new confirmed nonce + while data + .relayers + .front() + .map(|entry| entry.messages.end <= new_confirmed_nonce) + .unwrap_or(false) + { + data.relayers.pop_front(); + } + // Secondly, update the next record with lower nonce equal to new confirmed nonce if needed. + // Note: There will be max. 1 record to update as we don't allow messages from relayers to + // overlap. + match data.relayers.front_mut() { + Some(entry) if entry.messages.begin < new_confirmed_nonce => { + entry.messages.begin = new_confirmed_nonce + 1; + }, + _ => {}, + } + + self.storage.set_data(data); + Some(outbound_lane_data.latest_received_nonce) + } + + /// Receive new message. + pub fn receive_message, AccountId>( + &mut self, + relayer_at_bridged_chain: &S::Relayer, + relayer_at_this_chain: &AccountId, + nonce: MessageNonce, + message_data: DispatchMessageData, + ) -> ReceivalResult { + let mut data = self.storage.data(); + let is_correct_message = nonce == data.last_delivered_nonce() + 1; + if !is_correct_message { + return ReceivalResult::InvalidNonce + } + + // if there are more unrewarded relayer entries than we may accept, reject this message + if data.relayers.len() as MessageNonce >= self.storage.max_unrewarded_relayer_entries() { + return ReceivalResult::TooManyUnrewardedRelayers + } + + // if there are more unconfirmed messages than we may accept, reject this message + let unconfirmed_messages_count = nonce.saturating_sub(data.last_confirmed_nonce); + if unconfirmed_messages_count > self.storage.max_unconfirmed_messages() { + return ReceivalResult::TooManyUnconfirmedMessages + } + + // then, dispatch message + let dispatch_result = Dispatch::dispatch( + relayer_at_this_chain, + DispatchMessage { + key: MessageKey { lane_id: self.storage.id(), nonce }, + data: message_data, + }, + ); + + // now let's update inbound lane storage + let push_new = match data.relayers.back_mut() { + Some(entry) if entry.relayer == *relayer_at_bridged_chain => { + entry.messages.note_dispatched_message(); + false + }, + _ => true, + }; + if push_new { + data.relayers.push_back(UnrewardedRelayer { + relayer: (*relayer_at_bridged_chain).clone(), + messages: DeliveredMessages::new(nonce), + }); + } + self.storage.set_data(data); + + ReceivalResult::Dispatched(dispatch_result) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + inbound_lane, + mock::{ + dispatch_result, inbound_message_data, run_test, unrewarded_relayer, + TestMessageDispatch, TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, + TEST_RELAYER_B, TEST_RELAYER_C, + }, + RuntimeInboundLaneStorage, + }; + + fn receive_regular_message( + lane: &mut InboundLane>, + nonce: MessageNonce, + ) { + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + &TEST_RELAYER_A, + nonce, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::Dispatched(dispatch_result(0)) + ); + } + + #[test] + fn receive_status_update_ignores_status_from_the_future() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + receive_regular_message(&mut lane, 1); + assert_eq!( + lane.receive_state_update(OutboundLaneData { + latest_received_nonce: 10, + ..Default::default() + }), + None, + ); + + assert_eq!(lane.storage.data().last_confirmed_nonce, 0); + }); + } + + #[test] + fn receive_status_update_ignores_obsolete_status() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + receive_regular_message(&mut lane, 1); + receive_regular_message(&mut lane, 2); + receive_regular_message(&mut lane, 3); + assert_eq!( + lane.receive_state_update(OutboundLaneData { + latest_received_nonce: 3, + ..Default::default() + }), + Some(3), + ); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); + + assert_eq!( + lane.receive_state_update(OutboundLaneData { + latest_received_nonce: 3, + ..Default::default() + }), + None, + ); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); + }); + } + + #[test] + fn receive_status_update_works() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + receive_regular_message(&mut lane, 1); + receive_regular_message(&mut lane, 2); + receive_regular_message(&mut lane, 3); + assert_eq!(lane.storage.data().last_confirmed_nonce, 0); + assert_eq!( + lane.storage.data().relayers, + vec![unrewarded_relayer(1, 3, TEST_RELAYER_A)] + ); + + assert_eq!( + lane.receive_state_update(OutboundLaneData { + latest_received_nonce: 2, + ..Default::default() + }), + Some(2), + ); + assert_eq!(lane.storage.data().last_confirmed_nonce, 2); + assert_eq!( + lane.storage.data().relayers, + vec![unrewarded_relayer(3, 3, TEST_RELAYER_A)] + ); + + assert_eq!( + lane.receive_state_update(OutboundLaneData { + latest_received_nonce: 3, + ..Default::default() + }), + Some(3), + ); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().relayers, vec![]); + }); + } + + #[test] + fn receive_status_update_works_with_batches_from_relayers() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + let mut seed_storage_data = lane.storage.data(); + // Prepare data + seed_storage_data.last_confirmed_nonce = 0; + seed_storage_data.relayers.push_back(unrewarded_relayer(1, 1, TEST_RELAYER_A)); + // Simulate messages batch (2, 3, 4) from relayer #2 + seed_storage_data.relayers.push_back(unrewarded_relayer(2, 4, TEST_RELAYER_B)); + seed_storage_data.relayers.push_back(unrewarded_relayer(5, 5, TEST_RELAYER_C)); + lane.storage.set_data(seed_storage_data); + // Check + assert_eq!( + lane.receive_state_update(OutboundLaneData { + latest_received_nonce: 3, + ..Default::default() + }), + Some(3), + ); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); + assert_eq!( + lane.storage.data().relayers, + vec![ + unrewarded_relayer(4, 4, TEST_RELAYER_B), + unrewarded_relayer(5, 5, TEST_RELAYER_C) + ] + ); + }); + } + + #[test] + fn fails_to_receive_message_with_incorrect_nonce() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + &TEST_RELAYER_A, + 10, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::InvalidNonce + ); + assert_eq!(lane.storage.data().last_delivered_nonce(), 0); + }); + } + + #[test] + fn fails_to_receive_messages_above_unrewarded_relayer_entries_limit_per_lane() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + let max_nonce = + ::MaxUnrewardedRelayerEntriesAtInboundLane::get(); + for current_nonce in 1..max_nonce + 1 { + assert_eq!( + lane.receive_message::( + &(TEST_RELAYER_A + current_nonce), + &(TEST_RELAYER_A + current_nonce), + current_nonce, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::Dispatched(dispatch_result(0)) + ); + } + // Fails to dispatch new message from different than latest relayer. + assert_eq!( + lane.receive_message::( + &(TEST_RELAYER_A + max_nonce + 1), + &(TEST_RELAYER_A + max_nonce + 1), + max_nonce + 1, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::TooManyUnrewardedRelayers, + ); + // Fails to dispatch new messages from latest relayer. Prevents griefing attacks. + assert_eq!( + lane.receive_message::( + &(TEST_RELAYER_A + max_nonce), + &(TEST_RELAYER_A + max_nonce), + max_nonce + 1, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::TooManyUnrewardedRelayers, + ); + }); + } + + #[test] + fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + let max_nonce = ::MaxUnconfirmedMessagesAtInboundLane::get(); + for current_nonce in 1..=max_nonce { + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + &TEST_RELAYER_A, + current_nonce, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::Dispatched(dispatch_result(0)) + ); + } + // Fails to dispatch new message from different than latest relayer. + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_B, + &TEST_RELAYER_B, + max_nonce + 1, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::TooManyUnconfirmedMessages, + ); + // Fails to dispatch new messages from latest relayer. + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + &TEST_RELAYER_A, + max_nonce + 1, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::TooManyUnconfirmedMessages, + ); + }); + } + + #[test] + fn correctly_receives_following_messages_from_two_relayers_alternately() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + &TEST_RELAYER_A, + 1, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::Dispatched(dispatch_result(0)) + ); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_B, + &TEST_RELAYER_B, + 2, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::Dispatched(dispatch_result(0)) + ); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + &TEST_RELAYER_A, + 3, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::Dispatched(dispatch_result(0)) + ); + assert_eq!( + lane.storage.data().relayers, + vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B), + unrewarded_relayer(3, 3, TEST_RELAYER_A) + ] + ); + }); + } + + #[test] + fn rejects_same_message_from_two_different_relayers() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + &TEST_RELAYER_A, + 1, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::Dispatched(dispatch_result(0)) + ); + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_B, + &TEST_RELAYER_B, + 1, + inbound_message_data(REGULAR_PAYLOAD) + ), + ReceivalResult::InvalidNonce, + ); + }); + } + + #[test] + fn correct_message_is_processed_instantly() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + receive_regular_message(&mut lane, 1); + assert_eq!(lane.storage.data().last_delivered_nonce(), 1); + }); + } + + #[test] + fn unspent_weight_is_returned_by_receive_message() { + run_test(|| { + let mut lane = inbound_lane::(TEST_LANE_ID); + let mut payload = REGULAR_PAYLOAD; + *payload.dispatch_result.unspent_weight.ref_time_mut() = 1; + assert_eq!( + lane.receive_message::( + &TEST_RELAYER_A, + &TEST_RELAYER_A, + 1, + inbound_message_data(payload) + ), + ReceivalResult::Dispatched(dispatch_result(1)) + ); + }); + } +} diff --git a/modules/messages/src/lib.rs b/modules/messages/src/lib.rs new file mode 100644 index 00000000000..c94f5ffa752 --- /dev/null +++ b/modules/messages/src/lib.rs @@ -0,0 +1,2176 @@ +// Copyright 2019-2021 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 . + +//! Runtime module that allows sending and receiving messages using lane concept: +//! +//! 1) the message is sent using `send_message()` call; +//! 2) every outbound message is assigned nonce; +//! 3) the messages are stored in the storage; +//! 4) external component (relay) delivers messages to bridged chain; +//! 5) messages are processed in order (ordered by assigned nonce); +//! 6) relay may send proof-of-delivery back to this chain. +//! +//! Once message is sent, its progress can be tracked by looking at module events. +//! The assigned nonce is reported using `MessageAccepted` event. When message is +//! delivered to the the bridged chain, it is reported using `MessagesDelivered` event. +//! +//! **IMPORTANT NOTE**: after generating weights (custom `WeighInfo` implementation) for +//! your runtime (where this module is plugged to), please add test for these weights. +//! The test should call the `ensure_weights_are_correct` function from this module. +//! If this test fails with your weights, then either weights are computed incorrectly, +//! or some benchmarks assumptions are broken for your runtime. + +#![cfg_attr(not(feature = "std"), no_std)] +// Generated by `decl_event!` +#![allow(clippy::unused_unit)] + +pub use inbound_lane::StoredInboundLaneData; +pub use outbound_lane::StoredMessagePayload; +pub use weights::WeightInfo; +pub use weights_ext::{ + ensure_able_to_receive_confirmation, ensure_able_to_receive_message, + ensure_weights_are_correct, WeightInfoExt, EXPECTED_DEFAULT_MESSAGE_LENGTH, + EXTRA_STORAGE_PROOF_SIZE, +}; + +use crate::{ + inbound_lane::{InboundLane, InboundLaneStorage}, + outbound_lane::{OutboundLane, OutboundLaneStorage, ReceivalConfirmationResult}, +}; + +use bp_messages::{ + source_chain::{ + DeliveryConfirmationPayments, LaneMessageVerifier, SendMessageArtifacts, TargetHeaderChain, + }, + target_chain::{ + DeliveryPayments, DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, + SourceHeaderChain, + }, + total_unrewarded_messages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, + MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, + OutboundMessageDetails, UnrewardedRelayersState, +}; +use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, PreComputedSize, Size}; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get}; +use sp_runtime::traits::UniqueSaturatedFrom; +use sp_std::{cell::RefCell, marker::PhantomData, prelude::*}; + +mod inbound_lane; +mod outbound_lane; +mod weights_ext; + +pub mod weights; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +#[cfg(test)] +mod mock; + +pub use pallet::*; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-messages"; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use bp_messages::{ReceivalResult, ReceivedMessages}; + use bp_runtime::RangeInclusiveExt; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + // General types + + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + /// Benchmarks results from runtime we're plugged into. + type WeightInfo: WeightInfoExt; + + /// Gets the chain id value from the instance. + #[pallet::constant] + type BridgedChainId: Get; + + /// Get all active outbound lanes that the message pallet is serving. + type ActiveOutboundLanes: Get<&'static [LaneId]>; + /// Maximal number of unrewarded relayer entries at inbound lane. Unrewarded means that the + /// relayer has delivered messages, but either confirmations haven't been delivered back to + /// the source chain, or we haven't received reward confirmations yet. + /// + /// This constant limits maximal number of entries in the `InboundLaneData::relayers`. Keep + /// in mind that the same relayer account may take several (non-consecutive) entries in this + /// set. + type MaxUnrewardedRelayerEntriesAtInboundLane: Get; + /// Maximal number of unconfirmed messages at inbound lane. Unconfirmed means that the + /// message has been delivered, but either confirmations haven't been delivered back to the + /// source chain, or we haven't received reward confirmations for these messages yet. + /// + /// This constant limits difference between last message from last entry of the + /// `InboundLaneData::relayers` and first message at the first entry. + /// + /// There is no point of making this parameter lesser than + /// MaxUnrewardedRelayerEntriesAtInboundLane, because then maximal number of relayer entries + /// will be limited by maximal number of messages. + /// + /// This value also represents maximal number of messages in single delivery transaction. + /// Transaction that is declaring more messages than this value, will be rejected. Even if + /// these messages are from different lanes. + type MaxUnconfirmedMessagesAtInboundLane: Get; + + /// Maximal encoded size of the outbound payload. + #[pallet::constant] + type MaximalOutboundPayloadSize: Get; + /// Payload type of outbound messages. This payload is dispatched on the bridged chain. + type OutboundPayload: Parameter + Size; + + /// Payload type of inbound messages. This payload is dispatched on this chain. + type InboundPayload: Decode; + /// Identifier of relayer that deliver messages to this chain. Relayer reward is paid on the + /// bridged chain. + type InboundRelayer: Parameter + MaxEncodedLen; + /// Delivery payments. + type DeliveryPayments: DeliveryPayments; + + // Types that are used by outbound_lane (on source chain). + + /// Target header chain. + type TargetHeaderChain: TargetHeaderChain; + /// Message payload verifier. + type LaneMessageVerifier: LaneMessageVerifier; + /// Delivery confirmation payments. + type DeliveryConfirmationPayments: DeliveryConfirmationPayments; + + // Types that are used by inbound_lane (on target chain). + + /// Source header chain, as it is represented on target chain. + type SourceHeaderChain: SourceHeaderChain; + /// Message dispatch. + type MessageDispatch: MessageDispatch< + Self::AccountId, + DispatchPayload = Self::InboundPayload, + >; + } + + /// Shortcut to messages proof type for Config. + pub type MessagesProofOf = + <>::SourceHeaderChain as SourceHeaderChain>::MessagesProof; + /// Shortcut to messages delivery proof type for Config. + pub type MessagesDeliveryProofOf = + <>::TargetHeaderChain as TargetHeaderChain< + >::OutboundPayload, + ::AccountId, + >>::MessagesDeliveryProof; + + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + impl, I: 'static> OwnedBridgeModule for Pallet { + const LOG_TARGET: &'static str = LOG_TARGET; + type OwnerStorage = PalletOwner; + type OperatingMode = MessagesOperatingMode; + type OperatingModeStorage = PalletOperatingMode; + } + + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet + where + u32: TryFrom<::BlockNumber>, + { + fn on_idle(_block: T::BlockNumber, remaining_weight: Weight) -> Weight { + // we'll need at least to read outbound lane state, kill a message and update lane state + let db_weight = T::DbWeight::get(); + if !remaining_weight.all_gte(db_weight.reads_writes(1, 2)) { + return Weight::zero() + } + + // messages from lane with index `i` in `ActiveOutboundLanes` are pruned when + // `System::block_number() % lanes.len() == i`. Otherwise we need to read lane states on + // every block, wasting the whole `remaining_weight` for nothing and causing starvation + // of the last lane pruning + let active_lanes = T::ActiveOutboundLanes::get(); + let active_lanes_len = (active_lanes.len() as u32).into(); + let active_lane_index = u32::unique_saturated_from( + frame_system::Pallet::::block_number() % active_lanes_len, + ); + let active_lane_id = active_lanes[active_lane_index as usize]; + + // first db read - outbound lane state + let mut active_lane = outbound_lane::(active_lane_id); + let mut used_weight = db_weight.reads(1); + // and here we'll have writes + used_weight += active_lane.prune_messages(db_weight, remaining_weight - used_weight); + + // we already checked we have enough `remaining_weight` to cover this `used_weight` + used_weight + } + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Change `PalletOwner`. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(0)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { + >::set_owner(origin, new_owner) + } + + /// Halt or resume all/some pallet operations. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(1)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_operating_mode( + origin: OriginFor, + operating_mode: MessagesOperatingMode, + ) -> DispatchResult { + >::set_operating_mode(origin, operating_mode) + } + + /// Receive messages proof from bridged chain. + /// + /// The weight of the call assumes that the transaction always brings outbound lane + /// state update. Because of that, the submitter (relayer) has no benefit of not including + /// this data in the transaction, so reward confirmations lags should be minimal. + /// + /// The call fails if: + /// + /// - the pallet is halted; + /// + /// - the call origin is not `Signed(_)`; + /// + /// - there are too many messages in the proof; + /// + /// - the proof verification procedure returns an error - e.g. because header used to craft + /// proof is not imported by the associated finality pallet; + /// + /// - the `dispatch_weight` argument is not sufficient to dispatch all bundled messages. + /// + /// The call may succeed, but some messages may not be delivered e.g. if they are not fit + /// into the unrewarded relayers vector. + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::receive_messages_proof_weight(proof, *messages_count, *dispatch_weight))] + pub fn receive_messages_proof( + origin: OriginFor, + relayer_id_at_bridged_chain: T::InboundRelayer, + proof: MessagesProofOf, + messages_count: u32, + dispatch_weight: Weight, + ) -> DispatchResultWithPostInfo { + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; + let relayer_id_at_this_chain = ensure_signed(origin)?; + + // reject transactions that are declaring too many messages + ensure!( + MessageNonce::from(messages_count) <= T::MaxUnconfirmedMessagesAtInboundLane::get(), + Error::::TooManyMessagesInTheProof + ); + + // why do we need to know the weight of this (`receive_messages_proof`) call? Because + // we may want to return some funds for not-dispatching (or partially dispatching) some + // messages to the call origin (relayer). And this is done by returning actual weight + // from the call. But we only know dispatch weight of every messages. So to refund + // relayer because we have not dispatched Message, we need to: + // + // ActualWeight = DeclaredWeight - Message.DispatchWeight + // + // The DeclaredWeight is exactly what's computed here. Unfortunately it is impossible + // to get pre-computed value (and it has been already computed by the executive). + let declared_weight = T::WeightInfo::receive_messages_proof_weight( + &proof, + messages_count, + dispatch_weight, + ); + let mut actual_weight = declared_weight; + + // verify messages proof && convert proof into messages + let messages = verify_and_decode_messages_proof::< + T::SourceHeaderChain, + T::InboundPayload, + >(proof, messages_count) + .map_err(|err| { + log::trace!(target: LOG_TARGET, "Rejecting invalid messages proof: {:?}", err,); + + Error::::InvalidMessagesProof + })?; + + // dispatch messages and (optionally) update lane(s) state(s) + let mut total_messages = 0; + let mut valid_messages = 0; + let mut messages_received_status = Vec::with_capacity(messages.len()); + let mut dispatch_weight_left = dispatch_weight; + for (lane_id, lane_data) in messages { + let mut lane = inbound_lane::(lane_id); + + // subtract extra storage proof bytes from the actual PoV size - there may be + // less unrewarded relayers than the maximal configured value + let lane_extra_proof_size_bytes = lane.storage().extra_proof_size_bytes(); + actual_weight = actual_weight.set_proof_size( + actual_weight.proof_size().saturating_sub(lane_extra_proof_size_bytes), + ); + + if let Some(lane_state) = lane_data.lane_state { + let updated_latest_confirmed_nonce = lane.receive_state_update(lane_state); + if let Some(updated_latest_confirmed_nonce) = updated_latest_confirmed_nonce { + log::trace!( + target: LOG_TARGET, + "Received lane {:?} state update: latest_confirmed_nonce={}", + lane_id, + updated_latest_confirmed_nonce, + ); + } + } + + let mut lane_messages_received_status = + ReceivedMessages::new(lane_id, Vec::with_capacity(lane_data.messages.len())); + for mut message in lane_data.messages { + debug_assert_eq!(message.key.lane_id, lane_id); + total_messages += 1; + + // ensure that relayer has declared enough weight for dispatching next message + // on this lane. We can't dispatch lane messages out-of-order, so if declared + // weight is not enough, let's move to next lane + let message_dispatch_weight = T::MessageDispatch::dispatch_weight(&mut message); + if message_dispatch_weight.any_gt(dispatch_weight_left) { + log::trace!( + target: LOG_TARGET, + "Cannot dispatch any more messages on lane {:?}. Weight: declared={}, left={}", + lane_id, + message_dispatch_weight, + dispatch_weight_left, + ); + + fail!(Error::::InsufficientDispatchWeight); + } + + let receival_result = lane.receive_message::( + &relayer_id_at_bridged_chain, + &relayer_id_at_this_chain, + message.key.nonce, + message.data, + ); + + // note that we're returning unspent weight to relayer even if message has been + // rejected by the lane. This allows relayers to submit spam transactions with + // e.g. the same set of already delivered messages over and over again, without + // losing funds for messages dispatch. But keep in mind that relayer pays base + // delivery transaction cost anyway. And base cost covers everything except + // dispatch, so we have a balance here. + let unspent_weight = match &receival_result { + ReceivalResult::Dispatched(dispatch_result) => { + valid_messages += 1; + dispatch_result.unspent_weight + }, + ReceivalResult::InvalidNonce | + ReceivalResult::TooManyUnrewardedRelayers | + ReceivalResult::TooManyUnconfirmedMessages => message_dispatch_weight, + }; + lane_messages_received_status.push(message.key.nonce, receival_result); + + let unspent_weight = unspent_weight.min(message_dispatch_weight); + dispatch_weight_left -= message_dispatch_weight - unspent_weight; + actual_weight = actual_weight.saturating_sub(unspent_weight); + } + + messages_received_status.push(lane_messages_received_status); + } + + // let's now deal with relayer payments + T::DeliveryPayments::pay_reward( + relayer_id_at_this_chain, + total_messages, + valid_messages, + actual_weight, + ); + + log::debug!( + target: LOG_TARGET, + "Received messages: total={}, valid={}. Weight used: {}/{}.", + total_messages, + valid_messages, + actual_weight, + declared_weight, + ); + + Self::deposit_event(Event::MessagesReceived(messages_received_status)); + + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee: Pays::Yes }) + } + + /// Receive messages delivery proof from bridged chain. + #[pallet::call_index(3)] + #[pallet::weight(T::WeightInfo::receive_messages_delivery_proof_weight( + proof, + relayers_state, + ))] + pub fn receive_messages_delivery_proof( + origin: OriginFor, + proof: MessagesDeliveryProofOf, + mut relayers_state: UnrewardedRelayersState, + ) -> DispatchResultWithPostInfo { + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; + + let proof_size = proof.size(); + let confirmation_relayer = ensure_signed(origin)?; + let (lane_id, lane_data) = T::TargetHeaderChain::verify_messages_delivery_proof(proof) + .map_err(|err| { + log::trace!( + target: LOG_TARGET, + "Rejecting invalid messages delivery proof: {:?}", + err, + ); + + Error::::InvalidMessagesDeliveryProof + })?; + + // verify that the relayer has declared correct `lane_data::relayers` state + // (we only care about total number of entries and messages, because this affects call + // weight) + ensure!( + total_unrewarded_messages(&lane_data.relayers).unwrap_or(MessageNonce::MAX) == + relayers_state.total_messages && + lane_data.relayers.len() as MessageNonce == + relayers_state.unrewarded_relayer_entries, + Error::::InvalidUnrewardedRelayersState + ); + // the `last_delivered_nonce` field may also be used by the signed extension. Even + // though providing wrong value isn't critical, let's also check it here. + ensure!( + lane_data.last_delivered_nonce() == relayers_state.last_delivered_nonce, + Error::::InvalidUnrewardedRelayersState + ); + + // mark messages as delivered + let mut lane = outbound_lane::(lane_id); + let last_delivered_nonce = lane_data.last_delivered_nonce(); + let confirmed_messages = match lane.confirm_delivery( + relayers_state.total_messages, + last_delivered_nonce, + &lane_data.relayers, + ) { + ReceivalConfirmationResult::ConfirmedMessages(confirmed_messages) => + Some(confirmed_messages), + ReceivalConfirmationResult::NoNewConfirmations => None, + ReceivalConfirmationResult::TryingToConfirmMoreMessagesThanExpected( + to_confirm_messages_count, + ) => { + log::trace!( + target: LOG_TARGET, + "Messages delivery proof contains too many messages to confirm: {} vs declared {}", + to_confirm_messages_count, + relayers_state.total_messages, + ); + + fail!(Error::::TryingToConfirmMoreMessagesThanExpected); + }, + error => { + log::trace!( + target: LOG_TARGET, + "Messages delivery proof contains invalid unrewarded relayers vec: {:?}", + error, + ); + + fail!(Error::::InvalidUnrewardedRelayers); + }, + }; + + if let Some(confirmed_messages) = confirmed_messages { + // emit 'delivered' event + let received_range = confirmed_messages.begin..=confirmed_messages.end; + Self::deposit_event(Event::MessagesDelivered { + lane_id, + messages: confirmed_messages, + }); + + // if some new messages have been confirmed, reward relayers + let actually_rewarded_relayers = T::DeliveryConfirmationPayments::pay_reward( + lane_id, + lane_data.relayers, + &confirmation_relayer, + &received_range, + ); + + // update relayers state with actual numbers to compute actual weight below + relayers_state.unrewarded_relayer_entries = sp_std::cmp::min( + relayers_state.unrewarded_relayer_entries, + actually_rewarded_relayers, + ); + relayers_state.total_messages = sp_std::cmp::min( + relayers_state.total_messages, + received_range.checked_len().unwrap_or(MessageNonce::MAX), + ); + }; + + log::trace!( + target: LOG_TARGET, + "Received messages delivery proof up to (and including) {} at lane {:?}", + last_delivered_nonce, + lane_id, + ); + + // because of lags, the inbound lane state (`lane_data`) may have entries for + // already rewarded relayers and messages (if all entries are duplicated, then + // this transaction must be filtered out by our signed extension) + let actual_weight = T::WeightInfo::receive_messages_delivery_proof_weight( + &PreComputedSize(proof_size as usize), + &relayers_state, + ); + + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee: Pays::Yes }) + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// Message has been accepted and is waiting to be delivered. + MessageAccepted { lane_id: LaneId, nonce: MessageNonce }, + /// Messages have been received from the bridged chain. + MessagesReceived( + Vec< + ReceivedMessages< + >::DispatchLevelResult, + >, + >, + ), + /// Messages in the inclusive range have been delivered to the bridged chain. + MessagesDelivered { lane_id: LaneId, messages: DeliveredMessages }, + } + + #[pallet::error] + pub enum Error { + /// Pallet is not in Normal operating mode. + NotOperatingNormally, + /// The outbound lane is inactive. + InactiveOutboundLane, + /// The message is too large to be sent over the bridge. + MessageIsTooLarge, + /// Message has been treated as invalid by chain verifier. + MessageRejectedByChainVerifier, + /// Message has been treated as invalid by lane verifier. + MessageRejectedByLaneVerifier, + /// Submitter has failed to pay fee for delivering and dispatching messages. + FailedToWithdrawMessageFee, + /// The transaction brings too many messages. + TooManyMessagesInTheProof, + /// Invalid messages has been submitted. + InvalidMessagesProof, + /// Invalid messages delivery proof has been submitted. + InvalidMessagesDeliveryProof, + /// The bridged chain has invalid `UnrewardedRelayers` in its storage (fatal for the lane). + InvalidUnrewardedRelayers, + /// The relayer has declared invalid unrewarded relayers state in the + /// `receive_messages_delivery_proof` call. + InvalidUnrewardedRelayersState, + /// The cumulative dispatch weight, passed by relayer is not enough to cover dispatch + /// of all bundled messages. + InsufficientDispatchWeight, + /// The message someone is trying to work with (i.e. increase fee) is not yet sent. + MessageIsNotYetSent, + /// The number of actually confirmed messages is going to be larger than the number of + /// messages in the proof. This may mean that this or bridged chain storage is corrupted. + TryingToConfirmMoreMessagesThanExpected, + /// Error generated by the `OwnedBridgeModule` trait. + BridgeModule(bp_runtime::OwnedBridgeModuleError), + } + + /// Optional pallet owner. + /// + /// Pallet owner has a right to halt all pallet operations and then resume it. If it is + /// `None`, then there are no direct ways to halt/resume pallet operations, but other + /// runtime methods may still be used to do that (i.e. democracy::referendum to update halt + /// flag directly or call the `halt_operations`). + #[pallet::storage] + #[pallet::getter(fn module_owner)] + pub type PalletOwner, I: 'static = ()> = StorageValue<_, T::AccountId>; + + /// The current operating mode of the pallet. + /// + /// Depending on the mode either all, some, or no transactions will be allowed. + #[pallet::storage] + #[pallet::getter(fn operating_mode)] + pub type PalletOperatingMode, I: 'static = ()> = + StorageValue<_, MessagesOperatingMode, ValueQuery>; + + /// Map of lane id => inbound lane data. + #[pallet::storage] + pub type InboundLanes, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, LaneId, StoredInboundLaneData, ValueQuery>; + + /// Map of lane id => outbound lane data. + #[pallet::storage] + pub type OutboundLanes, I: 'static = ()> = StorageMap< + Hasher = Blake2_128Concat, + Key = LaneId, + Value = OutboundLaneData, + QueryKind = ValueQuery, + OnEmpty = GetDefault, + MaxValues = MaybeOutboundLanesCount, + >; + + /// All queued outbound messages. + #[pallet::storage] + pub type OutboundMessages, I: 'static = ()> = + StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload>; + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + /// Initial pallet operating mode. + pub operating_mode: MessagesOperatingMode, + /// Initial pallet owner. + pub owner: Option, + /// Dummy marker. + pub phantom: sp_std::marker::PhantomData, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { + operating_mode: Default::default(), + owner: Default::default(), + phantom: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + PalletOperatingMode::::put(self.operating_mode); + if let Some(ref owner) = self.owner { + PalletOwner::::put(owner); + } + } + } + + impl, I: 'static> Pallet { + /// Get stored data of the outbound message with given nonce. + pub fn outbound_message_data(lane: LaneId, nonce: MessageNonce) -> Option { + OutboundMessages::::get(MessageKey { lane_id: lane, nonce }).map(Into::into) + } + + /// Prepare data, related to given inbound message. + pub fn inbound_message_data( + lane: LaneId, + payload: MessagePayload, + outbound_details: OutboundMessageDetails, + ) -> InboundMessageDetails { + let mut dispatch_message = DispatchMessage { + key: MessageKey { lane_id: lane, nonce: outbound_details.nonce }, + data: payload.into(), + }; + InboundMessageDetails { + dispatch_weight: T::MessageDispatch::dispatch_weight(&mut dispatch_message), + } + } + + /// Return inbound lane data. + pub fn inbound_lane_data(lane: LaneId) -> InboundLaneData { + InboundLanes::::get(lane).0 + } + } + + /// Get-parameter that returns number of active outbound lanes that the pallet maintains. + pub struct MaybeOutboundLanesCount(PhantomData<(T, I)>); + + impl, I: 'static> Get> for MaybeOutboundLanesCount { + fn get() -> Option { + Some(T::ActiveOutboundLanes::get().len() as u32) + } + } +} + +impl bp_messages::source_chain::MessagesBridge + for Pallet +where + T: Config, + I: 'static, +{ + type Error = sp_runtime::DispatchErrorWithPostInfo; + + fn send_message( + sender: T::RuntimeOrigin, + lane: LaneId, + message: T::OutboundPayload, + ) -> Result { + crate::send_message::(sender, lane, message) + } +} + +/// Function that actually sends message. +fn send_message, I: 'static>( + submitter: T::RuntimeOrigin, + lane_id: LaneId, + payload: T::OutboundPayload, +) -> sp_std::result::Result< + SendMessageArtifacts, + sp_runtime::DispatchErrorWithPostInfo, +> { + ensure_normal_operating_mode::()?; + + // let's check if outbound lane is active + ensure!(T::ActiveOutboundLanes::get().contains(&lane_id), Error::::InactiveOutboundLane,); + + // let's first check if message can be delivered to target chain + T::TargetHeaderChain::verify_message(&payload).map_err(|err| { + log::trace!( + target: LOG_TARGET, + "Message to lane {:?} is rejected by target chain: {:?}", + lane_id, + err, + ); + + Error::::MessageRejectedByChainVerifier + })?; + + // now let's enforce any additional lane rules + let mut lane = outbound_lane::(lane_id); + T::LaneMessageVerifier::verify_message(&submitter, &lane_id, &lane.data(), &payload).map_err( + |err| { + log::trace!( + target: LOG_TARGET, + "Message to lane {:?} is rejected by lane verifier: {:?}", + lane_id, + err, + ); + + Error::::MessageRejectedByLaneVerifier + }, + )?; + + // finally, save message in outbound storage and emit event + let encoded_payload = payload.encode(); + let encoded_payload_len = encoded_payload.len(); + ensure!( + encoded_payload_len <= T::MaximalOutboundPayloadSize::get() as usize, + Error::::MessageIsTooLarge + ); + let nonce = lane.send_message(encoded_payload); + + log::trace!( + target: LOG_TARGET, + "Accepted message {} to lane {:?}. Message size: {:?}", + nonce, + lane_id, + encoded_payload_len, + ); + + Pallet::::deposit_event(Event::MessageAccepted { lane_id, nonce }); + + Ok(SendMessageArtifacts { nonce }) +} + +/// Ensure that the pallet is in normal operational mode. +fn ensure_normal_operating_mode, I: 'static>() -> Result<(), Error> { + if PalletOperatingMode::::get() == + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + { + return Ok(()) + } + + Err(Error::::NotOperatingNormally) +} + +/// Creates new inbound lane object, backed by runtime storage. +fn inbound_lane, I: 'static>( + lane_id: LaneId, +) -> InboundLane> { + InboundLane::new(inbound_lane_storage::(lane_id)) +} + +/// Creates new runtime inbound lane storage. +fn inbound_lane_storage, I: 'static>( + lane_id: LaneId, +) -> RuntimeInboundLaneStorage { + RuntimeInboundLaneStorage { + lane_id, + cached_data: RefCell::new(None), + _phantom: Default::default(), + } +} + +/// Creates new outbound lane object, backed by runtime storage. +fn outbound_lane, I: 'static>( + lane_id: LaneId, +) -> OutboundLane> { + OutboundLane::new(RuntimeOutboundLaneStorage { lane_id, _phantom: Default::default() }) +} + +/// Runtime inbound lane storage. +struct RuntimeInboundLaneStorage, I: 'static = ()> { + lane_id: LaneId, + cached_data: RefCell>>, + _phantom: PhantomData, +} + +impl, I: 'static> RuntimeInboundLaneStorage { + /// Returns number of bytes that may be subtracted from the PoV component of + /// `receive_messages_proof` call, because the actual inbound lane state is smaller than the + /// maximal configured. + /// + /// Maximal inbound lane state set size is configured by the + /// `MaxUnrewardedRelayerEntriesAtInboundLane` constant from the pallet configuration. The PoV + /// of the call includes the maximal size of inbound lane state. If the actual size is smaller, + /// we may subtract extra bytes from this component. + pub fn extra_proof_size_bytes(&self) -> u64 { + let max_encoded_len = StoredInboundLaneData::::max_encoded_len(); + let relayers_count = self.data().relayers.len(); + let actual_encoded_len = + InboundLaneData::::encoded_size_hint(relayers_count) + .unwrap_or(usize::MAX); + max_encoded_len.saturating_sub(actual_encoded_len) as _ + } +} + +impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage { + type Relayer = T::InboundRelayer; + + fn id(&self) -> LaneId { + self.lane_id + } + + fn max_unrewarded_relayer_entries(&self) -> MessageNonce { + T::MaxUnrewardedRelayerEntriesAtInboundLane::get() + } + + fn max_unconfirmed_messages(&self) -> MessageNonce { + T::MaxUnconfirmedMessagesAtInboundLane::get() + } + + fn data(&self) -> InboundLaneData { + match self.cached_data.clone().into_inner() { + Some(data) => data, + None => { + let data: InboundLaneData = + InboundLanes::::get(self.lane_id).into(); + *self.cached_data.try_borrow_mut().expect( + "we're in the single-threaded environment;\ + we have no recursive borrows; qed", + ) = Some(data.clone()); + data + }, + } + } + + fn set_data(&mut self, data: InboundLaneData) { + *self.cached_data.try_borrow_mut().expect( + "we're in the single-threaded environment;\ + we have no recursive borrows; qed", + ) = Some(data.clone()); + InboundLanes::::insert(self.lane_id, StoredInboundLaneData::(data)) + } +} + +/// Runtime outbound lane storage. +struct RuntimeOutboundLaneStorage { + lane_id: LaneId, + _phantom: PhantomData<(T, I)>, +} + +impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage { + fn id(&self) -> LaneId { + self.lane_id + } + + fn data(&self) -> OutboundLaneData { + OutboundLanes::::get(self.lane_id) + } + + fn set_data(&mut self, data: OutboundLaneData) { + OutboundLanes::::insert(self.lane_id, data) + } + + #[cfg(test)] + fn message(&self, nonce: &MessageNonce) -> Option { + OutboundMessages::::get(MessageKey { lane_id: self.lane_id, nonce: *nonce }) + .map(Into::into) + } + + fn save_message(&mut self, nonce: MessageNonce, message_payload: MessagePayload) { + OutboundMessages::::insert( + MessageKey { lane_id: self.lane_id, nonce }, + StoredMessagePayload::::try_from(message_payload).expect( + "save_message is called after all checks in send_message; \ + send_message checks message size; \ + qed", + ), + ); + } + + fn remove_message(&mut self, nonce: &MessageNonce) { + OutboundMessages::::remove(MessageKey { lane_id: self.lane_id, nonce: *nonce }); + } +} + +/// Verify messages proof and return proved messages with decoded payload. +fn verify_and_decode_messages_proof( + proof: Chain::MessagesProof, + messages_count: u32, +) -> Result>, Chain::Error> { + // `receive_messages_proof` weight formula and `MaxUnconfirmedMessagesAtInboundLane` check + // guarantees that the `message_count` is sane and Vec may be allocated. + // (tx with too many messages will either be rejected from the pool, or will fail earlier) + Chain::verify_messages_proof(proof, messages_count).map(|messages_by_lane| { + messages_by_lane + .into_iter() + .map(|(lane, lane_data)| { + ( + lane, + ProvedLaneMessages { + lane_state: lane_data.lane_state, + messages: lane_data.messages.into_iter().map(Into::into).collect(), + }, + ) + }) + .collect() + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::mock::{ + message, message_payload, run_test, unrewarded_relayer, AccountId, DbWeight, + RuntimeEvent as TestEvent, RuntimeOrigin, TestDeliveryConfirmationPayments, + TestDeliveryPayments, TestMessagesDeliveryProof, TestMessagesProof, TestRelayer, + TestRuntime, TestWeightInfo, MAX_OUTBOUND_PAYLOAD_SIZE, PAYLOAD_REJECTED_BY_TARGET_CHAIN, + REGULAR_PAYLOAD, TEST_LANE_ID, TEST_LANE_ID_2, TEST_LANE_ID_3, TEST_RELAYER_A, + TEST_RELAYER_B, + }; + use bp_messages::{BridgeMessagesCall, UnrewardedRelayer, UnrewardedRelayersState}; + use bp_test_utils::generate_owned_bridge_module_tests; + use frame_support::{ + assert_noop, assert_ok, + dispatch::Pays, + storage::generator::{StorageMap, StorageValue}, + traits::Hooks, + weights::Weight, + }; + use frame_system::{EventRecord, Pallet as System, Phase}; + use sp_runtime::DispatchError; + + fn get_ready_for_events() { + System::::set_block_number(1); + System::::reset_events(); + } + + fn inbound_unrewarded_relayers_state( + lane: bp_messages::LaneId, + ) -> bp_messages::UnrewardedRelayersState { + let inbound_lane_data = InboundLanes::::get(lane).0; + let last_delivered_nonce = inbound_lane_data.last_delivered_nonce(); + let relayers = inbound_lane_data.relayers; + bp_messages::UnrewardedRelayersState { + unrewarded_relayer_entries: relayers.len() as _, + messages_in_oldest_entry: relayers + .front() + .map(|entry| 1 + entry.messages.end - entry.messages.begin) + .unwrap_or(0), + total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX), + last_delivered_nonce, + } + } + + fn send_regular_message() { + get_ready_for_events(); + + let message_nonce = + outbound_lane::(TEST_LANE_ID).data().latest_generated_nonce + 1; + send_message::(RuntimeOrigin::signed(1), TEST_LANE_ID, REGULAR_PAYLOAD) + .expect("send_message has failed"); + + // check event with assigned nonce + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Messages(Event::MessageAccepted { + lane_id: TEST_LANE_ID, + nonce: message_nonce + }), + topics: vec![], + }], + ); + } + + fn receive_messages_delivery_proof() { + System::::set_block_number(1); + System::::reset_events(); + + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![UnrewardedRelayer { + relayer: 0, + messages: DeliveredMessages::new(1), + }] + .into_iter() + .collect(), + }, + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + last_delivered_nonce: 1, + ..Default::default() + }, + )); + + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Messages(Event::MessagesDelivered { + lane_id: TEST_LANE_ID, + messages: DeliveredMessages::new(1), + }), + topics: vec![], + }], + ); + } + + #[test] + fn pallet_rejects_transactions_if_halted() { + run_test(|| { + // send message first to be able to check that delivery_proof fails later + send_regular_message(); + + PalletOperatingMode::::put(MessagesOperatingMode::Basic( + BasicOperatingMode::Halted, + )); + + assert_noop!( + send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID, + REGULAR_PAYLOAD, + ), + Error::::NotOperatingNormally, + ); + + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Ok(vec![message(2, REGULAR_PAYLOAD)]).into(), + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), + ); + + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)] + .into_iter() + .collect(), + }, + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + ), + Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), + ); + }); + } + + #[test] + fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { + run_test(|| { + // send message first to be able to check that delivery_proof fails later + send_regular_message(); + + PalletOperatingMode::::put( + MessagesOperatingMode::RejectingOutboundMessages, + ); + + assert_noop!( + send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID, + REGULAR_PAYLOAD, + ), + Error::::NotOperatingNormally, + ); + + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), + 1, + REGULAR_PAYLOAD.declared_weight, + ),); + + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)] + .into_iter() + .collect(), + }, + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + )); + }); + } + + #[test] + fn send_message_works() { + run_test(|| { + send_regular_message(); + }); + } + + #[test] + fn send_message_rejects_too_large_message() { + run_test(|| { + let mut message_payload = message_payload(1, 0); + // the payload isn't simply extra, so it'll definitely overflow + // `MAX_OUTBOUND_PAYLOAD_SIZE` if we add `MAX_OUTBOUND_PAYLOAD_SIZE` bytes to extra + message_payload + .extra + .extend_from_slice(&[0u8; MAX_OUTBOUND_PAYLOAD_SIZE as usize]); + assert_noop!( + send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID, + message_payload.clone(), + ), + Error::::MessageIsTooLarge, + ); + + // let's check that we're able to send `MAX_OUTBOUND_PAYLOAD_SIZE` messages + while message_payload.encoded_size() as u32 > MAX_OUTBOUND_PAYLOAD_SIZE { + message_payload.extra.pop(); + } + assert_eq!(message_payload.encoded_size() as u32, MAX_OUTBOUND_PAYLOAD_SIZE); + assert_ok!(send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID, + message_payload, + ),); + }) + } + + #[test] + fn chain_verifier_rejects_invalid_message_in_send_message() { + run_test(|| { + // messages with this payload are rejected by target chain verifier + assert_noop!( + send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID, + PAYLOAD_REJECTED_BY_TARGET_CHAIN, + ), + Error::::MessageRejectedByChainVerifier, + ); + }); + } + + #[test] + fn lane_verifier_rejects_invalid_message_in_send_message() { + run_test(|| { + // messages with zero fee are rejected by lane verifier + let mut message = REGULAR_PAYLOAD; + message.reject_by_lane_verifier = true; + assert_noop!( + send_message::(RuntimeOrigin::signed(1), TEST_LANE_ID, message,), + Error::::MessageRejectedByLaneVerifier, + ); + }); + } + + #[test] + fn receive_messages_proof_works() { + run_test(|| { + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), + 1, + REGULAR_PAYLOAD.declared_weight, + )); + + assert_eq!(InboundLanes::::get(TEST_LANE_ID).0.last_delivered_nonce(), 1); + + assert!(TestDeliveryPayments::is_reward_paid(1)); + }); + } + + #[test] + fn receive_messages_proof_updates_confirmed_message_nonce() { + run_test(|| { + // say we have received 10 messages && last confirmed message is 8 + InboundLanes::::insert( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 8, + relayers: vec![ + unrewarded_relayer(9, 9, TEST_RELAYER_A), + unrewarded_relayer(10, 10, TEST_RELAYER_B), + ] + .into_iter() + .collect(), + }, + ); + assert_eq!( + inbound_unrewarded_relayers_state(TEST_LANE_ID), + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + messages_in_oldest_entry: 1, + total_messages: 2, + last_delivered_nonce: 10, + }, + ); + + // message proof includes outbound lane state with latest confirmed message updated to 9 + let mut message_proof: TestMessagesProof = + Ok(vec![message(11, REGULAR_PAYLOAD)]).into(); + message_proof.result.as_mut().unwrap()[0].1.lane_state = + Some(OutboundLaneData { latest_received_nonce: 9, ..Default::default() }); + + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + message_proof, + 1, + REGULAR_PAYLOAD.declared_weight, + )); + + assert_eq!( + InboundLanes::::get(TEST_LANE_ID).0, + InboundLaneData { + last_confirmed_nonce: 9, + relayers: vec![ + unrewarded_relayer(10, 10, TEST_RELAYER_B), + unrewarded_relayer(11, 11, TEST_RELAYER_A) + ] + .into_iter() + .collect(), + }, + ); + assert_eq!( + inbound_unrewarded_relayers_state(TEST_LANE_ID), + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + messages_in_oldest_entry: 1, + total_messages: 2, + last_delivered_nonce: 11, + }, + ); + }); + } + + #[test] + fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enough() { + run_test(|| { + let mut declared_weight = REGULAR_PAYLOAD.declared_weight; + *declared_weight.ref_time_mut() -= 1; + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), + 1, + declared_weight, + ), + Error::::InsufficientDispatchWeight + ); + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); + }); + } + + #[test] + fn receive_messages_proof_rejects_invalid_proof() { + run_test(|| { + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Err(()).into(), + 1, + Weight::zero(), + ), + Error::::InvalidMessagesProof, + ); + }); + } + + #[test] + fn receive_messages_proof_rejects_proof_with_too_many_messages() { + run_test(|| { + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Ok(vec![message(1, REGULAR_PAYLOAD)]).into(), + u32::MAX, + Weight::zero(), + ), + Error::::TooManyMessagesInTheProof, + ); + }); + } + + #[test] + fn receive_messages_delivery_proof_works() { + run_test(|| { + send_regular_message(); + receive_messages_delivery_proof(); + + assert_eq!( + OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, + 1, + ); + }); + } + + #[test] + fn receive_messages_delivery_proof_rewards_relayers() { + run_test(|| { + assert_ok!(send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID, + REGULAR_PAYLOAD, + )); + assert_ok!(send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID, + REGULAR_PAYLOAD, + )); + + // this reports delivery of message 1 => reward is paid to TEST_RELAYER_A + let single_message_delivery_proof = TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into_iter().collect(), + ..Default::default() + }, + ))); + let single_message_delivery_proof_size = single_message_delivery_proof.size(); + let result = Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + single_message_delivery_proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + last_delivered_nonce: 1, + ..Default::default() + }, + ); + assert_ok!(result); + assert_eq!( + result.unwrap().actual_weight.unwrap(), + TestWeightInfo::receive_messages_delivery_proof_weight( + &PreComputedSize(single_message_delivery_proof_size as _), + &UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }, + ) + ); + assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); + assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); + + // this reports delivery of both message 1 and message 2 => reward is paid only to + // TEST_RELAYER_B + let two_messages_delivery_proof = TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B), + ] + .into_iter() + .collect(), + ..Default::default() + }, + ))); + let two_messages_delivery_proof_size = two_messages_delivery_proof.size(); + let result = Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + two_messages_delivery_proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + total_messages: 2, + last_delivered_nonce: 2, + ..Default::default() + }, + ); + assert_ok!(result); + // even though the pre-dispatch weight was for two messages, the actual weight is + // for single message only + assert_eq!( + result.unwrap().actual_weight.unwrap(), + TestWeightInfo::receive_messages_delivery_proof_weight( + &PreComputedSize(two_messages_delivery_proof_size as _), + &UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + ..Default::default() + }, + ) + ); + assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); + assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); + }); + } + + #[test] + fn receive_messages_delivery_proof_rejects_invalid_proof() { + run_test(|| { + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Err(())), + Default::default(), + ), + Error::::InvalidMessagesDeliveryProof, + ); + }); + } + + #[test] + fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_invalid() { + run_test(|| { + // when number of relayers entries is invalid + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B) + ] + .into_iter() + .collect(), + ..Default::default() + } + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 2, + last_delivered_nonce: 2, + ..Default::default() + }, + ), + Error::::InvalidUnrewardedRelayersState, + ); + + // when number of messages is invalid + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B) + ] + .into_iter() + .collect(), + ..Default::default() + } + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + total_messages: 1, + last_delivered_nonce: 2, + ..Default::default() + }, + ), + Error::::InvalidUnrewardedRelayersState, + ); + + // when last delivered nonce is invalid + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + relayers: vec![ + unrewarded_relayer(1, 1, TEST_RELAYER_A), + unrewarded_relayer(2, 2, TEST_RELAYER_B) + ] + .into_iter() + .collect(), + ..Default::default() + } + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 2, + total_messages: 2, + last_delivered_nonce: 8, + ..Default::default() + }, + ), + Error::::InvalidUnrewardedRelayersState, + ); + }); + } + + #[test] + fn receive_messages_accepts_single_message_with_invalid_payload() { + run_test(|| { + let mut invalid_message = message(1, REGULAR_PAYLOAD); + invalid_message.payload = Vec::new(); + + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Ok(vec![invalid_message]).into(), + 1, + Weight::zero(), /* weight may be zero in this case (all messages are + * improperly encoded) */ + ),); + + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 1,); + }); + } + + #[test] + fn receive_messages_accepts_batch_with_message_with_invalid_payload() { + run_test(|| { + let mut invalid_message = message(2, REGULAR_PAYLOAD); + invalid_message.payload = Vec::new(); + + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + Ok( + vec![message(1, REGULAR_PAYLOAD), invalid_message, message(3, REGULAR_PAYLOAD),] + ) + .into(), + 3, + REGULAR_PAYLOAD.declared_weight + REGULAR_PAYLOAD.declared_weight, + ),); + + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 3,); + }); + } + + #[test] + fn actual_dispatch_weight_does_not_overlow() { + run_test(|| { + let message1 = message(1, message_payload(0, u64::MAX / 2)); + let message2 = message(2, message_payload(0, u64::MAX / 2)); + let message3 = message(3, message_payload(0, u64::MAX / 2)); + + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + // this may cause overflow if source chain storage is invalid + Ok(vec![message1, message2, message3]).into(), + 3, + Weight::MAX, + ), + Error::::InsufficientDispatchWeight + ); + assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); + }); + } + + #[test] + fn ref_time_refund_from_receive_messages_proof_works() { + run_test(|| { + fn submit_with_unspent_weight( + nonce: MessageNonce, + unspent_weight: u64, + ) -> (Weight, Weight) { + let mut payload = REGULAR_PAYLOAD; + *payload.dispatch_result.unspent_weight.ref_time_mut() = unspent_weight; + let proof = Ok(vec![message(nonce, payload)]).into(); + let messages_count = 1; + let pre_dispatch_weight = + ::WeightInfo::receive_messages_proof_weight( + &proof, + messages_count, + REGULAR_PAYLOAD.declared_weight, + ); + let result = Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + messages_count, + REGULAR_PAYLOAD.declared_weight, + ) + .expect("delivery has failed"); + let post_dispatch_weight = + result.actual_weight.expect("receive_messages_proof always returns Some"); + + // message delivery transactions are never free + assert_eq!(result.pays_fee, Pays::Yes); + + (pre_dispatch_weight, post_dispatch_weight) + } + + // when dispatch is returning `unspent_weight < declared_weight` + let (pre, post) = submit_with_unspent_weight(1, 1); + assert_eq!(post.ref_time(), pre.ref_time() - 1); + + // when dispatch is returning `unspent_weight = declared_weight` + let (pre, post) = + submit_with_unspent_weight(2, REGULAR_PAYLOAD.declared_weight.ref_time()); + assert_eq!( + post.ref_time(), + pre.ref_time() - REGULAR_PAYLOAD.declared_weight.ref_time() + ); + + // when dispatch is returning `unspent_weight > declared_weight` + let (pre, post) = + submit_with_unspent_weight(3, REGULAR_PAYLOAD.declared_weight.ref_time() + 1); + assert_eq!( + post.ref_time(), + pre.ref_time() - REGULAR_PAYLOAD.declared_weight.ref_time() + ); + + // when there's no unspent weight + let (pre, post) = submit_with_unspent_weight(4, 0); + assert_eq!(post.ref_time(), pre.ref_time()); + + // when dispatch is returning `unspent_weight < declared_weight` + let (pre, post) = submit_with_unspent_weight(5, 1); + assert_eq!(post.ref_time(), pre.ref_time() - 1); + }); + } + + #[test] + fn proof_size_refund_from_receive_messages_proof_works() { + run_test(|| { + let max_entries = crate::mock::MaxUnrewardedRelayerEntriesAtInboundLane::get() as usize; + + // if there's maximal number of unrewarded relayer entries at the inbound lane, then + // `proof_size` is unchanged in post-dispatch weight + let proof: TestMessagesProof = Ok(vec![message(101, REGULAR_PAYLOAD)]).into(); + let messages_count = 1; + let pre_dispatch_weight = + ::WeightInfo::receive_messages_proof_weight( + &proof, + messages_count, + REGULAR_PAYLOAD.declared_weight, + ); + InboundLanes::::insert( + TEST_LANE_ID, + StoredInboundLaneData(InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: 42, + messages: DeliveredMessages { begin: 0, end: 100 } + }; + max_entries + ] + .into_iter() + .collect(), + last_confirmed_nonce: 0, + }), + ); + let post_dispatch_weight = Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof.clone(), + messages_count, + REGULAR_PAYLOAD.declared_weight, + ) + .unwrap() + .actual_weight + .unwrap(); + assert_eq!(post_dispatch_weight.proof_size(), pre_dispatch_weight.proof_size()); + + // if count of unrewarded relayer entries is less than maximal, then some `proof_size` + // must be refunded + InboundLanes::::insert( + TEST_LANE_ID, + StoredInboundLaneData(InboundLaneData { + relayers: vec![ + UnrewardedRelayer { + relayer: 42, + messages: DeliveredMessages { begin: 0, end: 100 } + }; + max_entries - 1 + ] + .into_iter() + .collect(), + last_confirmed_nonce: 0, + }), + ); + let post_dispatch_weight = Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + messages_count, + REGULAR_PAYLOAD.declared_weight, + ) + .unwrap() + .actual_weight + .unwrap(); + assert!( + post_dispatch_weight.proof_size() < pre_dispatch_weight.proof_size(), + "Expected post-dispatch PoV {} to be less than pre-dispatch PoV {}", + post_dispatch_weight.proof_size(), + pre_dispatch_weight.proof_size(), + ); + }); + } + + #[test] + fn messages_delivered_callbacks_are_called() { + run_test(|| { + send_regular_message(); + send_regular_message(); + send_regular_message(); + + // messages 1+2 are confirmed in 1 tx, message 3 in a separate tx + // dispatch of message 2 has failed + let mut delivered_messages_1_and_2 = DeliveredMessages::new(1); + delivered_messages_1_and_2.note_dispatched_message(); + let messages_1_and_2_proof = Ok(( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 0, + relayers: vec![UnrewardedRelayer { + relayer: 0, + messages: delivered_messages_1_and_2.clone(), + }] + .into_iter() + .collect(), + }, + )); + let delivered_message_3 = DeliveredMessages::new(3); + let messages_3_proof = Ok(( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 0, + relayers: vec![UnrewardedRelayer { relayer: 0, messages: delivered_message_3 }] + .into_iter() + .collect(), + }, + )); + + // first tx with messages 1+2 + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(messages_1_and_2_proof), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 2, + last_delivered_nonce: 2, + ..Default::default() + }, + )); + // second tx with message 3 + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(messages_3_proof), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + last_delivered_nonce: 3, + ..Default::default() + }, + )); + }); + } + + #[test] + fn receive_messages_delivery_proof_rejects_proof_if_trying_to_confirm_more_messages_than_expected( + ) { + run_test(|| { + // send message first to be able to check that delivery_proof fails later + send_regular_message(); + + // 1) InboundLaneData declares that the `last_confirmed_nonce` is 1; + // 2) InboundLaneData has no entries => `InboundLaneData::last_delivered_nonce()` + // returns `last_confirmed_nonce`; + // 3) it means that we're going to confirm delivery of messages 1..=1; + // 4) so the number of declared messages (see `UnrewardedRelayersState`) is `0` and + // numer of actually confirmed messages is `1`. + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { last_confirmed_nonce: 1, relayers: Default::default() }, + ))), + UnrewardedRelayersState { last_delivered_nonce: 1, ..Default::default() }, + ), + Error::::TryingToConfirmMoreMessagesThanExpected, + ); + }); + } + + #[test] + fn storage_keys_computed_properly() { + assert_eq!( + PalletOperatingMode::::storage_value_final_key().to_vec(), + bp_messages::storage_keys::operating_mode_key("Messages").0, + ); + + assert_eq!( + OutboundMessages::::storage_map_final_key(MessageKey { + lane_id: TEST_LANE_ID, + nonce: 42 + }), + bp_messages::storage_keys::message_key("Messages", &TEST_LANE_ID, 42).0, + ); + + assert_eq!( + OutboundLanes::::storage_map_final_key(TEST_LANE_ID), + bp_messages::storage_keys::outbound_lane_data_key("Messages", &TEST_LANE_ID).0, + ); + + assert_eq!( + InboundLanes::::storage_map_final_key(TEST_LANE_ID), + bp_messages::storage_keys::inbound_lane_data_key("Messages", &TEST_LANE_ID).0, + ); + } + + #[test] + fn inbound_message_details_works() { + run_test(|| { + assert_eq!( + Pallet::::inbound_message_data( + TEST_LANE_ID, + REGULAR_PAYLOAD.encode(), + OutboundMessageDetails { nonce: 0, dispatch_weight: Weight::zero(), size: 0 }, + ), + InboundMessageDetails { dispatch_weight: REGULAR_PAYLOAD.declared_weight }, + ); + }); + } + + #[test] + fn on_idle_callback_respects_remaining_weight() { + run_test(|| { + send_regular_message(); + send_regular_message(); + send_regular_message(); + send_regular_message(); + + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 4, + relayers: vec![unrewarded_relayer(1, 4, TEST_RELAYER_A)] + .into_iter() + .collect(), + }, + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 4, + total_messages: 4, + last_delivered_nonce: 4, + }, + )); + + // all 4 messages may be pruned now + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, + 4 + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, + 1 + ); + System::::set_block_number(2); + + // if passed wight is too low to do anything + let dbw = DbWeight::get(); + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(1, 1)), + Weight::zero(), + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, + 1 + ); + + // if passed wight is enough to prune single message + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(1, 2)), + dbw.reads_writes(1, 2), + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, + 2 + ); + + // if passed wight is enough to prune two more messages + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(1, 3)), + dbw.reads_writes(1, 3), + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, + 4 + ); + + // if passed wight is enough to prune many messages + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(100, 100)), + dbw.reads_writes(1, 2), + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, + 5 + ); + }); + } + + #[test] + fn on_idle_callback_is_rotating_lanes_to_prune() { + run_test(|| { + // send + receive confirmation for lane 1 + send_regular_message(); + receive_messages_delivery_proof(); + // send + receive confirmation for lane 2 + assert_ok!(send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID_2, + REGULAR_PAYLOAD, + )); + assert_ok!(Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID_2, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)] + .into_iter() + .collect(), + }, + ))), + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + )); + + // nothing is pruned yet + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, + 1 + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, + 1 + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID_2).data().latest_received_nonce, + 1 + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, + 1 + ); + + // in block#2.on_idle lane messages of lane 1 are pruned + let dbw = DbWeight::get(); + System::::set_block_number(2); + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(100, 100)), + dbw.reads_writes(1, 2), + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, + 2 + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, + 1 + ); + + // in block#3.on_idle lane messages of lane 2 are pruned + System::::set_block_number(3); + + assert_eq!( + Pallet::::on_idle(0, dbw.reads_writes(100, 100)), + dbw.reads_writes(1, 2), + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, + 2 + ); + assert_eq!( + outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, + 2 + ); + }); + } + + #[test] + fn outbound_message_from_unconfigured_lane_is_rejected() { + run_test(|| { + assert_noop!( + send_message::( + RuntimeOrigin::signed(1), + TEST_LANE_ID_3, + REGULAR_PAYLOAD, + ), + Error::::InactiveOutboundLane, + ); + }); + } + + #[test] + fn test_bridge_messages_call_is_correctly_defined() { + let account_id = 1; + let message_proof: TestMessagesProof = Ok(vec![message(1, REGULAR_PAYLOAD)]).into(); + let message_delivery_proof = TestMessagesDeliveryProof(Ok(( + TEST_LANE_ID, + InboundLaneData { + last_confirmed_nonce: 1, + relayers: vec![UnrewardedRelayer { + relayer: 0, + messages: DeliveredMessages::new(1), + }] + .into_iter() + .collect(), + }, + ))); + let unrewarded_relayer_state = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + total_messages: 1, + last_delivered_nonce: 1, + ..Default::default() + }; + + let direct_receive_messages_proof_call = Call::::receive_messages_proof { + relayer_id_at_bridged_chain: account_id, + proof: message_proof.clone(), + messages_count: 1, + dispatch_weight: REGULAR_PAYLOAD.declared_weight, + }; + let indirect_receive_messages_proof_call = BridgeMessagesCall::< + AccountId, + TestMessagesProof, + TestMessagesDeliveryProof, + >::receive_messages_proof { + relayer_id_at_bridged_chain: account_id, + proof: message_proof, + messages_count: 1, + dispatch_weight: REGULAR_PAYLOAD.declared_weight, + }; + assert_eq!( + direct_receive_messages_proof_call.encode(), + indirect_receive_messages_proof_call.encode() + ); + + let direct_receive_messages_delivery_proof_call = + Call::::receive_messages_delivery_proof { + proof: message_delivery_proof.clone(), + relayers_state: unrewarded_relayer_state.clone(), + }; + let indirect_receive_messages_delivery_proof_call = BridgeMessagesCall::< + AccountId, + TestMessagesProof, + TestMessagesDeliveryProof, + >::receive_messages_delivery_proof { + proof: message_delivery_proof, + relayers_state: unrewarded_relayer_state, + }; + assert_eq!( + direct_receive_messages_delivery_proof_call.encode(), + indirect_receive_messages_delivery_proof_call.encode() + ); + } + + generate_owned_bridge_module_tests!( + MessagesOperatingMode::Basic(BasicOperatingMode::Normal), + MessagesOperatingMode::Basic(BasicOperatingMode::Halted) + ); + + #[test] + fn inbound_storage_extra_proof_size_bytes_works() { + fn relayer_entry() -> UnrewardedRelayer { + UnrewardedRelayer { relayer: 42u64, messages: DeliveredMessages { begin: 0, end: 100 } } + } + + fn storage(relayer_entries: usize) -> RuntimeInboundLaneStorage { + RuntimeInboundLaneStorage { + lane_id: Default::default(), + cached_data: RefCell::new(Some(InboundLaneData { + relayers: vec![relayer_entry(); relayer_entries].into_iter().collect(), + last_confirmed_nonce: 0, + })), + _phantom: Default::default(), + } + } + + let max_entries = crate::mock::MaxUnrewardedRelayerEntriesAtInboundLane::get() as usize; + + // when we have exactly `MaxUnrewardedRelayerEntriesAtInboundLane` unrewarded relayers + assert_eq!(storage(max_entries).extra_proof_size_bytes(), 0); + + // when we have less than `MaxUnrewardedRelayerEntriesAtInboundLane` unrewarded relayers + assert_eq!( + storage(max_entries - 1).extra_proof_size_bytes(), + relayer_entry().encode().len() as u64 + ); + assert_eq!( + storage(max_entries - 2).extra_proof_size_bytes(), + 2 * relayer_entry().encode().len() as u64 + ); + + // when we have more than `MaxUnrewardedRelayerEntriesAtInboundLane` unrewarded relayers + // (shall not happen in practice) + assert_eq!(storage(max_entries + 1).extra_proof_size_bytes(), 0); + } + + #[test] + fn maybe_outbound_lanes_count_returns_correct_value() { + assert_eq!( + MaybeOutboundLanesCount::::get(), + Some(mock::ActiveOutboundLanes::get().len() as u32) + ); + } +} diff --git a/modules/messages/src/mock.rs b/modules/messages/src/mock.rs new file mode 100644 index 00000000000..75f05b4820a --- /dev/null +++ b/modules/messages/src/mock.rs @@ -0,0 +1,498 @@ +// Copyright 2019-2021 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 . + +// From construct_runtime macro +#![allow(clippy::from_over_into)] + +use crate::Config; + +use bp_messages::{ + calc_relayers_rewards, + source_chain::{DeliveryConfirmationPayments, LaneMessageVerifier, TargetHeaderChain}, + target_chain::{ + DeliveryPayments, DispatchMessage, DispatchMessageData, MessageDispatch, + ProvedLaneMessages, ProvedMessages, SourceHeaderChain, + }, + DeliveredMessages, InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, + OutboundLaneData, UnrewardedRelayer, +}; +use bp_runtime::{messages::MessageDispatchResult, Size}; +use codec::{Decode, Encode}; +use frame_support::{ + parameter_types, + traits::ConstU64, + weights::{constants::RocksDbWeight, Weight}, +}; +use scale_info::TypeInfo; +use sp_core::H256; +use sp_runtime::{ + testing::Header as SubstrateHeader, + traits::{BlakeTwo256, ConstU32, IdentityLookup}, + Perbill, +}; +use std::{ + collections::{BTreeMap, VecDeque}, + ops::RangeInclusive, +}; + +pub type AccountId = u64; +pub type Balance = u64; +#[derive(Decode, Encode, Clone, Debug, PartialEq, Eq, TypeInfo)] +pub struct TestPayload { + /// Field that may be used to identify messages. + pub id: u64, + /// Reject this message by lane verifier? + pub reject_by_lane_verifier: bool, + /// Dispatch weight that is declared by the message sender. + pub declared_weight: Weight, + /// Message dispatch result. + /// + /// Note: in correct code `dispatch_result.unspent_weight` will always be <= `declared_weight`, + /// but for test purposes we'll be making it larger than `declared_weight` sometimes. + pub dispatch_result: MessageDispatchResult, + /// Extra bytes that affect payload size. + pub extra: Vec, +} +pub type TestMessageFee = u64; +pub type TestRelayer = u64; +pub type TestDispatchLevelResult = (); + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +use crate as pallet_bridge_messages; + +frame_support::construct_runtime! { + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Call, Event}, + Messages: pallet_bridge_messages::{Pallet, Call, Event}, + } +} + +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; + +impl frame_system::Config for TestRuntime { + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = SubstrateHeader; + 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>; +} + +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 HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +parameter_types! { + pub const MaxMessagesToPruneAtOnce: u64 = 10; + pub const MaxUnrewardedRelayerEntriesAtInboundLane: u64 = 16; + pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 32; + pub const TestBridgedChainId: bp_runtime::ChainId = *b"test"; + pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID, TEST_LANE_ID_2]; +} + +/// weights of messages pallet calls we use in tests. +pub type TestWeightInfo = (); + +impl Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = TestWeightInfo; + type ActiveOutboundLanes = ActiveOutboundLanes; + type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type MaximalOutboundPayloadSize = frame_support::traits::ConstU32; + type OutboundPayload = TestPayload; + + type InboundPayload = TestPayload; + type InboundRelayer = TestRelayer; + type DeliveryPayments = TestDeliveryPayments; + + type TargetHeaderChain = TestTargetHeaderChain; + type LaneMessageVerifier = TestLaneMessageVerifier; + type DeliveryConfirmationPayments = TestDeliveryConfirmationPayments; + + type SourceHeaderChain = TestSourceHeaderChain; + type MessageDispatch = TestMessageDispatch; + type BridgedChainId = TestBridgedChainId; +} + +#[cfg(feature = "runtime-benchmarks")] +impl crate::benchmarking::Config<()> for TestRuntime { + fn bench_lane_id() -> LaneId { + TEST_LANE_ID + } + + fn prepare_message_proof( + params: crate::benchmarking::MessageProofParams, + ) -> (TestMessagesProof, Weight) { + // in mock run we only care about benchmarks correctness, not the benchmark results + // => ignore size related arguments + let (messages, total_dispatch_weight) = + params.message_nonces.into_iter().map(|n| message(n, REGULAR_PAYLOAD)).fold( + (Vec::new(), Weight::zero()), + |(mut messages, total_dispatch_weight), message| { + let weight = REGULAR_PAYLOAD.declared_weight; + messages.push(message); + (messages, total_dispatch_weight.saturating_add(weight)) + }, + ); + let mut proof: TestMessagesProof = Ok(messages).into(); + proof.result.as_mut().unwrap().get_mut(0).unwrap().1.lane_state = params.outbound_lane_data; + (proof, total_dispatch_weight) + } + + fn prepare_message_delivery_proof( + params: crate::benchmarking::MessageDeliveryProofParams, + ) -> TestMessagesDeliveryProof { + // in mock run we only care about benchmarks correctness, not the benchmark results + // => ignore size related arguments + TestMessagesDeliveryProof(Ok((params.lane, params.inbound_lane_data))) + } + + fn is_relayer_rewarded(_relayer: &AccountId) -> bool { + true + } +} + +impl Size for TestPayload { + fn size(&self) -> u32 { + 16 + self.extra.len() as u32 + } +} + +/// Maximal outbound payload size. +pub const MAX_OUTBOUND_PAYLOAD_SIZE: u32 = 4096; + +/// Account that has balance to use in tests. +pub const ENDOWED_ACCOUNT: AccountId = 0xDEAD; + +/// Account id of test relayer. +pub const TEST_RELAYER_A: AccountId = 100; + +/// Account id of additional test relayer - B. +pub const TEST_RELAYER_B: AccountId = 101; + +/// Account id of additional test relayer - C. +pub const TEST_RELAYER_C: AccountId = 102; + +/// Error that is returned by all test implementations. +pub const TEST_ERROR: &str = "Test error"; + +/// Lane that we're using in tests. +pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]); + +/// Secondary lane that we're using in tests. +pub const TEST_LANE_ID_2: LaneId = LaneId([0, 0, 0, 2]); + +/// Inactive outbound lane. +pub const TEST_LANE_ID_3: LaneId = LaneId([0, 0, 0, 3]); + +/// Regular message payload. +pub const REGULAR_PAYLOAD: TestPayload = message_payload(0, 50); + +/// Payload that is rejected by `TestTargetHeaderChain`. +pub const PAYLOAD_REJECTED_BY_TARGET_CHAIN: TestPayload = message_payload(1, 50); + +/// Vec of proved messages, grouped by lane. +pub type MessagesByLaneVec = Vec<(LaneId, ProvedLaneMessages)>; + +/// Test messages proof. +#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] +pub struct TestMessagesProof { + pub result: Result, +} + +impl Size for TestMessagesProof { + fn size(&self) -> u32 { + 0 + } +} + +impl From, ()>> for TestMessagesProof { + fn from(result: Result, ()>) -> Self { + Self { + result: result.map(|messages| { + let mut messages_by_lane: BTreeMap> = + BTreeMap::new(); + for message in messages { + messages_by_lane.entry(message.key.lane_id).or_default().messages.push(message); + } + messages_by_lane.into_iter().collect() + }), + } + } +} + +/// Messages delivery proof used in tests. +#[derive(Debug, Encode, Decode, Eq, Clone, PartialEq, TypeInfo)] +pub struct TestMessagesDeliveryProof(pub Result<(LaneId, InboundLaneData), ()>); + +impl Size for TestMessagesDeliveryProof { + fn size(&self) -> u32 { + 0 + } +} + +/// Target header chain that is used in tests. +#[derive(Debug, Default)] +pub struct TestTargetHeaderChain; + +impl TargetHeaderChain for TestTargetHeaderChain { + type Error = &'static str; + + type MessagesDeliveryProof = TestMessagesDeliveryProof; + + fn verify_message(payload: &TestPayload) -> Result<(), Self::Error> { + if *payload == PAYLOAD_REJECTED_BY_TARGET_CHAIN { + Err(TEST_ERROR) + } else { + Ok(()) + } + } + + fn verify_messages_delivery_proof( + proof: Self::MessagesDeliveryProof, + ) -> Result<(LaneId, InboundLaneData), Self::Error> { + proof.0.map_err(|_| TEST_ERROR) + } +} + +/// Lane message verifier that is used in tests. +#[derive(Debug, Default)] +pub struct TestLaneMessageVerifier; + +impl LaneMessageVerifier for TestLaneMessageVerifier { + type Error = &'static str; + + fn verify_message( + _submitter: &RuntimeOrigin, + _lane: &LaneId, + _lane_outbound_data: &OutboundLaneData, + payload: &TestPayload, + ) -> Result<(), Self::Error> { + if !payload.reject_by_lane_verifier { + Ok(()) + } else { + Err(TEST_ERROR) + } + } +} + +/// Reward payments at the target chain during delivery transaction. +#[derive(Debug, Default)] +pub struct TestDeliveryPayments; + +impl TestDeliveryPayments { + /// Returns true if given relayer has been rewarded with given balance. The reward-paid flag is + /// cleared after the call. + pub fn is_reward_paid(relayer: AccountId) -> bool { + let key = (b":delivery-relayer-reward:", relayer).encode(); + frame_support::storage::unhashed::take::(&key).is_some() + } +} + +impl DeliveryPayments for TestDeliveryPayments { + type Error = &'static str; + + fn pay_reward( + relayer: AccountId, + _total_messages: MessageNonce, + _valid_messages: MessageNonce, + _actual_weight: Weight, + ) { + let key = (b":delivery-relayer-reward:", relayer).encode(); + frame_support::storage::unhashed::put(&key, &true); + } +} + +/// Reward payments at the source chain during delivery confirmation transaction. +#[derive(Debug, Default)] +pub struct TestDeliveryConfirmationPayments; + +impl TestDeliveryConfirmationPayments { + /// Returns true if given relayer has been rewarded with given balance. The reward-paid flag is + /// cleared after the call. + pub fn is_reward_paid(relayer: AccountId, fee: TestMessageFee) -> bool { + let key = (b":relayer-reward:", relayer, fee).encode(); + frame_support::storage::unhashed::take::(&key).is_some() + } +} + +impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayments { + type Error = &'static str; + + fn pay_reward( + _lane_id: LaneId, + messages_relayers: VecDeque>, + _confirmation_relayer: &AccountId, + received_range: &RangeInclusive, + ) -> MessageNonce { + let relayers_rewards = calc_relayers_rewards(messages_relayers, received_range); + let rewarded_relayers = relayers_rewards.len(); + for (relayer, reward) in &relayers_rewards { + let key = (b":relayer-reward:", relayer, reward).encode(); + frame_support::storage::unhashed::put(&key, &true); + } + + rewarded_relayers as _ + } +} + +/// Source header chain that is used in tests. +#[derive(Debug)] +pub struct TestSourceHeaderChain; + +impl SourceHeaderChain for TestSourceHeaderChain { + type Error = &'static str; + + type MessagesProof = TestMessagesProof; + + fn verify_messages_proof( + proof: Self::MessagesProof, + _messages_count: u32, + ) -> Result, Self::Error> { + proof.result.map(|proof| proof.into_iter().collect()).map_err(|_| TEST_ERROR) + } +} + +/// Source header chain that is used in tests. +#[derive(Debug)] +pub struct TestMessageDispatch; + +impl MessageDispatch for TestMessageDispatch { + type DispatchPayload = TestPayload; + type DispatchLevelResult = TestDispatchLevelResult; + + fn dispatch_weight(message: &mut DispatchMessage) -> Weight { + match message.data.payload.as_ref() { + Ok(payload) => payload.declared_weight, + Err(_) => Weight::zero(), + } + } + + fn dispatch( + _relayer_account: &AccountId, + message: DispatchMessage, + ) -> MessageDispatchResult { + match message.data.payload.as_ref() { + Ok(payload) => payload.dispatch_result.clone(), + Err(_) => dispatch_result(0), + } + } +} + +/// Return test lane message with given nonce and payload. +pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message { + Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, payload: payload.encode() } +} + +/// Return valid outbound message data, constructed from given payload. +pub fn outbound_message_data(payload: TestPayload) -> MessagePayload { + payload.encode() +} + +/// Return valid inbound (dispatch) message data, constructed from given payload. +pub fn inbound_message_data(payload: TestPayload) -> DispatchMessageData { + DispatchMessageData { payload: Ok(payload) } +} + +/// Constructs message payload using given arguments and zero unspent weight. +pub const fn message_payload(id: u64, declared_weight: u64) -> TestPayload { + TestPayload { + id, + reject_by_lane_verifier: false, + declared_weight: Weight::from_parts(declared_weight, 0), + dispatch_result: dispatch_result(0), + extra: Vec::new(), + } +} + +/// Returns message dispatch result with given unspent weight. +pub const fn dispatch_result( + unspent_weight: u64, +) -> MessageDispatchResult { + MessageDispatchResult { + unspent_weight: Weight::from_parts(unspent_weight, 0), + dispatch_level_result: (), + } +} + +/// Constructs unrewarded relayer entry from nonces range and relayer id. +pub fn unrewarded_relayer( + begin: MessageNonce, + end: MessageNonce, + relayer: TestRelayer, +) -> UnrewardedRelayer { + UnrewardedRelayer { relayer, messages: DeliveredMessages { begin, end } } +} + +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + pallet_balances::GenesisConfig:: { balances: vec![(ENDOWED_ACCOUNT, 1_000_000)] } + .assimilate_storage(&mut t) + .unwrap(); + sp_io::TestExternalities::new(t) +} + +/// Run pallet test. +pub fn run_test(test: impl FnOnce() -> T) -> T { + new_test_ext().execute_with(test) +} diff --git a/modules/messages/src/outbound_lane.rs b/modules/messages/src/outbound_lane.rs new file mode 100644 index 00000000000..33a58a40400 --- /dev/null +++ b/modules/messages/src/outbound_lane.rs @@ -0,0 +1,436 @@ +// Copyright 2019-2021 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 . + +//! Everything about outgoing messages sending. + +use crate::Config; + +use bp_messages::{ + DeliveredMessages, LaneId, MessageNonce, MessagePayload, OutboundLaneData, UnrewardedRelayer, +}; +use frame_support::{ + weights::{RuntimeDbWeight, Weight}, + BoundedVec, RuntimeDebug, +}; +use num_traits::Zero; +use sp_std::collections::vec_deque::VecDeque; + +/// Outbound lane storage. +pub trait OutboundLaneStorage { + /// Lane id. + fn id(&self) -> LaneId; + /// Get lane data from the storage. + fn data(&self) -> OutboundLaneData; + /// Update lane data in the storage. + fn set_data(&mut self, data: OutboundLaneData); + /// Returns saved outbound message payload. + #[cfg(test)] + fn message(&self, nonce: &MessageNonce) -> Option; + /// Save outbound message in the storage. + fn save_message(&mut self, nonce: MessageNonce, message_payload: MessagePayload); + /// Remove outbound message from the storage. + fn remove_message(&mut self, nonce: &MessageNonce); +} + +/// Outbound message data wrapper that implements `MaxEncodedLen`. +pub type StoredMessagePayload = BoundedVec>::MaximalOutboundPayloadSize>; + +/// Result of messages receival confirmation. +#[derive(RuntimeDebug, PartialEq, Eq)] +pub enum ReceivalConfirmationResult { + /// New messages have been confirmed by the confirmation transaction. + ConfirmedMessages(DeliveredMessages), + /// Confirmation transaction brings no new confirmation. This may be a result of relayer + /// error or several relayers running. + NoNewConfirmations, + /// Bridged chain is trying to confirm more messages than we have generated. May be a result + /// of invalid bridged chain storage. + FailedToConfirmFutureMessages, + /// The unrewarded relayers vec contains an empty entry. May be a result of invalid bridged + /// chain storage. + EmptyUnrewardedRelayerEntry, + /// The unrewarded relayers vec contains non-consecutive entries. May be a result of invalid + /// bridged chain storage. + NonConsecutiveUnrewardedRelayerEntries, + /// The chain has more messages that need to be confirmed than there is in the proof. + TryingToConfirmMoreMessagesThanExpected(MessageNonce), +} + +/// Outbound messages lane. +pub struct OutboundLane { + storage: S, +} + +impl OutboundLane { + /// Create new outbound lane backed by given storage. + pub fn new(storage: S) -> Self { + OutboundLane { storage } + } + + /// Get this lane data. + pub fn data(&self) -> OutboundLaneData { + self.storage.data() + } + + /// Send message over lane. + /// + /// Returns new message nonce. + pub fn send_message(&mut self, message_payload: MessagePayload) -> MessageNonce { + let mut data = self.storage.data(); + let nonce = data.latest_generated_nonce + 1; + data.latest_generated_nonce = nonce; + + self.storage.save_message(nonce, message_payload); + self.storage.set_data(data); + + nonce + } + + /// Confirm messages delivery. + pub fn confirm_delivery( + &mut self, + max_allowed_messages: MessageNonce, + latest_delivered_nonce: MessageNonce, + relayers: &VecDeque>, + ) -> ReceivalConfirmationResult { + let mut data = self.storage.data(); + if latest_delivered_nonce <= data.latest_received_nonce { + return ReceivalConfirmationResult::NoNewConfirmations + } + if latest_delivered_nonce > data.latest_generated_nonce { + return ReceivalConfirmationResult::FailedToConfirmFutureMessages + } + if latest_delivered_nonce - data.latest_received_nonce > max_allowed_messages { + // that the relayer has declared correct number of messages that the proof contains (it + // is checked outside of the function). But it may happen (but only if this/bridged + // chain storage is corrupted, though) that the actual number of confirmed messages if + // larger than declared. This would mean that 'reward loop' will take more time than the + // weight formula accounts, so we can't allow that. + return ReceivalConfirmationResult::TryingToConfirmMoreMessagesThanExpected( + latest_delivered_nonce - data.latest_received_nonce, + ) + } + + if let Err(e) = ensure_unrewarded_relayers_are_correct(latest_delivered_nonce, relayers) { + return e + } + + let prev_latest_received_nonce = data.latest_received_nonce; + data.latest_received_nonce = latest_delivered_nonce; + self.storage.set_data(data); + + ReceivalConfirmationResult::ConfirmedMessages(DeliveredMessages { + begin: prev_latest_received_nonce + 1, + end: latest_delivered_nonce, + }) + } + + /// Prune at most `max_messages_to_prune` already received messages. + /// + /// Returns weight, consumed by messages pruning and lane state update. + pub fn prune_messages( + &mut self, + db_weight: RuntimeDbWeight, + mut remaining_weight: Weight, + ) -> Weight { + let write_weight = db_weight.writes(1); + let two_writes_weight = write_weight + write_weight; + let mut spent_weight = Weight::zero(); + let mut data = self.storage.data(); + while remaining_weight.all_gte(two_writes_weight) && + data.oldest_unpruned_nonce <= data.latest_received_nonce + { + self.storage.remove_message(&data.oldest_unpruned_nonce); + + spent_weight += write_weight; + remaining_weight -= write_weight; + data.oldest_unpruned_nonce += 1; + } + + if !spent_weight.is_zero() { + spent_weight += write_weight; + self.storage.set_data(data); + } + + spent_weight + } +} + +/// Verifies unrewarded relayers vec. +/// +/// Returns `Err(_)` if unrewarded relayers vec contains invalid data, meaning that the bridged +/// chain has invalid runtime storage. +fn ensure_unrewarded_relayers_are_correct( + latest_received_nonce: MessageNonce, + relayers: &VecDeque>, +) -> Result<(), ReceivalConfirmationResult> { + let mut last_entry_end: Option = None; + for entry in relayers { + // unrewarded relayer entry must have at least 1 unconfirmed message + // (guaranteed by the `InboundLane::receive_message()`) + if entry.messages.end < entry.messages.begin { + return Err(ReceivalConfirmationResult::EmptyUnrewardedRelayerEntry) + } + // every entry must confirm range of messages that follows previous entry range + // (guaranteed by the `InboundLane::receive_message()`) + if let Some(last_entry_end) = last_entry_end { + let expected_entry_begin = last_entry_end.checked_add(1); + if expected_entry_begin != Some(entry.messages.begin) { + return Err(ReceivalConfirmationResult::NonConsecutiveUnrewardedRelayerEntries) + } + } + last_entry_end = Some(entry.messages.end); + // entry can't confirm messages larger than `inbound_lane_data.latest_received_nonce()` + // (guaranteed by the `InboundLane::receive_message()`) + if entry.messages.end > latest_received_nonce { + // technically this will be detected in the next loop iteration as + // `InvalidNumberOfDispatchResults` but to guarantee safety of loop operations below + // this is detected now + return Err(ReceivalConfirmationResult::FailedToConfirmFutureMessages) + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + mock::{ + outbound_message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime, + REGULAR_PAYLOAD, TEST_LANE_ID, + }, + outbound_lane, + }; + use frame_support::weights::constants::RocksDbWeight; + use sp_std::ops::RangeInclusive; + + fn unrewarded_relayers( + nonces: RangeInclusive, + ) -> VecDeque> { + vec![unrewarded_relayer(*nonces.start(), *nonces.end(), 0)] + .into_iter() + .collect() + } + + fn delivered_messages(nonces: RangeInclusive) -> DeliveredMessages { + DeliveredMessages { begin: *nonces.start(), end: *nonces.end() } + } + + fn assert_3_messages_confirmation_fails( + latest_received_nonce: MessageNonce, + relayers: &VecDeque>, + ) -> ReceivalConfirmationResult { + run_test(|| { + let mut lane = outbound_lane::(TEST_LANE_ID); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 0); + let result = lane.confirm_delivery(3, latest_received_nonce, relayers); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 0); + result + }) + } + + #[test] + fn send_message_works() { + run_test(|| { + let mut lane = outbound_lane::(TEST_LANE_ID); + assert_eq!(lane.storage.data().latest_generated_nonce, 0); + assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); + assert!(lane.storage.message(&1).is_some()); + assert_eq!(lane.storage.data().latest_generated_nonce, 1); + }); + } + + #[test] + fn confirm_delivery_works() { + run_test(|| { + let mut lane = outbound_lane::(TEST_LANE_ID); + assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); + assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); + assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 0); + assert_eq!( + lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), + ReceivalConfirmationResult::ConfirmedMessages(delivered_messages(1..=3)), + ); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 3); + }); + } + + #[test] + fn confirm_delivery_rejects_nonce_lesser_than_latest_received() { + run_test(|| { + let mut lane = outbound_lane::(TEST_LANE_ID); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 0); + assert_eq!( + lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), + ReceivalConfirmationResult::ConfirmedMessages(delivered_messages(1..=3)), + ); + assert_eq!( + lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), + ReceivalConfirmationResult::NoNewConfirmations, + ); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 3); + + assert_eq!( + lane.confirm_delivery(1, 2, &unrewarded_relayers(1..=1)), + ReceivalConfirmationResult::NoNewConfirmations, + ); + assert_eq!(lane.storage.data().latest_generated_nonce, 3); + assert_eq!(lane.storage.data().latest_received_nonce, 3); + }); + } + + #[test] + fn confirm_delivery_rejects_nonce_larger_than_last_generated() { + assert_eq!( + assert_3_messages_confirmation_fails(10, &unrewarded_relayers(1..=10),), + ReceivalConfirmationResult::FailedToConfirmFutureMessages, + ); + } + + #[test] + fn confirm_delivery_fails_if_entry_confirms_future_messages() { + assert_eq!( + assert_3_messages_confirmation_fails( + 3, + &unrewarded_relayers(1..=1) + .into_iter() + .chain(unrewarded_relayers(2..=30).into_iter()) + .chain(unrewarded_relayers(3..=3).into_iter()) + .collect(), + ), + ReceivalConfirmationResult::FailedToConfirmFutureMessages, + ); + } + + #[test] + #[allow(clippy::reversed_empty_ranges)] + fn confirm_delivery_fails_if_entry_is_empty() { + assert_eq!( + assert_3_messages_confirmation_fails( + 3, + &unrewarded_relayers(1..=1) + .into_iter() + .chain(unrewarded_relayers(2..=1).into_iter()) + .chain(unrewarded_relayers(2..=3).into_iter()) + .collect(), + ), + ReceivalConfirmationResult::EmptyUnrewardedRelayerEntry, + ); + } + + #[test] + fn confirm_delivery_fails_if_entries_are_non_consecutive() { + assert_eq!( + assert_3_messages_confirmation_fails( + 3, + &unrewarded_relayers(1..=1) + .into_iter() + .chain(unrewarded_relayers(3..=3).into_iter()) + .chain(unrewarded_relayers(2..=2).into_iter()) + .collect(), + ), + ReceivalConfirmationResult::NonConsecutiveUnrewardedRelayerEntries, + ); + } + + #[test] + fn prune_messages_works() { + run_test(|| { + let mut lane = outbound_lane::(TEST_LANE_ID); + // when lane is empty, nothing is pruned + assert_eq!( + lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), + Weight::zero() + ); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + // when nothing is confirmed, nothing is pruned + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + assert!(lane.storage.message(&1).is_some()); + assert!(lane.storage.message(&2).is_some()); + assert!(lane.storage.message(&3).is_some()); + assert_eq!( + lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), + Weight::zero() + ); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + // after confirmation, some messages are received + assert_eq!( + lane.confirm_delivery(2, 2, &unrewarded_relayers(1..=2)), + ReceivalConfirmationResult::ConfirmedMessages(delivered_messages(1..=2)), + ); + assert_eq!( + lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), + RocksDbWeight::get().writes(3), + ); + assert!(lane.storage.message(&1).is_none()); + assert!(lane.storage.message(&2).is_none()); + assert!(lane.storage.message(&3).is_some()); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 3); + // after last message is confirmed, everything is pruned + assert_eq!( + lane.confirm_delivery(1, 3, &unrewarded_relayers(3..=3)), + ReceivalConfirmationResult::ConfirmedMessages(delivered_messages(3..=3)), + ); + assert_eq!( + lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), + RocksDbWeight::get().writes(2), + ); + assert!(lane.storage.message(&1).is_none()); + assert!(lane.storage.message(&2).is_none()); + assert!(lane.storage.message(&3).is_none()); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); + }); + } + + #[test] + fn confirm_delivery_detects_when_more_than_expected_messages_are_confirmed() { + run_test(|| { + let mut lane = outbound_lane::(TEST_LANE_ID); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); + assert_eq!( + lane.confirm_delivery(0, 3, &unrewarded_relayers(1..=3)), + ReceivalConfirmationResult::TryingToConfirmMoreMessagesThanExpected(3), + ); + assert_eq!( + lane.confirm_delivery(2, 3, &unrewarded_relayers(1..=3)), + ReceivalConfirmationResult::TryingToConfirmMoreMessagesThanExpected(3), + ); + assert_eq!( + lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), + ReceivalConfirmationResult::ConfirmedMessages(delivered_messages(1..=3)), + ); + }); + } +} diff --git a/modules/messages/src/weights.rs b/modules/messages/src/weights.rs new file mode 100644 index 00000000000..baaef317241 --- /dev/null +++ b/modules/messages/src/weights.rs @@ -0,0 +1,525 @@ +// Copyright 2019-2021 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 . + +//! Autogenerated weights for RialtoMessages +//! +//! 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: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/millau-bridge-node +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=RialtoMessages +// --extrinsic=* +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --output=./modules/messages/src/weights.rs +// --template=./.maintain/millau-weight-template.hbs + +#![allow(clippy::all)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for RialtoMessages. +pub trait WeightInfo { + fn receive_single_message_proof() -> Weight; + fn receive_two_messages_proof() -> Weight; + fn receive_single_message_proof_with_outbound_lane_state() -> Weight; + fn receive_single_message_proof_1_kb() -> Weight; + fn receive_single_message_proof_16_kb() -> Weight; + fn receive_delivery_proof_for_single_message() -> Weight; + fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight; + fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight; + fn receive_single_message_proof_with_dispatch(i: u32) -> Weight; +} + +/// Weights for `RialtoMessages` 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) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// 51655, mode: MaxEncodedLen) + fn receive_single_message_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `618` + // Estimated: `57170` + // Minimum execution time: 52_321 nanoseconds. + Weight::from_parts(54_478_000, 57170) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// 51655, mode: MaxEncodedLen) + fn receive_two_messages_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `618` + // Estimated: `57170` + // Minimum execution time: 64_597 nanoseconds. + Weight::from_parts(69_267_000, 57170) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages 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: + // Measured: `618` + // Estimated: `57170` + // Minimum execution time: 64_079 nanoseconds. + Weight::from_parts(65_905_000, 57170) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages 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: `618` + // Estimated: `57170` + // Minimum execution time: 50_588 nanoseconds. + Weight::from_parts(53_544_000, 57170) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages 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: `618` + // Estimated: `57170` + // Minimum execution time: 78_269 nanoseconds. + Weight::from_parts(81_748_000, 57170) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// 539, mode: MaxEncodedLen) + /// + /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) + /// + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// mode: MaxEncodedLen) + fn receive_delivery_proof_for_single_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `9584` + // Minimum execution time: 45_786 nanoseconds. + Weight::from_parts(47_382_000, 9584) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// 539, mode: MaxEncodedLen) + /// + /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) + /// + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// mode: MaxEncodedLen) + fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { + // Proof Size summary in bytes: + // Measured: `596` + // Estimated: `9584` + // Minimum execution time: 44_544 nanoseconds. + Weight::from_parts(45_451_000, 9584) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// 539, mode: MaxEncodedLen) + /// + /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) + /// + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// mode: MaxEncodedLen) + fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { + // Proof Size summary in bytes: + // Measured: `596` + // Estimated: `12124` + // Minimum execution time: 47_344 nanoseconds. + Weight::from_parts(48_311_000, 12124) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// 51655, mode: MaxEncodedLen) + /// + /// The range of component `i` is `[128, 2048]`. + fn receive_single_message_proof_with_dispatch(i: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `618` + // Estimated: `57170` + // Minimum execution time: 52_385 nanoseconds. + Weight::from_parts(54_919_468, 57170) + // Standard Error: 108 + .saturating_add(Weight::from_parts(3_286, 0).saturating_mul(i.into())) + .saturating_add(T::DbWeight::get().reads(3_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// 51655, mode: MaxEncodedLen) + fn receive_single_message_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `618` + // Estimated: `57170` + // Minimum execution time: 52_321 nanoseconds. + Weight::from_parts(54_478_000, 57170) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// 51655, mode: MaxEncodedLen) + fn receive_two_messages_proof() -> Weight { + // Proof Size summary in bytes: + // Measured: `618` + // Estimated: `57170` + // Minimum execution time: 64_597 nanoseconds. + Weight::from_parts(69_267_000, 57170) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages 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: + // Measured: `618` + // Estimated: `57170` + // Minimum execution time: 64_079 nanoseconds. + Weight::from_parts(65_905_000, 57170) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages 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: `618` + // Estimated: `57170` + // Minimum execution time: 50_588 nanoseconds. + Weight::from_parts(53_544_000, 57170) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages 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: `618` + // Estimated: `57170` + // Minimum execution time: 78_269 nanoseconds. + Weight::from_parts(81_748_000, 57170) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// 539, mode: MaxEncodedLen) + /// + /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) + /// + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// mode: MaxEncodedLen) + fn receive_delivery_proof_for_single_message() -> Weight { + // Proof Size summary in bytes: + // Measured: `579` + // Estimated: `9584` + // Minimum execution time: 45_786 nanoseconds. + Weight::from_parts(47_382_000, 9584) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// 539, mode: MaxEncodedLen) + /// + /// Storage: BridgeRelayers RelayerRewards (r:1 w:1) + /// + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// mode: MaxEncodedLen) + fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { + // Proof Size summary in bytes: + // Measured: `596` + // Estimated: `9584` + // Minimum execution time: 44_544 nanoseconds. + Weight::from_parts(45_451_000, 9584) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages OutboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages OutboundLanes (max_values: Some(1), max_size: Some(44), added: + /// 539, mode: MaxEncodedLen) + /// + /// Storage: BridgeRelayers RelayerRewards (r:2 w:2) + /// + /// Proof: BridgeRelayers RelayerRewards (max_values: None, max_size: Some(65), added: 2540, + /// mode: MaxEncodedLen) + fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { + // Proof Size summary in bytes: + // Measured: `596` + // Estimated: `12124` + // Minimum execution time: 47_344 nanoseconds. + Weight::from_parts(48_311_000, 12124) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: BridgeRialtoMessages PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoMessages PalletOperatingMode (max_values: Some(1), max_size: Some(2), + /// added: 497, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoMessages InboundLanes (r:1 w:1) + /// + /// Proof: BridgeRialtoMessages InboundLanes (max_values: None, max_size: Some(49180), added: + /// 51655, mode: MaxEncodedLen) + /// + /// The range of component `i` is `[128, 2048]`. + fn receive_single_message_proof_with_dispatch(i: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `618` + // Estimated: `57170` + // Minimum execution time: 52_385 nanoseconds. + Weight::from_parts(54_919_468, 57170) + // Standard Error: 108 + .saturating_add(Weight::from_parts(3_286, 0).saturating_mul(i.into())) + .saturating_add(RocksDbWeight::get().reads(3_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } +} diff --git a/modules/messages/src/weights_ext.rs b/modules/messages/src/weights_ext.rs new file mode 100644 index 00000000000..090c03390ba --- /dev/null +++ b/modules/messages/src/weights_ext.rs @@ -0,0 +1,444 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Weight-related utilities. + +use crate::weights::WeightInfo; + +use bp_messages::{MessageNonce, UnrewardedRelayersState}; +use bp_runtime::{PreComputedSize, Size}; +use frame_support::weights::Weight; + +/// Size of the message being delivered in benchmarks. +pub const EXPECTED_DEFAULT_MESSAGE_LENGTH: u32 = 128; + +/// We assume that size of signed extensions on all our chains and size of all 'small' arguments of +/// 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. +/// Some reserve is reserved to account future chain growth. +pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; + +/// Ensure that weights from `WeightInfoExt` implementation are looking correct. +pub fn ensure_weights_are_correct() { + // all components of weight formulae must have zero `proof_size`, because the `proof_size` is + // benchmarked using `MaxEncodedLen` approach and there are no components that cause additional + // db reads + + // verify `receive_messages_proof` weight components + assert_ne!(W::receive_messages_proof_overhead().ref_time(), 0); + assert_ne!(W::receive_messages_proof_overhead().proof_size(), 0); + // W::receive_messages_proof_messages_overhead(1).ref_time() may be zero because: + // the message processing code (`InboundLane::receive_message`) is minimal and may not be + // accounted by our benchmarks + assert_eq!(W::receive_messages_proof_messages_overhead(1).proof_size(), 0); + // W::receive_messages_proof_outbound_lane_state_overhead().ref_time() may be zero because: + // the outbound lane state processing code (`InboundLane::receive_state_update`) is minimal and + // may not be accounted by our benchmarks + assert_eq!(W::receive_messages_proof_outbound_lane_state_overhead().proof_size(), 0); + assert_ne!(W::storage_proof_size_overhead(1).ref_time(), 0); + assert_eq!(W::storage_proof_size_overhead(1).proof_size(), 0); + + // verify `receive_messages_delivery_proof` weight components + assert_ne!(W::receive_messages_delivery_proof_overhead().ref_time(), 0); + assert_ne!(W::receive_messages_delivery_proof_overhead().proof_size(), 0); + // W::receive_messages_delivery_proof_messages_overhead(1).ref_time() may be zero because: + // there's no code that iterates over confirmed messages in confirmation transaction + assert_eq!(W::receive_messages_delivery_proof_messages_overhead(1).proof_size(), 0); + assert_ne!(W::receive_messages_delivery_proof_relayers_overhead(1).ref_time(), 0); + // W::receive_messages_delivery_proof_relayers_overhead(1).proof_size() is an exception + // it may or may not cause additional db reads, so proof size may vary + assert_ne!(W::storage_proof_size_overhead(1).ref_time(), 0); + assert_eq!(W::storage_proof_size_overhead(1).proof_size(), 0); + + // verify `receive_message_proof` weight + let receive_messages_proof_weight = + W::receive_messages_proof_weight(&PreComputedSize(1), 10, Weight::zero()); + assert_ne!(receive_messages_proof_weight.ref_time(), 0); + assert_ne!(receive_messages_proof_weight.proof_size(), 0); + messages_proof_size_does_not_affect_proof_size::(); + messages_count_does_not_affect_proof_size::(); + + // verify `receive_message_proof` weight + let receive_messages_delivery_proof_weight = W::receive_messages_delivery_proof_weight( + &PreComputedSize(1), + &UnrewardedRelayersState::default(), + ); + assert_ne!(receive_messages_delivery_proof_weight.ref_time(), 0); + assert_ne!(receive_messages_delivery_proof_weight.proof_size(), 0); + messages_delivery_proof_size_does_not_affect_proof_size::(); + total_messages_in_delivery_proof_does_not_affect_proof_size::(); +} + +/// Ensure that we're able to receive maximal (by-size and by-weight) message from other chain. +pub fn ensure_able_to_receive_message( + max_extrinsic_size: u32, + max_extrinsic_weight: Weight, + max_incoming_message_proof_size: u32, + max_incoming_message_dispatch_weight: Weight, +) { + // verify that we're able to receive proof of maximal-size message + let max_delivery_transaction_size = + max_incoming_message_proof_size.saturating_add(SIGNED_EXTENSIONS_SIZE); + assert!( + max_delivery_transaction_size <= max_extrinsic_size, + "Size of maximal message delivery transaction {max_incoming_message_proof_size} + {SIGNED_EXTENSIONS_SIZE} is larger than maximal possible transaction size {max_extrinsic_size}", + ); + + // verify that we're able to receive proof of maximal-size message with maximal dispatch weight + let max_delivery_transaction_dispatch_weight = W::receive_messages_proof_weight( + &PreComputedSize( + (max_incoming_message_proof_size + W::expected_extra_storage_proof_size()) as usize, + ), + 1, + max_incoming_message_dispatch_weight, + ); + assert!( + max_delivery_transaction_dispatch_weight.all_lte(max_extrinsic_weight), + "Weight of maximal message delivery transaction + {max_delivery_transaction_dispatch_weight} is larger than maximal possible transaction weight {max_extrinsic_weight}", + ); +} + +/// Ensure that we're able to receive maximal confirmation from other chain. +pub fn ensure_able_to_receive_confirmation( + max_extrinsic_size: u32, + max_extrinsic_weight: Weight, + max_inbound_lane_data_proof_size_from_peer_chain: u32, + max_unrewarded_relayer_entries_at_peer_inbound_lane: MessageNonce, + max_unconfirmed_messages_at_inbound_lane: MessageNonce, +) { + // verify that we're able to receive confirmation of maximal-size + let max_confirmation_transaction_size = + max_inbound_lane_data_proof_size_from_peer_chain.saturating_add(SIGNED_EXTENSIONS_SIZE); + assert!( + max_confirmation_transaction_size <= max_extrinsic_size, + "Size of maximal message delivery confirmation transaction {max_inbound_lane_data_proof_size_from_peer_chain} + {SIGNED_EXTENSIONS_SIZE} is larger than maximal possible transaction size {max_extrinsic_size}", + ); + + // verify that we're able to reward maximal number of relayers that have delivered maximal + // number of messages + let max_confirmation_transaction_dispatch_weight = W::receive_messages_delivery_proof_weight( + &PreComputedSize(max_inbound_lane_data_proof_size_from_peer_chain as usize), + &UnrewardedRelayersState { + unrewarded_relayer_entries: max_unrewarded_relayer_entries_at_peer_inbound_lane, + total_messages: max_unconfirmed_messages_at_inbound_lane, + ..Default::default() + }, + ); + assert!( + max_confirmation_transaction_dispatch_weight.all_lte(max_extrinsic_weight), + "Weight of maximal confirmation transaction {max_confirmation_transaction_dispatch_weight} is larger than maximal possible transaction weight {max_extrinsic_weight}", + ); +} + +/// Panics if `proof_size` of message delivery call depends on the message proof size. +fn messages_proof_size_does_not_affect_proof_size() { + let dispatch_weight = Weight::zero(); + let weight_when_proof_size_is_8k = + W::receive_messages_proof_weight(&PreComputedSize(8 * 1024), 1, dispatch_weight); + let weight_when_proof_size_is_16k = + W::receive_messages_proof_weight(&PreComputedSize(16 * 1024), 1, dispatch_weight); + + ensure_weight_components_are_not_zero(weight_when_proof_size_is_8k); + ensure_weight_components_are_not_zero(weight_when_proof_size_is_16k); + ensure_proof_size_is_the_same( + weight_when_proof_size_is_8k, + weight_when_proof_size_is_16k, + "Messages proof size does not affect values that we read from our storage", + ); +} + +/// Panics if `proof_size` of message delivery call depends on the messages count. +/// +/// In practice, it will depend on the messages count, because most probably every +/// message will read something from db during dispatch. But this must be accounted +/// by the `dispatch_weight`. +fn messages_count_does_not_affect_proof_size() { + let messages_proof_size = PreComputedSize(8 * 1024); + let dispatch_weight = Weight::zero(); + let weight_of_one_incoming_message = + W::receive_messages_proof_weight(&messages_proof_size, 1, dispatch_weight); + let weight_of_two_incoming_messages = + W::receive_messages_proof_weight(&messages_proof_size, 2, dispatch_weight); + + ensure_weight_components_are_not_zero(weight_of_one_incoming_message); + ensure_weight_components_are_not_zero(weight_of_two_incoming_messages); + ensure_proof_size_is_the_same( + weight_of_one_incoming_message, + weight_of_two_incoming_messages, + "Number of same-lane incoming messages does not affect values that we read from our storage", + ); +} + +/// Panics if `proof_size` of delivery confirmation call depends on the delivery proof size. +fn messages_delivery_proof_size_does_not_affect_proof_size() { + let relayers_state = UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }; + let weight_when_proof_size_is_8k = + W::receive_messages_delivery_proof_weight(&PreComputedSize(8 * 1024), &relayers_state); + let weight_when_proof_size_is_16k = + W::receive_messages_delivery_proof_weight(&PreComputedSize(16 * 1024), &relayers_state); + + ensure_weight_components_are_not_zero(weight_when_proof_size_is_8k); + ensure_weight_components_are_not_zero(weight_when_proof_size_is_16k); + ensure_proof_size_is_the_same( + weight_when_proof_size_is_8k, + weight_when_proof_size_is_16k, + "Messages delivery proof size does not affect values that we read from our storage", + ); +} + +/// Panics if `proof_size` of delivery confirmation call depends on the number of confirmed +/// messages. +fn total_messages_in_delivery_proof_does_not_affect_proof_size() { + let proof_size = PreComputedSize(8 * 1024); + let weight_when_1k_messages_confirmed = W::receive_messages_delivery_proof_weight( + &proof_size, + &UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1024, + last_delivered_nonce: 1, + }, + ); + let weight_when_2k_messages_confirmed = W::receive_messages_delivery_proof_weight( + &proof_size, + &UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 2048, + last_delivered_nonce: 1, + }, + ); + + ensure_weight_components_are_not_zero(weight_when_1k_messages_confirmed); + ensure_weight_components_are_not_zero(weight_when_2k_messages_confirmed); + ensure_proof_size_is_the_same( + weight_when_1k_messages_confirmed, + weight_when_2k_messages_confirmed, + "More messages in delivery proof does not affect values that we read from our storage", + ); +} + +/// Panics if either Weight' `proof_size` or `ref_time` are zero. +fn ensure_weight_components_are_not_zero(weight: Weight) { + assert_ne!(weight.ref_time(), 0); + assert_ne!(weight.proof_size(), 0); +} + +/// Panics if `proof_size` of `weight1` is not equal to `proof_size` of `weight2`. +fn ensure_proof_size_is_the_same(weight1: Weight, weight2: Weight, msg: &str) { + assert_eq!( + weight1.proof_size(), + weight2.proof_size(), + "{msg}: {} must be equal to {}", + weight1.proof_size(), + weight2.proof_size(), + ); +} + +/// Extended weight info. +pub trait WeightInfoExt: WeightInfo { + /// Size of proof that is already included in the single message delivery weight. + /// + /// The message submitter (at source chain) has already covered this cost. But there are two + /// factors that may increase proof size: (1) the message size may be larger than predefined + /// and (2) relayer may add extra trie nodes to the proof. So if proof size is larger than + /// this value, we're going to charge relayer for that. + fn expected_extra_storage_proof_size() -> u32; + + // Functions that are directly mapped to extrinsics weights. + + /// Weight of message delivery extrinsic. + fn receive_messages_proof_weight( + proof: &impl Size, + messages_count: u32, + dispatch_weight: Weight, + ) -> Weight { + // basic components of extrinsic weight + let transaction_overhead = Self::receive_messages_proof_overhead(); + let outbound_state_delivery_weight = + Self::receive_messages_proof_outbound_lane_state_overhead(); + let messages_delivery_weight = + Self::receive_messages_proof_messages_overhead(MessageNonce::from(messages_count)); + let messages_dispatch_weight = dispatch_weight; + + // proof size overhead weight + let expected_proof_size = EXPECTED_DEFAULT_MESSAGE_LENGTH + .saturating_mul(messages_count.saturating_sub(1)) + .saturating_add(Self::expected_extra_storage_proof_size()); + let actual_proof_size = proof.size(); + let proof_size_overhead = Self::storage_proof_size_overhead( + actual_proof_size.saturating_sub(expected_proof_size), + ); + + transaction_overhead + .saturating_add(outbound_state_delivery_weight) + .saturating_add(messages_delivery_weight) + .saturating_add(messages_dispatch_weight) + .saturating_add(proof_size_overhead) + } + + /// Weight of confirmation delivery extrinsic. + fn receive_messages_delivery_proof_weight( + proof: &impl Size, + relayers_state: &UnrewardedRelayersState, + ) -> Weight { + // basic components of extrinsic weight + let transaction_overhead = Self::receive_messages_delivery_proof_overhead(); + let messages_overhead = + Self::receive_messages_delivery_proof_messages_overhead(relayers_state.total_messages); + let relayers_overhead = Self::receive_messages_delivery_proof_relayers_overhead( + relayers_state.unrewarded_relayer_entries, + ); + + // proof size overhead weight + let expected_proof_size = Self::expected_extra_storage_proof_size(); + let actual_proof_size = proof.size(); + let proof_size_overhead = Self::storage_proof_size_overhead( + actual_proof_size.saturating_sub(expected_proof_size), + ); + + transaction_overhead + .saturating_add(messages_overhead) + .saturating_add(relayers_overhead) + .saturating_add(proof_size_overhead) + } + + // Functions that are used by extrinsics weights formulas. + + /// Returns weight overhead of message delivery transaction (`receive_messages_proof`). + fn receive_messages_proof_overhead() -> Weight { + let weight_of_two_messages_and_two_tx_overheads = + Self::receive_single_message_proof().saturating_mul(2); + let weight_of_two_messages_and_single_tx_overhead = Self::receive_two_messages_proof(); + weight_of_two_messages_and_two_tx_overheads + .saturating_sub(weight_of_two_messages_and_single_tx_overhead) + } + + /// Returns weight that needs to be accounted when receiving given a number of messages with + /// message delivery transaction (`receive_messages_proof`). + fn receive_messages_proof_messages_overhead(messages: MessageNonce) -> Weight { + let weight_of_two_messages_and_single_tx_overhead = Self::receive_two_messages_proof(); + let weight_of_single_message_and_single_tx_overhead = Self::receive_single_message_proof(); + weight_of_two_messages_and_single_tx_overhead + .saturating_sub(weight_of_single_message_and_single_tx_overhead) + .saturating_mul(messages as _) + } + + /// Returns weight that needs to be accounted when message delivery transaction + /// (`receive_messages_proof`) is carrying outbound lane state proof. + fn receive_messages_proof_outbound_lane_state_overhead() -> Weight { + let weight_of_single_message_and_lane_state = + Self::receive_single_message_proof_with_outbound_lane_state(); + let weight_of_single_message = Self::receive_single_message_proof(); + weight_of_single_message_and_lane_state.saturating_sub(weight_of_single_message) + } + + /// Returns weight overhead of delivery confirmation transaction + /// (`receive_messages_delivery_proof`). + fn receive_messages_delivery_proof_overhead() -> Weight { + let weight_of_two_messages_and_two_tx_overheads = + Self::receive_delivery_proof_for_single_message().saturating_mul(2); + let weight_of_two_messages_and_single_tx_overhead = + Self::receive_delivery_proof_for_two_messages_by_single_relayer(); + weight_of_two_messages_and_two_tx_overheads + .saturating_sub(weight_of_two_messages_and_single_tx_overhead) + } + + /// Returns weight that needs to be accounted when receiving confirmations for given a number of + /// messages with delivery confirmation transaction (`receive_messages_delivery_proof`). + fn receive_messages_delivery_proof_messages_overhead(messages: MessageNonce) -> Weight { + let weight_of_two_messages = + Self::receive_delivery_proof_for_two_messages_by_single_relayer(); + let weight_of_single_message = Self::receive_delivery_proof_for_single_message(); + weight_of_two_messages + .saturating_sub(weight_of_single_message) + .saturating_mul(messages as _) + } + + /// Returns weight that needs to be accounted when receiving confirmations for given a number of + /// relayers entries with delivery confirmation transaction (`receive_messages_delivery_proof`). + fn receive_messages_delivery_proof_relayers_overhead(relayers: MessageNonce) -> Weight { + let weight_of_two_messages_by_two_relayers = + Self::receive_delivery_proof_for_two_messages_by_two_relayers(); + let weight_of_two_messages_by_single_relayer = + Self::receive_delivery_proof_for_two_messages_by_single_relayer(); + weight_of_two_messages_by_two_relayers + .saturating_sub(weight_of_two_messages_by_single_relayer) + .saturating_mul(relayers as _) + } + + /// Returns weight that needs to be accounted when storage proof of given size is received + /// (either in `receive_messages_proof` or `receive_messages_delivery_proof`). + /// + /// **IMPORTANT**: this overhead is already included in the 'base' transaction cost - e.g. proof + /// size depends on messages count or number of entries in the unrewarded relayers set. So this + /// shouldn't be added to cost of transaction, but instead should act as a minimal cost that the + /// relayer must pay when it relays proof of given size (even if cost based on other parameters + /// is less than that cost). + fn storage_proof_size_overhead(proof_size: u32) -> Weight { + let proof_size_in_bytes = proof_size; + let byte_weight = (Self::receive_single_message_proof_16_kb() - + Self::receive_single_message_proof_1_kb()) / + (15 * 1024); + proof_size_in_bytes * byte_weight + } + + // Functions that may be used by runtime developers. + + /// Returns dispatch weight of message of given size. + /// + /// This function would return correct value only if your runtime is configured to run + /// `receive_single_message_proof_with_dispatch` benchmark. See its requirements for + /// details. + fn message_dispatch_weight(message_size: u32) -> Weight { + // There may be a tiny overweight/underweight here, because we don't account how message + // size affects all steps before dispatch. But the effect should be small enough and we + // may ignore it. + Self::receive_single_message_proof_with_dispatch(message_size) + .saturating_sub(Self::receive_single_message_proof()) + } +} + +impl WeightInfoExt for () { + fn expected_extra_storage_proof_size() -> u32 { + EXTRA_STORAGE_PROOF_SIZE + } +} + +impl WeightInfoExt for crate::weights::BridgeWeight { + fn expected_extra_storage_proof_size() -> u32 { + EXTRA_STORAGE_PROOF_SIZE + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{mock::TestRuntime, weights::BridgeWeight}; + + #[test] + fn ensure_default_weights_are_correct() { + ensure_weights_are_correct::>(); + } +} diff --git a/modules/parachains/Cargo.toml b/modules/parachains/Cargo.toml new file mode 100644 index 00000000000..39c3ba626aa --- /dev/null +++ b/modules/parachains/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "pallet-bridge-parachains" +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 } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +# Bridge Dependencies + +bp-header-chain = { path = "../../primitives/header-chain", default-features = false } +bp-parachains = { path = "../../primitives/parachains", default-features = false } +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +pallet-bridge-grandpa = { path = "../grandpa", default-features = false } + +# Substrate Dependencies + +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +bp-header-chain = { path = "../../primitives/header-chain" } +bp-test-utils = { path = "../../primitives/test-utils" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-parachains/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "frame-benchmarking/std", + "log/std", + "pallet-bridge-grandpa/std", + "scale-info/std", + "sp-runtime/std", + "sp-std/std", + "sp-trie/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/parachains/README.md b/modules/parachains/README.md new file mode 100644 index 00000000000..5982c65ad31 --- /dev/null +++ b/modules/parachains/README.md @@ -0,0 +1,90 @@ +# Bridge Parachains Pallet + +The bridge parachains pallet is a light client for one or several parachains of the bridged relay chain. +It serves as a source of finalized parachain headers and is used when you need to build a bridge with +a parachain. + +The pallet requires [bridge GRANDPA pallet](../grandpa/) to be deployed at the same chain - it is used +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. + +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, +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. + +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 +[bridge GRANDPA pallet](../grandpa/). Once the proof is verified, the pallet knows that the given parachain +header has been finalized by the relay chain. The parachain header fields may then be used to verify storage +proofs, coming from the parachain. This allows the pallet to be used e.g. as a source of finality for the messages +pallet. + +## Pallet Operations + +The main entrypoint of the pallet is the `submit_parachain_heads` call. It has three arguments: + +- storage proof of parachain heads from the `Heads` map; + +- parachain identifiers and hashes of their heads from the storage proof; + +- the relay block, at which the storage proof has been generated. + +The pallet may track multiple parachains. And the parachains may use different primitives - one may use 128-bit block +numbers, other - 32-bit. To avoid extra decode operations, the pallet is using relay chain block number to order +parachain headers. Any finalized descendant of finalized relay block `RB`, which has parachain block `PB` in +its `Heads` map, is guaranteed to have either `PB`, or its descendant. So parachain block number grows with relay +block number. + +The pallet may reject parachain head if it already knows better (or the same) head. In addition, pallet rejects +heads of untracked parachains. + +The pallet doesn't track anything behind parachain heads. So it requires no initialization - it is ready to accept +headers right after deployment. + +## Non-Essential Functionality + +There may be a special account in every runtime where the bridge parachains 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 set_operating_mode()`: the module owner (or sudo account) may call this function to stop all + module operations. After this call, all finality proofs will be rejected until further `set_operating_mode` call'. + This call may be used when something extraordinary happens with the bridge. + +If pallet owner is not defined, the governance may be used to make those calls. + +## Signed Extension to Reject Obsolete Headers + +It'd be better for anyone (for chain and for submitters) to reject all transactions that are submitting +already known parachain heads to the pallet. This way, we leave block space to other useful transactions and +we don't charge concurrent submitters for their honest actions. + +To deal with that, we have a [signed extension](./src/call_ext) that may be added to the runtime. +It does exactly what is required - rejects all transactions with already known heads. The submitter +pays nothing for such transactions - they're simply removed from the transaction pool, when the block +is built. + +The signed extension, however, is a bit limited - it only works with transactions that provide single +parachain head. So it won't work with multiple parachain heads transactions. This fits our needs +for [Kusama <> Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md). If you need to deal +with other transaction formats, you may implement similar extension for your runtime. + +You may also take a look at the [`generate_bridge_reject_obsolete_headers_and_messages`](../../bin/runtime-common/src/lib.rs) +macro that bundles several similar signed extensions in a single one. + +## Parachains Finality Relay + +We have an offchain actor, who is watching for new parachain heads and submits them to the bridged chain. +It is the parachains relay - you may look at the [crate level documentation and the code](../../relays/parachains/). diff --git a/modules/parachains/src/benchmarking.rs b/modules/parachains/src/benchmarking.rs new file mode 100644 index 00000000000..59c4642cde9 --- /dev/null +++ b/modules/parachains/src/benchmarking.rs @@ -0,0 +1,116 @@ +// Copyright 2019-2021 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 . + +//! Parachains finality pallet benchmarking. + +use crate::{ + weights_ext::DEFAULT_PARACHAIN_HEAD_SIZE, Call, RelayBlockHash, RelayBlockHasher, + RelayBlockNumber, +}; + +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use bp_runtime::StorageProofSize; +use frame_benchmarking::{account, benchmarks_instance_pallet}; +use frame_system::RawOrigin; +use sp_std::prelude::*; + +/// Pallet we're benchmarking here. +pub struct Pallet, I: 'static = ()>(crate::Pallet); + +/// Trait that must be implemented by runtime to benchmark the parachains finality pallet. +pub trait Config: crate::Config { + /// Returns vector of supported parachains. + fn parachains() -> Vec; + /// Generate parachain heads proof and prepare environment for verifying this proof. + fn prepare_parachain_heads_proof( + parachains: &[ParaId], + parachain_head_size: u32, + proof_size: StorageProofSize, + ) -> (RelayBlockNumber, RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>); +} + +benchmarks_instance_pallet! { + where_clause { + where + >::BridgedChain: + bp_runtime::Chain< + BlockNumber = RelayBlockNumber, + Hash = RelayBlockHash, + Hasher = RelayBlockHasher, + >, + } + + // Benchmark `submit_parachain_heads` extrinsic with different number of parachains. + submit_parachain_heads_with_n_parachains { + let p in 1..(T::parachains().len() + 1) as u32; + + let sender = account("sender", 0, 0); + let mut parachains = T::parachains(); + let _ = if p <= parachains.len() as u32 { + parachains.split_off(p as usize) + } else { + Default::default() + }; + log::trace!(target: crate::LOG_TARGET, "=== {:?}", parachains.len()); + let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( + ¶chains, + DEFAULT_PARACHAIN_HEAD_SIZE, + StorageProofSize::Minimal(0), + ); + let at_relay_block = (relay_block_number, relay_block_hash); + }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) + verify { + for parachain in parachains { + assert!(crate::Pallet::::best_parachain_head(parachain).is_some()); + } + } + + // Benchmark `submit_parachain_heads` extrinsic with 1kb proof size. + submit_parachain_heads_with_1kb_proof { + let sender = account("sender", 0, 0); + let parachains = vec![T::parachains()[0]]; + let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( + ¶chains, + DEFAULT_PARACHAIN_HEAD_SIZE, + StorageProofSize::HasLargeLeaf(1024), + ); + let at_relay_block = (relay_block_number, relay_block_hash); + }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) + verify { + for parachain in parachains { + assert!(crate::Pallet::::best_parachain_head(parachain).is_some()); + } + } + + // Benchmark `submit_parachain_heads` extrinsic with 16kb proof size. + submit_parachain_heads_with_16kb_proof { + let sender = account("sender", 0, 0); + let parachains = vec![T::parachains()[0]]; + let (relay_block_number, relay_block_hash, parachain_heads_proof, parachains_heads) = T::prepare_parachain_heads_proof( + ¶chains, + DEFAULT_PARACHAIN_HEAD_SIZE, + StorageProofSize::HasLargeLeaf(16 * 1024), + ); + let at_relay_block = (relay_block_number, relay_block_hash); + }: submit_parachain_heads(RawOrigin::Signed(sender), at_relay_block, parachains_heads, parachain_heads_proof) + verify { + for parachain in parachains { + assert!(crate::Pallet::::best_parachain_head(parachain).is_some()); + } + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) +} diff --git a/modules/parachains/src/call_ext.rs b/modules/parachains/src/call_ext.rs new file mode 100644 index 00000000000..ee3770146c2 --- /dev/null +++ b/modules/parachains/src/call_ext.rs @@ -0,0 +1,243 @@ +// Copyright 2021 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 . + +use crate::{Config, Pallet, RelayBlockNumber}; +use bp_parachains::BestParaHeadHash; +use bp_polkadot_core::parachains::{ParaHash, ParaId}; +use frame_support::{dispatch::CallableCallFor, traits::IsSubType, RuntimeDebug}; +use sp_runtime::transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}; + +/// Info about a `SubmitParachainHeads` call which tries to update a single parachain. +#[derive(PartialEq, RuntimeDebug)] +pub struct SubmitParachainHeadsInfo { + /// Number of the finalized relay block that has been used to prove parachain finality. + pub at_relay_block_number: RelayBlockNumber, + /// Parachain identifier. + pub para_id: ParaId, + /// Hash of the bundled parachain head. + pub para_head_hash: ParaHash, +} + +/// Helper struct that provides methods for working with the `SubmitParachainHeads` call. +pub struct SubmitParachainHeadsHelper, I: 'static> { + _phantom_data: sp_std::marker::PhantomData<(T, I)>, +} + +impl, I: 'static> SubmitParachainHeadsHelper { + /// Check if the para head provided by the `SubmitParachainHeads` is better than the best one + /// we know. + pub fn is_obsolete(update: &SubmitParachainHeadsInfo) -> bool { + let stored_best_head = match crate::ParasInfo::::get(update.para_id) { + Some(stored_best_head) => stored_best_head, + None => return false, + }; + + if stored_best_head.best_head_hash.at_relay_block_number >= update.at_relay_block_number { + log::trace!( + target: crate::LOG_TARGET, + "The parachain head can't be updated. The parachain head for {:?} \ + was already updated at better relay chain block {} >= {}.", + update.para_id, + stored_best_head.best_head_hash.at_relay_block_number, + update.at_relay_block_number + ); + return true + } + + if stored_best_head.best_head_hash.head_hash == update.para_head_hash { + log::trace!( + target: crate::LOG_TARGET, + "The parachain head can't be updated. The parachain head hash for {:?} \ + was already updated to {} at block {} < {}.", + update.para_id, + update.para_head_hash, + stored_best_head.best_head_hash.at_relay_block_number, + update.at_relay_block_number + ); + return true + } + + false + } + + /// Check if the `SubmitParachainHeads` was successfully executed. + pub fn was_successful(update: &SubmitParachainHeadsInfo) -> bool { + match crate::ParasInfo::::get(update.para_id) { + Some(stored_best_head) => + stored_best_head.best_head_hash == + BestParaHeadHash { + at_relay_block_number: update.at_relay_block_number, + head_hash: update.para_head_hash, + }, + None => false, + } + } +} + +/// Trait representing a call that is a sub type of this pallet's call. +pub trait CallSubType, I: 'static>: + IsSubType, T>> +{ + /// Create a new instance of `SubmitParachainHeadsInfo` from a `SubmitParachainHeads` call with + /// one single parachain entry. + fn one_entry_submit_parachain_heads_info(&self) -> Option { + if let Some(crate::Call::::submit_parachain_heads { + ref at_relay_block, + ref parachains, + .. + }) = self.is_sub_type() + { + if let &[(para_id, para_head_hash)] = parachains.as_slice() { + return Some(SubmitParachainHeadsInfo { + at_relay_block_number: at_relay_block.0, + para_id, + para_head_hash, + }) + } + } + + None + } + + /// Create a new instance of `SubmitParachainHeadsInfo` from a `SubmitParachainHeads` call with + /// one single parachain entry, if the entry is for the provided parachain id. + fn submit_parachain_heads_info_for(&self, para_id: u32) -> Option { + self.one_entry_submit_parachain_heads_info() + .filter(|update| update.para_id.0 == para_id) + } + + /// Validate parachain heads in order to avoid "mining" transactions that provide + /// outdated bridged parachain heads. Without this validation, even honest relayers + /// may lose their funds if there are multiple relays running and submitting the + /// same information. + /// + /// This validation only works with transactions that are updating single parachain + /// head. We can't use unbounded validation - it may take too long and either break + /// block production, or "eat" significant portion of block production time literally + /// for nothing. In addition, the single-parachain-head-per-transaction is how the + /// pallet will be used in our environment. + fn check_obsolete_submit_parachain_heads(&self) -> TransactionValidity + where + Self: Sized, + { + let update = match self.one_entry_submit_parachain_heads_info() { + Some(update) => update, + None => return Ok(ValidTransaction::default()), + }; + + if SubmitParachainHeadsHelper::::is_obsolete(&update) { + return InvalidTransaction::Stale.into() + } + + Ok(ValidTransaction::default()) + } +} + +impl CallSubType for T::RuntimeCall +where + T: Config, + T::RuntimeCall: IsSubType, T>>, +{ +} + +#[cfg(test)] +mod tests { + use crate::{ + mock::{run_test, RuntimeCall, TestRuntime}, + CallSubType, ParaInfo, ParasInfo, RelayBlockNumber, + }; + use bp_parachains::BestParaHeadHash; + use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; + + fn validate_submit_parachain_heads( + num: RelayBlockNumber, + parachains: Vec<(ParaId, ParaHash)>, + ) -> bool { + RuntimeCall::Parachains(crate::Call::::submit_parachain_heads { + at_relay_block: (num, Default::default()), + parachains, + parachain_heads_proof: ParaHeadsProof(Vec::new()), + }) + .check_obsolete_submit_parachain_heads() + .is_ok() + } + + fn sync_to_relay_header_10() { + ParasInfo::::insert( + ParaId(1), + ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 10, + head_hash: [1u8; 32].into(), + }, + next_imported_hash_position: 0, + }, + ); + } + + #[test] + fn extension_rejects_header_from_the_obsolete_relay_block() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#5 => tx is + // rejected + sync_to_relay_header_10(); + assert!(!validate_submit_parachain_heads(5, vec![(ParaId(1), [1u8; 32].into())])); + }); + } + + #[test] + fn extension_rejects_header_from_the_same_relay_block() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#10 => tx is + // rejected + sync_to_relay_header_10(); + assert!(!validate_submit_parachain_heads(10, vec![(ParaId(1), [1u8; 32].into())])); + }); + } + + #[test] + fn extension_rejects_header_from_new_relay_block_with_same_hash() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#10 => tx is + // rejected + sync_to_relay_header_10(); + assert!(!validate_submit_parachain_heads(20, vec![(ParaId(1), [1u8; 32].into())])); + }); + } + + #[test] + fn extension_accepts_new_header() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#15 => tx is + // accepted + sync_to_relay_header_10(); + assert!(validate_submit_parachain_heads(15, vec![(ParaId(1), [2u8; 32].into())])); + }); + } + + #[test] + fn extension_accepts_if_more_than_one_parachain_is_submitted() { + run_test(|| { + // when current best finalized is #10 and we're trying to import header#5, but another + // parachain head is also supplied => tx is accepted + sync_to_relay_header_10(); + assert!(validate_submit_parachain_heads( + 5, + vec![(ParaId(1), [1u8; 32].into()), (ParaId(2), [1u8; 32].into())] + )); + }); + } +} diff --git a/modules/parachains/src/lib.rs b/modules/parachains/src/lib.rs new file mode 100644 index 00000000000..6c89b09513c --- /dev/null +++ b/modules/parachains/src/lib.rs @@ -0,0 +1,1609 @@ +// Copyright 2021 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 . + +//! Parachains finality module. +//! +//! This module needs to be deployed with GRANDPA module, which is syncing relay +//! chain blocks. The main entry point of this module is `submit_parachain_heads`, which +//! accepts storage proof of some parachain `Heads` entries from bridged relay chain. +//! It requires corresponding relay headers to be already synced. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use weights::WeightInfo; +pub use weights_ext::WeightInfoExt; + +use bp_header_chain::{HeaderChain, HeaderChainError}; +use bp_parachains::{parachain_head_storage_key_at_source, ParaInfo, ParaStoredHeaderData}; +use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; +use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain, StorageProofError}; +use frame_support::dispatch::PostDispatchInfo; +use sp_std::{marker::PhantomData, vec::Vec}; + +#[cfg(feature = "runtime-benchmarks")] +use bp_parachains::ParaStoredHeaderDataBuilder; +#[cfg(feature = "runtime-benchmarks")] +use bp_runtime::HeaderOf; +#[cfg(feature = "runtime-benchmarks")] +use codec::Encode; + +// Re-export in crate namespace for `construct_runtime!`. +pub use call_ext::*; +pub use pallet::*; + +pub mod weights; +pub mod weights_ext; + +#[cfg(feature = "runtime-benchmarks")] +pub mod benchmarking; + +mod call_ext; +#[cfg(test)] +mod mock; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-parachains"; + +/// Block hash of the bridged relay chain. +pub type RelayBlockHash = bp_polkadot_core::Hash; +/// Block number of the bridged relay chain. +pub type RelayBlockNumber = bp_polkadot_core::BlockNumber; +/// Hasher of the bridged relay chain. +pub type RelayBlockHasher = bp_polkadot_core::Hasher; + +/// Artifacts of the parachains head update. +struct UpdateParachainHeadArtifacts { + /// New best head of the parachain. + pub best_head: ParaInfo, + /// If `true`, some old parachain head has been pruned during update. + pub prune_happened: bool, +} + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use bp_parachains::{ + BestParaHeadHash, ImportedParaHeadsKeyProvider, ParaStoredHeaderDataBuilder, + ParasInfoKeyProvider, + }; + use bp_runtime::{ + BasicOperatingMode, BoundedStorageValue, OwnedBridgeModule, StorageDoubleMapKeyProvider, + StorageMapKeyProvider, + }; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + /// Stored parachain head data of given parachains pallet. + pub type StoredParaHeadDataOf = + BoundedStorageValue<>::MaxParaHeadDataSize, ParaStoredHeaderData>; + /// Weight info of the given parachains pallet. + pub type WeightInfoOf = >::WeightInfo; + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// The caller has provided head of parachain that the pallet is not configured to track. + UntrackedParachainRejected { parachain: ParaId }, + /// The caller has declared that he has provided given parachain head, but it is missing + /// from the storage proof. + MissingParachainHead { parachain: ParaId }, + /// The caller has provided parachain head hash that is not matching the hash read from the + /// storage proof. + IncorrectParachainHeadHash { + parachain: ParaId, + parachain_head_hash: ParaHash, + actual_parachain_head_hash: ParaHash, + }, + /// The caller has provided obsolete parachain head, which is already known to the pallet. + RejectedObsoleteParachainHead { parachain: ParaId, parachain_head_hash: ParaHash }, + /// The caller has provided parachain head that exceeds the maximal configured head size. + RejectedLargeParachainHead { + parachain: ParaId, + parachain_head_hash: ParaHash, + parachain_head_size: u32, + }, + /// Parachain head has been updated. + UpdatedParachainHead { parachain: ParaId, parachain_head_hash: ParaHash }, + } + + #[pallet::error] + pub enum Error { + /// Relay chain block hash is unknown to us. + UnknownRelayChainBlock, + /// The number of stored relay block is different from what the relayer has provided. + InvalidRelayChainBlockNumber, + /// Error generated by a method defined in `bp-header-chain`. + HeaderChain(HeaderChainError), + /// Given parachain head is unknown. + UnknownParaHead, + /// The storage proof doesn't contains storage root. So it is invalid for given header. + StorageRootMismatch, + /// Failed to extract state root from given parachain head. + FailedToExtractStateRoot, + /// Error generated by the `OwnedBridgeModule` trait. + BridgeModule(bp_runtime::OwnedBridgeModuleError), + } + + /// Convenience trait for defining `BridgedChain` bounds. + pub trait BoundedBridgeGrandpaConfig: + pallet_bridge_grandpa::Config + { + type BridgedRelayChain: Chain< + BlockNumber = RelayBlockNumber, + Hash = RelayBlockHash, + Hasher = RelayBlockHasher, + >; + } + + impl BoundedBridgeGrandpaConfig for T + where + T: pallet_bridge_grandpa::Config, + T::BridgedChain: + Chain, + { + type BridgedRelayChain = T::BridgedChain; + } + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: + BoundedBridgeGrandpaConfig + { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + /// Benchmarks results from runtime we're plugged into. + type WeightInfo: WeightInfoExt; + + /// Instance of bridges GRANDPA pallet (within this runtime) that this pallet is linked to. + /// + /// The GRANDPA pallet instance must be configured to import headers of relay chain that + /// we're interested in. + type BridgesGrandpaPalletInstance: 'static; + + /// Name of the original `paras` pallet in the `construct_runtime!()` call at the bridged + /// chain. + /// + /// Please keep in mind that this should be the name of the `runtime_parachains::paras` + /// pallet from polkadot repository, not the `pallet-bridge-parachains`. + #[pallet::constant] + type ParasPalletName: Get<&'static str>; + + /// Parachain head data builder. + /// + /// We never store parachain heads here, since they may be too big (e.g. because of large + /// digest items). Instead we're using the same approach as `pallet-bridge-grandpa` + /// pallet - we are only storing `bp_messages::StoredHeaderData` (number and state root), + /// which is enough for our applications. However, we work with different parachains here + /// and they can use different primitives (for block numbers and hash). So we can't store + /// it directly. Instead, we're storing `bp_messages::StoredHeaderData` in SCALE-encoded + /// form, wrapping it into `bp_parachains::ParaStoredHeaderData`. + /// + /// This builder helps to convert from `HeadData` to `bp_parachains::ParaStoredHeaderData`. + type ParaStoredHeaderDataBuilder: ParaStoredHeaderDataBuilder; + + /// Maximal number of single parachain heads to keep in the storage. + /// + /// The setting is there to prevent growing the on-chain state indefinitely. Note + /// the setting does not relate to parachain block numbers - we will simply keep as much + /// items in the storage, so it doesn't guarantee any fixed timeframe for heads. + /// + /// Incautious change of this constant may lead to orphan entries in the runtime storage. + #[pallet::constant] + type HeadsToKeep: Get; + + /// Maximal size (in bytes) of the SCALE-encoded parachain head data + /// (`bp_parachains::ParaStoredHeaderData`). + /// + /// Keep in mind that the size of any tracked parachain header data must not exceed this + /// value. So if you're going to track multiple parachains, one of which is using large + /// hashes, you shall choose this maximal value. + /// + /// There's no mandatory headers in this pallet, so it can't stall if there's some header + /// that exceeds this bound. + #[pallet::constant] + type MaxParaHeadDataSize: Get; + } + + /// Optional pallet owner. + /// + /// Pallet owner has a right to halt all pallet operations and then resume them. If it is + /// `None`, then there are no direct ways to halt/resume pallet operations, but other + /// runtime methods may still be used to do that (i.e. democracy::referendum to update halt + /// flag directly or call the `halt_operations`). + #[pallet::storage] + pub type PalletOwner, I: 'static = ()> = + StorageValue<_, T::AccountId, OptionQuery>; + + /// The current operating mode of the pallet. + /// + /// Depending on the mode either all, or no transactions will be allowed. + #[pallet::storage] + pub type PalletOperatingMode, I: 'static = ()> = + StorageValue<_, BasicOperatingMode, ValueQuery>; + + /// Parachains info. + /// + /// Contains the following info: + /// - best parachain head hash + /// - the head of the `ImportedParaHashes` ring buffer + #[pallet::storage] + pub type ParasInfo, I: 'static = ()> = StorageMap< + Hasher = ::Hasher, + Key = ::Key, + Value = ::Value, + QueryKind = OptionQuery, + OnEmpty = GetDefault, + MaxValues = MaybeMaxParachains, + >; + + /// State roots of parachain heads which have been imported into the pallet. + #[pallet::storage] + pub type ImportedParaHeads, I: 'static = ()> = StorageDoubleMap< + Hasher1 = ::Hasher1, + Key1 = ::Key1, + Hasher2 = ::Hasher2, + Key2 = ::Key2, + Value = StoredParaHeadDataOf, + QueryKind = OptionQuery, + OnEmpty = GetDefault, + MaxValues = MaybeMaxTotalParachainHashes, + >; + + /// A ring buffer of imported parachain head hashes. Ordered by the insertion time. + #[pallet::storage] + pub(super) type ImportedParaHashes, I: 'static = ()> = StorageDoubleMap< + Hasher1 = Blake2_128Concat, + Key1 = ParaId, + Hasher2 = Twox64Concat, + Key2 = u32, + Value = ParaHash, + QueryKind = OptionQuery, + OnEmpty = GetDefault, + MaxValues = MaybeMaxTotalParachainHashes, + >; + + #[pallet::pallet] + pub struct Pallet(PhantomData<(T, I)>); + + impl, I: 'static> OwnedBridgeModule for Pallet { + const LOG_TARGET: &'static str = LOG_TARGET; + type OwnerStorage = PalletOwner; + type OperatingMode = BasicOperatingMode; + type OperatingModeStorage = PalletOperatingMode; + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Submit proof of one or several parachain heads. + /// + /// The proof is supposed to be proof of some `Heads` entries from the + /// `polkadot-runtime-parachains::paras` pallet instance, deployed at the bridged chain. + /// The proof is supposed to be crafted at the `relay_header_hash` that must already be + /// imported by corresponding GRANDPA pallet at this chain. + /// + /// The call fails if: + /// + /// - the pallet is halted; + /// + /// - the relay chain block `at_relay_block` is not imported by the associated bridge + /// GRANDPA pallet. + /// + /// The call may succeed, but some heads may not be updated e.g. because pallet knows + /// better head or it isn't tracked by the pallet. + #[pallet::call_index(0)] + #[pallet::weight(WeightInfoOf::::submit_parachain_heads_weight( + T::DbWeight::get(), + parachain_heads_proof, + parachains.len() as _, + ))] + pub fn submit_parachain_heads( + _origin: OriginFor, + at_relay_block: (RelayBlockNumber, RelayBlockHash), + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> DispatchResultWithPostInfo { + Self::ensure_not_halted().map_err(Error::::BridgeModule)?; + + // we'll need relay chain header to verify that parachains heads are always increasing. + let (relay_block_number, relay_block_hash) = at_relay_block; + let relay_block = pallet_bridge_grandpa::ImportedHeaders::< + T, + T::BridgesGrandpaPalletInstance, + >::get(relay_block_hash) + .ok_or(Error::::UnknownRelayChainBlock)?; + ensure!( + relay_block.number == relay_block_number, + Error::::InvalidRelayChainBlockNumber, + ); + + // now parse storage proof and read parachain heads + let mut actual_weight = WeightInfoOf::::submit_parachain_heads_weight( + T::DbWeight::get(), + ¶chain_heads_proof, + parachains.len() as _, + ); + + pallet_bridge_grandpa::Pallet::::parse_finalized_storage_proof( + relay_block_hash, + parachain_heads_proof.0, + move |mut storage| { + for (parachain, parachain_head_hash) in parachains { + let parachain_head = match Pallet::::read_parachain_head(&mut storage, parachain) { + Ok(Some(parachain_head)) => parachain_head, + Ok(None) => { + log::trace!( + target: LOG_TARGET, + "The head of parachain {:?} is None. {}", + parachain, + if ParasInfo::::contains_key(parachain) { + "Looks like it is not yet registered at the source relay chain" + } else { + "Looks like it has been deregistered from the source relay chain" + }, + ); + Self::deposit_event(Event::MissingParachainHead { parachain }); + continue; + }, + Err(e) => { + log::trace!( + target: LOG_TARGET, + "The read of head of parachain {:?} has failed: {:?}", + parachain, + e, + ); + Self::deposit_event(Event::MissingParachainHead { parachain }); + continue; + }, + }; + + // if relayer has specified invalid parachain head hash, ignore the head + // (this isn't strictly necessary, but better safe than sorry) + let actual_parachain_head_hash = parachain_head.hash(); + if parachain_head_hash != actual_parachain_head_hash { + log::trace!( + target: LOG_TARGET, + "The submitter has specified invalid parachain {:?} head hash: {:?} vs {:?}", + parachain, + parachain_head_hash, + actual_parachain_head_hash, + ); + Self::deposit_event(Event::IncorrectParachainHeadHash { + parachain, + parachain_head_hash, + actual_parachain_head_hash, + }); + continue; + } + + // convert from parachain head into stored parachain head data + let parachain_head_data = match T::ParaStoredHeaderDataBuilder::try_build( + parachain, + ¶chain_head, + ) { + Some(parachain_head_data) => parachain_head_data, + None => { + log::trace!( + target: LOG_TARGET, + "The head of parachain {:?} has been provided, but it is not tracked by the pallet", + parachain, + ); + Self::deposit_event(Event::UntrackedParachainRejected { parachain }); + continue; + }, + }; + + let update_result: Result<_, ()> = ParasInfo::::try_mutate(parachain, |stored_best_head| { + let artifacts = Pallet::::update_parachain_head( + parachain, + stored_best_head.take(), + relay_block_number, + parachain_head_data, + parachain_head_hash, + )?; + *stored_best_head = Some(artifacts.best_head); + Ok(artifacts.prune_happened) + }); + + // we're refunding weight if update has not happened and if pruning has not happened + let is_update_happened = matches!(update_result, Ok(_)); + if !is_update_happened { + actual_weight = actual_weight + .saturating_sub(WeightInfoOf::::parachain_head_storage_write_weight(T::DbWeight::get())); + } + let is_prune_happened = matches!(update_result, Ok(true)); + if !is_prune_happened { + actual_weight = actual_weight + .saturating_sub(WeightInfoOf::::parachain_head_pruning_weight(T::DbWeight::get())); + } + } + + // even though we may have accepted some parachain heads, we can't allow relayers to submit + // proof with unused trie nodes + // => treat this as an error + // + // (we can throw error here, because now all our calls are transactional) + storage.ensure_no_unused_nodes() + }, + ) + .and_then(|r| r.map_err(HeaderChainError::StorageProof)) + .map_err(|e| { + log::trace!(target: LOG_TARGET, "Parachain heads storage proof is invalid: {:?}", e); + Error::::HeaderChain(e) + })?; + + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee: Pays::Yes }) + } + + /// Change `PalletOwner`. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(1)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_owner(origin: OriginFor, new_owner: Option) -> DispatchResult { + >::set_owner(origin, new_owner) + } + + /// Halt or resume all pallet operations. + /// + /// May only be called either by root, or by `PalletOwner`. + #[pallet::call_index(2)] + #[pallet::weight((T::DbWeight::get().reads_writes(1, 1), DispatchClass::Operational))] + pub fn set_operating_mode( + origin: OriginFor, + operating_mode: BasicOperatingMode, + ) -> DispatchResult { + >::set_operating_mode(origin, operating_mode) + } + } + + impl, I: 'static> Pallet { + /// Get stored parachain info. + pub fn best_parachain_info(parachain: ParaId) -> Option { + ParasInfo::::get(parachain) + } + + /// Get best finalized head data of the given parachain. + pub fn best_parachain_head(parachain: ParaId) -> Option { + let best_para_head_hash = ParasInfo::::get(parachain)?.best_head_hash.head_hash; + ImportedParaHeads::::get(parachain, best_para_head_hash).map(|h| h.into_inner()) + } + + /// Get best finalized head hash of the given parachain. + pub fn best_parachain_head_hash(parachain: ParaId) -> Option { + Some(ParasInfo::::get(parachain)?.best_head_hash.head_hash) + } + + /// Get best finalized head id of the given parachain. + pub fn best_parachain_head_id + Parachain>( + ) -> Result>, codec::Error> { + let parachain = ParaId(C::PARACHAIN_ID); + let best_head_hash = match Self::best_parachain_head_hash(parachain) { + Some(best_head_hash) => best_head_hash, + None => return Ok(None), + }; + let encoded_head = match Self::parachain_head(parachain, best_head_hash) { + Some(encoded_head) => encoded_head, + None => return Ok(None), + }; + encoded_head + .decode_parachain_head_data::() + .map(|data| Some(HeaderId(data.number, best_head_hash))) + } + + /// Get parachain head data with given hash. + pub fn parachain_head(parachain: ParaId, hash: ParaHash) -> Option { + ImportedParaHeads::::get(parachain, hash).map(|h| h.into_inner()) + } + + /// Read parachain head from storage proof. + fn read_parachain_head( + storage: &mut bp_runtime::StorageProofChecker, + parachain: ParaId, + ) -> Result, StorageProofError> { + let parachain_head_key = + parachain_head_storage_key_at_source(T::ParasPalletName::get(), parachain); + storage.read_and_decode_value(parachain_head_key.0.as_ref()) + } + + /// Try to update parachain head. + pub(super) fn update_parachain_head( + parachain: ParaId, + stored_best_head: Option, + new_at_relay_block_number: RelayBlockNumber, + new_head_data: ParaStoredHeaderData, + new_head_hash: ParaHash, + ) -> Result { + // check if head has been already updated at better relay chain block. Without this + // check, we may import heads in random order + let update = SubmitParachainHeadsInfo { + at_relay_block_number: new_at_relay_block_number, + para_id: parachain, + para_head_hash: new_head_hash, + }; + if SubmitParachainHeadsHelper::::is_obsolete(&update) { + Self::deposit_event(Event::RejectedObsoleteParachainHead { + parachain, + parachain_head_hash: new_head_hash, + }); + return Err(()) + } + + // verify that the parachain head data size is <= `MaxParaHeadDataSize` + let updated_head_data = + match StoredParaHeadDataOf::::try_from_inner(new_head_data) { + Ok(updated_head_data) => updated_head_data, + Err(e) => { + log::trace!( + target: LOG_TARGET, + "The parachain head can't be updated. The parachain head data size \ + for {:?} is {}. It exceeds maximal configured size {}.", + parachain, + e.value_size, + e.maximal_size, + ); + + Self::deposit_event(Event::RejectedLargeParachainHead { + parachain, + parachain_head_hash: new_head_hash, + parachain_head_size: e.value_size as _, + }); + + return Err(()) + }, + }; + + let next_imported_hash_position = stored_best_head + .map_or(0, |stored_best_head| stored_best_head.next_imported_hash_position); + + // insert updated best parachain head + let head_hash_to_prune = + ImportedParaHashes::::try_get(parachain, next_imported_hash_position); + let updated_best_para_head = ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: new_at_relay_block_number, + head_hash: new_head_hash, + }, + next_imported_hash_position: (next_imported_hash_position + 1) % + T::HeadsToKeep::get(), + }; + ImportedParaHashes::::insert( + parachain, + next_imported_hash_position, + new_head_hash, + ); + ImportedParaHeads::::insert(parachain, new_head_hash, updated_head_data); + log::trace!( + target: LOG_TARGET, + "Updated head of parachain {:?} to {}", + parachain, + new_head_hash, + ); + + // remove old head + let prune_happened = head_hash_to_prune.is_ok(); + if let Ok(head_hash_to_prune) = head_hash_to_prune { + log::trace!( + target: LOG_TARGET, + "Pruning old head of parachain {:?}: {}", + parachain, + head_hash_to_prune, + ); + ImportedParaHeads::::remove(parachain, head_hash_to_prune); + } + Self::deposit_event(Event::UpdatedParachainHead { + parachain, + parachain_head_hash: new_head_hash, + }); + + Ok(UpdateParachainHeadArtifacts { best_head: updated_best_para_head, prune_happened }) + } + } + + #[pallet::genesis_config] + pub struct GenesisConfig, I: 'static = ()> { + /// Initial pallet operating mode. + pub operating_mode: BasicOperatingMode, + /// Initial pallet owner. + pub owner: Option, + /// Dummy marker. + pub phantom: sp_std::marker::PhantomData, + } + + #[cfg(feature = "std")] + impl, I: 'static> Default for GenesisConfig { + fn default() -> Self { + Self { + operating_mode: Default::default(), + owner: Default::default(), + phantom: Default::default(), + } + } + } + + #[pallet::genesis_build] + impl, I: 'static> GenesisBuild for GenesisConfig { + fn build(&self) { + PalletOperatingMode::::put(self.operating_mode); + if let Some(ref owner) = self.owner { + PalletOwner::::put(owner); + } + } + } + + /// Returns maximal number of parachains, supported by the pallet. + pub struct MaybeMaxParachains(PhantomData<(T, I)>); + + impl, I: 'static> Get> for MaybeMaxParachains { + fn get() -> Option { + Some(T::ParaStoredHeaderDataBuilder::supported_parachains()) + } + } + + /// Returns total number of all parachains hashes/heads, stored by the pallet. + pub struct MaybeMaxTotalParachainHashes(PhantomData<(T, I)>); + + impl, I: 'static> Get> for MaybeMaxTotalParachainHashes { + fn get() -> Option { + Some( + T::ParaStoredHeaderDataBuilder::supported_parachains() + .saturating_mul(T::HeadsToKeep::get()), + ) + } + } +} + +/// Single parachain header chain adapter. +pub struct ParachainHeaders(PhantomData<(T, I, C)>); + +impl, I: 'static, C: Parachain> HeaderChain + for ParachainHeaders +{ + fn finalized_header_state_root(hash: HashOf) -> Option> { + Pallet::::parachain_head(ParaId(C::PARACHAIN_ID), hash) + .and_then(|head| head.decode_parachain_head_data::().ok()) + .map(|h| h.state_root) + } +} + +/// (Re)initialize pallet with given header for using it in `pallet-bridge-messages` benchmarks. +#[cfg(feature = "runtime-benchmarks")] +pub fn initialize_for_benchmarks, I: 'static, PC: Parachain>( + header: HeaderOf, +) { + let parachain = ParaId(PC::PARACHAIN_ID); + let parachain_head = ParaHead(header.encode()); + let updated_head_data = T::ParaStoredHeaderDataBuilder::try_build(parachain, ¶chain_head) + .expect("failed to build stored parachain head in benchmarks"); + Pallet::::update_parachain_head( + parachain, + None, + 0, + updated_head_data, + parachain_head.hash(), + ) + .expect("failed to insert parachain head in benchmarks"); +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + use crate::mock::{ + run_test, test_relay_header, BigParachainHeader, RegularParachainHasher, + RegularParachainHeader, RuntimeEvent as TestEvent, RuntimeOrigin, TestRuntime, + PARAS_PALLET_NAME, UNTRACKED_PARACHAIN_ID, + }; + use codec::Encode; + + use bp_parachains::{ + BestParaHeadHash, BridgeParachainCall, ImportedParaHeadsKeyProvider, ParasInfoKeyProvider, + }; + use bp_runtime::{ + record_all_trie_keys, BasicOperatingMode, OwnedBridgeModuleError, + StorageDoubleMapKeyProvider, StorageMapKeyProvider, + }; + use bp_test_utils::{ + authority_list, generate_owned_bridge_module_tests, make_default_justification, + }; + use frame_support::{ + assert_noop, assert_ok, + dispatch::DispatchResultWithPostInfo, + storage::generator::{StorageDoubleMap, StorageMap}, + traits::{Get, OnInitialize}, + weights::Weight, + }; + use frame_system::{EventRecord, Pallet as System, Phase}; + use sp_core::Hasher; + use sp_runtime::{traits::Header as HeaderT, DispatchError}; + use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; + + type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1; + type WeightInfo = ::WeightInfo; + type DbWeight = ::DbWeight; + + pub(crate) fn initialize(state_root: RelayBlockHash) -> RelayBlockHash { + pallet_bridge_grandpa::Pallet::::initialize( + RuntimeOrigin::root(), + bp_header_chain::InitializationData { + header: Box::new(test_relay_header(0, state_root)), + authority_list: authority_list(), + set_id: 1, + operating_mode: BasicOperatingMode::Normal, + }, + ) + .unwrap(); + + System::::set_block_number(1); + System::::reset_events(); + + test_relay_header(0, state_root).hash() + } + + fn proceed(num: RelayBlockNumber, state_root: RelayBlockHash) -> ParaHash { + pallet_bridge_grandpa::Pallet::::on_initialize( + 0, + ); + + let header = test_relay_header(num, state_root); + let hash = header.hash(); + let justification = make_default_justification(&header); + assert_ok!( + pallet_bridge_grandpa::Pallet::::submit_finality_proof( + RuntimeOrigin::signed(1), + Box::new(header), + justification, + ) + ); + + hash + } + + pub(crate) fn prepare_parachain_heads_proof( + heads: Vec<(u32, ParaHead)>, + ) -> (RelayBlockHash, ParaHeadsProof, Vec<(ParaId, ParaHash)>) { + let mut parachains = Vec::with_capacity(heads.len()); + let mut root = Default::default(); + let mut mdb = MemoryDB::default(); + { + let mut trie = TrieDBMutBuilderV1::::new(&mut mdb, &mut root).build(); + for (parachain, head) in heads { + let storage_key = + parachain_head_storage_key_at_source(PARAS_PALLET_NAME, ParaId(parachain)); + trie.insert(&storage_key.0, &head.encode()) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in tests"); + parachains.push((ParaId(parachain), head.hash())); + } + } + + // 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, ParaHeadsProof(storage_proof), parachains) + } + + fn initial_best_head(parachain: u32) -> ParaInfo { + ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(parachain, 0).hash(), + }, + next_imported_hash_position: 1, + } + } + + pub(crate) fn head_data(parachain: u32, head_number: u32) -> ParaHead { + ParaHead( + RegularParachainHeader::new( + head_number as _, + Default::default(), + RegularParachainHasher::hash(&(parachain, head_number).encode()), + Default::default(), + Default::default(), + ) + .encode(), + ) + } + + fn stored_head_data(parachain: u32, head_number: u32) -> ParaStoredHeaderData { + ParaStoredHeaderData( + (head_number as u64, RegularParachainHasher::hash(&(parachain, head_number).encode())) + .encode(), + ) + } + + fn big_head_data(parachain: u32, head_number: u32) -> ParaHead { + ParaHead( + BigParachainHeader::new( + head_number as _, + Default::default(), + RegularParachainHasher::hash(&(parachain, head_number).encode()), + Default::default(), + Default::default(), + ) + .encode(), + ) + } + + fn big_stored_head_data(parachain: u32, head_number: u32) -> ParaStoredHeaderData { + ParaStoredHeaderData( + (head_number as u128, RegularParachainHasher::hash(&(parachain, head_number).encode())) + .encode(), + ) + } + + fn head_hash(parachain: u32, head_number: u32) -> ParaHash { + head_data(parachain, head_number).hash() + } + + fn import_parachain_1_head( + relay_chain_block: RelayBlockNumber, + relay_state_root: RelayBlockHash, + parachains: Vec<(ParaId, ParaHash)>, + proof: ParaHeadsProof, + ) -> DispatchResultWithPostInfo { + Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (relay_chain_block, test_relay_header(relay_chain_block, relay_state_root).hash()), + parachains, + proof, + ) + } + + fn weight_of_import_parachain_1_head(proof: &ParaHeadsProof, prune_expected: bool) -> Weight { + let db_weight = ::DbWeight::get(); + WeightInfoOf::::submit_parachain_heads_weight(db_weight, proof, 1) + .saturating_sub(if prune_expected { + Weight::zero() + } else { + WeightInfoOf::::parachain_head_pruning_weight(db_weight) + }) + } + + #[test] + fn submit_parachain_heads_checks_operating_mode() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]); + + run_test(|| { + initialize(state_root); + + // `submit_parachain_heads()` should fail when the pallet is halted. + PalletOperatingMode::::put(BasicOperatingMode::Halted); + assert_noop!( + Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains.clone(), + proof.clone(), + ), + Error::::BridgeModule(OwnedBridgeModuleError::Halted) + ); + + // `submit_parachain_heads()` should succeed now that the pallet is resumed. + PalletOperatingMode::::put(BasicOperatingMode::Normal); + assert_ok!(Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + ),); + }); + } + + #[test] + fn imports_initial_parachain_heads() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 0)), (3, head_data(3, 10))]); + run_test(|| { + initialize(state_root); + + // we're trying to update heads of parachains 1, 2 and 3 + let expected_weight = + WeightInfo::submit_parachain_heads_weight(DbWeight::get(), &proof, 2); + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + ); + assert_ok!(result); + assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); + + // but only 1 and 2 are updated, because proof is missing head of parachain#2 + assert_eq!(ParasInfo::::get(ParaId(1)), Some(initial_best_head(1))); + assert_eq!(ParasInfo::::get(ParaId(2)), None); + assert_eq!( + ParasInfo::::get(ParaId(3)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(3, 10).hash() + }, + next_imported_hash_position: 1, + }) + ); + + assert_eq!( + ImportedParaHeads::::get( + ParaId(1), + initial_best_head(1).best_head_hash.head_hash + ) + .map(|h| h.into_inner()), + Some(stored_head_data(1, 0)) + ); + assert_eq!( + ImportedParaHeads::::get( + ParaId(2), + initial_best_head(2).best_head_hash.head_hash + ) + .map(|h| h.into_inner()), + None + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(3), head_hash(3, 10)) + .map(|h| h.into_inner()), + Some(stored_head_data(3, 10)) + ); + + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: initial_best_head(1).best_head_hash.head_hash, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(3), + parachain_head_hash: head_data(3, 10).hash(), + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn imports_parachain_heads_is_able_to_progress() { + let (state_root_5, proof_5, parachains_5) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + let (state_root_10, proof_10, parachains_10) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]); + run_test(|| { + // start with relay block #0 and import head#5 of parachain#1 + initialize(state_root_5); + assert_ok!(import_parachain_1_head(0, state_root_5, parachains_5, proof_5)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(1, 5).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 5).hash()) + .map(|h| h.into_inner()), + Some(stored_head_data(1, 5)) + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 10).hash()) + .map(|h| h.into_inner()), + None + ); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + }], + ); + + // import head#10 of parachain#1 at relay block #1 + let relay_1_hash = proceed(1, state_root_10); + assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 1, + head_hash: head_data(1, 10).hash() + }, + next_imported_hash_position: 2, + }) + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 5).hash()) + .map(|h| h.into_inner()), + Some(stored_head_data(1, 5)) + ); + assert_eq!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 10).hash()) + .map(|h| h.into_inner()), + Some(stored_head_data(1, 10)) + ); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Grandpa1( + pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader { + number: 1, + hash: relay_1_hash, + } + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 10).hash(), + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn ignores_untracked_parachain() { + let (state_root, proof, parachains) = prepare_parachain_heads_proof(vec![ + (1, head_data(1, 5)), + (UNTRACKED_PARACHAIN_ID, head_data(1, 5)), + (2, head_data(1, 5)), + ]); + run_test(|| { + // start with relay block #0 and try to import head#5 of parachain#1 and untracked + // parachain + let expected_weight = + WeightInfo::submit_parachain_heads_weight(DbWeight::get(), &proof, 3) + .saturating_sub(WeightInfo::parachain_head_storage_write_weight( + DbWeight::get(), + )); + initialize(state_root); + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + ); + assert_ok!(result); + assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(1, 5).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!(ParasInfo::::get(ParaId(UNTRACKED_PARACHAIN_ID)), None,); + assert_eq!( + ParasInfo::::get(ParaId(2)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(1, 5).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UntrackedParachainRejected { + parachain: ParaId(UNTRACKED_PARACHAIN_ID), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(2), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn does_nothing_when_already_imported_this_head_at_previous_relay_header() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]); + run_test(|| { + // import head#0 of parachain#1 at relay block#0 + initialize(state_root); + assert_ok!(import_parachain_1_head(0, state_root, parachains.clone(), proof.clone())); + assert_eq!(ParasInfo::::get(ParaId(1)), Some(initial_best_head(1))); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: initial_best_head(1).best_head_hash.head_hash, + }), + topics: vec![], + }], + ); + + // try to import head#0 of parachain#1 at relay block#1 + // => call succeeds, but nothing is changed + let relay_1_hash = proceed(1, state_root); + assert_ok!(import_parachain_1_head(1, state_root, parachains, proof)); + assert_eq!(ParasInfo::::get(ParaId(1)), Some(initial_best_head(1))); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: initial_best_head(1).best_head_hash.head_hash, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Grandpa1( + pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader { + number: 1, + hash: relay_1_hash, + } + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::RejectedObsoleteParachainHead { + parachain: ParaId(1), + parachain_head_hash: initial_best_head(1).best_head_hash.head_hash, + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn does_nothing_when_already_imported_head_at_better_relay_header() { + let (state_root_5, proof_5, parachains_5) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + let (state_root_10, proof_10, parachains_10) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]); + run_test(|| { + // start with relay block #0 + initialize(state_root_5); + + // head#10 of parachain#1 at relay block#1 + let relay_1_hash = proceed(1, state_root_10); + assert_ok!(import_parachain_1_head(1, state_root_10, parachains_10, proof_10)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 1, + head_hash: head_data(1, 10).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Grandpa1( + pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader { + number: 1, + hash: relay_1_hash, + } + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 10).hash(), + }), + topics: vec![], + } + ], + ); + + // now try to import head#5 at relay block#0 + // => nothing is changed, because better head has already been imported + assert_ok!(import_parachain_1_head(0, state_root_5, parachains_5, proof_5)); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 1, + head_hash: head_data(1, 10).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Grandpa1( + pallet_bridge_grandpa::Event::UpdatedBestFinalizedHeader { + number: 1, + hash: relay_1_hash, + } + ), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 10).hash(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::RejectedObsoleteParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + } + ], + ); + }); + } + + #[test] + fn does_nothing_when_parachain_head_is_too_large() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5)), (4, big_head_data(1, 5))]); + run_test(|| { + // start with relay block #0 and try to import head#5 of parachain#1 and big parachain + initialize(state_root); + let result = Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + ); + assert_ok!(result); + assert_eq!( + ParasInfo::::get(ParaId(1)), + Some(ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: 0, + head_hash: head_data(1, 5).hash() + }, + next_imported_hash_position: 1, + }) + ); + assert_eq!(ParasInfo::::get(ParaId(4)), None); + assert_eq!( + System::::events(), + vec![ + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::UpdatedParachainHead { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 5).hash(), + }), + topics: vec![], + }, + EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::RejectedLargeParachainHead { + parachain: ParaId(4), + parachain_head_hash: big_head_data(1, 5).hash(), + parachain_head_size: big_stored_head_data(1, 5).encoded_size() as u32, + }), + topics: vec![], + }, + ], + ); + }); + } + + #[test] + fn prunes_old_heads() { + run_test(|| { + let heads_to_keep = crate::mock::HeadsToKeep::get(); + + // import exactly `HeadsToKeep` headers + for i in 0..heads_to_keep { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, i))]); + if i == 0 { + initialize(state_root); + } else { + proceed(i, state_root); + } + + let expected_weight = weight_of_import_parachain_1_head(&proof, false); + let result = import_parachain_1_head(i, state_root, parachains, proof); + assert_ok!(result); + assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); + } + + // nothing is pruned yet + for i in 0..heads_to_keep { + assert!(ImportedParaHeads::::get(ParaId(1), head_data(1, i).hash()) + .is_some()); + } + + // import next relay chain header and next parachain head + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, heads_to_keep))]); + proceed(heads_to_keep, state_root); + let expected_weight = weight_of_import_parachain_1_head(&proof, true); + let result = import_parachain_1_head(heads_to_keep, state_root, parachains, proof); + assert_ok!(result); + assert_eq!(result.expect("checked above").actual_weight, Some(expected_weight)); + + // and the head#0 is pruned + assert!( + ImportedParaHeads::::get(ParaId(1), head_data(1, 0).hash()).is_none() + ); + for i in 1..=heads_to_keep { + assert!(ImportedParaHeads::::get(ParaId(1), head_data(1, i).hash()) + .is_some()); + } + }); + } + + #[test] + fn fails_on_unknown_relay_chain_block() { + let (state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + run_test(|| { + // start with relay block #0 + initialize(state_root); + + // try to import head#5 of parachain#1 at unknown relay chain block #1 + assert_noop!( + import_parachain_1_head(1, state_root, parachains, proof), + Error::::UnknownRelayChainBlock + ); + }); + } + + #[test] + fn fails_on_invalid_storage_proof() { + let (_state_root, proof, parachains) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + run_test(|| { + // start with relay block #0 + initialize(Default::default()); + + // try to import head#5 of parachain#1 at relay chain block #0 + assert_noop!( + import_parachain_1_head(0, Default::default(), parachains, proof), + Error::::HeaderChain(HeaderChainError::StorageProof( + StorageProofError::StorageRootMismatch + )) + ); + }); + } + + #[test] + fn is_not_rewriting_existing_head_if_failed_to_read_updated_head() { + let (state_root_5, proof_5, parachains_5) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 5))]); + let (state_root_10_at_20, proof_10_at_20, parachains_10_at_20) = + prepare_parachain_heads_proof(vec![(2, head_data(2, 10))]); + let (state_root_10_at_30, proof_10_at_30, parachains_10_at_30) = + prepare_parachain_heads_proof(vec![(1, head_data(1, 10))]); + run_test(|| { + // we've already imported head#5 of parachain#1 at relay block#10 + initialize(state_root_5); + import_parachain_1_head(0, state_root_5, parachains_5, proof_5).expect("ok"); + assert_eq!( + Pallet::::best_parachain_head(ParaId(1)), + Some(stored_head_data(1, 5)) + ); + + // then if someone is pretending to provide updated head#10 of parachain#1 at relay + // block#20, but fails to do that + // + // => we'll leave previous value + proceed(20, state_root_10_at_20); + assert_ok!(Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (20, test_relay_header(20, state_root_10_at_20).hash()), + parachains_10_at_20, + proof_10_at_20, + ),); + assert_eq!( + Pallet::::best_parachain_head(ParaId(1)), + Some(stored_head_data(1, 5)) + ); + + // then if someone is pretending to provide updated head#10 of parachain#1 at relay + // block#30, and actualy provides it + // + // => we'll update value + proceed(30, state_root_10_at_30); + assert_ok!(Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (30, test_relay_header(30, state_root_10_at_30).hash()), + parachains_10_at_30, + proof_10_at_30, + ),); + assert_eq!( + Pallet::::best_parachain_head(ParaId(1)), + Some(stored_head_data(1, 10)) + ); + }); + } + + #[test] + fn storage_keys_computed_properly() { + assert_eq!( + ParasInfo::::storage_map_final_key(ParaId(42)).to_vec(), + ParasInfoKeyProvider::final_key("Parachains", &ParaId(42)).0 + ); + + assert_eq!( + ImportedParaHeads::::storage_double_map_final_key( + ParaId(42), + ParaHash::from([21u8; 32]) + ) + .to_vec(), + ImportedParaHeadsKeyProvider::final_key( + "Parachains", + &ParaId(42), + &ParaHash::from([21u8; 32]) + ) + .0, + ); + } + + #[test] + fn ignores_parachain_head_if_it_is_missing_from_storage_proof() { + let (state_root, proof, _) = prepare_parachain_heads_proof(vec![]); + let parachains = vec![(ParaId(2), Default::default())]; + run_test(|| { + initialize(state_root); + assert_ok!(Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + )); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::MissingParachainHead { + parachain: ParaId(2), + }), + topics: vec![], + }], + ); + }); + } + + #[test] + fn ignores_parachain_head_if_parachain_head_hash_is_wrong() { + let (state_root, proof, _) = prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]); + let parachains = vec![(ParaId(1), head_data(1, 10).hash())]; + run_test(|| { + initialize(state_root); + assert_ok!(Pallet::::submit_parachain_heads( + RuntimeOrigin::signed(1), + (0, test_relay_header(0, state_root).hash()), + parachains, + proof, + )); + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Parachains(Event::IncorrectParachainHeadHash { + parachain: ParaId(1), + parachain_head_hash: head_data(1, 10).hash(), + actual_parachain_head_hash: head_data(1, 0).hash(), + }), + topics: vec![], + }], + ); + }); + } + + #[test] + fn test_bridge_parachain_call_is_correctly_defined() { + let (state_root, proof, _) = prepare_parachain_heads_proof(vec![(1, head_data(1, 0))]); + let parachains = vec![(ParaId(2), Default::default())]; + let relay_header_id = (0, test_relay_header(0, state_root).hash()); + + let direct_submit_parachain_heads_call = Call::::submit_parachain_heads { + at_relay_block: relay_header_id, + parachains: parachains.clone(), + parachain_heads_proof: proof.clone(), + }; + let indirect_submit_parachain_heads_call = BridgeParachainCall::submit_parachain_heads { + at_relay_block: relay_header_id, + parachains, + parachain_heads_proof: proof, + }; + assert_eq!( + direct_submit_parachain_heads_call.encode(), + indirect_submit_parachain_heads_call.encode() + ); + } + + generate_owned_bridge_module_tests!(BasicOperatingMode::Normal, BasicOperatingMode::Halted); + + #[test] + fn maybe_max_parachains_returns_correct_value() { + assert_eq!(MaybeMaxParachains::::get(), Some(mock::TOTAL_PARACHAINS)); + } + + #[test] + fn maybe_max_total_parachain_hashes_returns_correct_value() { + assert_eq!( + MaybeMaxTotalParachainHashes::::get(), + Some(mock::TOTAL_PARACHAINS * mock::HeadsToKeep::get()), + ); + } +} diff --git a/modules/parachains/src/mock.rs b/modules/parachains/src/mock.rs new file mode 100644 index 00000000000..3086adc1cc2 --- /dev/null +++ b/modules/parachains/src/mock.rs @@ -0,0 +1,349 @@ +// Copyright 2019-2021 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 . + +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 sp_runtime::{ + testing::{Header, H256}, + traits::{BlakeTwo256, Header as HeaderT, IdentityLookup}, + MultiSignature, Perbill, +}; + +use crate as pallet_bridge_parachains; + +pub type AccountId = u64; +pub type TestNumber = u64; + +pub type RelayBlockHeader = + sp_runtime::generic::Header; + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +pub const PARAS_PALLET_NAME: &str = "Paras"; +pub const UNTRACKED_PARACHAIN_ID: u32 = 10; +// use exact expected encoded size: `vec_len_size + header_number_size + state_root_hash_size` +pub const MAXIMAL_PARACHAIN_HEAD_DATA_SIZE: u32 = 1 + 8 + 32; +// total parachains that we use in tests +pub const TOTAL_PARACHAINS: u32 = 4; + +pub type RegularParachainHeader = sp_runtime::testing::Header; +pub type RegularParachainHasher = BlakeTwo256; +pub type BigParachainHeader = sp_runtime::generic::Header; + +pub struct Parachain1; + +impl Chain for Parachain1 { + type BlockNumber = u64; + type Hash = H256; + type Hasher = RegularParachainHasher; + type Header = RegularParachainHeader; + type AccountId = u64; + type Balance = u64; + type Index = u64; + type Signature = MultiSignature; + + fn max_extrinsic_size() -> u32 { + 0 + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl Parachain for Parachain1 { + const PARACHAIN_ID: u32 = 1; +} + +pub struct Parachain2; + +impl Chain for Parachain2 { + type BlockNumber = u64; + type Hash = H256; + type Hasher = RegularParachainHasher; + type Header = RegularParachainHeader; + type AccountId = u64; + type Balance = u64; + type Index = u64; + type Signature = MultiSignature; + + fn max_extrinsic_size() -> u32 { + 0 + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl Parachain for Parachain2 { + const PARACHAIN_ID: u32 = 2; +} + +pub struct Parachain3; + +impl Chain for Parachain3 { + type BlockNumber = u64; + type Hash = H256; + type Hasher = RegularParachainHasher; + type Header = RegularParachainHeader; + type AccountId = u64; + type Balance = u64; + type Index = u64; + type Signature = MultiSignature; + + fn max_extrinsic_size() -> u32 { + 0 + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl Parachain for Parachain3 { + const PARACHAIN_ID: u32 = 3; +} + +// this parachain is using u128 as block number and stored head data size exceeds limit +pub struct BigParachain; + +impl Chain for BigParachain { + type BlockNumber = u128; + type Hash = H256; + type Hasher = RegularParachainHasher; + type Header = BigParachainHeader; + type AccountId = u64; + type Balance = u64; + type Index = u64; + type Signature = MultiSignature; + + fn max_extrinsic_size() -> u32 { + 0 + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl Parachain for BigParachain { + const PARACHAIN_ID: u32 = 4; +} + +construct_runtime! { + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Grandpa1: pallet_bridge_grandpa::::{Pallet, Event}, + Grandpa2: pallet_bridge_grandpa::::{Pallet, Event}, + Parachains: pallet_bridge_parachains::{Call, Pallet, Event}, + } +} + +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(); +} + +impl frame_system::Config for TestRuntime { + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = TestNumber; + type Hash = H256; + type Hashing = RegularParachainHasher; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + 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; +} + +impl pallet_bridge_grandpa::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = TestBridgedChain; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<2>; + type HeadersToKeep = HeadersToKeep; + type WeightInfo = (); +} + +impl pallet_bridge_grandpa::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = TestBridgedChain; + type MaxFreeMandatoryHeadersPerBlock = ConstU32<2>; + type HeadersToKeep = HeadersToKeep; + type WeightInfo = (); +} + +parameter_types! { + pub const HeadsToKeep: u32 = 4; + pub const ParasPalletName: &'static str = PARAS_PALLET_NAME; + pub GetTenFirstParachains: Vec = (0..10).map(ParaId).collect(); +} + +impl pallet_bridge_parachains::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1; + type ParasPalletName = ParasPalletName; + type ParaStoredHeaderDataBuilder = (Parachain1, Parachain2, Parachain3, BigParachain); + type HeadsToKeep = HeadsToKeep; + type MaxParaHeadDataSize = ConstU32; +} + +#[cfg(feature = "runtime-benchmarks")] +impl pallet_bridge_parachains::benchmarking::Config<()> for TestRuntime { + fn parachains() -> Vec { + vec![ + ParaId(Parachain1::PARACHAIN_ID), + ParaId(Parachain2::PARACHAIN_ID), + ParaId(Parachain3::PARACHAIN_ID), + ] + } + + fn prepare_parachain_heads_proof( + parachains: &[ParaId], + _parachain_head_size: u32, + _proof_size: bp_runtime::StorageProofSize, + ) -> ( + crate::RelayBlockNumber, + crate::RelayBlockHash, + bp_polkadot_core::parachains::ParaHeadsProof, + Vec<(ParaId, bp_polkadot_core::parachains::ParaHash)>, + ) { + // in mock run we only care about benchmarks correctness, not the benchmark results + // => ignore size related arguments + let (state_root, proof, parachains) = crate::tests::prepare_parachain_heads_proof( + parachains.iter().map(|p| (p.0, crate::tests::head_data(p.0, 1))).collect(), + ); + let relay_genesis_hash = crate::tests::initialize(state_root); + (0, relay_genesis_hash, proof, parachains) + } +} + +#[derive(Debug)] +pub struct TestBridgedChain; + +impl Chain for TestBridgedChain { + type BlockNumber = crate::RelayBlockNumber; + type Hash = crate::RelayBlockHash; + type Hasher = crate::RelayBlockHasher; + type Header = RelayBlockHeader; + + type AccountId = AccountId; + type Balance = u32; + type Index = u32; + type Signature = sp_runtime::testing::TestSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +impl ChainWithGrandpa for TestBridgedChain { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; + const MAX_AUTHORITIES_COUNT: u32 = 16; + const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + const MAX_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; +} + +#[derive(Debug)] +pub struct OtherBridgedChain; + +impl Chain for OtherBridgedChain { + type BlockNumber = u64; + type Hash = crate::RelayBlockHash; + type Hasher = crate::RelayBlockHasher; + type Header = sp_runtime::generic::Header; + + type AccountId = AccountId; + type Balance = u32; + type Index = u32; + type Signature = sp_runtime::testing::TestSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +impl ChainWithGrandpa for OtherBridgedChain { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; + const MAX_AUTHORITIES_COUNT: u32 = 16; + const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + const MAX_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 64; +} + +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { + sp_io::TestExternalities::new(Default::default()) +} + +/// Run pallet test. +pub fn run_test(test: impl FnOnce() -> T) -> T { + new_test_ext().execute_with(|| { + System::set_block_number(1); + System::reset_events(); + test() + }) +} + +/// Return test relay chain header with given number. +pub fn test_relay_header( + num: crate::RelayBlockNumber, + state_root: crate::RelayBlockHash, +) -> RelayBlockHeader { + RelayBlockHeader::new( + num, + Default::default(), + state_root, + Default::default(), + Default::default(), + ) +} diff --git a/modules/parachains/src/weights.rs b/modules/parachains/src/weights.rs new file mode 100644 index 00000000000..54a835cbc87 --- /dev/null +++ b/modules/parachains/src/weights.rs @@ -0,0 +1,273 @@ +// Copyright 2019-2021 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 . + +//! Autogenerated weights for pallet_bridge_parachains +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/millau-bridge-node +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_bridge_parachains +// --extrinsic=* +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --output=./modules/parachains/src/weights.rs +// --template=./.maintain/millau-weight-template.hbs + +#![allow(clippy::all)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_bridge_parachains. +pub trait WeightInfo { + fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight; + fn submit_parachain_heads_with_1kb_proof() -> Weight; + fn submit_parachain_heads_with_16kb_proof() -> Weight; +} + +/// Weights for `pallet_bridge_parachains` 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: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// added: 496, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// 555, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Some(64), added: 1549, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// + /// Proof: BridgeRialtoParachains ImportedParaHeads (max_values: Some(1024), max_size: + /// Some(196), added: 1681, 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: `366` + // Estimated: `4648` + // Minimum execution time: 36_701 nanoseconds. + Weight::from_parts(38_597_828, 4648) + // Standard Error: 190_859 + .saturating_add(Weight::from_parts(60_685, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// added: 496, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// 555, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Some(64), added: 1549, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// + /// Proof: BridgeRialtoParachains 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: + // Measured: `366` + // Estimated: `4648` + // Minimum execution time: 38_189 nanoseconds. + Weight::from_parts(39_252_000, 4648) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// added: 496, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// 555, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Some(64), added: 1549, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// + /// Proof: BridgeRialtoParachains 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: + // Measured: `366` + // Estimated: `4648` + // Minimum execution time: 62_868 nanoseconds. + Weight::from_parts(63_581_000, 4648) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// added: 496, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// 555, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Some(64), added: 1549, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// + /// Proof: BridgeRialtoParachains ImportedParaHeads (max_values: Some(1024), max_size: + /// Some(196), added: 1681, 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: `366` + // Estimated: `4648` + // Minimum execution time: 36_701 nanoseconds. + Weight::from_parts(38_597_828, 4648) + // Standard Error: 190_859 + .saturating_add(Weight::from_parts(60_685, 0).saturating_mul(p.into())) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// added: 496, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// 555, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Some(64), added: 1549, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// + /// Proof: BridgeRialtoParachains 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: + // Measured: `366` + // Estimated: `4648` + // Minimum execution time: 38_189 nanoseconds. + Weight::from_parts(39_252_000, 4648) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: BridgeRialtoParachains PalletOperatingMode (r:1 w:0) + /// + /// Proof: BridgeRialtoParachains PalletOperatingMode (max_values: Some(1), max_size: Some(1), + /// added: 496, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoGrandpa ImportedHeaders (r:1 w:0) + /// + /// Proof: BridgeRialtoGrandpa ImportedHeaders (max_values: Some(14400), max_size: Some(68), + /// added: 2048, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ParasInfo (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ParasInfo (max_values: Some(1), max_size: Some(60), added: + /// 555, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHashes (r:1 w:1) + /// + /// Proof: BridgeRialtoParachains ImportedParaHashes (max_values: Some(1024), max_size: + /// Some(64), added: 1549, mode: MaxEncodedLen) + /// + /// Storage: BridgeRialtoParachains ImportedParaHeads (r:0 w:1) + /// + /// Proof: BridgeRialtoParachains 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: + // Measured: `366` + // Estimated: `4648` + // Minimum execution time: 62_868 nanoseconds. + Weight::from_parts(63_581_000, 4648) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } +} diff --git a/modules/parachains/src/weights_ext.rs b/modules/parachains/src/weights_ext.rs new file mode 100644 index 00000000000..eecdfe90359 --- /dev/null +++ b/modules/parachains/src/weights_ext.rs @@ -0,0 +1,107 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Weight-related utilities. + +use crate::weights::{BridgeWeight, WeightInfo}; + +use bp_runtime::Size; +use frame_support::weights::{RuntimeDbWeight, Weight}; + +/// Size of the regular parachain head. +/// +/// It's not that we are expecting all parachain heads to share the same size or that we would +/// reject all heads that have larger/lesser size. It is about head size that we use in benchmarks. +/// Relayer would need to pay additional fee for extra bytes. +/// +/// 384 is a bit larger (1.3 times) than the size of the randomly chosen Polkadot block. +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. +pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; + +/// Extended weight info. +pub trait WeightInfoExt: WeightInfo { + /// Storage proof overhead, that is included in every storage proof. + /// + /// The relayer would pay some extra fee for additional proof bytes, since they mean + /// more hashing operations. + fn expected_extra_storage_proof_size() -> u32; + + /// Weight of the parachain heads delivery extrinsic. + fn submit_parachain_heads_weight( + db_weight: RuntimeDbWeight, + proof: &impl Size, + parachains_count: u32, + ) -> Weight { + // weight of the `submit_parachain_heads` with exactly `parachains_count` parachain + // heads of the default size (`DEFAULT_PARACHAIN_HEAD_SIZE`) + let base_weight = Self::submit_parachain_heads_with_n_parachains(parachains_count); + + // overhead because of extra storage proof bytes + let expected_proof_size = parachains_count + .saturating_mul(DEFAULT_PARACHAIN_HEAD_SIZE) + .saturating_add(Self::expected_extra_storage_proof_size()); + let actual_proof_size = proof.size(); + let proof_size_overhead = Self::storage_proof_size_overhead( + actual_proof_size.saturating_sub(expected_proof_size), + ); + + // potential pruning weight (refunded if hasn't happened) + let pruning_weight = + Self::parachain_head_pruning_weight(db_weight).saturating_mul(parachains_count as u64); + + base_weight.saturating_add(proof_size_overhead).saturating_add(pruning_weight) + } + + /// Returns weight of single parachain head storage update. + /// + /// This weight only includes db write operations that happens if parachain head is actually + /// updated. All extra weights (weight of storage proof validation, additional checks, ...) is + /// not included. + fn parachain_head_storage_write_weight(db_weight: RuntimeDbWeight) -> Weight { + // it's just a couple of operations - we need to write the hash (`ImportedParaHashes`) and + // the head itself (`ImportedParaHeads`. Pruning is not included here + db_weight.writes(2) + } + + /// Returns weight of single parachain head pruning. + fn parachain_head_pruning_weight(db_weight: RuntimeDbWeight) -> Weight { + // it's just one write operation, we don't want any benchmarks for that + db_weight.writes(1) + } + + /// Returns weight that needs to be accounted when storage proof of given size is received. + fn storage_proof_size_overhead(extra_proof_bytes: u32) -> Weight { + let extra_byte_weight = (Self::submit_parachain_heads_with_16kb_proof() - + Self::submit_parachain_heads_with_1kb_proof()) / + (15 * 1024); + extra_byte_weight.saturating_mul(extra_proof_bytes as u64) + } +} + +impl WeightInfoExt for () { + fn expected_extra_storage_proof_size() -> u32 { + EXTRA_STORAGE_PROOF_SIZE + } +} + +impl WeightInfoExt for BridgeWeight { + fn expected_extra_storage_proof_size() -> u32 { + EXTRA_STORAGE_PROOF_SIZE + } +} diff --git a/modules/relayers/Cargo.toml b/modules/relayers/Cargo.toml new file mode 100644 index 00000000000..c654c60d02b --- /dev/null +++ b/modules/relayers/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "pallet-bridge-relayers" +description = "Module used to store relayer rewards and coordinate relayers set." +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 } +log = { version = "0.4.17", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +# Bridge dependencies + +bp-messages = { path = "../../primitives/messages", default-features = false } +bp-relayers = { path = "../../primitives/relayers", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +pallet-bridge-messages = { path = "../messages", default-features = false } + +# Substrate Dependencies + +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +bp-runtime = { path = "../../primitives/runtime" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = ["std"] +std = [ + "bp-messages/std", + "bp-relayers/std", + "bp-runtime/std", + "codec/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "log/std", + "scale-info/std", + "sp-arithmetic/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/relayers/README.md b/modules/relayers/README.md new file mode 100644 index 00000000000..656200f4486 --- /dev/null +++ b/modules/relayers/README.md @@ -0,0 +1,14 @@ +# Bridge Relayers Pallet + +The pallet serves as a storage for pending bridge relayer rewards. Any runtime component may register reward +to some relayer for doing some useful job at some messages lane. Later, the relayer may claim its rewards +using the `claim_rewards` call. + +The reward payment procedure is abstracted from the pallet code. One of possible implementations, is the +[`PayLaneRewardFromAccount`](../../primitives/relayers/src/lib.rs), which just does a `Currency::transfer` +call to relayer account from the relayer-rewards account, determined by the message lane id. + +We have two examples of how this pallet is used in production. Rewards are registered at the target chain to +compensate fees of message delivery transactions (and linked finality delivery calls). At the source chain, rewards +are registered during delivery confirmation transactions. You may find more information about that in the +[Kusama <> Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md) documentation. diff --git a/modules/relayers/src/benchmarking.rs b/modules/relayers/src/benchmarking.rs new file mode 100644 index 00000000000..a762a5693c2 --- /dev/null +++ b/modules/relayers/src/benchmarking.rs @@ -0,0 +1,59 @@ +// Copyright 2019-2021 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 . + +//! Benchmarks for the relayers Pallet. + +#![cfg(feature = "runtime-benchmarks")] + +use crate::*; + +use bp_messages::LaneId; +use bp_relayers::RewardsAccountOwner; +use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_system::RawOrigin; + +/// Reward amount that is (hopefully) is larger than existential deposit across all chains. +const REWARD_AMOUNT: u32 = u32::MAX; + +/// Pallet we're benchmarking here. +pub struct Pallet(crate::Pallet); + +/// Trait that must be implemented by runtime. +pub trait Config: crate::Config { + /// Prepare environment for paying given reward for serving given lane. + fn prepare_environment(account_params: RewardsAccountParams, reward: Self::Reward); +} + +benchmarks! { + // Benchmark `claim_rewards` call. + claim_rewards { + let lane = LaneId([0, 0, 0, 0]); + let account_params = + RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); + let relayer: T::AccountId = whitelisted_caller(); + let reward = T::Reward::from(REWARD_AMOUNT); + + T::prepare_environment(account_params, reward); + RelayerRewards::::insert(&relayer, account_params, reward); + }: _(RawOrigin::Signed(relayer), account_params) + verify { + // we can't check anything here, because `PaymentProcedure` is responsible for + // payment logic, so we assume that if call has succeeded, the procedure has + // also completed successfully + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) +} diff --git a/modules/relayers/src/lib.rs b/modules/relayers/src/lib.rs new file mode 100644 index 00000000000..bd33b811b30 --- /dev/null +++ b/modules/relayers/src/lib.rs @@ -0,0 +1,309 @@ +// Copyright 2019-2021 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 . + +//! Runtime module that is used to store relayer rewards and (in the future) to +//! coordinate relations between relayers. + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +use bp_relayers::{PaymentProcedure, RelayerRewardsKeyProvider, RewardsAccountParams}; +use bp_runtime::StorageDoubleMapKeyProvider; +use frame_support::sp_runtime::Saturating; +use sp_arithmetic::traits::{AtLeast32BitUnsigned, Zero}; +use sp_std::marker::PhantomData; + +pub use pallet::*; +pub use payment_adapter::DeliveryConfirmationPaymentsAdapter; +pub use weights::WeightInfo; + +pub mod benchmarking; + +mod mock; +mod payment_adapter; + +pub mod weights; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "runtime::bridge-relayers"; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + /// `RelayerRewardsKeyProvider` for given configuration. + type RelayerRewardsKeyProviderOf = + RelayerRewardsKeyProvider<::AccountId, ::Reward>; + + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Type of relayer reward. + type Reward: AtLeast32BitUnsigned + Copy + Parameter + MaxEncodedLen; + /// Pay rewards adapter. + type PaymentProcedure: PaymentProcedure; + /// Pallet call weights. + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::call] + impl Pallet { + /// Claim accumulated rewards. + #[pallet::call_index(0)] + #[pallet::weight(T::WeightInfo::claim_rewards())] + pub fn claim_rewards( + origin: OriginFor, + rewards_account_params: RewardsAccountParams, + ) -> DispatchResult { + let relayer = ensure_signed(origin)?; + + RelayerRewards::::try_mutate_exists( + &relayer, + rewards_account_params, + |maybe_reward| -> DispatchResult { + let reward = maybe_reward.take().ok_or(Error::::NoRewardForRelayer)?; + T::PaymentProcedure::pay_reward(&relayer, rewards_account_params, reward) + .map_err(|e| { + log::trace!( + target: LOG_TARGET, + "Failed to pay {:?} rewards to {:?}: {:?}", + rewards_account_params, + relayer, + e, + ); + Error::::FailedToPayReward + })?; + + Self::deposit_event(Event::::RewardPaid { + relayer: relayer.clone(), + rewards_account_params, + reward, + }); + Ok(()) + }, + ) + } + } + + impl Pallet { + /// Register reward for given relayer. + pub fn register_relayer_reward( + rewards_account_params: RewardsAccountParams, + relayer: &T::AccountId, + reward: T::Reward, + ) { + if reward.is_zero() { + return + } + + RelayerRewards::::mutate( + relayer, + rewards_account_params, + |old_reward: &mut Option| { + let new_reward = old_reward.unwrap_or_else(Zero::zero).saturating_add(reward); + *old_reward = Some(new_reward); + + log::trace!( + target: crate::LOG_TARGET, + "Relayer {:?} can now claim reward for serving payer {:?}: {:?}", + relayer, + rewards_account_params, + new_reward, + ); + }, + ); + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Reward has been paid to the relayer. + RewardPaid { + /// Relayer account that has been rewarded. + relayer: T::AccountId, + /// Relayer has received reward from this account. + rewards_account_params: RewardsAccountParams, + /// Reward amount. + reward: T::Reward, + }, + } + + #[pallet::error] + pub enum Error { + /// No reward can be claimed by given relayer. + NoRewardForRelayer, + /// Reward payment procedure has failed. + FailedToPayReward, + } + + /// Map of the relayer => accumulated reward. + #[pallet::storage] + #[pallet::getter(fn relayer_reward)] + pub type RelayerRewards = StorageDoubleMap< + _, + as StorageDoubleMapKeyProvider>::Hasher1, + as StorageDoubleMapKeyProvider>::Key1, + as StorageDoubleMapKeyProvider>::Hasher2, + as StorageDoubleMapKeyProvider>::Key2, + as StorageDoubleMapKeyProvider>::Value, + OptionQuery, + >; +} + +#[cfg(test)] +mod tests { + use super::*; + use mock::{RuntimeEvent as TestEvent, *}; + + use crate::Event::RewardPaid; + use bp_messages::LaneId; + use bp_relayers::RewardsAccountOwner; + use frame_support::{ + assert_noop, assert_ok, + traits::fungible::{Inspect, Mutate}, + }; + use frame_system::{EventRecord, Pallet as System, Phase}; + use sp_runtime::DispatchError; + + fn get_ready_for_events() { + System::::set_block_number(1); + System::::reset_events(); + } + + #[test] + fn root_cant_claim_anything() { + run_test(|| { + assert_noop!( + Pallet::::claim_rewards( + RuntimeOrigin::root(), + TEST_REWARDS_ACCOUNT_PARAMS + ), + DispatchError::BadOrigin, + ); + }); + } + + #[test] + fn relayer_cant_claim_if_no_reward_exists() { + run_test(|| { + assert_noop!( + Pallet::::claim_rewards( + RuntimeOrigin::signed(REGULAR_RELAYER), + TEST_REWARDS_ACCOUNT_PARAMS + ), + Error::::NoRewardForRelayer, + ); + }); + } + + #[test] + fn relayer_cant_claim_if_payment_procedure_fails() { + run_test(|| { + RelayerRewards::::insert( + FAILING_RELAYER, + TEST_REWARDS_ACCOUNT_PARAMS, + 100, + ); + assert_noop!( + Pallet::::claim_rewards( + RuntimeOrigin::signed(FAILING_RELAYER), + TEST_REWARDS_ACCOUNT_PARAMS + ), + Error::::FailedToPayReward, + ); + }); + } + + #[test] + fn relayer_can_claim_reward() { + run_test(|| { + get_ready_for_events(); + + RelayerRewards::::insert( + REGULAR_RELAYER, + TEST_REWARDS_ACCOUNT_PARAMS, + 100, + ); + assert_ok!(Pallet::::claim_rewards( + RuntimeOrigin::signed(REGULAR_RELAYER), + TEST_REWARDS_ACCOUNT_PARAMS + )); + assert_eq!( + RelayerRewards::::get(REGULAR_RELAYER, TEST_REWARDS_ACCOUNT_PARAMS), + None + ); + + //Check if the `RewardPaid` event was emitted. + assert_eq!( + System::::events(), + vec![EventRecord { + phase: Phase::Initialization, + event: TestEvent::Relayers(RewardPaid { + relayer: REGULAR_RELAYER, + rewards_account_params: TEST_REWARDS_ACCOUNT_PARAMS, + reward: 100 + }), + topics: vec![], + }], + ); + }); + } + + #[test] + fn pay_reward_from_account_actually_pays_reward() { + type Balances = pallet_balances::Pallet; + type PayLaneRewardFromAccount = bp_relayers::PayRewardFromAccount; + + run_test(|| { + let in_lane_0 = RewardsAccountParams::new( + LaneId([0, 0, 0, 0]), + *b"test", + RewardsAccountOwner::ThisChain, + ); + let out_lane_1 = RewardsAccountParams::new( + LaneId([0, 0, 0, 1]), + *b"test", + RewardsAccountOwner::BridgedChain, + ); + + let in_lane0_rewards_account = PayLaneRewardFromAccount::rewards_account(in_lane_0); + let out_lane1_rewards_account = PayLaneRewardFromAccount::rewards_account(out_lane_1); + + Balances::mint_into(&in_lane0_rewards_account, 100).unwrap(); + Balances::mint_into(&out_lane1_rewards_account, 100).unwrap(); + assert_eq!(Balances::balance(&in_lane0_rewards_account), 100); + assert_eq!(Balances::balance(&out_lane1_rewards_account), 100); + assert_eq!(Balances::balance(&1), 0); + + PayLaneRewardFromAccount::pay_reward(&1, in_lane_0, 100).unwrap(); + assert_eq!(Balances::balance(&in_lane0_rewards_account), 0); + assert_eq!(Balances::balance(&out_lane1_rewards_account), 100); + assert_eq!(Balances::balance(&1), 100); + + PayLaneRewardFromAccount::pay_reward(&1, out_lane_1, 100).unwrap(); + assert_eq!(Balances::balance(&in_lane0_rewards_account), 0); + assert_eq!(Balances::balance(&out_lane1_rewards_account), 0); + assert_eq!(Balances::balance(&1), 200); + }); + } +} diff --git a/modules/relayers/src/mock.rs b/modules/relayers/src/mock.rs new file mode 100644 index 00000000000..fe8c586eecc --- /dev/null +++ b/modules/relayers/src/mock.rs @@ -0,0 +1,151 @@ +// Copyright 2019-2021 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(test)] + +use crate as pallet_bridge_relayers; + +use bp_messages::LaneId; +use bp_relayers::{PaymentProcedure, RewardsAccountOwner, RewardsAccountParams}; +use frame_support::{parameter_types, weights::RuntimeDbWeight}; +use sp_core::H256; +use sp_runtime::{ + testing::Header as SubstrateHeader, + traits::{BlakeTwo256, ConstU32, IdentityLookup}, +}; + +pub type AccountId = u64; +pub type Balance = u64; + +type Block = frame_system::mocking::MockBlock; +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + +frame_support::construct_runtime! { + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances::{Pallet, Event}, + Relayers: pallet_bridge_relayers::{Pallet, Call, Event}, + } +} + +parameter_types! { + pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; +} + +impl frame_system::Config for TestRuntime { + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = SubstrateHeader; + 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>; +} + +impl pallet_balances::Config for TestRuntime { + type MaxLocks = (); + type Balance = Balance; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = frame_support::traits::ConstU64<1>; + type AccountStore = frame_system::Pallet; + type WeightInfo = (); + type MaxReserves = (); + type ReserveIdentifier = (); + type HoldIdentifier = (); + type FreezeIdentifier = (); + type MaxHolds = ConstU32<0>; + type MaxFreezes = ConstU32<0>; +} + +impl pallet_bridge_relayers::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type Reward = Balance; + type PaymentProcedure = TestPaymentProcedure; + type WeightInfo = (); +} + +#[cfg(feature = "runtime-benchmarks")] +impl pallet_bridge_relayers::benchmarking::Config for TestRuntime { + fn prepare_environment(account_params: RewardsAccountParams, reward: Balance) { + use frame_support::traits::fungible::Mutate; + let rewards_account = + bp_relayers::PayRewardFromAccount::::rewards_account( + account_params, + ); + Balances::mint_into(&rewards_account, reward).unwrap(); + } +} + +/// Message lane that we're using in tests. +pub const TEST_REWARDS_ACCOUNT_PARAMS: RewardsAccountParams = + RewardsAccountParams::new(LaneId([0, 0, 0, 0]), *b"test", RewardsAccountOwner::ThisChain); + +/// Regular relayer that may receive rewards. +pub const REGULAR_RELAYER: AccountId = 1; + +/// Relayer that can't receive rewards. +pub const FAILING_RELAYER: AccountId = 2; + +/// Payment procedure that rejects payments to the `FAILING_RELAYER`. +pub struct TestPaymentProcedure; + +impl PaymentProcedure for TestPaymentProcedure { + type Error = (); + + fn pay_reward( + relayer: &AccountId, + _lane_id: RewardsAccountParams, + _reward: Balance, + ) -> Result<(), Self::Error> { + match *relayer { + FAILING_RELAYER => Err(()), + _ => Ok(()), + } + } +} + +/// Return test externalities to use in tests. +pub fn new_test_ext() -> sp_io::TestExternalities { + let t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + sp_io::TestExternalities::new(t) +} + +/// Run pallet test. +pub fn run_test(test: impl FnOnce() -> T) -> T { + new_test_ext().execute_with(test) +} diff --git a/modules/relayers/src/payment_adapter.rs b/modules/relayers/src/payment_adapter.rs new file mode 100644 index 00000000000..a9536cfc027 --- /dev/null +++ b/modules/relayers/src/payment_adapter.rs @@ -0,0 +1,158 @@ +// Copyright 2019-2021 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 . + +//! Code that allows relayers pallet to be used as a payment mechanism for the messages pallet. + +use crate::{Config, Pallet}; + +use bp_messages::{ + source_chain::{DeliveryConfirmationPayments, RelayersRewards}, + LaneId, MessageNonce, +}; +use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; +use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; +use sp_arithmetic::traits::{Saturating, Zero}; +use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive}; + +/// Adapter that allows relayers pallet to be used as a delivery+dispatch payment mechanism +/// for the messages pallet. +pub struct DeliveryConfirmationPaymentsAdapter( + PhantomData<(T, MI, DeliveryReward)>, +); + +impl DeliveryConfirmationPayments + for DeliveryConfirmationPaymentsAdapter +where + T: Config + pallet_bridge_messages::Config, + MI: 'static, + DeliveryReward: Get, +{ + type Error = &'static str; + + fn pay_reward( + lane_id: LaneId, + messages_relayers: VecDeque>, + confirmation_relayer: &T::AccountId, + received_range: &RangeInclusive, + ) -> MessageNonce { + let relayers_rewards = + bp_messages::calc_relayers_rewards::(messages_relayers, received_range); + let rewarded_relayers = relayers_rewards.len(); + + register_relayers_rewards::( + confirmation_relayer, + relayers_rewards, + RewardsAccountParams::new( + lane_id, + T::BridgedChainId::get(), + RewardsAccountOwner::BridgedChain, + ), + DeliveryReward::get(), + ); + + rewarded_relayers as _ + } +} + +// Update rewards to given relayers, optionally rewarding confirmation relayer. +fn register_relayers_rewards( + confirmation_relayer: &T::AccountId, + relayers_rewards: RelayersRewards, + lane_id: RewardsAccountParams, + delivery_fee: T::Reward, +) { + // reward every relayer except `confirmation_relayer` + let mut confirmation_relayer_reward = T::Reward::zero(); + for (relayer, messages) in relayers_rewards { + // sane runtime configurations guarantee that the number of messages will be below + // `u32::MAX` + let relayer_reward = T::Reward::saturated_from(messages).saturating_mul(delivery_fee); + + if relayer != *confirmation_relayer { + Pallet::::register_relayer_reward(lane_id, &relayer, relayer_reward); + } else { + confirmation_relayer_reward = + confirmation_relayer_reward.saturating_add(relayer_reward); + } + } + + // finally - pay reward to confirmation relayer + Pallet::::register_relayer_reward( + lane_id, + confirmation_relayer, + confirmation_relayer_reward, + ); +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{mock::*, RelayerRewards}; + + const RELAYER_1: AccountId = 1; + const RELAYER_2: AccountId = 2; + const RELAYER_3: AccountId = 3; + + fn relayers_rewards() -> RelayersRewards { + vec![(RELAYER_1, 2), (RELAYER_2, 3)].into_iter().collect() + } + + #[test] + fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() { + run_test(|| { + register_relayers_rewards::( + &RELAYER_2, + relayers_rewards(), + TEST_REWARDS_ACCOUNT_PARAMS, + 50, + ); + + assert_eq!( + RelayerRewards::::get(RELAYER_1, TEST_REWARDS_ACCOUNT_PARAMS), + Some(100) + ); + assert_eq!( + RelayerRewards::::get(RELAYER_2, TEST_REWARDS_ACCOUNT_PARAMS), + Some(150) + ); + }); + } + + #[test] + fn confirmation_relayer_is_not_rewarded_if_it_has_not_delivered_any_messages() { + run_test(|| { + register_relayers_rewards::( + &RELAYER_3, + relayers_rewards(), + TEST_REWARDS_ACCOUNT_PARAMS, + 50, + ); + + assert_eq!( + RelayerRewards::::get(RELAYER_1, TEST_REWARDS_ACCOUNT_PARAMS), + Some(100) + ); + assert_eq!( + RelayerRewards::::get(RELAYER_2, TEST_REWARDS_ACCOUNT_PARAMS), + Some(150) + ); + assert_eq!( + RelayerRewards::::get(RELAYER_3, TEST_REWARDS_ACCOUNT_PARAMS), + None + ); + }); + } +} diff --git a/modules/relayers/src/weights.rs b/modules/relayers/src/weights.rs new file mode 100644 index 00000000000..1f111aaf136 --- /dev/null +++ b/modules/relayers/src/weights.rs @@ -0,0 +1,101 @@ +// Copyright 2019-2021 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 . + +//! Autogenerated weights for pallet_bridge_relayers +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-03-02, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `covid`, CPU: `11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz` +//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 + +// Executed Command: +// target/release/millau-bridge-node +// benchmark +// pallet +// --chain=dev +// --steps=50 +// --repeat=20 +// --pallet=pallet_bridge_relayers +// --extrinsic=* +// --execution=wasm +// --wasm-execution=Compiled +// --heap-pages=4096 +// --output=./modules/relayers/src/weights.rs +// --template=./.maintain/millau-weight-template.hbs + +#![allow(clippy::all)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{ + traits::Get, + weights::{constants::RocksDbWeight, Weight}, +}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for pallet_bridge_relayers. +pub trait WeightInfo { + fn claim_rewards() -> Weight; +} + +/// Weights for `pallet_bridge_relayers` 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: BridgeRelayers RelayerRewards (r:1 w:1) + /// + /// Proof: BridgeRelayers RelayerRewards (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(96), added: 2571, mode: + /// MaxEncodedLen) + fn claim_rewards() -> Weight { + // Proof Size summary in bytes: + // Measured: `275` + // Estimated: `5111` + // Minimum execution time: 48_639 nanoseconds. + Weight::from_parts(49_600_000, 5111) + .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: BridgeRelayers RelayerRewards (r:1 w:1) + /// + /// Proof: BridgeRelayers RelayerRewards (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(96), added: 2571, mode: + /// MaxEncodedLen) + fn claim_rewards() -> Weight { + // Proof Size summary in bytes: + // Measured: `275` + // Estimated: `5111` + // Minimum execution time: 48_639 nanoseconds. + Weight::from_parts(49_600_000, 5111) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) + } +} diff --git a/modules/shift-session-manager/Cargo.toml b/modules/shift-session-manager/Cargo.toml new file mode 100644 index 00000000000..2d7dc272a6f --- /dev/null +++ b/modules/shift-session-manager/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "pallet-shift-session-manager" +description = "A Substrate Runtime module that selects 2/3 of initial validators for every session" +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 } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "pallet-session/std", + "scale-info/std", + "sp-staking/std", + "sp-std/std", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", +] diff --git a/modules/shift-session-manager/README.md b/modules/shift-session-manager/README.md new file mode 100644 index 00000000000..8dfbfd416e3 --- /dev/null +++ b/modules/shift-session-manager/README.md @@ -0,0 +1,10 @@ +# Shift Session Manager Pallet + +**THIS PALLET IS NOT INTENDED TO BE USED IN PRODUCTION** + +The pallet does not provide any calls or runtime storage entries. It only provides implementation of the +`pallet_session::SessionManager`. This implementation, starting from session `3` selects two thirds of initial +validators and changes the set on every session. We are using it at our testnets ([Rialto](../../bin/rialto/) and +[Millau](../../bin/millau/)) to be sure that the set changes every session. On well-known production chains +(like Kusama and Polkadot) the alternative is the set of [nPoS](https://research.web3.foundation/en/latest/polkadot/NPoS/index.html) +pallets, which selects validators, based on their nominations. diff --git a/modules/shift-session-manager/src/lib.rs b/modules/shift-session-manager/src/lib.rs new file mode 100644 index 00000000000..1c38a52b0c2 --- /dev/null +++ b/modules/shift-session-manager/src/lib.rs @@ -0,0 +1,266 @@ +// Copyright 2019-2021 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 . + +//! Substrate session manager that selects 2/3 validators from initial set, +//! starting from session 2. + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::traits::{ValidatorSet, ValidatorSetWithIdentification}; +use sp_std::prelude::*; + +pub use pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::config] + #[pallet::disable_frame_system_supertrait_check] + pub trait Config: pallet_session::Config {} + + #[pallet::pallet] + #[pallet::without_storage_info] + pub struct Pallet(PhantomData); + + #[pallet::hooks] + impl Hooks> for Pallet {} + + #[pallet::call] + impl Pallet {} + + /// Validators of first two sessions. + #[pallet::storage] + pub(super) type InitialValidators = StorageValue<_, Vec>; +} + +impl ValidatorSet for Pallet { + type ValidatorId = T::ValidatorId; + type ValidatorIdOf = T::ValidatorIdOf; + + fn session_index() -> sp_staking::SessionIndex { + pallet_session::Pallet::::current_index() + } + + fn validators() -> Vec { + pallet_session::Pallet::::validators() + } +} + +impl ValidatorSetWithIdentification for Pallet { + type Identification = (); + type IdentificationOf = (); +} + +impl pallet_session::SessionManager for Pallet { + fn end_session(_: sp_staking::SessionIndex) {} + fn start_session(_: sp_staking::SessionIndex) {} + fn new_session(session_index: sp_staking::SessionIndex) -> Option> { + // we don't want to add even more fields to genesis config => just return None + if session_index == 0 || session_index == 1 { + return None + } + + // the idea that on first call (i.e. when session 1 ends) we're reading current + // set of validators from session module (they are initial validators) and save + // in our 'local storage'. + // then for every session we select (deterministically) 2/3 of these initial + // validators to serve validators of new session + let available_validators = InitialValidators::::get().unwrap_or_else(|| { + let validators = >::validators(); + InitialValidators::::put(validators.clone()); + validators + }); + + Some(Self::select_validators(session_index, &available_validators)) + } +} + +impl Pallet { + /// Select validators for session. + fn select_validators( + session_index: sp_staking::SessionIndex, + available_validators: &[T::ValidatorId], + ) -> Vec { + let available_validators_count = available_validators.len(); + let count = sp_std::cmp::max(1, 2 * available_validators_count / 3); + let offset = session_index as usize % available_validators_count; + let end = offset + count; + let session_validators = match end.overflowing_sub(available_validators_count) { + (wrapped_end, false) if wrapped_end != 0 => available_validators[offset..] + .iter() + .chain(available_validators[..wrapped_end].iter()) + .cloned() + .collect(), + _ => available_validators[offset..end].to_vec(), + }; + + session_validators + } +} + +#[cfg(test)] +mod tests { + // From construct_runtime macro + #![allow(clippy::from_over_into)] + + use super::*; + use frame_support::{ + parameter_types, + sp_io::TestExternalities, + sp_runtime::{ + testing::{Header, UintAuthorityId}, + traits::{BlakeTwo256, ConvertInto, IdentityLookup}, + Perbill, RuntimeAppPublic, + }, + traits::GenesisBuild, + weights::Weight, + BasicExternalities, + }; + use sp_core::H256; + + type AccountId = u64; + + type Block = frame_system::mocking::MockBlock; + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + + frame_support::construct_runtime! { + pub enum TestRuntime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Session: pallet_session::{Pallet}, + } + } + + parameter_types! { + pub const MaximumBlockWeight: Weight = Weight::from_parts(1024, 0); + pub const MaximumBlockLength: u32 = 2 * 1024; + pub const AvailableBlockRatio: Perbill = Perbill::one(); + } + + impl frame_system::Config for TestRuntime { + type RuntimeOrigin = RuntimeOrigin; + type Index = u64; + type RuntimeCall = RuntimeCall; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Header = Header; + type 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>; + } + + parameter_types! { + pub const Period: u64 = 1; + pub const Offset: u64 = 0; + } + + impl pallet_session::Config for TestRuntime { + type RuntimeEvent = (); + type ValidatorId = ::AccountId; + type ValidatorIdOf = ConvertInto; + type ShouldEndSession = pallet_session::PeriodicSessions; + type NextSessionRotation = pallet_session::PeriodicSessions; + type SessionManager = (); + type SessionHandler = TestSessionHandler; + type Keys = UintAuthorityId; + type WeightInfo = (); + } + + impl Config for TestRuntime {} + + pub struct TestSessionHandler; + impl pallet_session::SessionHandler for TestSessionHandler { + const KEY_TYPE_IDS: &'static [sp_runtime::KeyTypeId] = &[UintAuthorityId::ID]; + + fn on_genesis_session(_validators: &[(AccountId, Ks)]) { + } + + fn on_new_session( + _: bool, + _: &[(AccountId, Ks)], + _: &[(AccountId, Ks)], + ) { + } + + fn on_disabled(_: u32) {} + } + + fn new_test_ext() -> TestExternalities { + let mut t = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let keys = vec![ + (1, 1, UintAuthorityId(1)), + (2, 2, UintAuthorityId(2)), + (3, 3, UintAuthorityId(3)), + (4, 4, UintAuthorityId(4)), + (5, 5, UintAuthorityId(5)), + ]; + + BasicExternalities::execute_with_storage(&mut t, || { + for (ref k, ..) in &keys { + frame_system::Pallet::::inc_providers(k); + } + }); + + pallet_session::GenesisConfig:: { keys } + .assimilate_storage(&mut t) + .unwrap(); + TestExternalities::new(t) + } + + #[test] + fn shift_session_manager_works() { + new_test_ext().execute_with(|| { + let all_accs = vec![1, 2, 3, 4, 5]; + + // at least 1 validator is selected + assert_eq!(Pallet::::select_validators(0, &[1]), vec![1],); + + // at session#0, shift is also 0 + assert_eq!(Pallet::::select_validators(0, &all_accs), vec![1, 2, 3],); + + // at session#1, shift is also 1 + assert_eq!(Pallet::::select_validators(1, &all_accs), vec![2, 3, 4],); + + // at session#3, we're wrapping + assert_eq!(Pallet::::select_validators(3, &all_accs), vec![4, 5, 1],); + + // at session#5, we're starting from the beginning again + assert_eq!(Pallet::::select_validators(5, &all_accs), vec![1, 2, 3],); + }); + } +} diff --git a/primitives/beefy/Cargo.toml b/primitives/beefy/Cargo.toml new file mode 100644 index 00000000000..9039064fbf4 --- /dev/null +++ b/primitives/beefy/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "bp-beefy" +description = "Primitives of pallet-bridge-beefy module." +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.0.0", default-features = false, features = ["derive", "bit-vec"] } +scale-info = { version = "2.5.0", default-features = false, features = ["bit-vec", "derive"] } +serde = { version = "1.0", optional = true } + +# Bridge Dependencies + +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Dependencies + +binary-merkle-tree = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-consensus-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-runtime/std", + "codec/std", + "frame-support/std", + "pallet-beefy-mmr/std", + "pallet-mmr/std", + "scale-info/std", + "serde", + "sp-consensus-beefy/std", + "sp-runtime/std", + "sp-std/std" +] diff --git a/primitives/beefy/src/lib.rs b/primitives/beefy/src/lib.rs new file mode 100644 index 00000000000..de260d45eca --- /dev/null +++ b/primitives/beefy/src/lib.rs @@ -0,0 +1,149 @@ +// Copyright 2019-2021 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 . + +//! Primitives that are used to interact with BEEFY bridge pallet. + +#![cfg_attr(not(feature = "std"), no_std)] +#![warn(missing_docs)] + +pub use binary_merkle_tree::merkle_root; +pub use pallet_beefy_mmr::BeefyEcdsaToEthereum; +pub use pallet_mmr::{ + primitives::{DataOrHash as MmrDataOrHash, Proof as MmrProof}, + verify_leaves_proof as verify_mmr_leaves_proof, +}; +pub use sp_consensus_beefy::{ + crypto::{AuthorityId as EcdsaValidatorId, AuthoritySignature as EcdsaValidatorSignature}, + known_payloads::MMR_ROOT_ID as MMR_ROOT_PAYLOAD_ID, + mmr::{BeefyAuthoritySet, MmrLeafVersion}, + BeefyAuthorityId, Commitment, Payload as BeefyPayload, SignedCommitment, ValidatorSet, + ValidatorSetId, BEEFY_ENGINE_ID, +}; + +use bp_runtime::{BasicOperatingMode, BlockNumberOf, Chain, HashOf}; +use codec::{Decode, Encode}; +use frame_support::Parameter; +use scale_info::TypeInfo; +use sp_runtime::{ + traits::{Convert, MaybeSerializeDeserialize}, + RuntimeAppPublic, RuntimeDebug, +}; +use sp_std::prelude::*; + +/// Substrate-based chain with BEEFY && MMR pallets deployed. +/// +/// Both BEEFY and MMR pallets and their clients may be configured to use different +/// primitives. Some of types can be configured in low-level pallets, but are constrained +/// when BEEFY+MMR bundle is used. +pub trait ChainWithBeefy: Chain { + /// The hashing algorithm used to compute the digest of the BEEFY commitment. + /// + /// Corresponds to the hashing algorithm, used by `sc_consensus_beefy::BeefyKeystore`. + type CommitmentHasher: sp_runtime::traits::Hash; + + /// The hashing algorithm used to build the MMR. + /// + /// The same algorithm is also used to compute merkle roots in BEEFY + /// (e.g. validator addresses root in leaf data). + /// + /// Corresponds to the `Hashing` field of the `pallet-mmr` configuration. + type MmrHashing: sp_runtime::traits::Hash; + + /// The output type of the hashing algorithm used to build the MMR. + /// + /// This type is actually stored in the MMR. + + /// Corresponds to the `Hash` field of the `pallet-mmr` configuration. + type MmrHash: sp_std::hash::Hash + + Parameter + + Copy + + AsRef<[u8]> + + Default + + MaybeSerializeDeserialize + + PartialOrd; + + /// The type expected for the MMR leaf extra data. + type BeefyMmrLeafExtra: Parameter; + + /// A way to identify a BEEFY validator. + /// + /// Corresponds to the `BeefyId` field of the `pallet-beefy` configuration. + type AuthorityId: BeefyAuthorityId + Parameter; + + /// A way to convert validator id to its raw representation in the BEEFY merkle tree. + /// + /// Corresponds to the `BeefyAuthorityToMerkleLeaf` field of the `pallet-beefy-mmr` + /// configuration. + type AuthorityIdToMerkleLeaf: Convert>; +} + +/// BEEFY validator id used by given Substrate chain. +pub type BeefyAuthorityIdOf = ::AuthorityId; +/// BEEFY validator set, containing both validator identifiers and the numeric set id. +pub type BeefyAuthoritySetOf = ValidatorSet>; +/// BEEFY authority set, containing both validator identifiers and the numeric set id. +pub type BeefyAuthoritySetInfoOf = sp_consensus_beefy::mmr::BeefyAuthoritySet>; +/// BEEFY validator signature used by given Substrate chain. +pub type BeefyValidatorSignatureOf = + <::AuthorityId as RuntimeAppPublic>::Signature; +/// Signed BEEFY commitment used by given Substrate chain. +pub type BeefySignedCommitmentOf = + SignedCommitment, BeefyValidatorSignatureOf>; +/// Hash algorithm, used to compute the digest of the BEEFY commitment before signing it. +pub type BeefyCommitmentHasher = ::CommitmentHasher; +/// Hash algorithm used in Beefy MMR construction by given Substrate chain. +pub type MmrHashingOf = ::MmrHashing; +/// Hash type, used in MMR construction by given Substrate chain. +pub type MmrHashOf = ::MmrHash; +/// BEEFY MMR proof type used by the given Substrate chain. +pub type MmrProofOf = MmrProof>; +/// The type of the MMR leaf extra data used by the given Substrate chain. +pub type BeefyMmrLeafExtraOf = ::BeefyMmrLeafExtra; +/// A way to convert a validator id to its raw representation in the BEEFY merkle tree, used by +/// the given Substrate chain. +pub type BeefyAuthorityIdToMerkleLeafOf = ::AuthorityIdToMerkleLeaf; +/// Actual type of leafs in the BEEFY MMR. +pub type BeefyMmrLeafOf = sp_consensus_beefy::mmr::MmrLeaf< + BlockNumberOf, + HashOf, + MmrHashOf, + BeefyMmrLeafExtraOf, +>; + +/// Data required for initializing the BEEFY pallet. +/// +/// Provides the initial context that the bridge needs in order to know +/// where to start the sync process from. +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Clone, TypeInfo)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +pub struct InitializationData { + /// Pallet operating mode. + pub operating_mode: BasicOperatingMode, + /// Number of the best block, finalized by BEEFY. + pub best_block_number: BlockNumber, + /// BEEFY authority set that will be finalizing descendants of the `best_beefy_block_number` + /// block. + pub authority_set: BeefyAuthoritySet, +} + +/// Basic data, stored by the pallet for every imported commitment. +#[derive(Encode, Decode, RuntimeDebug, PartialEq, TypeInfo)] +pub struct ImportedCommitment { + /// Block number and hash of the finalized block parent. + pub parent_number_and_hash: (BlockNumber, BlockHash), + /// MMR root at the imported block. + pub mmr_root: MmrHash, +} diff --git a/primitives/chain-bridge-hub-cumulus/Cargo.toml b/primitives/chain-bridge-hub-cumulus/Cargo.toml new file mode 100644 index 00000000000..2bbe3d029a3 --- /dev/null +++ b/primitives/chain-bridge-hub-cumulus/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "bp-bridge-hub-cumulus" +description = "Primitives of BridgeHubRococo parachain runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +# Bridge Dependencies + +bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false } +bp-messages = { path = "../../primitives/messages", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } + +# Substrate Based Dependencies + +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +# Polkadot Dependencies +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-polkadot-core/std", + "bp-messages/std", + "bp-runtime/std", + "frame-system/std", + "frame-support/std", + "sp-api/std", + "sp-std/std", + "polkadot-primitives/std", +] diff --git a/primitives/chain-bridge-hub-cumulus/src/lib.rs b/primitives/chain-bridge-hub-cumulus/src/lib.rs new file mode 100644 index 00000000000..4c9f9e20468 --- /dev/null +++ b/primitives/chain-bridge-hub-cumulus/src/lib.rs @@ -0,0 +1,216 @@ +// Copyright 2022 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)] + +pub use bp_polkadot_core::{ + AccountId, AccountInfoStorageMapKeyProvider, AccountPublic, Balance, BlockNumber, Hash, Hasher, + Hashing, Header, Index, Nonce, Perbill, Signature, SignedBlock, UncheckedExtrinsic, + EXTRA_STORAGE_PROOF_SIZE, TX_EXTRA_BYTES, +}; + +use bp_messages::*; +use bp_runtime::extensions::{ + BridgeRejectObsoleteHeadersAndMessages, ChargeTransactionPayment, CheckEra, CheckGenesis, + CheckNonZeroSender, CheckNonce, CheckSpecVersion, CheckTxVersion, CheckWeight, + GenericSignedExtension, RefundBridgedParachainMessagesSchema, +}; +use frame_support::{ + dispatch::DispatchClass, + parameter_types, + sp_runtime::{MultiAddress, MultiSigner}, + weights::constants, +}; +use frame_system::limits; +use sp_std::time::Duration; + +/// Average block interval in Cumulus-based parachains. +/// +/// Corresponds to the `MILLISECS_PER_BLOCK` from `parachains_common` crate. +pub const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(12); + +/// All cumulus bridge hubs allow normal extrinsics to fill block up to 75 percent. +/// +/// This is a copy-paste from the cumulus repo's `parachains-common` crate. +pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// All cumulus bridge hubs chains allow for 0.5 seconds of compute with a 6-second average block +/// time. +/// +/// 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::v4::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. +/// +/// This is a copy-paste from the cumulus repo's `parachains-common` crate. +pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); + +parameter_types! { + pub BlockLength: limits::BlockLength = limits::BlockLength::max_with_normal_ratio( + 5 * 1024 * 1024, + NORMAL_DISPATCH_RATIO, + ); + + /// Importing a block with 0 Extrinsics. + pub const BlockExecutionWeight: Weight = Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS, 0) + .saturating_mul(5_000_000); + /// Executing a NO-OP `System::remarks` Extrinsic. + pub const ExtrinsicBaseWeight: Weight = Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS, 0) + .saturating_mul(125_000); + + pub BlockWeights: limits::BlockWeights = limits::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 an 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(); +} + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// The address format for describing accounts. +pub type Address = MultiAddress; + +// Note about selecting values of two following constants: +// +// Normal transactions have limit of 75% of 1/2 second weight for Cumulus parachains. Let's keep +// some reserve for the rest of stuff there => let's select values that fit in 50% of maximal limit. +// +// Using current constants, the limit would be: +// +// `75% * WEIGHT_REF_TIME_PER_SECOND * 1 / 2 * 50% = 0.75 * 1_000_000_000_000 / 2 * 0.5 = +// 187_500_000_000` +// +// According to (preliminary) weights of messages pallet, cost of additional message is zero and the +// cost of additional relayer is `8_000_000 + db read + db write`. Let's say we want no more than +// 4096 unconfirmed messages (no any scientific justification for that - it just looks large +// enough). And then we can't have more than 4096 relayers. E.g. for 1024 relayers is (using +// `RocksDbWeight`): +// +// `1024 * (8_000_000 + db read + db write) = 1024 * (8_000_000 + 25_000_000 + 100_000_000) = +// 136_192_000_000` +// +// So 1024 looks like good approximation for the number of relayers. If something is wrong in those +// assumptions, or something will change, it shall be caught by the +// `ensure_able_to_receive_confirmation` test. + +/// 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; + +/// Extra signed extension data that is used by all bridge hubs. +pub type SignedExtra = ( + CheckNonZeroSender, + CheckSpecVersion, + CheckTxVersion, + CheckGenesis, + CheckEra, + CheckNonce, + CheckWeight, + ChargeTransactionPayment, + 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: Index, + tip: Balance, + ) -> Self; + + /// Return transaction nonce. + fn nonce(&self) -> Index; + + /// 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: Index, + 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) -> Index { + self.payload.5 .0 + } + + /// Return transaction tip. + fn tip(&self) -> Balance { + self.payload.7 .0 + } +} diff --git a/primitives/chain-bridge-hub-kusama/Cargo.toml b/primitives/chain-bridge-hub-kusama/Cargo.toml new file mode 100644 index 00000000000..6d4334eaa57 --- /dev/null +++ b/primitives/chain-bridge-hub-kusama/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "bp-bridge-hub-kusama" +description = "Primitives of BridgeHubRococo parachain runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", 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-std/std", +] diff --git a/primitives/chain-bridge-hub-kusama/src/lib.rs b/primitives/chain-bridge-hub-kusama/src/lib.rs new file mode 100644 index 00000000000..6ca2cd047fb --- /dev/null +++ b/primitives/chain-bridge-hub-kusama/src/lib.rs @@ -0,0 +1,84 @@ +// Copyright 2022 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 BridgeHubKusama 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, + sp_runtime::{MultiAddress, MultiSigner}, + RuntimeDebug, +}; +use sp_std::prelude::*; + +/// BridgeHubKusama parachain. +#[derive(RuntimeDebug)] +pub struct BridgeHubKusama; + +impl Chain for BridgeHubKusama { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Index; + 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 BridgeHubKusama { + const PARACHAIN_ID: u32 = BRIDGE_HUB_KUSAMA_PARACHAIN_ID; +} + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// The address format for describing accounts. +pub type Address = MultiAddress; + +/// Identifier of BridgeHubKusama in the Kusama relay chain. +pub const BRIDGE_HUB_KUSAMA_PARACHAIN_ID: u32 = 1002; + +/// Name of the With-BridgeHubKusama messages pallet instance that is deployed at bridged chains. +// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945) +pub const WITH_BRIDGE_HUB_KUSAMA_MESSAGES_PALLET_NAME: &str = "BridgeKusamaMessages"; + +/// Name of the With-BridgeHubKusama bridge-relayers pallet instance that is deployed at bridged +/// chains. +// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945) +pub const WITH_BRIDGE_HUB_KUSAMA_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; + +decl_bridge_finality_runtime_apis!(bridge_hub_kusama); +decl_bridge_messages_runtime_apis!(bridge_hub_kusama); diff --git a/primitives/chain-bridge-hub-polkadot/Cargo.toml b/primitives/chain-bridge-hub-polkadot/Cargo.toml new file mode 100644 index 00000000000..2a0ab3213c8 --- /dev/null +++ b/primitives/chain-bridge-hub-polkadot/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "bp-bridge-hub-polkadot" +description = "Primitives of BridgeHubWococo parachain runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-bridge-hub-cumulus/std", + "bp-runtime/std", + "bp-messages/std", + "frame-support/std", + "sp-api/std", + "sp-std/std", +] diff --git a/primitives/chain-bridge-hub-polkadot/src/lib.rs b/primitives/chain-bridge-hub-polkadot/src/lib.rs new file mode 100644 index 00000000000..646fb0a6e41 --- /dev/null +++ b/primitives/chain-bridge-hub-polkadot/src/lib.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2021 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 BridgeHubPolkadot 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, RuntimeDebug}; +use sp_std::prelude::*; + +/// BridgeHubPolkadot parachain. +#[derive(RuntimeDebug)] +pub struct BridgeHubPolkadot; + +impl Chain for BridgeHubPolkadot { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Index; + 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 BridgeHubPolkadot { + const PARACHAIN_ID: u32 = BRIDGE_HUB_POLKADOT_PARACHAIN_ID; +} + +/// Identifier of BridgeHubPolkadot in the Polkadot relay chain. +// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945) +pub const BRIDGE_HUB_POLKADOT_PARACHAIN_ID: u32 = 1002; + +/// Name of the With-BridgeHubPolkadot messages pallet instance that is deployed at bridged chains. +// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945) +pub const WITH_BRIDGE_HUB_POLKADOT_MESSAGES_PALLET_NAME: &str = "BridgePolkadotMessages"; + +/// Name of the With-BridgeHubPolkadot bridge-relayers pallet instance that is deployed at bridged +/// chains. +// TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945) +pub const WITH_BRIDGE_HUB_POLKADOT_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; + +decl_bridge_finality_runtime_apis!(bridge_hub_polkadot); +decl_bridge_messages_runtime_apis!(bridge_hub_polkadot); diff --git a/primitives/chain-bridge-hub-rococo/Cargo.toml b/primitives/chain-bridge-hub-rococo/Cargo.toml new file mode 100644 index 00000000000..85c4225ab55 --- /dev/null +++ b/primitives/chain-bridge-hub-rococo/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "bp-bridge-hub-rococo" +description = "Primitives of BridgeHubRococo parachain runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", 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-std/std", +] diff --git a/primitives/chain-bridge-hub-rococo/src/lib.rs b/primitives/chain-bridge-hub-rococo/src/lib.rs new file mode 100644 index 00000000000..936e4d1beb7 --- /dev/null +++ b/primitives/chain-bridge-hub-rococo/src/lib.rs @@ -0,0 +1,82 @@ +// Copyright 2022 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 BridgeHubRococo 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, + sp_runtime::{MultiAddress, MultiSigner}, + RuntimeDebug, +}; +use sp_std::prelude::*; + +/// BridgeHubRococo parachain. +#[derive(RuntimeDebug)] +pub struct BridgeHubRococo; + +impl Chain for BridgeHubRococo { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Index; + 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 BridgeHubRococo { + const PARACHAIN_ID: u32 = BRIDGE_HUB_ROCOCO_PARACHAIN_ID; +} + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// The address format for describing accounts. +pub type Address = MultiAddress; + +/// Identifier of BridgeHubRococo in the Rococo relay chain. +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"; + +/// 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"; + +decl_bridge_finality_runtime_apis!(bridge_hub_rococo); +decl_bridge_messages_runtime_apis!(bridge_hub_rococo); diff --git a/primitives/chain-bridge-hub-wococo/Cargo.toml b/primitives/chain-bridge-hub-wococo/Cargo.toml new file mode 100644 index 00000000000..24ecdb7adbc --- /dev/null +++ b/primitives/chain-bridge-hub-wococo/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "bp-bridge-hub-wococo" +description = "Primitives of BridgeHubWococo parachain runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-bridge-hub-cumulus/std", + "bp-runtime/std", + "bp-messages/std", + "frame-support/std", + "sp-api/std", + "sp-std/std", +] diff --git a/primitives/chain-bridge-hub-wococo/src/lib.rs b/primitives/chain-bridge-hub-wococo/src/lib.rs new file mode 100644 index 00000000000..00704995c5e --- /dev/null +++ b/primitives/chain-bridge-hub-wococo/src/lib.rs @@ -0,0 +1,72 @@ +// Copyright 2019-2021 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, RuntimeDebug}; +use sp_std::prelude::*; + +/// 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 Index = Index; + 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"; + +decl_bridge_finality_runtime_apis!(bridge_hub_wococo); +decl_bridge_messages_runtime_apis!(bridge_hub_wococo); diff --git a/primitives/chain-kusama/Cargo.toml b/primitives/chain-kusama/Cargo.toml new file mode 100644 index 00000000000..7f48ded1a37 --- /dev/null +++ b/primitives/chain-kusama/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "bp-kusama" +description = "Primitives of Kusama runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "frame-support/std", + "sp-api/std", +] diff --git a/primitives/chain-kusama/src/lib.rs b/primitives/chain-kusama/src/lib.rs new file mode 100644 index 00000000000..8e5aec8afda --- /dev/null +++ b/primitives/chain-kusama/src/lib.rs @@ -0,0 +1,65 @@ +// Copyright 2019-2021 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::weights::Weight; + +/// Kusama Chain +pub struct Kusama; + +impl Chain for Kusama { + type BlockNumber = ::BlockNumber; + type Hash = ::Hash; + type Hasher = ::Hasher; + type Header = ::Header; + + type AccountId = ::AccountId; + type Balance = ::Balance; + type Index = ::Index; + type Signature = ::Signature; + + fn max_extrinsic_size() -> u32 { + PolkadotLike::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + PolkadotLike::max_extrinsic_weight() + } +} + +impl ChainWithGrandpa for Kusama { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_KUSAMA_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; +} + +/// Name of the parachains pallet in the Kusama runtime. +pub const PARAS_PALLET_NAME: &str = "Paras"; + +/// Name of the With-Kusama GRANDPA pallet instance that is deployed at bridged chains. +pub const WITH_KUSAMA_GRANDPA_PALLET_NAME: &str = "BridgeKusamaGrandpa"; + +decl_bridge_finality_runtime_apis!(kusama); diff --git a/primitives/chain-millau/Cargo.toml b/primitives/chain-millau/Cargo.toml new file mode 100644 index 00000000000..d1e2e0edd96 --- /dev/null +++ b/primitives/chain-millau/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "bp-millau" +description = "Primitives of Millau runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] + +fixed-hash = { version = "0.8.0", default-features = false } +hash256-std-hasher = { version = "0.15.2", default-features = false } +impl-codec = { version = "0.6", default-features = false } +impl-serde = { version = "0.4.0", optional = true } +parity-util-mem = { version = "0.12.0", default-features = false, features = ["primitive-types"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } + +# Bridge Dependencies + +bp-beefy = { path = "../beefy", default-features = false } +bp-header-chain = { path = "../header-chain", default-features = false } +bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Based Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-beefy/std", + "bp-header-chain/std", + "bp-messages/std", + "bp-runtime/std", + "fixed-hash/std", + "frame-support/std", + "frame-system/std", + "hash256-std-hasher/std", + "impl-codec/std", + "impl-serde", + "parity-util-mem/std", + "scale-info/std", + "serde", + "sp-api/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "sp-trie/std", +] diff --git a/primitives/chain-millau/src/lib.rs b/primitives/chain-millau/src/lib.rs new file mode 100644 index 00000000000..b7f67ca07e2 --- /dev/null +++ b/primitives/chain-millau/src/lib.rs @@ -0,0 +1,249 @@ +// Copyright 2019-2021 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)] + +mod millau_hash; + +use bp_beefy::ChainWithBeefy; +use bp_header_chain::ChainWithGrandpa; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; +use bp_runtime::{decl_bridge_runtime_apis, Chain}; +use frame_support::{ + dispatch::DispatchClass, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, IdentityFee, Weight}, + RuntimeDebug, +}; +use frame_system::limits; +use scale_info::TypeInfo; +use sp_core::{storage::StateVersion, Hasher as HasherT}; +use sp_runtime::{ + traits::{IdentifyAccount, Verify}, + MultiSignature, MultiSigner, Perbill, +}; +use sp_std::prelude::*; +use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration}; + +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_runtime::traits::Keccak256; + +pub use millau_hash::MillauHash; + +/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at +/// Millau chain. 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; + +/// Number of bytes, included in the signed Millau transaction apart from the encoded call itself. +/// +/// Can be computed by subtracting encoded call size from raw transaction size. +pub const TX_EXTRA_BYTES: u32 = 103; + +/// Maximum weight of single Millau block. +/// +/// This represents 0.5 seconds of compute assuming a target block time of six seconds. +/// +/// Max PoV size is set to max value, since it isn't important for relay/standalone chains. +pub const MAXIMUM_BLOCK_WEIGHT: Weight = + Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), u64::MAX); + +/// Represents the portion of a block that will be used by Normal extrinsics. +pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// Maximal number of unrewarded relayer entries in Millau confirmation transaction. +pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 128; + +/// Maximal number of unconfirmed messages in Millau confirmation transaction. +pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; + +/// The target length of a session (how often authorities change) on Millau measured in of number of +/// blocks. +/// +/// Note that since this is a target sessions may change before/after this time depending on network +/// conditions. +pub const SESSION_LENGTH: BlockNumber = 5 * time_units::MINUTES; + +/// Maximal number of GRANDPA authorities at Millau. +pub const MAX_AUTHORITIES_COUNT: u32 = 5; + +/// Reasonable number of headers in the `votes_ancestries` on Millau chain. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +pub const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + +/// Approximate average header size in `votes_ancestries` field of justification on Millau chain. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +pub const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 256; + +/// Approximate maximal header size on Millau chain. +/// +/// We expect maximal header to have digest item with the new authorities set for every consensus +/// engine (GRANDPA, Babe, BEEFY, ...) - so we multiply it by 3. And also +/// `AVERAGE_HEADER_SIZE_IN_JUSTIFICATION` bytes for other stuff. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +pub const MAX_HEADER_SIZE: u32 = MAX_AUTHORITIES_COUNT + .saturating_mul(3) + .saturating_add(AVERAGE_HEADER_SIZE_IN_JUSTIFICATION); + +/// Re-export `time_units` to make usage easier. +pub use time_units::*; + +/// Human readable time units defined in terms of number of blocks. +pub mod time_units { + use super::BlockNumber; + + pub const MILLISECS_PER_BLOCK: u64 = 6000; + pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + + pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); + pub const HOURS: BlockNumber = MINUTES * 60; + pub const DAYS: BlockNumber = HOURS * 24; +} + +/// Block number type used in Millau. +pub type BlockNumber = u64; + +/// Hash type used in Millau. +pub type Hash = ::Out; + +/// Type of object that can produce hashes on Millau. +pub type Hasher = BlakeTwoAndKeccak256; + +/// The header type used by Millau. +pub type Header = sp_runtime::generic::Header; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// Balance of an account. +pub type Balance = u64; + +/// Index of a transaction in the chain. +pub type Index = u32; + +/// Weight-to-Fee type used by Millau. +pub type WeightToFee = IdentityFee; + +/// Millau chain. +#[derive(RuntimeDebug)] +pub struct Millau; + +impl Chain for Millau { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Index; + 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 Millau { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_MILLAU_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; +} + +impl ChainWithBeefy for Millau { + type CommitmentHasher = Keccak256; + type MmrHashing = Keccak256; + type MmrHash = ::Output; + type BeefyMmrLeafExtra = (); + type AuthorityId = bp_beefy::EcdsaValidatorId; + type AuthorityIdToMerkleLeaf = bp_beefy::BeefyEcdsaToEthereum; +} + +/// Millau Hasher (Blake2-256 ++ Keccak-256) implementation. +#[derive(PartialEq, Eq, Clone, Copy, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct BlakeTwoAndKeccak256; + +impl sp_core::Hasher for BlakeTwoAndKeccak256 { + type Out = MillauHash; + type StdHasher = hash256_std_hasher::Hash256StdHasher; + const LENGTH: usize = 64; + + fn hash(s: &[u8]) -> Self::Out { + let mut combined_hash = MillauHash::default(); + combined_hash.as_mut()[..32].copy_from_slice(&sp_io::hashing::blake2_256(s)); + combined_hash.as_mut()[32..].copy_from_slice(&sp_io::hashing::keccak_256(s)); + combined_hash + } +} + +impl sp_runtime::traits::Hash for BlakeTwoAndKeccak256 { + type Output = MillauHash; + + fn trie_root(input: Vec<(Vec, Vec)>, state_version: StateVersion) -> Self::Output { + match state_version { + StateVersion::V0 => LayoutV0::::trie_root(input), + StateVersion::V1 => LayoutV1::::trie_root(input), + } + } + + fn ordered_trie_root(input: Vec>, state_version: StateVersion) -> Self::Output { + match state_version { + StateVersion::V0 => LayoutV0::::ordered_trie_root(input), + StateVersion::V1 => LayoutV1::::ordered_trie_root(input), + } + } +} + +frame_support::parameter_types! { + pub BlockLength: limits::BlockLength = + limits::BlockLength::max_with_normal_ratio(2 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub BlockWeights: limits::BlockWeights = + limits::BlockWeights::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO); +} + +/// Name of the With-Millau GRANDPA pallet instance that is deployed at bridged chains. +pub const WITH_MILLAU_GRANDPA_PALLET_NAME: &str = "BridgeMillauGrandpa"; +/// Name of the With-Millau messages pallet instance that is deployed at bridged chains. +pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages"; +/// Name of the transaction payment pallet at the Millau runtime. +pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment"; + +decl_bridge_runtime_apis!(millau); diff --git a/primitives/chain-millau/src/millau_hash.rs b/primitives/chain-millau/src/millau_hash.rs new file mode 100644 index 00000000000..11968b2f282 --- /dev/null +++ b/primitives/chain-millau/src/millau_hash.rs @@ -0,0 +1,58 @@ +// Copyright 2019-2021 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 . + +use parity_util_mem::MallocSizeOf; +use scale_info::TypeInfo; +use sp_runtime::traits::CheckEqual; + +// `sp_core::H512` can't be used, because it doesn't implement `CheckEqual`, which is required +// by `frame_system::Config::Hash`. + +fixed_hash::construct_fixed_hash! { + /// Hash type used in Millau chain. + #[derive(MallocSizeOf, TypeInfo)] + pub struct MillauHash(64); +} + +#[cfg(feature = "std")] +impl_serde::impl_fixed_hash_serde!(MillauHash, 64); + +impl_codec::impl_fixed_hash_codec!(MillauHash, 64); + +impl CheckEqual for MillauHash { + #[cfg(feature = "std")] + fn check_equal(&self, other: &Self) { + use sp_core::hexdisplay::HexDisplay; + if self != other { + println!( + "Hash: given={}, expected={}", + HexDisplay::from(self.as_fixed_bytes()), + HexDisplay::from(other.as_fixed_bytes()), + ); + } + } + + #[cfg(not(feature = "std"))] + fn check_equal(&self, other: &Self) { + use frame_support::Printable; + + if self != other { + "Hash not equal".print(); + self.as_bytes().print(); + other.as_bytes().print(); + } + } +} diff --git a/primitives/chain-polkadot/Cargo.toml b/primitives/chain-polkadot/Cargo.toml new file mode 100644 index 00000000000..def26bdda1c --- /dev/null +++ b/primitives/chain-polkadot/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "bp-polkadot" +description = "Primitives of Polkadot runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "frame-support/std", + "sp-api/std", +] diff --git a/primitives/chain-polkadot/src/lib.rs b/primitives/chain-polkadot/src/lib.rs new file mode 100644 index 00000000000..92995601698 --- /dev/null +++ b/primitives/chain-polkadot/src/lib.rs @@ -0,0 +1,65 @@ +// Copyright 2019-2021 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::weights::Weight; + +/// Polkadot Chain +pub struct Polkadot; + +impl Chain for Polkadot { + type BlockNumber = ::BlockNumber; + type Hash = ::Hash; + type Hasher = ::Hasher; + type Header = ::Header; + + type AccountId = ::AccountId; + type Balance = ::Balance; + type Index = ::Index; + type Signature = ::Signature; + + fn max_extrinsic_size() -> u32 { + PolkadotLike::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + PolkadotLike::max_extrinsic_weight() + } +} + +impl ChainWithGrandpa for Polkadot { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_POLKADOT_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; +} + +/// Name of the parachains pallet in the Polkadot runtime. +pub const PARAS_PALLET_NAME: &str = "Paras"; + +/// Name of the With-Polkadot GRANDPA pallet instance that is deployed at bridged chains. +pub const WITH_POLKADOT_GRANDPA_PALLET_NAME: &str = "BridgePolkadotGrandpa"; + +decl_bridge_finality_runtime_apis!(polkadot); diff --git a/primitives/chain-rialto-parachain/Cargo.toml b/primitives/chain-rialto-parachain/Cargo.toml new file mode 100644 index 00000000000..3335c6bcc41 --- /dev/null +++ b/primitives/chain-rialto-parachain/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "bp-rialto-parachain" +description = "Primitives of Rialto parachain runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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-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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-bridge-hub-cumulus/std", + "bp-messages/std", + "bp-runtime/std", + "frame-support/std", + "frame-system/std", + "sp-api/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/primitives/chain-rialto-parachain/src/lib.rs b/primitives/chain-rialto-parachain/src/lib.rs new file mode 100644 index 00000000000..67b1a135f34 --- /dev/null +++ b/primitives/chain-rialto-parachain/src/lib.rs @@ -0,0 +1,152 @@ +// Copyright 2019-2021 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)] + +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; +use bp_runtime::{decl_bridge_runtime_apis, Chain, Parachain}; +use frame_support::{ + dispatch::DispatchClass, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, IdentityFee, Weight}, + RuntimeDebug, +}; +use frame_system::limits; +use sp_core::Hasher as HasherT; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, MultiSigner, Perbill, +}; +use sp_std::vec::Vec; + +/// Identifier of RialtoParachain in the Rialto relay chain. +/// +/// This identifier is not something that is declared either by Rialto or RialtoParachain. This +/// is an identifier of registration. So in theory it may be changed. But since bridge is going +/// to be deployed after parachain registration AND since parachain de-registration is highly +/// likely impossible, it is fine to declare this constant here. +pub const RIALTO_PARACHAIN_ID: u32 = 2000; + +/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at +/// RialtoParachain chain. 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; + +/// Can be computed by subtracting encoded call size from raw transaction size. +pub const TX_EXTRA_BYTES: u32 = 104; + +/// Maximal weight of single RialtoParachain block. +/// +/// This represents two seconds of compute assuming a target block time of six seconds. +/// +/// Max PoV size is set to `5Mb` as all Cumulus-based parachains do. +pub const MAXIMUM_BLOCK_WEIGHT: Weight = + Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), 5 * 1024 * 1024); + +/// Represents the portion of a block that will be used by Normal extrinsics. +pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// Maximal number of unrewarded relayer entries in Rialto confirmation transaction. +pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; + +/// Maximal number of unconfirmed messages in Rialto confirmation transaction. +pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1024; + +/// Block number type used in Rialto. +pub type BlockNumber = u32; + +/// Hash type used in Rialto. +pub type Hash = ::Out; + +/// The type of object that can produce hashes on Rialto. +pub type Hasher = BlakeTwo256; + +/// The header type used by Rialto. +pub type Header = sp_runtime::generic::Header; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// Balance of an account. +pub type Balance = u128; + +/// An instant or duration in time. +pub type Moment = u64; + +/// Index of a transaction in the parachain. +pub type Index = u32; + +/// Weight-to-Fee type used by Rialto parachain. +pub type WeightToFee = IdentityFee; + +/// Rialto parachain. +#[derive(RuntimeDebug)] +pub struct RialtoParachain; + +impl Chain for RialtoParachain { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Index; + 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 RialtoParachain { + const PARACHAIN_ID: u32 = RIALTO_PARACHAIN_ID; +} + +// Technically this is incorrect, because rialto-parachain isn't a bridge hub, but we're +// trying to keep it close to the bridge hubs code (at least in this aspect). +pub use bp_bridge_hub_cumulus::SignedExtension; + +frame_support::parameter_types! { + pub BlockLength: limits::BlockLength = + limits::BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub BlockWeights: limits::BlockWeights = + limits::BlockWeights::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO); +} + +/// Name of the With-Rialto-Parachain messages pallet instance that is deployed at bridged chains. +pub const WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME: &str = "BridgeRialtoParachainMessages"; +/// Name of the transaction payment pallet at the Rialto parachain runtime. +pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment"; + +decl_bridge_runtime_apis!(rialto_parachain); diff --git a/primitives/chain-rialto/Cargo.toml b/primitives/chain-rialto/Cargo.toml new file mode 100644 index 00000000000..0a70e0504c9 --- /dev/null +++ b/primitives/chain-rialto/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "bp-rialto" +description = "Primitives of Rialto runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] + +# Bridge Dependencies + +bp-header-chain = { path = "../header-chain", default-features = false } +bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Based Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-messages/std", + "bp-runtime/std", + "frame-support/std", + "frame-system/std", + "sp-api/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/primitives/chain-rialto/src/lib.rs b/primitives/chain-rialto/src/lib.rs new file mode 100644 index 00000000000..01349f131be --- /dev/null +++ b/primitives/chain-rialto/src/lib.rs @@ -0,0 +1,214 @@ +// Copyright 2019-2021 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)] + +use bp_header_chain::ChainWithGrandpa; +use bp_messages::{ + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, +}; +use bp_runtime::{decl_bridge_runtime_apis, Chain}; +use frame_support::{ + dispatch::DispatchClass, + weights::{constants::WEIGHT_REF_TIME_PER_SECOND, IdentityFee, Weight}, + RuntimeDebug, +}; +use frame_system::limits; +use sp_core::Hasher as HasherT; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, MultiSigner, Perbill, +}; +use sp_std::prelude::*; + +/// 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. +/// Some reserve is reserved to account future chain growth. +pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; + +/// Number of bytes, included in the signed Rialto transaction apart from the encoded call itself. +/// +/// Can be computed by subtracting encoded call size from raw transaction size. +pub const TX_EXTRA_BYTES: u32 = 104; + +/// Maximal weight of single Rialto block. +/// +/// This represents two seconds of compute assuming a target block time of six seconds. +/// +/// Max PoV size is set to max value, since it isn't important for relay/standalone chains. +pub const MAXIMUM_BLOCK_WEIGHT: Weight = + Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX); + +/// Represents the portion of a block that will be used by Normal extrinsics. +pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// Maximal number of unrewarded relayer entries in Rialto confirmation transaction. +pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; + +/// Maximal number of unconfirmed messages in Rialto confirmation transaction. +pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1024; + +/// The target length of a session (how often authorities change) on Rialto measured in of number of +/// blocks. +/// +/// Note that since this is a target sessions may change before/after this time depending on network +/// conditions. +pub const SESSION_LENGTH: BlockNumber = 4; + +/// Maximal number of GRANDPA authorities at Rialto. +pub const MAX_AUTHORITIES_COUNT: u32 = 5; + +/// Reasonable number of headers in the `votes_ancestries` on Rialto chain. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +pub const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 8; + +/// Approximate average header size in `votes_ancestries` field of justification on Rialto chain. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +pub const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 256; + +/// Approximate maximal header size on Rialto chain. +/// +/// We expect maximal header to have digest item with the new authorities set for every consensus +/// engine (GRANDPA, Babe, BEEFY, ...) - so we multiply it by 3. And also +/// `AVERAGE_HEADER_SIZE_IN_JUSTIFICATION` bytes for other stuff. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +pub const MAX_HEADER_SIZE: u32 = MAX_AUTHORITIES_COUNT + .saturating_mul(3) + .saturating_add(AVERAGE_HEADER_SIZE_IN_JUSTIFICATION); + +/// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Rialto +/// 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; + +/// Re-export `time_units` to make usage easier. +pub use time_units::*; + +/// Human readable time units defined in terms of number of blocks. +pub mod time_units { + use super::{BlockNumber, SESSION_LENGTH}; + + pub const MILLISECS_PER_BLOCK: u64 = 6000; + pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + + 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 EPOCH_DURATION_IN_SLOTS: BlockNumber = SESSION_LENGTH; + + // 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks. + pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4); +} + +/// Block number type used in Rialto. +pub type BlockNumber = u32; + +/// Hash type used in Rialto. +pub type Hash = ::Out; + +/// The type of object that can produce hashes on Rialto. +pub type Hasher = BlakeTwo256; + +/// The header type used by Rialto. +pub type Header = sp_runtime::generic::Header; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// Balance of an account. +pub type Balance = u128; + +/// An instant or duration in time. +pub type Moment = u64; + +/// Index of a transaction in the chain. +pub type Index = u32; + +/// Weight-to-Fee type used by Rialto. +pub type WeightToFee = IdentityFee; + +/// Rialto chain. +#[derive(RuntimeDebug)] +pub struct Rialto; + +impl Chain for Rialto { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Index; + 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 Rialto { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_RIALTO_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; +} + +frame_support::parameter_types! { + pub BlockLength: limits::BlockLength = + limits::BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); + pub BlockWeights: limits::BlockWeights = + limits::BlockWeights::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO); +} + +/// Name of the With-Rialto GRANDPA pallet instance that is deployed at bridged chains. +pub const WITH_RIALTO_GRANDPA_PALLET_NAME: &str = "BridgeRialtoGrandpa"; +/// Name of the With-Rialto messages pallet instance that is deployed at bridged chains. +pub const WITH_RIALTO_MESSAGES_PALLET_NAME: &str = "BridgeRialtoMessages"; +/// Name of the With-Rialto parachains bridge pallet instance that is deployed at bridged chains. +pub const WITH_RIALTO_BRIDGE_PARAS_PALLET_NAME: &str = "BridgeRialtoParachains"; + +/// Name of the parachain registrar pallet in the Rialto runtime. +pub const PARAS_REGISTRAR_PALLET_NAME: &str = "Registrar"; + +/// Name of the parachains pallet in the Rialto runtime. +pub const PARAS_PALLET_NAME: &str = "Paras"; + +decl_bridge_runtime_apis!(rialto); diff --git a/primitives/chain-rococo/Cargo.toml b/primitives/chain-rococo/Cargo.toml new file mode 100644 index 00000000000..4e21bd38b7a --- /dev/null +++ b/primitives/chain-rococo/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "bp-rococo" +description = "Primitives of Rococo runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 + +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "frame-support/std", + "sp-api/std", +] diff --git a/primitives/chain-rococo/src/lib.rs b/primitives/chain-rococo/src/lib.rs new file mode 100644 index 00000000000..0cb0b1d41e6 --- /dev/null +++ b/primitives/chain-rococo/src/lib.rs @@ -0,0 +1,76 @@ +// Copyright 2019-2021 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}; + +/// Rococo Chain +pub struct Rococo; + +impl Chain for Rococo { + type BlockNumber = ::BlockNumber; + type Hash = ::Hash; + type Hasher = ::Hasher; + type Header = ::Header; + + type AccountId = ::AccountId; + type Balance = ::Balance; + type Index = ::Index; + type Signature = ::Signature; + + fn max_extrinsic_size() -> u32 { + PolkadotLike::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + PolkadotLike::max_extrinsic_weight() + } +} + +impl ChainWithGrandpa for Rococo { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = WITH_ROCOCO_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; +} + +/// Name of the parachains pallet in the Rococo runtime. +pub const PARAS_PALLET_NAME: &str = "Paras"; + +/// Name of the With-Rococo GRANDPA pallet instance that is deployed at bridged chains. +pub const WITH_ROCOCO_GRANDPA_PALLET_NAME: &str = "BridgeRococoGrandpa"; + +/// Maximal size of encoded `bp_parachains::ParaStoredHeaderData` structure among all Rococo +/// 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!(rococo); diff --git a/primitives/chain-westend/Cargo.toml b/primitives/chain-westend/Cargo.toml new file mode 100644 index 00000000000..13a2e597f9d --- /dev/null +++ b/primitives/chain-westend/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "bp-westend" +description = "Primitives of Westend runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "frame-support/std", + "sp-api/std", +] diff --git a/primitives/chain-westend/src/lib.rs b/primitives/chain-westend/src/lib.rs new file mode 100644 index 00000000000..74e8895aff9 --- /dev/null +++ b/primitives/chain-westend/src/lib.rs @@ -0,0 +1,108 @@ +// Copyright 2019-2021 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, Parachain}; +use frame_support::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 Index = ::Index; + 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; +} + +/// Westmint parachain definition +#[derive(Debug, Clone, Copy)] +pub struct Westmint; + +// Westmint seems to use the same configuration as all Polkadot-like chains, so we'll use Westend +// primitives here. +impl Chain for Westmint { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Nonce; + type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + Westend::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + Westend::max_extrinsic_weight() + } +} + +impl Parachain for Westmint { + const PARACHAIN_ID: u32 = WESTMINT_PARACHAIN_ID; +} + +/// Name of the parachains pallet at the Westend 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"; +/// Name of the With-Westend parachains bridge pallet instance that is deployed at bridged chains. +pub const WITH_WESTEND_BRIDGE_PARAS_PALLET_NAME: &str = "BridgeWestendParachains"; + +/// Maximal SCALE-encoded size of parachains headers that are stored at Westend `Paras` pallet. +/// +/// 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; + +/// Identifier of Westmint parachain at the Westend relay chain. +pub const WESTMINT_PARACHAIN_ID: u32 = 1000; + +decl_bridge_finality_runtime_apis!(westend); + +decl_bridge_finality_runtime_apis!(westmint); diff --git a/primitives/chain-wococo/Cargo.toml b/primitives/chain-wococo/Cargo.toml new file mode 100644 index 00000000000..25fd7b9fd94 --- /dev/null +++ b/primitives/chain-wococo/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "bp-wococo" +description = "Primitives of Wococo runtime." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "bp-rococo/std", + "frame-support/std", + "sp-api/std", +] diff --git a/primitives/chain-wococo/src/lib.rs b/primitives/chain-wococo/src/lib.rs new file mode 100644 index 00000000000..2df019496ab --- /dev/null +++ b/primitives/chain-wococo/src/lib.rs @@ -0,0 +1,65 @@ +// Copyright 2019-2021 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 Index = ::Index; + 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; +} + +/// 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); diff --git a/primitives/header-chain/Cargo.toml b/primitives/header-chain/Cargo.toml new file mode 100644 index 00000000000..5b9f87614a8 --- /dev/null +++ b/primitives/header-chain/Cargo.toml @@ -0,0 +1,45 @@ +[package] +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" +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.5.0", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true } + +# Bridge dependencies + +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +bp-test-utils = { path = "../test-utils" } +hex = "0.4" +hex-literal = "0.4" + +[features] +default = ["std"] +std = [ + "bp-runtime/std", + "codec/std", + "finality-grandpa/std", + "serde/std", + "frame-support/std", + "scale-info/std", + "sp-core/std", + "sp-consensus-grandpa/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/primitives/header-chain/src/justification.rs b/primitives/header-chain/src/justification.rs new file mode 100644 index 00000000000..06ed782763d --- /dev/null +++ b/primitives/header-chain/src/justification.rs @@ -0,0 +1,390 @@ +// Copyright 2019-2021 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 . + +//! Pallet for checking GRANDPA Finality Proofs. +//! +//! Adapted copy of substrate/client/finality-grandpa/src/justification.rs. If origin +//! will ever be moved to the sp_consensus_grandpa, we should reuse that implementation. + +use crate::ChainWithGrandpa; + +use bp_runtime::{BlockNumberOf, Chain, HashOf}; +use codec::{Decode, Encode, MaxEncodedLen}; +use finality_grandpa::voter_set::VoterSet; +use frame_support::RuntimeDebug; +use scale_info::TypeInfo; +use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, SetId}; +use sp_runtime::{traits::Header as HeaderT, SaturatedConversion}; +use sp_std::{ + collections::{btree_map::BTreeMap, btree_set::BTreeSet}, + prelude::*, +}; + +/// A GRANDPA Justification is a proof that a given header was finalized +/// at a certain height and with a certain set of authorities. +/// +/// This particular proof is used to prove that headers on a bridged chain +/// (so not our chain) have been finalized correctly. +#[derive(Encode, Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] +pub struct GrandpaJustification { + /// The round (voting period) this justification is valid for. + pub round: u64, + /// The set of votes for the chain which is to be finalized. + pub commit: + finality_grandpa::Commit, + /// A proof that the chain of blocks in the commit are related to each other. + pub votes_ancestries: Vec
, +} + +impl GrandpaJustification { + /// Returns reasonable size of justification using constants from the provided chain. + /// + /// An imprecise analogue of `MaxEncodedLen` implementation. We don't use it for + /// any precise calculations - that's just an estimation. + pub fn max_reasonable_size(required_precommits: u32) -> u32 + where + C: Chain
+ ChainWithGrandpa, + { + // we don't need precise results here - just estimations, so some details + // are removed from computations (e.g. bytes required to encode vector length) + + // structures in `finality_grandpa` crate are not implementing `MaxEncodedLength`, so + // here's our estimation for the `finality_grandpa::Commit` struct size + // + // precommit is: hash + number + // signed precommit is: precommit + signature (64b) + authority id + // commit is: hash + number + vec of signed precommits + let signed_precommit_size: u32 = BlockNumberOf::::max_encoded_len() + .saturating_add(HashOf::::max_encoded_len().saturated_into()) + .saturating_add(64) + .saturating_add(AuthorityId::max_encoded_len().saturated_into()) + .saturated_into(); + let max_expected_signed_commit_size = signed_precommit_size + .saturating_mul(required_precommits) + .saturating_add(BlockNumberOf::::max_encoded_len().saturated_into()) + .saturating_add(HashOf::::max_encoded_len().saturated_into()); + + // justification is a signed GRANDPA commit, `votes_ancestries` vector and round number + let max_expected_votes_ancestries_size = C::REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY + .saturating_mul(C::AVERAGE_HEADER_SIZE_IN_JUSTIFICATION); + + 8u32.saturating_add(max_expected_signed_commit_size) + .saturating_add(max_expected_votes_ancestries_size) + } +} + +impl crate::FinalityProof for GrandpaJustification { + fn target_header_number(&self) -> H::Number { + self.commit.target_number + } +} + +/// Justification verification error. +#[derive(Eq, RuntimeDebug, PartialEq)] +pub enum Error { + /// Failed to decode justification. + JustificationDecode, + /// Justification is finalizing unexpected header. + InvalidJustificationTarget, + /// Justification contains redundant votes. + RedundantVotesInJustification, + /// Justification contains unknown authority precommit. + UnknownAuthorityVote, + /// Justification contains duplicate authority precommit. + DuplicateAuthorityVote, + /// The authority has provided an invalid signature. + InvalidAuthoritySignature, + /// The justification contains precommit for header that is not a descendant of the commit + /// header. + PrecommitIsNotCommitDescendant, + /// The cumulative weight of all votes in the justification is not enough to justify commit + /// header finalization. + TooLowCumulativeWeight, + /// The justification contains extra (unused) headers in its `votes_ancestries` field. + ExtraHeadersInVotesAncestries, +} + +/// Given GRANDPA authorities set size, return number of valid authorities votes that the +/// justification must have to be valid. +/// +/// This function assumes that all authorities have the same vote weight. +pub fn required_justification_precommits(authorities_set_length: u32) -> u32 { + authorities_set_length - authorities_set_length.saturating_sub(1) / 3 +} + +/// Decode justification target. +pub fn decode_justification_target( + raw_justification: &[u8], +) -> Result<(Header::Hash, Header::Number), Error> { + GrandpaJustification::
::decode(&mut &*raw_justification) + .map(|justification| (justification.commit.target_hash, justification.commit.target_number)) + .map_err(|_| Error::JustificationDecode) +} + +/// Verify and optimize given justification by removing unknown and duplicate votes. +pub fn verify_and_optimize_justification( + finalized_target: (Header::Hash, Header::Number), + authorities_set_id: SetId, + authorities_set: &VoterSet, + justification: GrandpaJustification
, +) -> Result, Error> +where + Header::Number: finality_grandpa::BlockNumberOps, +{ + let mut optimizer = OptimizationCallbacks(Vec::new()); + verify_justification_with_callbacks( + finalized_target, + authorities_set_id, + authorities_set, + &justification, + &mut optimizer, + )?; + Ok(optimizer.optimize(justification)) +} + +/// Verify that justification, that is generated by given authority set, finalizes given header. +pub fn verify_justification( + finalized_target: (Header::Hash, Header::Number), + authorities_set_id: SetId, + authorities_set: &VoterSet, + justification: &GrandpaJustification
, +) -> Result<(), Error> +where + Header::Number: finality_grandpa::BlockNumberOps, +{ + verify_justification_with_callbacks( + finalized_target, + authorities_set_id, + authorities_set, + justification, + &mut StrictVerificationCallbacks, + ) +} + +/// Verification callbacks. +trait VerificationCallbacks { + /// Called when we see a precommit from unknown authority. + fn on_unkown_authority(&mut self, precommit_idx: usize) -> Result<(), Error>; + /// Called when we see a precommit with duplicate vote from known authority. + fn on_duplicate_authority_vote(&mut self, precommit_idx: usize) -> Result<(), Error>; + /// Called when we see a precommit after we've collected enough votes from authorities. + fn on_redundant_authority_vote(&mut self, precommit_idx: usize) -> Result<(), Error>; +} + +/// Verification callbacks that reject all unknown, duplicate or redundant votes. +struct StrictVerificationCallbacks; + +impl VerificationCallbacks for StrictVerificationCallbacks { + fn on_unkown_authority(&mut self, _precommit_idx: usize) -> Result<(), Error> { + Err(Error::UnknownAuthorityVote) + } + + fn on_duplicate_authority_vote(&mut self, _precommit_idx: usize) -> Result<(), Error> { + Err(Error::DuplicateAuthorityVote) + } + + fn on_redundant_authority_vote(&mut self, _precommit_idx: usize) -> Result<(), Error> { + Err(Error::RedundantVotesInJustification) + } +} + +/// Verification callbacks for justification optimization. +struct OptimizationCallbacks(Vec); + +impl OptimizationCallbacks { + fn optimize( + self, + mut justification: GrandpaJustification
, + ) -> GrandpaJustification
{ + for invalid_precommit_idx in self.0.into_iter().rev() { + justification.commit.precommits.remove(invalid_precommit_idx); + } + justification + } +} + +impl VerificationCallbacks for OptimizationCallbacks { + fn on_unkown_authority(&mut self, precommit_idx: usize) -> Result<(), Error> { + self.0.push(precommit_idx); + Ok(()) + } + + fn on_duplicate_authority_vote(&mut self, precommit_idx: usize) -> Result<(), Error> { + self.0.push(precommit_idx); + Ok(()) + } + + fn on_redundant_authority_vote(&mut self, precommit_idx: usize) -> Result<(), Error> { + self.0.push(precommit_idx); + Ok(()) + } +} + +/// Verify that justification, that is generated by given authority set, finalizes given header. +fn verify_justification_with_callbacks( + finalized_target: (Header::Hash, Header::Number), + authorities_set_id: SetId, + authorities_set: &VoterSet, + justification: &GrandpaJustification
, + callbacks: &mut C, +) -> Result<(), Error> +where + Header::Number: finality_grandpa::BlockNumberOps, +{ + // ensure that it is justification for the expected header + if (justification.commit.target_hash, justification.commit.target_number) != finalized_target { + return Err(Error::InvalidJustificationTarget) + } + + let threshold = authorities_set.threshold().0.into(); + let mut chain = AncestryChain::new(&justification.votes_ancestries); + let mut signature_buffer = Vec::new(); + let mut votes = BTreeSet::new(); + let mut cumulative_weight = 0u64; + + for (precommit_idx, signed) in justification.commit.precommits.iter().enumerate() { + // if we have collected enough precommits, we probabably want to fail/remove extra + // precommits + if cumulative_weight >= threshold { + callbacks.on_redundant_authority_vote(precommit_idx)?; + continue + } + + // authority must be in the set + let authority_info = match authorities_set.get(&signed.id) { + Some(authority_info) => authority_info, + None => { + callbacks.on_unkown_authority(precommit_idx)?; + continue + }, + }; + + // check if authority has already voted in the same round. + // + // there's a lot of code in `validate_commit` and `import_precommit` functions inside + // `finality-grandpa` crate (mostly related to reporting equivocations). But the only thing + // that we care about is that only first vote from the authority is accepted + if !votes.insert(signed.id.clone()) { + callbacks.on_duplicate_authority_vote(precommit_idx)?; + continue + } + + // everything below this line can't just `continue`, because state is already altered + + // precommits aren't allowed for block lower than the target + if signed.precommit.target_number < justification.commit.target_number { + return Err(Error::PrecommitIsNotCommitDescendant) + } + // all precommits must be descendants of target block + chain = chain + .ensure_descendant(&justification.commit.target_hash, &signed.precommit.target_hash)?; + // since we know now that the precommit target is the descendant of the justification + // target, we may increase 'weight' of the justification target + // + // there's a lot of code in the `VoteGraph::insert` method inside `finality-grandpa` crate, + // but in the end it is only used to find GHOST, which we don't care about. The only thing + // that we care about is that the justification target has enough weight + cumulative_weight = cumulative_weight.checked_add(authority_info.weight().0.into()).expect( + "sum of weights of ALL authorities is expected not to overflow - this is guaranteed by\ + existence of VoterSet;\ + the order of loop conditions guarantees that we can account vote from same authority\ + multiple times;\ + thus we'll never overflow the u64::MAX;\ + qed", + ); + + // verify authority signature + if !sp_consensus_grandpa::check_message_signature_with_buffer( + &finality_grandpa::Message::Precommit(signed.precommit.clone()), + &signed.id, + &signed.signature, + justification.round, + authorities_set_id, + &mut signature_buffer, + ) { + return Err(Error::InvalidAuthoritySignature) + } + } + + // check that there are no extra headers in the justification + if !chain.unvisited.is_empty() { + return Err(Error::ExtraHeadersInVotesAncestries) + } + + // check that the cumulative weight of validators voted for the justification target (or one + // of its descendents) is larger than required threshold. + if cumulative_weight >= threshold { + Ok(()) + } else { + Err(Error::TooLowCumulativeWeight) + } +} + +/// Votes ancestries with useful methods. +#[derive(RuntimeDebug)] +pub struct AncestryChain { + /// Header hash => parent header hash mapping. + pub parents: BTreeMap, + /// Hashes of headers that were not visited by `is_ancestor` method. + pub unvisited: BTreeSet, +} + +impl AncestryChain
{ + /// Create new ancestry chain. + pub fn new(ancestry: &[Header]) -> AncestryChain
{ + let mut parents = BTreeMap::new(); + let mut unvisited = BTreeSet::new(); + for ancestor in ancestry { + let hash = ancestor.hash(); + let parent_hash = *ancestor.parent_hash(); + parents.insert(hash, parent_hash); + unvisited.insert(hash); + } + AncestryChain { parents, unvisited } + } + + /// Returns `Ok(_)` if `precommit_target` is a descendant of the `commit_target` block and + /// `Err(_)` otherwise. + pub fn ensure_descendant( + mut self, + commit_target: &Header::Hash, + precommit_target: &Header::Hash, + ) -> Result { + let mut current_hash = *precommit_target; + loop { + if current_hash == *commit_target { + break + } + + let is_visited_before = !self.unvisited.remove(¤t_hash); + current_hash = match self.parents.get(¤t_hash) { + Some(parent_hash) => { + if is_visited_before { + // `Some(parent_hash)` means that the `current_hash` is in the `parents` + // container `is_visited_before` means that it has been visited before in + // some of previous calls => since we assume that previous call has finished + // with `true`, this also will be finished with `true` + return Ok(self) + } + + *parent_hash + }, + None => return Err(Error::PrecommitIsNotCommitDescendant), + }; + } + Ok(self) + } +} diff --git a/primitives/header-chain/src/lib.rs b/primitives/header-chain/src/lib.rs new file mode 100644 index 00000000000..5e2bbad242e --- /dev/null +++ b/primitives/header-chain/src/lib.rs @@ -0,0 +1,227 @@ +// Copyright 2019-2021 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 . + +//! Defines traits which represent a common interface for Substrate pallets which want to +//! incorporate bridge functionality. + +#![cfg_attr(not(feature = "std"), no_std)] + +use bp_runtime::{ + BasicOperatingMode, Chain, HashOf, HasherOf, HeaderOf, RawStorageProof, StorageProofChecker, + StorageProofError, +}; +use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; +use core::{clone::Clone, cmp::Eq, default::Default, fmt::Debug}; +use frame_support::PalletError; +use scale_info::TypeInfo; +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; +use sp_consensus_grandpa::{AuthorityList, ConsensusLog, SetId, GRANDPA_ENGINE_ID}; +use sp_runtime::{traits::Header as HeaderT, Digest, RuntimeDebug}; +use sp_std::boxed::Box; + +pub mod justification; +pub mod storage_keys; + +/// Header chain error. +#[derive(Clone, Decode, Encode, Eq, PartialEq, PalletError, Debug, TypeInfo)] +pub enum HeaderChainError { + /// Header with given hash is missing from the chain. + UnknownHeader, + /// Storage proof related error. + StorageProof(StorageProofError), +} + +/// Header data that we're storing on-chain. +/// +/// Even though we may store full header, our applications (XCM) only use couple of header +/// fields. Extracting those values makes on-chain storage and PoV smaller, which is good. +#[derive(Clone, Decode, Encode, Eq, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +pub struct StoredHeaderData { + /// Header number. + pub number: Number, + /// Header state root. + pub state_root: Hash, +} + +/// Stored header data builder. +pub trait StoredHeaderDataBuilder { + /// Build header data from self. + fn build(&self) -> StoredHeaderData; +} + +impl StoredHeaderDataBuilder for H { + fn build(&self) -> StoredHeaderData { + StoredHeaderData { number: *self.number(), state_root: *self.state_root() } + } +} + +/// Substrate header chain, abstracted from the way it is stored. +pub trait HeaderChain { + /// Returns state (storage) root of given finalized header. + fn finalized_header_state_root(header_hash: HashOf) -> Option>; + /// Parse storage proof using finalized header. + fn parse_finalized_storage_proof( + header_hash: HashOf, + storage_proof: RawStorageProof, + parse: impl FnOnce(StorageProofChecker>) -> R, + ) -> Result { + let state_root = Self::finalized_header_state_root(header_hash) + .ok_or(HeaderChainError::UnknownHeader)?; + let storage_proof_checker = bp_runtime::StorageProofChecker::new(state_root, storage_proof) + .map_err(HeaderChainError::StorageProof)?; + + Ok(parse(storage_proof_checker)) + } +} + +/// A type that can be used as a parameter in a dispatchable function. +/// +/// When using `decl_module` all arguments for call functions must implement this trait. +pub trait Parameter: Codec + EncodeLike + Clone + Eq + Debug + TypeInfo {} +impl Parameter for T where T: Codec + EncodeLike + Clone + Eq + Debug + TypeInfo {} + +/// A GRANDPA Authority List and ID. +#[derive(Default, Encode, Eq, Decode, RuntimeDebug, PartialEq, Clone, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct AuthoritySet { + /// List of GRANDPA authorities for the current round. + pub authorities: AuthorityList, + /// Monotonic identifier of the current GRANDPA authority set. + pub set_id: SetId, +} + +impl AuthoritySet { + /// Create a new GRANDPA Authority Set. + pub fn new(authorities: AuthorityList, set_id: SetId) -> Self { + Self { authorities, set_id } + } +} + +/// Data required for initializing the GRANDPA bridge pallet. +/// +/// The bridge needs to know where to start its sync from, and this provides that initial context. +#[derive(Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, Clone, TypeInfo)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct InitializationData { + /// The header from which we should start syncing. + pub header: Box, + /// The initial authorities of the pallet. + pub authority_list: AuthorityList, + /// The ID of the initial authority set. + pub set_id: SetId, + /// Pallet operating mode. + pub operating_mode: BasicOperatingMode, +} + +/// Abstract finality proof that is justifying block finality. +pub trait FinalityProof: Clone + Send + Sync + Debug { + /// Return number of header that this proof is generated for. + fn target_header_number(&self) -> Number; +} + +/// A trait that provides helper methods for querying the consensus log. +pub trait ConsensusLogReader { + /// Returns true if digest contains item that schedules authorities set change. + fn schedules_authorities_change(digest: &Digest) -> bool; +} + +/// A struct that provides helper methods for querying the GRANDPA consensus log. +pub struct GrandpaConsensusLogReader(sp_std::marker::PhantomData); + +impl GrandpaConsensusLogReader { + pub fn find_authorities_change( + digest: &Digest, + ) -> Option> { + // find the first consensus digest with the right ID which converts to + // the right kind of consensus log. + digest + .convert_first(|log| log.consensus_try_to(&GRANDPA_ENGINE_ID)) + .and_then(|log| match log { + ConsensusLog::ScheduledChange(change) => Some(change), + _ => None, + }) + } +} + +impl ConsensusLogReader for GrandpaConsensusLogReader { + fn schedules_authorities_change(digest: &Digest) -> bool { + GrandpaConsensusLogReader::::find_authorities_change(digest).is_some() + } +} + +/// A minimized version of `pallet-bridge-grandpa::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeGrandpaCall { + /// `pallet-bridge-grandpa::Call::submit_finality_proof` + #[codec(index = 0)] + submit_finality_proof { + finality_target: Box
, + justification: justification::GrandpaJustification
, + }, + /// `pallet-bridge-grandpa::Call::initialize` + #[codec(index = 1)] + initialize { init_data: InitializationData
}, +} + +/// The `BridgeGrandpaCall` used by a chain. +pub type BridgeGrandpaCallOf = BridgeGrandpaCall>; + +/// Substrate-based chain that is using direct GRANDPA finality. +/// +/// Keep in mind that parachains are relying on relay chain GRANDPA, so they should not implement +/// this trait. +pub trait ChainWithGrandpa: Chain { + /// Name of the bridge GRANDPA pallet (used in `construct_runtime` macro call) that is deployed + /// at some other chain to bridge with this `ChainWithGrandpa`. + /// + /// We assume that all chains that are bridging with this `ChainWithGrandpa` are using + /// the same name. + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str; + + /// Max number of GRANDPA authorities at the chain. + /// + /// This is a strict constant. If bridged chain will have more authorities than that, + /// the GRANDPA bridge pallet may halt. + const MAX_AUTHORITIES_COUNT: u32; + + /// Max reasonable number of headers in `votes_ancestries` vector of the GRANDPA justification. + /// + /// This isn't a strict limit. The relay may submit justifications with more headers in its + /// ancestry and the pallet will accept such justification. The limit is only used to compute + /// maximal refund amount and submitting justifications which exceed the limit, may be costly + /// to submitter. + const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32; + + /// Maximal size of the chain header. The header may be the header that enacts new GRANDPA + /// authorities set (so it has large digest inside). + /// + /// This isn't a strict limit. The relay may submit larger headers and the pallet will accept + /// the call. The limit is only used to compute maximal refund amount and doing calls which + /// exceed the limit, may be costly to submitter. + const MAX_HEADER_SIZE: u32; + + /// Average size of the chain header from justification ancestry. We don't expect to see there + /// headers that change GRANDPA authorities set (GRANDPA will probably be able to finalize at + /// least one additional header per session on non test chains), so this is average size of + /// headers that aren't changing the set. + /// + /// This isn't a strict limit. The relay may submit justifications with larger headers in its + /// ancestry and the pallet will accept the call. The limit is only used to compute maximal + /// refund amount and doing calls which exceed the limit, may be costly to submitter. + const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32; +} diff --git a/primitives/header-chain/src/storage_keys.rs b/primitives/header-chain/src/storage_keys.rs new file mode 100644 index 00000000000..c4dbe53bd9a --- /dev/null +++ b/primitives/header-chain/src/storage_keys.rs @@ -0,0 +1,104 @@ +// Copyright 2019-2021 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 . + +//! Storage keys of bridge GRANDPA pallet. + +/// Name of the `IsHalted` storage value. +pub const PALLET_OPERATING_MODE_VALUE_NAME: &str = "PalletOperatingMode"; +/// Name of the `BestFinalized` storage value. +pub const BEST_FINALIZED_VALUE_NAME: &str = "BestFinalized"; +/// Name of the `CurrentAuthoritySet` storage value. +pub const CURRENT_AUTHORITY_SET_VALUE_NAME: &str = "CurrentAuthoritySet"; + +use sp_core::storage::StorageKey; + +/// Storage key of the `PalletOperatingMode` variable in the runtime storage. +pub fn pallet_operating_mode_key(pallet_prefix: &str) -> StorageKey { + StorageKey( + bp_runtime::storage_value_final_key( + pallet_prefix.as_bytes(), + PALLET_OPERATING_MODE_VALUE_NAME.as_bytes(), + ) + .to_vec(), + ) +} + +/// Storage key of the `CurrentAuthoritySet` variable in the runtime storage. +pub fn current_authority_set_key(pallet_prefix: &str) -> StorageKey { + StorageKey( + bp_runtime::storage_value_final_key( + pallet_prefix.as_bytes(), + CURRENT_AUTHORITY_SET_VALUE_NAME.as_bytes(), + ) + .to_vec(), + ) +} + +/// Storage key of the best finalized header number and hash value in the runtime storage. +pub fn best_finalized_key(pallet_prefix: &str) -> StorageKey { + StorageKey( + bp_runtime::storage_value_final_key( + pallet_prefix.as_bytes(), + BEST_FINALIZED_VALUE_NAME.as_bytes(), + ) + .to_vec(), + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use hex_literal::hex; + + #[test] + fn pallet_operating_mode_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // compatibility with previous pallet. + let storage_key = pallet_operating_mode_key("BridgeGrandpa").0; + assert_eq!( + storage_key, + hex!("0b06f475eddb98cf933a12262e0388de0f4cf0917788d791142ff6c1f216e7b3").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + + #[test] + fn current_authority_set_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // compatibility with previous pallet. + let storage_key = current_authority_set_key("BridgeGrandpa").0; + assert_eq!( + storage_key, + hex!("0b06f475eddb98cf933a12262e0388de24a7b8b5717ea33346fa595a66ccbcb0").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + + #[test] + fn best_finalized_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // compatibility with previous pallet. + let storage_key = best_finalized_key("BridgeGrandpa").0; + assert_eq!( + storage_key, + hex!("0b06f475eddb98cf933a12262e0388dea4ebafdd473c549fdb24c5c991c5591c").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } +} diff --git a/primitives/header-chain/tests/implementation_match.rs b/primitives/header-chain/tests/implementation_match.rs new file mode 100644 index 00000000000..c70683b173d --- /dev/null +++ b/primitives/header-chain/tests/implementation_match.rs @@ -0,0 +1,418 @@ +// Copyright 2020-2021 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 . + +//! Tests inside this module are made to ensure that our custom justification verification +//! implementation works similar to the [`finality_grandpa::validate_commit`] and explicitly +//! show where we behave different. +//! +//! Some of tests in this module may partially duplicate tests from `justification.rs`, +//! but their purpose is different. + +use bp_header_chain::justification::{verify_justification, Error, GrandpaJustification}; +use bp_test_utils::{ + header_id, make_justification_for_header, signed_precommit, test_header, Account, + JustificationGeneratorParams, ALICE, BOB, CHARLIE, DAVE, EVE, FERDIE, TEST_GRANDPA_SET_ID, +}; +use finality_grandpa::voter_set::VoterSet; +use sp_consensus_grandpa::{AuthorityId, AuthorityWeight}; +use sp_runtime::traits::Header as HeaderT; + +type TestHeader = sp_runtime::testing::Header; +type TestHash = ::Hash; +type TestNumber = ::Number; + +/// Implementation of `finality_grandpa::Chain` that is used in tests. +struct AncestryChain(bp_header_chain::justification::AncestryChain); + +impl AncestryChain { + fn new(ancestry: &[TestHeader]) -> Self { + Self(bp_header_chain::justification::AncestryChain::new(ancestry)) + } +} + +impl finality_grandpa::Chain for AncestryChain { + fn ancestry( + &self, + base: TestHash, + block: TestHash, + ) -> Result, finality_grandpa::Error> { + let mut route = Vec::new(); + let mut current_hash = block; + loop { + if current_hash == base { + break + } + match self.0.parents.get(¤t_hash).cloned() { + Some(parent_hash) => { + current_hash = parent_hash; + route.push(current_hash); + }, + _ => return Err(finality_grandpa::Error::NotDescendent), + } + } + route.pop(); // remove the base + + Ok(route) + } +} + +/// Get a full set of accounts. +fn full_accounts_set() -> Vec<(Account, AuthorityWeight)> { + vec![(ALICE, 1), (BOB, 1), (CHARLIE, 1), (DAVE, 1), (EVE, 1)] +} + +/// Get a full set of GRANDPA authorities. +fn full_voter_set() -> VoterSet { + VoterSet::new(full_accounts_set().iter().map(|(id, w)| (AuthorityId::from(*id), *w))).unwrap() +} + +/// Get a minimal set of accounts. +fn minimal_accounts_set() -> Vec<(Account, AuthorityWeight)> { + // there are 5 accounts in the full set => we need 2/3 + 1 accounts, which results in 4 accounts + vec![(ALICE, 1), (BOB, 1), (CHARLIE, 1), (DAVE, 1)] +} + +/// Get a minimal subset of GRANDPA authorities that have enough cumulative vote weight to justify a +/// header finality. +pub fn minimal_voter_set() -> VoterSet { + VoterSet::new(minimal_accounts_set().iter().map(|(id, w)| (AuthorityId::from(*id), *w))) + .unwrap() +} + +/// Make a valid GRANDPA justification with sensible defaults. +pub fn make_default_justification(header: &TestHeader) -> GrandpaJustification { + make_justification_for_header(JustificationGeneratorParams { + header: header.clone(), + authorities: minimal_accounts_set(), + ..Default::default() + }) +} + +// the `finality_grandpa::validate_commit` function has two ways to report an unsuccessful +// commit validation: +// +// 1) to return `Err()` (which only may happen if `finality_grandpa::Chain` implementation +// returns an error); +// 2) to return `Ok(validation_result)` if `validation_result.is_valid()` is false. +// +// Our implementation would just return error in both cases. + +#[test] +fn same_result_when_precommit_target_has_lower_number_than_commit_target() { + let mut justification = make_default_justification(&test_header(1)); + // the number of header in precommit (0) is lower than number of header in commit (1) + justification.commit.precommits[0].precommit.target_number = 0; + + // our implementation returns an error + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &full_voter_set(), + &justification, + ), + Err(Error::PrecommitIsNotCommitDescendant), + ); + + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == false`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(!result.is_valid()); +} + +#[test] +fn same_result_when_precommit_target_is_not_descendant_of_commit_target() { + let not_descendant = test_header::(10); + let mut justification = make_default_justification(&test_header(1)); + // the route from header of commit (1) to header of precommit (10) is missing from + // the votes ancestries + justification.commit.precommits[0].precommit.target_number = *not_descendant.number(); + justification.commit.precommits[0].precommit.target_hash = not_descendant.hash(); + justification.votes_ancestries.push(not_descendant); + + // our implementation returns an error + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &full_voter_set(), + &justification, + ), + Err(Error::PrecommitIsNotCommitDescendant), + ); + + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == false`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(!result.is_valid()); +} + +#[test] +fn same_result_when_there_are_not_enough_cumulative_weight_to_finalize_commit_target() { + // just remove one authority from the minimal set and we shall not reach the threshold + let mut authorities_set = minimal_accounts_set(); + authorities_set.pop(); + let justification = make_justification_for_header(JustificationGeneratorParams { + header: test_header(1), + authorities: authorities_set, + ..Default::default() + }); + + // our implementation returns an error + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &full_voter_set(), + &justification, + ), + Err(Error::TooLowCumulativeWeight), + ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == false`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(!result.is_valid()); +} + +// tests below are our differences with the original implementation + +#[test] +fn different_result_when_justification_contains_duplicate_vote() { + let mut justification = make_justification_for_header(JustificationGeneratorParams { + header: test_header(1), + authorities: minimal_accounts_set(), + ancestors: 0, + ..Default::default() + }); + // the justification may contain exactly the same vote (i.e. same precommit and same signature) + // multiple times && it isn't treated as an error by original implementation + let last_precommit = justification.commit.precommits.pop().unwrap(); + justification.commit.precommits.push(justification.commit.precommits[0].clone()); + justification.commit.precommits.push(last_precommit); + + // our implementation fails + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &full_voter_set(), + &justification, + ), + Err(Error::DuplicateAuthorityVote), + ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == true`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(result.is_valid()); +} + +#[test] +fn different_results_when_authority_equivocates_once_in_a_round() { + let mut justification = make_justification_for_header(JustificationGeneratorParams { + header: test_header(1), + authorities: minimal_accounts_set(), + ancestors: 0, + ..Default::default() + }); + // the justification original implementation allows authority to submit two different + // votes in a single round, of which only first is 'accepted' + let last_precommit = justification.commit.precommits.pop().unwrap(); + justification.commit.precommits.push(signed_precommit::( + &ALICE, + header_id::(1), + justification.round, + TEST_GRANDPA_SET_ID, + )); + justification.commit.precommits.push(last_precommit); + + // our implementation fails + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &full_voter_set(), + &justification, + ), + Err(Error::DuplicateAuthorityVote), + ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == true`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(result.is_valid()); +} + +#[test] +fn different_results_when_authority_equivocates_twice_in_a_round() { + let mut justification = make_justification_for_header(JustificationGeneratorParams { + header: test_header(1), + authorities: minimal_accounts_set(), + ancestors: 0, + ..Default::default() + }); + // there's some code in the original implementation that should return an error when + // same authority submits more than two different votes in a single round: + // https://github.com/paritytech/finality-grandpa/blob/6aeea2d1159d0f418f0b86e70739f2130629ca09/src/lib.rs#L473 + // but there's also a code that prevents this from happening: + // https://github.com/paritytech/finality-grandpa/blob/6aeea2d1159d0f418f0b86e70739f2130629ca09/src/round.rs#L287 + // => so now we are also just ignoring all votes from the same authority, except the first one + let last_precommit = justification.commit.precommits.pop().unwrap(); + let prev_last_precommit = justification.commit.precommits.pop().unwrap(); + justification.commit.precommits.push(signed_precommit::( + &ALICE, + header_id::(1), + justification.round, + TEST_GRANDPA_SET_ID, + )); + justification.commit.precommits.push(signed_precommit::( + &ALICE, + header_id::(1), + justification.round, + TEST_GRANDPA_SET_ID, + )); + justification.commit.precommits.push(last_precommit); + justification.commit.precommits.push(prev_last_precommit); + + // our implementation fails + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &full_voter_set(), + &justification, + ), + Err(Error::DuplicateAuthorityVote), + ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == true`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(result.is_valid()); +} + +#[test] +fn different_results_when_there_are_more_than_enough_votes() { + let mut justification = make_justification_for_header(JustificationGeneratorParams { + header: test_header(1), + authorities: minimal_accounts_set(), + ancestors: 0, + ..Default::default() + }); + // the reference implementation just keep verifying signatures even if we have + // collected enough votes. We are not + justification.commit.precommits.push(signed_precommit::( + &EVE, + header_id::(1), + justification.round, + TEST_GRANDPA_SET_ID, + )); + + // our implementation fails + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &full_voter_set(), + &justification, + ), + Err(Error::RedundantVotesInJustification), + ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == true`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(result.is_valid()); +} + +#[test] +fn different_results_when_there_is_a_vote_of_unknown_authority() { + let mut justification = make_justification_for_header(JustificationGeneratorParams { + header: test_header(1), + authorities: minimal_accounts_set(), + ancestors: 0, + ..Default::default() + }); + // the reference implementation just keep verifying signatures even if we have + // collected enough votes. We are not + let last_precommit = justification.commit.precommits.pop().unwrap(); + justification.commit.precommits.push(signed_precommit::( + &FERDIE, + header_id::(1), + justification.round, + TEST_GRANDPA_SET_ID, + )); + justification.commit.precommits.push(last_precommit); + + // our implementation fails + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &full_voter_set(), + &justification, + ), + Err(Error::UnknownAuthorityVote), + ); + // original implementation returns `Ok(validation_result)` + // with `validation_result.is_valid() == true`. + let result = finality_grandpa::validate_commit( + &justification.commit, + &full_voter_set(), + &AncestryChain::new(&justification.votes_ancestries), + ) + .unwrap(); + + assert!(result.is_valid()); +} diff --git a/primitives/header-chain/tests/justification.rs b/primitives/header-chain/tests/justification.rs new file mode 100644 index 00000000000..3cd63b935d0 --- /dev/null +++ b/primitives/header-chain/tests/justification.rs @@ -0,0 +1,280 @@ +// Copyright 2020-2021 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 . + +//! Tests for Grandpa Justification code. + +use bp_header_chain::justification::{ + required_justification_precommits, verify_and_optimize_justification, verify_justification, + Error, +}; +use bp_test_utils::*; + +type TestHeader = sp_runtime::testing::Header; + +#[test] +fn valid_justification_accepted() { + let authorities = vec![(ALICE, 1), (BOB, 1), (CHARLIE, 1)]; + let params = JustificationGeneratorParams { + header: test_header(1), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: authorities.clone(), + ancestors: 7, + forks: 3, + }; + + let justification = make_justification_for_header::(params.clone()); + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + &justification, + ), + Ok(()), + ); + + assert_eq!(justification.commit.precommits.len(), authorities.len()); + assert_eq!(justification.votes_ancestries.len(), params.ancestors as usize); +} + +#[test] +fn valid_justification_accepted_with_single_fork() { + let params = JustificationGeneratorParams { + header: test_header(1), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: vec![(ALICE, 1), (BOB, 1), (CHARLIE, 1)], + ancestors: 5, + forks: 1, + }; + + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + &make_justification_for_header::(params) + ), + Ok(()), + ); +} + +#[test] +fn valid_justification_accepted_with_arbitrary_number_of_authorities() { + use finality_grandpa::voter_set::VoterSet; + use sp_consensus_grandpa::AuthorityId; + + let n = 15; + let required_signatures = required_justification_precommits(n as _); + let authorities = accounts(n).iter().map(|k| (*k, 1)).collect::>(); + + let params = JustificationGeneratorParams { + header: test_header(1), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: authorities.clone().into_iter().take(required_signatures as _).collect(), + ancestors: n.into(), + forks: required_signatures, + }; + + let authorities = authorities + .iter() + .map(|(id, w)| (AuthorityId::from(*id), *w)) + .collect::>(); + let voter_set = VoterSet::new(authorities).unwrap(); + + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set, + &make_justification_for_header::(params) + ), + Ok(()), + ); +} + +#[test] +fn justification_with_invalid_target_rejected() { + assert_eq!( + verify_justification::( + header_id::(2), + TEST_GRANDPA_SET_ID, + &voter_set(), + &make_default_justification::(&test_header(1)), + ), + Err(Error::InvalidJustificationTarget), + ); +} + +#[test] +fn justification_with_invalid_commit_rejected() { + let mut justification = make_default_justification::(&test_header(1)); + justification.commit.precommits.clear(); + + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + &justification, + ), + Err(Error::ExtraHeadersInVotesAncestries), + ); +} + +#[test] +fn justification_with_invalid_authority_signature_rejected() { + let mut justification = make_default_justification::(&test_header(1)); + justification.commit.precommits[0].signature = + sp_core::crypto::UncheckedFrom::unchecked_from([1u8; 64]); + + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + &justification, + ), + Err(Error::InvalidAuthoritySignature), + ); +} + +#[test] +fn justification_with_invalid_precommit_ancestry() { + let mut justification = make_default_justification::(&test_header(1)); + justification.votes_ancestries.push(test_header(10)); + + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + &justification, + ), + Err(Error::ExtraHeadersInVotesAncestries), + ); +} + +#[test] +fn justification_is_invalid_if_we_dont_meet_threshold() { + // Need at least three authorities to sign off or else the voter set threshold can't be reached + let authorities = vec![(ALICE, 1), (BOB, 1)]; + + let params = JustificationGeneratorParams { + header: test_header(1), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: authorities.clone(), + ancestors: 2 * authorities.len() as u32, + forks: 2, + }; + + assert_eq!( + verify_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + &make_justification_for_header::(params) + ), + Err(Error::TooLowCumulativeWeight), + ); +} + +#[test] +fn optimizer_does_noting_with_minimal_justification() { + let justification = make_default_justification::(&test_header(1)); + + let num_precommits_before = justification.commit.precommits.len(); + let justification = verify_and_optimize_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + justification, + ) + .unwrap(); + let num_precommits_after = justification.commit.precommits.len(); + + assert_eq!(num_precommits_before, num_precommits_after); +} + +#[test] +fn unknown_authority_votes_are_removed_by_optimizer() { + let mut justification = make_default_justification::(&test_header(1)); + justification.commit.precommits.push(signed_precommit::( + &bp_test_utils::Account(42), + header_id::(1), + justification.round, + TEST_GRANDPA_SET_ID, + )); + + let num_precommits_before = justification.commit.precommits.len(); + let justification = verify_and_optimize_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + justification, + ) + .unwrap(); + let num_precommits_after = justification.commit.precommits.len(); + + assert_eq!(num_precommits_before - 1, num_precommits_after); +} + +#[test] +fn duplicate_authority_votes_are_removed_by_optimizer() { + let mut justification = make_default_justification::(&test_header(1)); + justification + .commit + .precommits + .push(justification.commit.precommits.first().cloned().unwrap()); + + let num_precommits_before = justification.commit.precommits.len(); + let justification = verify_and_optimize_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + justification, + ) + .unwrap(); + let num_precommits_after = justification.commit.precommits.len(); + + assert_eq!(num_precommits_before - 1, num_precommits_after); +} + +#[test] +fn redundant_authority_votes_are_removed_by_optimizer() { + let mut justification = make_default_justification::(&test_header(1)); + justification.commit.precommits.push(signed_precommit::( + &EVE, + header_id::(1), + justification.round, + TEST_GRANDPA_SET_ID, + )); + + let num_precommits_before = justification.commit.precommits.len(); + let justification = verify_and_optimize_justification::( + header_id::(1), + TEST_GRANDPA_SET_ID, + &voter_set(), + justification, + ) + .unwrap(); + let num_precommits_after = justification.commit.precommits.len(); + + assert_eq!(num_precommits_before - 1, num_precommits_after); +} diff --git a/primitives/messages/Cargo.toml b/primitives/messages/Cargo.toml new file mode 100644 index 00000000000..32d7c65ebcb --- /dev/null +++ b/primitives/messages/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "bp-messages" +description = "Primitives of messages module." +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", "bit-vec"] } +scale-info = { version = "2.5.0", default-features = false, features = ["bit-vec", "derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } + +# Bridge dependencies + +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +hex = "0.4" +hex-literal = "0.4" + +[features] +default = ["std"] +std = [ + "bp-runtime/std", + "codec/std", + "frame-support/std", + "scale-info/std", + "serde", + "sp-core/std", + "sp-std/std" +] diff --git a/primitives/messages/src/lib.rs b/primitives/messages/src/lib.rs new file mode 100644 index 00000000000..3910837a442 --- /dev/null +++ b/primitives/messages/src/lib.rs @@ -0,0 +1,471 @@ +// Copyright 2019-2021 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 . + +//! Primitives of messages module. + +#![cfg_attr(not(feature = "std"), no_std)] +// RuntimeApi generated functions +#![allow(clippy::too_many_arguments)] + +use bp_runtime::{BasicOperatingMode, OperatingMode, RangeInclusiveExt}; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::RuntimeDebug; +use scale_info::TypeInfo; +use source_chain::RelayersRewards; +use sp_core::TypeId; +use sp_std::{collections::vec_deque::VecDeque, ops::RangeInclusive, prelude::*}; + +pub mod source_chain; +pub mod storage_keys; +pub mod target_chain; + +use bp_runtime::messages::MessageDispatchResult; +// Weight is reexported to avoid additional frame-support dependencies in related crates. +pub use frame_support::weights::Weight; + +/// Messages pallet operating mode. +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +pub enum MessagesOperatingMode { + /// Basic operating mode (Normal/Halted) + Basic(BasicOperatingMode), + /// The pallet is not accepting outbound messages. Inbound messages and receiving proofs + /// are still accepted. + /// + /// This mode may be used e.g. when bridged chain expects upgrade. Then to avoid dispatch + /// failures, the pallet owner may stop accepting new messages, while continuing to deliver + /// queued messages to the bridged chain. Once upgrade is completed, the mode may be switched + /// back to `Normal`. + RejectingOutboundMessages, +} + +impl Default for MessagesOperatingMode { + fn default() -> Self { + MessagesOperatingMode::Basic(BasicOperatingMode::Normal) + } +} + +impl OperatingMode for MessagesOperatingMode { + fn is_halted(&self) -> bool { + match self { + Self::Basic(operating_mode) => operating_mode.is_halted(), + _ => false, + } + } +} + +/// Lane id which implements `TypeId`. +#[derive( + Clone, Copy, Decode, Default, Encode, Eq, Ord, PartialOrd, PartialEq, TypeInfo, MaxEncodedLen, +)] +pub struct LaneId(pub [u8; 4]); + +impl core::fmt::Debug for LaneId { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(fmt) + } +} + +impl AsRef<[u8]> for LaneId { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl TypeId for LaneId { + const TYPE_ID: [u8; 4] = *b"blan"; +} + +/// Message nonce. Valid messages will never have 0 nonce. +pub type MessageNonce = u64; + +/// Message id as a tuple. +pub type BridgeMessageId = (LaneId, MessageNonce); + +/// Opaque message payload. We only decode this payload when it is dispatched. +pub type MessagePayload = Vec; + +/// Message key (unique message identifier) as it is stored in the storage. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +pub struct MessageKey { + /// ID of the message lane. + pub lane_id: LaneId, + /// Message nonce. + pub nonce: MessageNonce, +} + +/// Message as it is stored in the storage. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct Message { + /// Message key. + pub key: MessageKey, + /// Message payload. + pub payload: MessagePayload, +} + +/// Inbound lane data. +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct InboundLaneData { + /// Identifiers of relayers and messages that they have delivered to this lane (ordered by + /// message nonce). + /// + /// This serves as a helper storage item, to allow the source chain to easily pay rewards + /// to the relayers who successfully delivered messages to the target chain (inbound lane). + /// + /// It is guaranteed to have at most N entries, where N is configured at the module level. + /// If there are N entries in this vec, then: + /// 1) all incoming messages are rejected if they're missing corresponding + /// `proof-of(outbound-lane.state)`; 2) all incoming messages are rejected if + /// `proof-of(outbound-lane.state).last_delivered_nonce` is equal to + /// `self.last_confirmed_nonce`. Given what is said above, all nonces in this queue are in + /// range: `(self.last_confirmed_nonce; self.last_delivered_nonce()]`. + /// + /// When a relayer sends a single message, both of MessageNonces are the same. + /// When relayer sends messages in a batch, the first arg is the lowest nonce, second arg the + /// highest nonce. Multiple dispatches from the same relayer are allowed. + pub relayers: VecDeque>, + + /// Nonce of the last message that + /// a) has been delivered to the target (this) chain and + /// b) the delivery has been confirmed on the source chain + /// + /// that the target chain knows of. + /// + /// This value is updated indirectly when an `OutboundLane` state of the source + /// chain is received alongside with new messages delivery. + pub last_confirmed_nonce: MessageNonce, +} + +impl Default for InboundLaneData { + fn default() -> Self { + InboundLaneData { relayers: VecDeque::new(), last_confirmed_nonce: 0 } + } +} + +impl InboundLaneData { + /// Returns approximate size of the struct, given a number of entries in the `relayers` set and + /// size of each entry. + /// + /// Returns `None` if size overflows `usize` limits. + pub fn encoded_size_hint(relayers_entries: usize) -> Option + where + RelayerId: MaxEncodedLen, + { + let message_nonce_size = MessageNonce::max_encoded_len(); + let relayer_id_encoded_size = RelayerId::max_encoded_len(); + let relayers_entry_size = relayer_id_encoded_size.checked_add(2 * message_nonce_size)?; + let relayers_size = relayers_entries.checked_mul(relayers_entry_size)?; + relayers_size.checked_add(message_nonce_size) + } + + /// Returns the approximate size of the struct as u32, given a number of entries in the + /// `relayers` set and the size of each entry. + /// + /// Returns `u32::MAX` if size overflows `u32` limits. + pub fn encoded_size_hint_u32(relayers_entries: usize) -> u32 + where + RelayerId: MaxEncodedLen, + { + Self::encoded_size_hint(relayers_entries) + .and_then(|x| u32::try_from(x).ok()) + .unwrap_or(u32::MAX) + } + + /// Nonce of the last message that has been delivered to this (target) chain. + pub fn last_delivered_nonce(&self) -> MessageNonce { + self.relayers + .back() + .map(|entry| entry.messages.end) + .unwrap_or(self.last_confirmed_nonce) + } +} + +/// Outbound message details, returned by runtime APIs. +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct OutboundMessageDetails { + /// Nonce assigned to the message. + pub nonce: MessageNonce, + /// Message dispatch weight. + /// + /// Depending on messages pallet configuration, it may be declared by the message submitter, + /// computed automatically or just be zero if dispatch fee is paid at the target chain. + pub dispatch_weight: Weight, + /// Size of the encoded message. + pub size: u32, +} + +/// Inbound message details, returned by runtime APIs. +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct InboundMessageDetails { + /// Computed message dispatch weight. + /// + /// Runtime API guarantees that it will match the value, returned by + /// `target_chain::MessageDispatch::dispatch_weight`. This means that if the runtime + /// has failed to decode the message, it will be zero - that's because `undecodable` + /// message cannot be dispatched. + pub dispatch_weight: Weight, +} + +/// Unrewarded relayer entry stored in the inbound lane data. +/// +/// This struct represents a continuous range of messages that have been delivered by the same +/// relayer and whose confirmations are still pending. +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct UnrewardedRelayer { + /// Identifier of the relayer. + pub relayer: RelayerId, + /// Messages range, delivered by this relayer. + pub messages: DeliveredMessages, +} + +/// Received messages with their dispatch result. +#[derive(Clone, Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct ReceivedMessages { + /// Id of the lane which is receiving messages. + pub lane: LaneId, + /// Result of messages which we tried to dispatch + pub receive_results: Vec<(MessageNonce, ReceivalResult)>, +} + +impl ReceivedMessages { + pub fn new( + lane: LaneId, + receive_results: Vec<(MessageNonce, ReceivalResult)>, + ) -> Self { + ReceivedMessages { lane, receive_results } + } + + pub fn push(&mut self, message: MessageNonce, result: ReceivalResult) { + self.receive_results.push((message, result)); + } +} + +/// Result of single message receival. +#[derive(RuntimeDebug, Encode, Decode, PartialEq, Eq, Clone, TypeInfo)] +pub enum ReceivalResult { + /// Message has been received and dispatched. Note that we don't care whether dispatch has + /// been successful or not - in both case message falls into this category. + /// + /// The message dispatch result is also returned. + Dispatched(MessageDispatchResult), + /// Message has invalid nonce and lane has rejected to accept this message. + InvalidNonce, + /// There are too many unrewarded relayer entries at the lane. + TooManyUnrewardedRelayers, + /// There are too many unconfirmed messages at the lane. + TooManyUnconfirmedMessages, +} + +/// Delivered messages with their dispatch result. +#[derive(Clone, Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct DeliveredMessages { + /// Nonce of the first message that has been delivered (inclusive). + pub begin: MessageNonce, + /// Nonce of the last message that has been delivered (inclusive). + pub end: MessageNonce, +} + +impl DeliveredMessages { + /// Create new `DeliveredMessages` struct that confirms delivery of single nonce with given + /// dispatch result. + pub fn new(nonce: MessageNonce) -> Self { + DeliveredMessages { begin: nonce, end: nonce } + } + + /// Return total count of delivered messages. + pub fn total_messages(&self) -> MessageNonce { + (self.begin..=self.end).checked_len().unwrap_or(0) + } + + /// Note new dispatched message. + pub fn note_dispatched_message(&mut self) { + self.end += 1; + } + + /// Returns true if delivered messages contain message with given nonce. + pub fn contains_message(&self, nonce: MessageNonce) -> bool { + (self.begin..=self.end).contains(&nonce) + } +} + +/// Gist of `InboundLaneData::relayers` field used by runtime APIs. +#[derive(Clone, Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct UnrewardedRelayersState { + /// Number of entries in the `InboundLaneData::relayers` set. + pub unrewarded_relayer_entries: MessageNonce, + /// Number of messages in the oldest entry of `InboundLaneData::relayers`. This is the + /// minimal number of reward proofs required to push out this entry from the set. + pub messages_in_oldest_entry: MessageNonce, + /// Total number of messages in the relayers vector. + pub total_messages: MessageNonce, + /// Nonce of the latest message that has been delivered to the target chain. + /// + /// This corresponds to the result of the `InboundLaneData::last_delivered_nonce` call + /// at the bridged chain. + pub last_delivered_nonce: MessageNonce, +} + +/// Outbound lane data. +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] +pub struct OutboundLaneData { + /// Nonce of the oldest message that we haven't yet pruned. May point to not-yet-generated + /// message if all sent messages are already pruned. + pub oldest_unpruned_nonce: MessageNonce, + /// Nonce of the latest message, received by bridged chain. + pub latest_received_nonce: MessageNonce, + /// Nonce of the latest message, generated by us. + pub latest_generated_nonce: MessageNonce, +} + +impl Default for OutboundLaneData { + fn default() -> Self { + OutboundLaneData { + // it is 1 because we're pruning everything in [oldest_unpruned_nonce; + // latest_received_nonce] + oldest_unpruned_nonce: 1, + latest_received_nonce: 0, + latest_generated_nonce: 0, + } + } +} + +/// Returns total number of messages in the `InboundLaneData::relayers` vector. +/// +/// Returns `None` if there are more messages that `MessageNonce` may fit (i.e. `MessageNonce + 1`). +pub fn total_unrewarded_messages( + relayers: &VecDeque>, +) -> Option { + match (relayers.front(), relayers.back()) { + (Some(front), Some(back)) => { + if let Some(difference) = back.messages.end.checked_sub(front.messages.begin) { + difference.checked_add(1) + } else { + Some(0) + } + }, + _ => Some(0), + } +} + +/// Calculate the number of messages that the relayers have delivered. +pub fn calc_relayers_rewards( + messages_relayers: VecDeque>, + received_range: &RangeInclusive, +) -> RelayersRewards +where + AccountId: sp_std::cmp::Ord, +{ + // remember to reward relayers that have delivered messages + // this loop is bounded by `T::MaxUnrewardedRelayerEntriesAtInboundLane` on the bridged chain + let mut relayers_rewards = RelayersRewards::new(); + for entry in messages_relayers { + let nonce_begin = sp_std::cmp::max(entry.messages.begin, *received_range.start()); + let nonce_end = sp_std::cmp::min(entry.messages.end, *received_range.end()); + if nonce_end >= nonce_begin { + *relayers_rewards.entry(entry.relayer).or_default() += nonce_end - nonce_begin + 1; + } + } + relayers_rewards +} + +/// A minimized version of `pallet-bridge-messages::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeMessagesCall { + /// `pallet-bridge-messages::Call::receive_messages_proof` + #[codec(index = 2)] + receive_messages_proof { + relayer_id_at_bridged_chain: AccountId, + proof: MessagesProof, + messages_count: u32, + dispatch_weight: Weight, + }, + /// `pallet-bridge-messages::Call::receive_messages_delivery_proof` + #[codec(index = 3)] + receive_messages_delivery_proof { + proof: MessagesDeliveryProof, + relayers_state: UnrewardedRelayersState, + }, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn total_unrewarded_messages_does_not_overflow() { + assert_eq!( + total_unrewarded_messages( + &vec![ + UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0) }, + UnrewardedRelayer { + relayer: 2, + messages: DeliveredMessages::new(MessageNonce::MAX) + }, + ] + .into_iter() + .collect() + ), + None, + ); + } + + #[test] + fn inbound_lane_data_returns_correct_hint() { + let test_cases = vec![ + // single relayer, multiple messages + (1, 128u8), + // multiple relayers, single message per relayer + (128u8, 128u8), + // several messages per relayer + (13u8, 128u8), + ]; + for (relayer_entries, messages_count) in test_cases { + let expected_size = InboundLaneData::::encoded_size_hint(relayer_entries as _); + let actual_size = InboundLaneData { + relayers: (1u8..=relayer_entries) + .map(|i| UnrewardedRelayer { + relayer: i, + messages: DeliveredMessages::new(i as _), + }) + .collect(), + last_confirmed_nonce: messages_count as _, + } + .encode() + .len(); + let difference = (expected_size.unwrap() as f64 - actual_size as f64).abs(); + assert!( + difference / (std::cmp::min(actual_size, expected_size.unwrap()) as f64) < 0.1, + "Too large difference between actual ({actual_size}) and expected ({expected_size:?}) inbound lane data size. Test case: {relayer_entries}+{messages_count}", + ); + } + } + + #[test] + fn contains_result_works() { + let delivered_messages = DeliveredMessages { begin: 100, end: 150 }; + + assert!(!delivered_messages.contains_message(99)); + assert!(delivered_messages.contains_message(100)); + assert!(delivered_messages.contains_message(150)); + assert!(!delivered_messages.contains_message(151)); + } + + #[test] + fn lane_id_debug_format_matches_inner_array_format() { + assert_eq!(format!("{:?}", LaneId([0, 0, 0, 0])), format!("{:?}", [0, 0, 0, 0]),); + } +} diff --git a/primitives/messages/src/source_chain.rs b/primitives/messages/src/source_chain.rs new file mode 100644 index 00000000000..394a934171f --- /dev/null +++ b/primitives/messages/src/source_chain.rs @@ -0,0 +1,211 @@ +// Copyright 2019-2021 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 . + +//! Primitives of messages module, that are used on the source chain. + +use crate::{InboundLaneData, LaneId, MessageNonce, OutboundLaneData}; + +use crate::UnrewardedRelayer; +use bp_runtime::Size; +use frame_support::{Parameter, RuntimeDebug}; +use sp_std::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + fmt::Debug, + ops::RangeInclusive, +}; + +/// Number of messages, delivered by relayers. +pub type RelayersRewards = BTreeMap; + +/// Target chain API. Used by source chain to verify target chain proofs. +/// +/// All implementations of this trait should only work with finalized data that +/// can't change. Wrong implementation may lead to invalid lane states (i.e. lane +/// that's stuck) and/or processing messages without paying fees. +/// +/// The `Payload` type here means the payload of the message that is sent from the +/// source chain to the target chain. The `AccountId` type here means the account +/// type used by the source chain. +pub trait TargetHeaderChain { + /// Error type. + type Error: Debug; + + /// Proof that messages have been received by target chain. + type MessagesDeliveryProof: Parameter + Size; + + /// Verify message payload before we accept it. + /// + /// **CAUTION**: this is very important function. Incorrect implementation may lead + /// to stuck lanes and/or relayers loses. + /// + /// The proper implementation must ensure that the delivery-transaction with this + /// payload would (at least) be accepted into target chain transaction pool AND + /// eventually will be successfully mined. The most obvious incorrect implementation + /// example would be implementation for BTC chain that accepts payloads larger than + /// 1MB. BTC nodes aren't accepting transactions that are larger than 1MB, so relayer + /// will be unable to craft valid transaction => this (and all subsequent) messages will + /// never be delivered. + fn verify_message(payload: &Payload) -> Result<(), Self::Error>; + + /// Verify messages delivery proof and return lane && nonce of the latest received message. + fn verify_messages_delivery_proof( + proof: Self::MessagesDeliveryProof, + ) -> Result<(LaneId, InboundLaneData), Self::Error>; +} + +/// Lane message verifier. +/// +/// Runtime developer may implement any additional validation logic over message-lane mechanism. +/// E.g. if lanes should have some security (e.g. you can only accept Lane1 messages from +/// Submitter1, Lane2 messages for those who has submitted first message to this lane, disable +/// Lane3 until some block, ...), then it may be built using this verifier. +/// +/// Any fee requirements should also be enforced here. +pub trait LaneMessageVerifier { + /// Error type. + type Error: Debug + Into<&'static str>; + + /// Verify message payload and return Ok(()) if message is valid and allowed to be sent over the + /// lane. + fn verify_message( + submitter: &SenderOrigin, + lane: &LaneId, + outbound_data: &OutboundLaneData, + payload: &Payload, + ) -> Result<(), Self::Error>; +} + +/// Manages payments that are happening at the source chain during delivery confirmation +/// transaction. +pub trait DeliveryConfirmationPayments { + /// Error type. + type Error: Debug + Into<&'static str>; + + /// Pay rewards for delivering messages to the given relayers. + /// + /// The implementation may also choose to pay reward to the `confirmation_relayer`, which is + /// a relayer that has submitted delivery confirmation transaction. + /// + /// Returns number of actually rewarded relayers. + fn pay_reward( + lane_id: LaneId, + messages_relayers: VecDeque>, + confirmation_relayer: &AccountId, + received_range: &RangeInclusive, + ) -> MessageNonce; +} + +impl DeliveryConfirmationPayments for () { + type Error = &'static str; + + fn pay_reward( + _lane_id: LaneId, + _messages_relayers: VecDeque>, + _confirmation_relayer: &AccountId, + _received_range: &RangeInclusive, + ) -> MessageNonce { + // this implementation is not rewarding relayers at all + 0 + } +} + +/// Send message artifacts. +#[derive(Eq, RuntimeDebug, PartialEq)] +pub struct SendMessageArtifacts { + /// Nonce of the message. + pub nonce: MessageNonce, +} + +/// Messages bridge API to be used from other pallets. +pub trait MessagesBridge { + /// Error type. + type Error: Debug; + + /// Send message over the bridge. + /// + /// Returns unique message nonce or error if send has failed. + fn send_message( + sender: SenderOrigin, + lane: LaneId, + message: Payload, + ) -> Result; +} + +/// Bridge that does nothing when message is being sent. +#[derive(Eq, RuntimeDebug, PartialEq)] +pub struct NoopMessagesBridge; + +impl MessagesBridge for NoopMessagesBridge { + type Error = &'static str; + + fn send_message( + _sender: SenderOrigin, + _lane: LaneId, + _message: Payload, + ) -> Result { + Ok(SendMessageArtifacts { nonce: 0 }) + } +} + +/// Structure that may be used in place of `TargetHeaderChain`, `LaneMessageVerifier` and +/// `MessageDeliveryAndDispatchPayment` on chains, where outbound messages are forbidden. +pub struct ForbidOutboundMessages; + +/// Error message that is used in `ForbidOutboundMessages` implementation. +const ALL_OUTBOUND_MESSAGES_REJECTED: &str = + "This chain is configured to reject all outbound messages"; + +impl TargetHeaderChain for ForbidOutboundMessages { + type Error = &'static str; + + type MessagesDeliveryProof = (); + + fn verify_message(_payload: &Payload) -> Result<(), Self::Error> { + Err(ALL_OUTBOUND_MESSAGES_REJECTED) + } + + fn verify_messages_delivery_proof( + _proof: Self::MessagesDeliveryProof, + ) -> Result<(LaneId, InboundLaneData), Self::Error> { + Err(ALL_OUTBOUND_MESSAGES_REJECTED) + } +} + +impl LaneMessageVerifier for ForbidOutboundMessages { + type Error = &'static str; + + fn verify_message( + _submitter: &SenderOrigin, + _lane: &LaneId, + _outbound_data: &OutboundLaneData, + _payload: &Payload, + ) -> Result<(), Self::Error> { + Err(ALL_OUTBOUND_MESSAGES_REJECTED) + } +} + +impl DeliveryConfirmationPayments for ForbidOutboundMessages { + type Error = &'static str; + + fn pay_reward( + _lane_id: LaneId, + _messages_relayers: VecDeque>, + _confirmation_relayer: &AccountId, + _received_range: &RangeInclusive, + ) -> MessageNonce { + 0 + } +} diff --git a/primitives/messages/src/storage_keys.rs b/primitives/messages/src/storage_keys.rs new file mode 100644 index 00000000000..4edf9828cfd --- /dev/null +++ b/primitives/messages/src/storage_keys.rs @@ -0,0 +1,128 @@ +// Copyright 2019-2021 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 . + +//! Storage keys of bridge messages pallet. + +/// Name of the `OPERATING_MODE_VALUE_NAME` storage value. +pub const OPERATING_MODE_VALUE_NAME: &str = "PalletOperatingMode"; +/// Name of the `OutboundMessages` storage map. +pub const OUTBOUND_MESSAGES_MAP_NAME: &str = "OutboundMessages"; +/// Name of the `OutboundLanes` storage map. +pub const OUTBOUND_LANES_MAP_NAME: &str = "OutboundLanes"; +/// Name of the `InboundLanes` storage map. +pub const INBOUND_LANES_MAP_NAME: &str = "InboundLanes"; + +use crate::{LaneId, MessageKey, MessageNonce}; + +use codec::Encode; +use frame_support::Blake2_128Concat; +use sp_core::storage::StorageKey; + +/// Storage key of the `PalletOperatingMode` value in the runtime storage. +pub fn operating_mode_key(pallet_prefix: &str) -> StorageKey { + StorageKey( + bp_runtime::storage_value_final_key( + pallet_prefix.as_bytes(), + OPERATING_MODE_VALUE_NAME.as_bytes(), + ) + .to_vec(), + ) +} + +/// Storage key of the outbound message in the runtime storage. +pub fn message_key(pallet_prefix: &str, lane: &LaneId, nonce: MessageNonce) -> StorageKey { + bp_runtime::storage_map_final_key::( + pallet_prefix, + OUTBOUND_MESSAGES_MAP_NAME, + &MessageKey { lane_id: *lane, nonce }.encode(), + ) +} + +/// Storage key of the outbound message lane state in the runtime storage. +pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { + bp_runtime::storage_map_final_key::( + pallet_prefix, + OUTBOUND_LANES_MAP_NAME, + &lane.encode(), + ) +} + +/// Storage key of the inbound message lane state in the runtime storage. +pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { + bp_runtime::storage_map_final_key::( + pallet_prefix, + INBOUND_LANES_MAP_NAME, + &lane.encode(), + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use hex_literal::hex; + + #[test] + fn operating_mode_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is possibly + // breaking all existing message relays. + let storage_key = operating_mode_key("BridgeMessages").0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed010f4cf0917788d791142ff6c1f216e7b3").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + + #[test] + fn storage_message_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // all previously crafted messages proofs. + let storage_key = message_key("BridgeMessages", &LaneId(*b"test"), 42).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea79446af0e09063bd4a7874aef8a997cec746573742a00000000000000").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + + #[test] + fn outbound_lane_data_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // all previously crafted outbound lane state proofs. + let storage_key = outbound_lane_data_key("BridgeMessages", &LaneId(*b"test")).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1f44a8995dd50b6657a037a7839304535b74657374").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + + #[test] + fn inbound_lane_data_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // all previously crafted inbound lane state proofs. + let storage_key = inbound_lane_data_key("BridgeMessages", &LaneId(*b"test")).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fab44a8995dd50b6657a037a7839304535b74657374").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } +} diff --git a/primitives/messages/src/target_chain.rs b/primitives/messages/src/target_chain.rs new file mode 100644 index 00000000000..8496b90214c --- /dev/null +++ b/primitives/messages/src/target_chain.rs @@ -0,0 +1,205 @@ +// Copyright 2019-2021 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 . + +//! Primitives of messages module, that are used on the target chain. + +use crate::{LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData}; + +use bp_runtime::{messages::MessageDispatchResult, Size}; +use codec::{Decode, Encode, Error as CodecError}; +use frame_support::{weights::Weight, Parameter, RuntimeDebug}; +use scale_info::TypeInfo; +use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, marker::PhantomData, prelude::*}; + +/// Proved messages from the source chain. +pub type ProvedMessages = BTreeMap>; + +/// Proved messages from single lane of the source chain. +#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] +pub struct ProvedLaneMessages { + /// Optional outbound lane state. + pub lane_state: Option, + /// Messages sent through this lane. + pub messages: Vec, +} + +/// Message data with decoded dispatch payload. +#[derive(RuntimeDebug)] +pub struct DispatchMessageData { + /// Result of dispatch payload decoding. + pub payload: Result, +} + +/// Message with decoded dispatch payload. +#[derive(RuntimeDebug)] +pub struct DispatchMessage { + /// Message key. + pub key: MessageKey, + /// Message data with decoded dispatch payload. + pub data: DispatchMessageData, +} + +/// Source chain API. Used by target chain, to verify source chain proofs. +/// +/// All implementations of this trait should only work with finalized data that +/// can't change. Wrong implementation may lead to invalid lane states (i.e. lane +/// that's stuck) and/or processing messages without paying fees. +pub trait SourceHeaderChain { + /// Error type. + type Error: Debug; + + /// Proof that messages are sent from source chain. This may also include proof + /// of corresponding outbound lane states. + type MessagesProof: Parameter + Size; + + /// Verify messages proof and return proved messages. + /// + /// Returns error if either proof is incorrect, or the number of messages in the proof + /// is not matching the `messages_count`. + /// + /// Messages vector is required to be sorted by nonce within each lane. Out-of-order + /// messages will be rejected. + /// + /// The `messages_count` argument verification (sane limits) is supposed to be made + /// outside this function. This function only verifies that the proof declares exactly + /// `messages_count` messages. + fn verify_messages_proof( + proof: Self::MessagesProof, + messages_count: u32, + ) -> Result, Self::Error>; +} + +/// Called when inbound message is received. +pub trait MessageDispatch { + /// Decoded message payload type. Valid message may contain invalid payload. In this case + /// message is delivered, but dispatch fails. Therefore, two separate types of payload + /// (opaque `MessagePayload` used in delivery and this `DispatchPayload` used in dispatch). + type DispatchPayload: Decode; + + /// Fine-grained result of single message dispatch (for better diagnostic purposes) + type DispatchLevelResult: Clone + sp_std::fmt::Debug + Eq; + + /// Estimate dispatch weight. + /// + /// This function must return correct upper bound of dispatch weight. The return value + /// of this function is expected to match return value of the corresponding + /// `FromInboundLaneApi::message_details().dispatch_weight` call. + fn dispatch_weight(message: &mut DispatchMessage) -> Weight; + + /// Called when inbound message is received. + /// + /// It is up to the implementers of this trait to determine whether the message + /// is invalid (i.e. improperly encoded, has too large weight, ...) or not. + /// + /// If your configuration allows paying dispatch fee at the target chain, then + /// it must be paid inside this method to the `relayer_account`. + fn dispatch( + relayer_account: &AccountId, + message: DispatchMessage, + ) -> MessageDispatchResult; +} + +/// Manages payments that are happening at the target chain during message delivery transaction. +pub trait DeliveryPayments { + /// Error type. + type Error: Debug + Into<&'static str>; + + /// Pay rewards for delivering messages to the given relayer. + /// + /// This method is called during message delivery transaction which has been submitted + /// by the `relayer`. The transaction brings `total_messages` messages but only + /// `valid_messages` have been accepted. The post-dispatch transaction weight is the + /// `actual_weight`. + fn pay_reward( + relayer: AccountId, + total_messages: MessageNonce, + valid_messages: MessageNonce, + actual_weight: Weight, + ); +} + +impl Default for ProvedLaneMessages { + fn default() -> Self { + ProvedLaneMessages { lane_state: None, messages: Vec::new() } + } +} + +impl From for DispatchMessage { + fn from(message: Message) -> Self { + DispatchMessage { key: message.key, data: message.payload.into() } + } +} + +impl From for DispatchMessageData { + fn from(payload: MessagePayload) -> Self { + DispatchMessageData { payload: DispatchPayload::decode(&mut &payload[..]) } + } +} + +impl DeliveryPayments for () { + type Error = &'static str; + + fn pay_reward( + _relayer: AccountId, + _total_messages: MessageNonce, + _valid_messages: MessageNonce, + _actual_weight: Weight, + ) { + // this implementation is not rewarding relayer at all + } +} + +/// Structure that may be used in place of `SourceHeaderChain` and `MessageDispatch` on chains, +/// where inbound messages are forbidden. +pub struct ForbidInboundMessages( + PhantomData<(MessagesProof, DispatchPayload)>, +); + +/// Error message that is used in `ForbidOutboundMessages` implementation. +const ALL_INBOUND_MESSAGES_REJECTED: &str = + "This chain is configured to reject all inbound messages"; + +impl SourceHeaderChain + for ForbidInboundMessages +{ + type Error = &'static str; + type MessagesProof = MessagesProof; + + fn verify_messages_proof( + _proof: Self::MessagesProof, + _messages_count: u32, + ) -> Result, Self::Error> { + Err(ALL_INBOUND_MESSAGES_REJECTED) + } +} + +impl MessageDispatch + for ForbidInboundMessages +{ + type DispatchPayload = DispatchPayload; + type DispatchLevelResult = (); + + fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + Weight::MAX + } + + fn dispatch( + _: &AccountId, + _: DispatchMessage, + ) -> MessageDispatchResult { + MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } + } +} diff --git a/primitives/parachains/Cargo.toml b/primitives/parachains/Cargo.toml new file mode 100644 index 00000000000..e47b8c5e68c --- /dev/null +++ b/primitives/parachains/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "bp-parachains" +description = "Primitives of parachains module." +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" +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.5.0", default-features = false, features = ["derive"] } + +# 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 dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "bp-polkadot-core/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/primitives/parachains/src/lib.rs b/primitives/parachains/src/lib.rs new file mode 100644 index 00000000000..e619fc7b641 --- /dev/null +++ b/primitives/parachains/src/lib.rs @@ -0,0 +1,180 @@ +// Copyright 2019-2021 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 . + +//! Primitives of parachains module. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub use bp_header_chain::StoredHeaderData; + +use bp_polkadot_core::{ + parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}, + BlockNumber as RelayBlockNumber, Hash as RelayBlockHash, +}; +use bp_runtime::{ + BlockNumberOf, Chain, HashOf, HeaderOf, Parachain, StorageDoubleMapKeyProvider, + StorageMapKeyProvider, +}; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{Blake2_128Concat, RuntimeDebug, Twox64Concat}; +use scale_info::TypeInfo; +use sp_core::storage::StorageKey; +use sp_runtime::traits::Header as HeaderT; +use sp_std::{marker::PhantomData, prelude::*}; + +/// Best known parachain head hash. +#[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +pub struct BestParaHeadHash { + /// Number of relay block where this head has been read. + /// + /// Parachain head is opaque to relay chain. So we can't simply decode it as a header of + /// parachains and call `block_number()` on it. Instead, we're using the fact that parachain + /// head is always built on top of previous head (because it is blockchain) and relay chain + /// always imports parachain heads in order. What it means for us is that at any given + /// **finalized** relay block `B`, head of parachain will be ancestor (or the same) of all + /// parachain heads available at descendants of `B`. + pub at_relay_block_number: RelayBlockNumber, + /// Hash of parachain head. + pub head_hash: ParaHash, +} + +/// Best known parachain head as it is stored in the runtime storage. +#[derive(Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] +pub struct ParaInfo { + /// Best known parachain head hash. + pub best_head_hash: BestParaHeadHash, + /// Current ring buffer position for this parachain. + pub next_imported_hash_position: u32, +} + +/// Returns runtime storage key of given parachain head at the source chain. +/// +/// The head is stored by the `paras` pallet in the `Heads` map. +pub fn parachain_head_storage_key_at_source( + paras_pallet_name: &str, + para_id: ParaId, +) -> StorageKey { + bp_runtime::storage_map_final_key::(paras_pallet_name, "Heads", ¶_id.encode()) +} + +/// Can be use to access the runtime storage key of the parachains info at the target chain. +/// +/// The info is stored by the `pallet-bridge-parachains` pallet in the `ParasInfo` map. +pub struct ParasInfoKeyProvider; +impl StorageMapKeyProvider for ParasInfoKeyProvider { + const MAP_NAME: &'static str = "ParasInfo"; + + type Hasher = Blake2_128Concat; + type Key = ParaId; + type Value = ParaInfo; +} + +/// Can be use to access the runtime storage key of the parachain head at the target chain. +/// +/// The head is stored by the `pallet-bridge-parachains` pallet in the `ImportedParaHeads` map. +pub struct ImportedParaHeadsKeyProvider; +impl StorageDoubleMapKeyProvider for ImportedParaHeadsKeyProvider { + const MAP_NAME: &'static str = "ImportedParaHeads"; + + type Hasher1 = Blake2_128Concat; + type Key1 = ParaId; + type Hasher2 = Blake2_128Concat; + type Key2 = ParaHash; + type Value = ParaStoredHeaderData; +} + +/// Stored data of the parachain head. It is encoded version of the +/// `bp_runtime::StoredHeaderData` structure. +/// +/// We do not know exact structure of the parachain head, so we always store encoded version +/// of the `bp_runtime::StoredHeaderData`. It is only decoded when we talk about specific parachain. +#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)] +pub struct ParaStoredHeaderData(pub Vec); + +impl ParaStoredHeaderData { + /// Decode stored parachain head data. + pub fn decode_parachain_head_data( + &self, + ) -> Result, HashOf>, codec::Error> { + StoredHeaderData::, HashOf>::decode(&mut &self.0[..]) + } +} + +/// Stored parachain head data builder. +pub trait ParaStoredHeaderDataBuilder { + /// Return number of parachains that are supported by this builder. + fn supported_parachains() -> u32; + + /// Try to build head data from encoded head of parachain with given id. + fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option; +} + +/// Helper for using single parachain as `ParaStoredHeaderDataBuilder`. +pub struct SingleParaStoredHeaderDataBuilder(PhantomData); + +impl ParaStoredHeaderDataBuilder for SingleParaStoredHeaderDataBuilder { + fn supported_parachains() -> u32 { + 1 + } + + fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option { + if para_id == ParaId(C::PARACHAIN_ID) { + let header = HeaderOf::::decode(&mut ¶_head.0[..]).ok()?; + return Some(ParaStoredHeaderData( + StoredHeaderData { number: *header.number(), state_root: *header.state_root() } + .encode(), + )) + } + None + } +} + +// Tries to build header data from each tuple member, short-circuiting on first successful one. +#[impl_trait_for_tuples::impl_for_tuples(1, 30)] +#[tuple_types_custom_trait_bound(Parachain)] +impl ParaStoredHeaderDataBuilder for C { + fn supported_parachains() -> u32 { + let mut result = 0; + for_tuples!( #( + result += SingleParaStoredHeaderDataBuilder::::supported_parachains(); + )* ); + result + } + + fn try_build(para_id: ParaId, para_head: &ParaHead) -> Option { + for_tuples!( #( + let maybe_para_head = SingleParaStoredHeaderDataBuilder::::try_build(para_id, para_head); + if let Some(maybe_para_head) = maybe_para_head { + return Some(maybe_para_head); + } + )* ); + + None + } +} + +/// A minimized version of `pallet-bridge-parachains::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeParachainCall { + /// `pallet-bridge-parachains::Call::submit_parachain_heads` + #[codec(index = 0)] + submit_parachain_heads { + at_relay_block: (RelayBlockNumber, RelayBlockHash), + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + }, +} diff --git a/primitives/polkadot-core/Cargo.toml b/primitives/polkadot-core/Cargo.toml new file mode 100644 index 00000000000..daae99ec71c --- /dev/null +++ b/primitives/polkadot-core/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "bp-polkadot-core" +description = "Primitives of Polkadot-like 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"] } +parity-util-mem = { version = "0.12.0", optional = true } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } + +# Bridge Dependencies + +bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Based Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +hex = "0.4" + +[features] +default = ["std"] +std = [ + "bp-messages/std", + "bp-runtime/std", + "frame-support/std", + "frame-system/std", + "codec/std", + "parity-util-mem", + "scale-info/std", + "serde", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/primitives/polkadot-core/src/lib.rs b/primitives/polkadot-core/src/lib.rs new file mode 100644 index 00000000000..3774d283fc4 --- /dev/null +++ b/primitives/polkadot-core/src/lib.rs @@ -0,0 +1,292 @@ +// Copyright 2019-2021 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)] + +use bp_messages::MessageNonce; +use bp_runtime::{Chain, EncodedOrDecodedCall, StorageMapKeyProvider}; +use frame_support::{ + dispatch::DispatchClass, + parameter_types, + weights::{ + constants::{BlockExecutionWeight, WEIGHT_REF_TIME_PER_SECOND}, + Weight, + }, + Blake2_128Concat, RuntimeDebug, +}; +use frame_system::limits; +use sp_core::{storage::StorageKey, Hasher as HasherT}; +use sp_runtime::{ + generic, + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiAddress, MultiSignature, OpaqueExtrinsic, +}; +use sp_std::prelude::Vec; + +// Re-export's to avoid extra substrate dependencies in chain-specific crates. +pub use frame_support::{weights::constants::ExtrinsicBaseWeight, Parameter}; +pub use sp_runtime::{traits::Convert, Perbill}; + +pub mod parachains; + +/// Maximal number of GRANDPA authorities at Polkadot-like chains. +/// +/// Ideally, we would set it to the value of `MaxAuthorities` constant from bridged runtime +/// configurations. But right now it is set to the `100_000`, which makes PoV size for +/// our bridge hub parachains huge. So let's stick to the real-world value here. +/// +/// Right now both Kusama and Polkadot aim to have around 1000 validators. Let's be safe here and +/// take a bit more here. +pub const MAX_AUTHORITIES_COUNT: u32 = 1_256; + +/// Reasonable number of headers in the `votes_ancestries` on Polkadot-like chains. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +/// +/// This value comes from recent (February, 2023) Kusama and Polkadot headers. There are no +/// justifications with any additional headers in votes ancestry, so reasonable headers may +/// be set to zero. But we assume that there may be small GRANDPA lags, so we're leaving some +/// reserve here. +pub const REASONABLE_HEADERS_IN_JUSTIFICATON_ANCESTRY: u32 = 2; + +/// Approximate average header size in `votes_ancestries` field of justification on Polkadot-like +/// chains. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +/// +/// This value comes from recent (February, 2023) Kusama headers. Average is `336` there, but some +/// non-mandatory headers has size `40kb` (they contain the BABE epoch descriptor with all +/// authorities - just like our mandatory header). Since we assume `2` headers in justification +/// votes ancestry, let's set average header to `40kb / 2`. +pub const AVERAGE_HEADER_SIZE_IN_JUSTIFICATION: u32 = 20 * 1024; + +/// Approximate maximal header size on Polkadot-like chains. +/// +/// See [`bp-header-chain::ChainWithGrandpa`] for more details. +/// +/// This value comes from recent (February, 2023) Kusama headers. Maximal header is a mandatory +/// header. In its SCALE-encoded form it is `80348` bytes. Let's have some reserve here. +pub const MAX_HEADER_SIZE: u32 = 90_000; + +/// Number of extra bytes (excluding size of storage value itself) of storage proof, built at +/// Polkadot-like chain. This mostly depends on number of entries in the storage trie. +/// Some reserve is reserved to account future chain growth. +/// +/// To compute this value, we've synced Kusama chain blocks [0; 6545733] to see if there were +/// any significant changes of the storage proof size (NO): +/// +/// - at block 3072 the storage proof size overhead was 579 bytes; +/// - at block 2479616 it was 578 bytes; +/// - at block 4118528 it was 711 bytes; +/// - at block 6540800 it was 779 bytes. +/// +/// The number of storage entries at the block 6546170 was 351207 and number of trie nodes in +/// the storage proof was 5 (log(16, 351207) ~ 4.6). +/// +/// So the assumption is that the storage proof size overhead won't be larger than 1024 in the +/// nearest future. If it'll ever break this barrier, then we'll need to update this constant +/// at next runtime upgrade. +pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024; + +/// All Polkadot-like chains allow normal extrinsics to fill block up to 75 percent. +/// +/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// All Polkadot-like chains allow 2 seconds of compute with a 6-second average block time. +/// +/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate. +pub const MAXIMUM_BLOCK_WEIGHT: Weight = + Weight::from_parts(WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), u64::MAX); + +/// All Polkadot-like chains assume that an on-initialize consumes 1 percent of the weight on +/// average, hence a single extrinsic will not be allowed to consume more than +/// `AvailableBlockRatio - 1 percent`. +/// +/// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate. +pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(1); + +parameter_types! { + /// All Polkadot-like chains have maximal block size set to 5MB. + /// + /// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate. + pub BlockLength: limits::BlockLength = limits::BlockLength::max_with_normal_ratio( + 5 * 1024 * 1024, + NORMAL_DISPATCH_RATIO, + ); + /// All Polkadot-like chains have the same block weights. + /// + /// This is a copy-paste from the Polkadot repo's `polkadot-runtime-common` crate. + pub BlockWeights: limits::BlockWeights = limits::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 an 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(); +} + +// TODO [#78] may need to be updated after https://github.com/paritytech/parity-bridges-common/issues/78 +/// Maximal number of messages in single delivery transaction. +pub const MAX_MESSAGES_IN_DELIVERY_TRANSACTION: MessageNonce = 128; + +/// Maximal number of bytes, included in the signed Polkadot-like transaction apart from the encoded +/// call itself. +/// +/// Can be computed by subtracting encoded call size from raw transaction size. +pub const TX_EXTRA_BYTES: u32 = 256; + +/// Re-export `time_units` to make usage easier. +pub use time_units::*; + +/// Human readable time units defined in terms of number of blocks. +pub mod time_units { + use super::BlockNumber; + + pub const MILLISECS_PER_BLOCK: u64 = 6000; + pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + + pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); + pub const HOURS: BlockNumber = MINUTES * 60; + pub const DAYS: BlockNumber = HOURS * 24; +} + +/// Block number type used in Polkadot-like chains. +pub type BlockNumber = u32; + +/// Hash type used in Polkadot-like chains. +pub type Hash = ::Out; + +/// Account Index (a.k.a. nonce). +pub type Index = u32; + +/// Hashing type. +pub type Hashing = BlakeTwo256; + +/// The type of object that can produce hashes on Polkadot-like chains. +pub type Hasher = BlakeTwo256; + +/// The header type used by Polkadot-like chains. +pub type Header = generic::Header; + +/// Signature type used by Polkadot-like chains. +pub type Signature = MultiSignature; + +/// Public key of account on Polkadot-like chains. +pub type AccountPublic = ::Signer; + +/// Id of account on Polkadot-like chains. +pub type AccountId = ::AccountId; + +/// Address of account on Polkadot-like chains. +pub type AccountAddress = MultiAddress; + +/// Index of a transaction on the Polkadot-like chains. +pub type Nonce = u32; + +/// Block type of Polkadot-like chains. +pub type Block = generic::Block; + +/// Polkadot-like block signed with a Justification. +pub type SignedBlock = generic::SignedBlock; + +/// The balance of an account on Polkadot-like chain. +pub type Balance = u128; + +/// Unchecked Extrinsic type. +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic, Signature, SignedExt>; + +/// Account address, used by the Polkadot-like chain. +pub type Address = MultiAddress; + +/// Polkadot-like chain. +#[derive(RuntimeDebug)] +pub struct PolkadotLike; + +impl Chain for PolkadotLike { + type BlockNumber = BlockNumber; + type Hash = Hash; + type Hasher = Hasher; + type Header = Header; + + type AccountId = AccountId; + type Balance = Balance; + type Index = Index; + 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) + } +} + +/// Provides a storage key for account data. +/// +/// We need to use this approach when we don't have access to the runtime. +/// The equivalent command to invoke in case full `Runtime` is known is this: +/// `let key = frame_system::Account::::storage_map_final_key(&account_id);` +pub struct AccountInfoStorageMapKeyProvider; + +impl StorageMapKeyProvider for AccountInfoStorageMapKeyProvider { + const MAP_NAME: &'static str = "Account"; + type Hasher = Blake2_128Concat; + type Key = AccountId; + // This should actually be `AccountInfo`, but we don't use this property in order to decode the + // data. So we use `Vec` as if we would work with encoded data. + type Value = Vec; +} + +impl AccountInfoStorageMapKeyProvider { + const PALLET_NAME: &'static str = "System"; + + pub fn final_key(id: &AccountId) -> StorageKey { + ::final_key(Self::PALLET_NAME, id) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_generate_storage_key() { + let acc = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + ] + .into(); + let key = AccountInfoStorageMapKeyProvider::final_key(&acc); + assert_eq!(hex::encode(key), "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92dccd599abfe1920a1cff8a7358231430102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"); + } +} diff --git a/primitives/polkadot-core/src/parachains.rs b/primitives/polkadot-core/src/parachains.rs new file mode 100644 index 00000000000..0b410dff49f --- /dev/null +++ b/primitives/polkadot-core/src/parachains.rs @@ -0,0 +1,98 @@ +// Copyright 2019-2021 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 . + +//! Primitives of polkadot-like chains, that are related to parachains functionality. +//! +//! Even though this (bridges) repository references polkadot repository, we can't +//! reference polkadot crates from pallets. That's because bridges repository is +//! included in the polkadot repository and included pallets are used by polkadot +//! chains. Having pallets that are referencing polkadot, would mean that there may +//! be two versions of polkadot crates included in the runtime. Which is bad. + +use bp_runtime::{RawStorageProof, Size}; +use codec::{CompactAs, Decode, Encode, MaxEncodedLen}; +use frame_support::RuntimeDebug; +use scale_info::TypeInfo; +use sp_core::Hasher; +use sp_std::vec::Vec; + +#[cfg(feature = "std")] +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "std")] +use parity_util_mem::MallocSizeOf; + +/// Parachain id. +/// +/// This is an equivalent of the `polkadot_parachain::Id`, which is a compact-encoded `u32`. +#[derive( + Clone, + CompactAs, + Copy, + Decode, + Default, + Encode, + Eq, + Hash, + MaxEncodedLen, + Ord, + PartialEq, + PartialOrd, + RuntimeDebug, + TypeInfo, +)] +pub struct ParaId(pub u32); + +impl From for ParaId { + fn from(id: u32) -> Self { + ParaId(id) + } +} + +/// Parachain head. +/// +/// This is an equivalent of the `polkadot_parachain::HeadData`. +/// +/// The parachain head means (at least in Cumulus) a SCALE-encoded parachain header. +#[derive( + PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, Default, +)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, MallocSizeOf))] +pub struct ParaHead(pub Vec); + +impl ParaHead { + /// Returns the hash of this head data. + pub fn hash(&self) -> crate::Hash { + sp_runtime::traits::BlakeTwo256::hash(&self.0) + } +} + +/// Parachain head hash. +pub type ParaHash = crate::Hash; + +/// Parachain head hasher. +pub type ParaHasher = crate::Hasher; + +/// Raw storage proof of parachain heads, stored in polkadot-like chain runtime. +#[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] +pub struct ParaHeadsProof(pub RawStorageProof); + +impl Size for ParaHeadsProof { + fn size(&self) -> u32 { + u32::try_from(self.0.iter().fold(0usize, |sum, node| sum.saturating_add(node.len()))) + .unwrap_or(u32::MAX) + } +} diff --git a/primitives/relayers/Cargo.toml b/primitives/relayers/Cargo.toml new file mode 100644 index 00000000000..8ac31258488 --- /dev/null +++ b/primitives/relayers/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "bp-relayers" +description = "Primitives of relayers module." +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", "bit-vec"] } +scale-info = { version = "2.5.0", default-features = false, features = ["bit-vec", "derive"] } + +# Bridge Dependencies + +bp-messages = { path = "../messages", default-features = false } +bp-runtime = { path = "../runtime", default-features = false } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[dev-dependencies] +hex = "0.4" +hex-literal = "0.4" + +[features] +default = ["std"] +std = [ + "bp-messages/std", + "bp-runtime/std", + "frame-support/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/primitives/relayers/src/lib.rs b/primitives/relayers/src/lib.rs new file mode 100644 index 00000000000..f14b841fa9e --- /dev/null +++ b/primitives/relayers/src/lib.rs @@ -0,0 +1,202 @@ +// Copyright 2019-2021 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 . + +//! Primitives of messages module. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +use bp_messages::LaneId; +use bp_runtime::{ChainId, StorageDoubleMapKeyProvider}; +use frame_support::{traits::tokens::Preservation, Blake2_128Concat, Identity}; +use scale_info::TypeInfo; +use sp_runtime::{ + codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}, + traits::AccountIdConversion, + TypeId, +}; +use sp_std::{fmt::Debug, marker::PhantomData}; + +/// The owner of the sovereign account that should pay the rewards. +/// +/// Each of the 2 final points connected by a bridge owns a sovereign account at each end of the +/// bridge. So here, at this end of the bridge there can be 2 sovereign accounts that pay rewards. +#[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +pub enum RewardsAccountOwner { + /// The sovereign account of the final chain on this end of the bridge. + ThisChain, + /// The sovereign account of the final chain on the other end of the bridge. + BridgedChain, +} + +/// Structure used to identify the account that pays a reward to the relayer. +/// +/// A bridge connects 2 bridge ends. Each one is located on a separate relay chain. The bridge ends +/// can be the final destinations of the bridge, or they can be intermediary points +/// (e.g. a bridge hub) used to forward messages between pairs of parachains on the bridged relay +/// chains. A pair of such parachains is connected using a bridge lane. Each of the 2 final +/// destinations of a bridge lane must have a sovereign account at each end of the bridge and each +/// of the sovereign accounts will pay rewards for different operations. So we need multiple +/// parameters to identify the account that pays a reward to the relayer. +#[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] +pub struct RewardsAccountParams { + lane_id: LaneId, + bridged_chain_id: ChainId, + owner: RewardsAccountOwner, +} + +impl RewardsAccountParams { + /// Create a new instance of `RewardsAccountParams`. + pub const fn new( + lane_id: LaneId, + bridged_chain_id: ChainId, + owner: RewardsAccountOwner, + ) -> Self { + Self { lane_id, bridged_chain_id, owner } + } +} + +impl TypeId for RewardsAccountParams { + const TYPE_ID: [u8; 4] = *b"brap"; +} + +/// Reward payment procedure. +pub trait PaymentProcedure { + /// Error that may be returned by the procedure. + type Error: Debug; + + /// Pay reward to the relayer from the account with provided params. + fn pay_reward( + relayer: &Relayer, + rewards_account_params: RewardsAccountParams, + reward: Reward, + ) -> Result<(), Self::Error>; +} + +impl PaymentProcedure for () { + type Error = &'static str; + + fn pay_reward(_: &Relayer, _: RewardsAccountParams, _: Reward) -> Result<(), Self::Error> { + Ok(()) + } +} + +/// Reward payment procedure that does `balances::transfer` call from the account, derived from +/// given params. +pub struct PayRewardFromAccount(PhantomData<(T, Relayer)>); + +impl PayRewardFromAccount +where + Relayer: Decode + Encode, +{ + /// Return account that pays rewards based on the provided parameters. + pub fn rewards_account(params: RewardsAccountParams) -> Relayer { + params.into_sub_account_truncating(b"rewards-account") + } +} + +impl PaymentProcedure for PayRewardFromAccount +where + T: frame_support::traits::fungible::Mutate, + Relayer: Decode + Encode, +{ + type Error = sp_runtime::DispatchError; + + fn pay_reward( + relayer: &Relayer, + rewards_account_params: RewardsAccountParams, + reward: T::Balance, + ) -> Result<(), Self::Error> { + T::transfer( + &Self::rewards_account(rewards_account_params), + relayer, + reward, + Preservation::Expendable, + ) + .map(drop) + } +} + +/// Can be use to access the runtime storage key within the `RelayerRewards` map of the relayers +/// pallet. +pub struct RelayerRewardsKeyProvider(PhantomData<(AccountId, Reward)>); + +impl StorageDoubleMapKeyProvider for RelayerRewardsKeyProvider +where + AccountId: Codec + EncodeLike, + Reward: Codec + EncodeLike, +{ + const MAP_NAME: &'static str = "RelayerRewards"; + + type Hasher1 = Blake2_128Concat; + type Key1 = AccountId; + type Hasher2 = Identity; + type Key2 = RewardsAccountParams; + type Value = Reward; +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_messages::LaneId; + use sp_runtime::testing::H256; + + #[test] + fn different_lanes_are_using_different_accounts() { + assert_eq!( + PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( + LaneId([0, 0, 0, 0]), + *b"test", + RewardsAccountOwner::ThisChain + )), + hex_literal::hex!("62726170000000007465737400726577617264732d6163636f756e7400000000") + .into(), + ); + + assert_eq!( + PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( + LaneId([0, 0, 0, 1]), + *b"test", + RewardsAccountOwner::ThisChain + )), + hex_literal::hex!("62726170000000017465737400726577617264732d6163636f756e7400000000") + .into(), + ); + } + + #[test] + fn different_directions_are_using_different_accounts() { + assert_eq!( + PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( + LaneId([0, 0, 0, 0]), + *b"test", + RewardsAccountOwner::ThisChain + )), + hex_literal::hex!("62726170000000007465737400726577617264732d6163636f756e7400000000") + .into(), + ); + + assert_eq!( + PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( + LaneId([0, 0, 0, 0]), + *b"test", + RewardsAccountOwner::BridgedChain + )), + hex_literal::hex!("62726170000000007465737401726577617264732d6163636f756e7400000000") + .into(), + ); + } +} diff --git a/primitives/runtime/Cargo.toml b/primitives/runtime/Cargo.toml new file mode 100644 index 00000000000..4d48ad61894 --- /dev/null +++ b/primitives/runtime/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "bp-runtime" +description = "Primitives that may be used at (bridges) runtime level." +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 } +hash-db = { version = "0.16.0", default-features = false } +impl-trait-for-tuples = "0.2.2" +num-traits = { version = "0.2", default-features = false } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, features = ["derive"] } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +trie-db = { version = "0.27.1", default-features = false } + +[dev-dependencies] +hex-literal = "0.4" + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-support/std", + "frame-system/std", + "hash-db/std", + "num-traits/std", + "scale-info/std", + "serde", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", + "sp-state-machine/std", + "sp-trie/std", + "trie-db/std", +] diff --git a/primitives/runtime/src/chain.rs b/primitives/runtime/src/chain.rs new file mode 100644 index 00000000000..94b3a193c58 --- /dev/null +++ b/primitives/runtime/src/chain.rs @@ -0,0 +1,375 @@ +// Copyright 2019-2021 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 . + +use crate::HeaderIdProvider; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{weights::Weight, Parameter}; +use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero}; +use sp_runtime::{ + traits::{ + AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, + MaybeSerialize, MaybeSerializeDeserialize, Member, SimpleBitOps, Verify, + }, + FixedPointOperand, +}; +use sp_std::{convert::TryFrom, fmt::Debug, hash::Hash, str::FromStr, vec, vec::Vec}; + +/// Chain call, that is either SCALE-encoded, or decoded. +#[derive(Debug, Clone, PartialEq)] +pub enum EncodedOrDecodedCall { + /// The call that is SCALE-encoded. + /// + /// This variant is used when we the chain runtime is not bundled with the relay, but + /// we still need the represent call in some RPC calls or transactions. + Encoded(Vec), + /// The decoded call. + Decoded(ChainCall), +} + +impl EncodedOrDecodedCall { + /// Returns decoded call. + pub fn to_decoded(&self) -> Result { + match self { + Self::Encoded(ref encoded_call) => + ChainCall::decode(&mut &encoded_call[..]).map_err(Into::into), + Self::Decoded(ref decoded_call) => Ok(decoded_call.clone()), + } + } + + /// Converts self to decoded call. + pub fn into_decoded(self) -> Result { + match self { + Self::Encoded(encoded_call) => + ChainCall::decode(&mut &encoded_call[..]).map_err(Into::into), + Self::Decoded(decoded_call) => Ok(decoded_call), + } + } +} + +impl From for EncodedOrDecodedCall { + fn from(call: ChainCall) -> EncodedOrDecodedCall { + EncodedOrDecodedCall::Decoded(call) + } +} + +impl Decode for EncodedOrDecodedCall { + fn decode(input: &mut I) -> Result { + // having encoded version is better than decoded, because decoding isn't required + // everywhere and for mocked calls it may lead to **unneeded** errors + match input.remaining_len()? { + Some(remaining_len) => { + let mut encoded_call = vec![0u8; remaining_len]; + input.read(&mut encoded_call)?; + Ok(EncodedOrDecodedCall::Encoded(encoded_call)) + }, + None => Ok(EncodedOrDecodedCall::Decoded(ChainCall::decode(input)?)), + } + } +} + +impl Encode for EncodedOrDecodedCall { + fn encode(&self) -> Vec { + match *self { + Self::Encoded(ref encoded_call) => encoded_call.clone(), + Self::Decoded(ref decoded_call) => decoded_call.encode(), + } + } +} + +/// Minimal Substrate-based chain representation that may be used from no_std environment. +pub trait Chain: Send + Sync + 'static { + /// A type that fulfills the abstract idea of what a Substrate block number is. + // Constraits come from the associated Number type of `sp_runtime::traits::Header` + // See here for more info: + // https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Number + // + // Note that the `AsPrimitive` trait is required by the GRANDPA justification + // verifier, and is not usually part of a Substrate Header's Number type. + type BlockNumber: Parameter + + Member + + MaybeSerializeDeserialize + + Hash + + Copy + + Default + + MaybeDisplay + + AtLeast32BitUnsigned + + FromStr + + AsPrimitive + + Default + + Saturating + + MaxEncodedLen; + + /// A type that fulfills the abstract idea of what a Substrate hash is. + // Constraits come from the associated Hash type of `sp_runtime::traits::Header` + // See here for more info: + // https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Hash + type Hash: Parameter + + Member + + MaybeSerializeDeserialize + + Hash + + Ord + + Copy + + MaybeDisplay + + Default + + SimpleBitOps + + AsRef<[u8]> + + AsMut<[u8]> + + MaxEncodedLen; + + /// A type that fulfills the abstract idea of what a Substrate hasher (a type + /// that produces hashes) is. + // Constraits come from the associated Hashing type of `sp_runtime::traits::Header` + // See here for more info: + // https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Hashing + type Hasher: HashT; + + /// A type that fulfills the abstract idea of what a Substrate header is. + // See here for more info: + // https://crates.parity.io/sp_runtime/traits/trait.Header.html + type Header: Parameter + + HeaderT + + HeaderIdProvider + + MaybeSerializeDeserialize; + + /// The user account identifier type for the runtime. + type AccountId: Parameter + + Member + + MaybeSerializeDeserialize + + Debug + + MaybeDisplay + + Ord + + MaxEncodedLen; + /// Balance of an account in native tokens. + /// + /// The chain may support multiple tokens, but this particular type is for token that is used + /// to pay for transaction dispatch, to reward different relayers (headers, messages), etc. + type Balance: AtLeast32BitUnsigned + + FixedPointOperand + + Parameter + + Member + + MaybeSerializeDeserialize + + Clone + + Copy + + Bounded + + CheckedSub + + PartialOrd + + SaturatingAdd + + Zero + + TryFrom + + MaxEncodedLen; + /// Index of a transaction used by the chain. + type Index: Parameter + + Member + + MaybeSerialize + + Debug + + Default + + MaybeDisplay + + MaybeSerializeDeserialize + + AtLeast32Bit + + Copy + + MaxEncodedLen; + /// Signature type, used on this chain. + type Signature: Parameter + Verify; + + /// Get the maximum size (in bytes) of a Normal extrinsic at this chain. + fn max_extrinsic_size() -> u32; + /// Get the maximum weight (compute time) that a Normal extrinsic at this chain can use. + fn max_extrinsic_weight() -> Weight; +} + +/// A trait that provides the type of the underlying chain. +pub trait UnderlyingChainProvider { + /// Underlying chain type. + type Chain: Chain; +} + +impl Chain for T +where + T: Send + Sync + 'static + UnderlyingChainProvider, +{ + type BlockNumber = ::BlockNumber; + type Hash = ::Hash; + type Hasher = ::Hasher; + type Header = ::Header; + type AccountId = ::AccountId; + type Balance = ::Balance; + type Index = ::Index; + type Signature = ::Signature; + + fn max_extrinsic_size() -> u32 { + ::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + ::max_extrinsic_weight() + } +} + +/// Minimal parachain representation that may be used from no_std environment. +pub trait Parachain: Chain { + /// Parachain identifier. + const PARACHAIN_ID: u32; +} + +impl Parachain for T +where + T: Chain + UnderlyingChainProvider, + ::Chain: Parachain, +{ + const PARACHAIN_ID: u32 = <::Chain as Parachain>::PARACHAIN_ID; +} + +/// Underlying chain type. +pub type UnderlyingChainOf = ::Chain; + +/// Block number used by the chain. +pub type BlockNumberOf = ::BlockNumber; + +/// Hash type used by the chain. +pub type HashOf = ::Hash; + +/// Hasher type used by the chain. +pub type HasherOf = ::Hasher; + +/// Header type used by the chain. +pub type HeaderOf = ::Header; + +/// Account id type used by the chain. +pub type AccountIdOf = ::AccountId; + +/// Balance type used by the chain. +pub type BalanceOf = ::Balance; + +/// Transaction index type used by the chain. +pub type IndexOf = ::Index; + +/// Signature type used by the chain. +pub type SignatureOf = ::Signature; + +/// Account public type used by the chain. +pub type AccountPublicOf = as Verify>::Signer; + +/// Transaction era used by the chain. +pub type TransactionEraOf = crate::TransactionEra, HashOf>; + +/// Convenience macro that declares bridge finality runtime apis and related constants for a chain. +/// This includes: +/// - chain-specific bridge runtime APIs: +/// - `FinalityApi` +/// - constants that are stringified names of runtime API methods: +/// - `BEST_FINALIZED__HEADER_METHOD` +/// The name of the chain has to be specified in snake case (e.g. `rialto_parachain`). +#[macro_export] +macro_rules! decl_bridge_finality_runtime_apis { + ($chain: ident) => { + bp_runtime::paste::item! { + mod [<$chain _finality_api>] { + use super::*; + + /// Name of the `FinalityApi::best_finalized` runtime method. + pub const []: &str = + stringify!([<$chain:camel FinalityApi_best_finalized>]); + + sp_api::decl_runtime_apis! { + /// API for querying information about the finalized chain headers. + /// + /// This API is implemented by runtimes that are receiving messages from this chain, not by this + /// chain's runtime itself. + pub trait [<$chain:camel FinalityApi>] { + /// Returns number and hash of the best finalized header known to the bridge module. + fn best_finalized() -> Option>; + } + } + } + + pub use [<$chain _finality_api>]::*; + } + }; +} + +/// Convenience macro that declares bridge messages runtime apis and related constants for a chain. +/// This includes: +/// - chain-specific bridge runtime APIs: +/// - `ToOutboundLaneApi` +/// - `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`). +#[macro_export] +macro_rules! decl_bridge_messages_runtime_apis { + ($chain: ident) => { + bp_runtime::paste::item! { + mod [<$chain _messages_api>] { + use super::*; + + /// Name of the `ToOutboundLaneApi::message_details` runtime method. + pub const []: &str = + stringify!([]); + + /// Name of the `FromInboundLaneApi::message_details` runtime method. + pub const []: &str = + stringify!([]); + + sp_api::decl_runtime_apis! { + /// Outbound message lane API for messages that are sent to this chain. + /// + /// This API is implemented by runtimes that are receiving messages from this chain, not by this + /// chain's runtime itself. + pub trait [] { + /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all + /// messages in given inclusive range. + /// + /// 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; + } + + /// Inbound message lane API for messages sent by this chain. + /// + /// This API is implemented by runtimes that are receiving messages from this chain, not by this + /// chain's runtime itself. + /// + /// Entries of the resulting vector are matching entries of the `messages` vector. Entries of the + /// `messages` vector may (and need to) be read using `ToOutboundLaneApi::message_details`. + pub trait [] { + /// Return details of given inbound messages. + fn message_details( + lane: LaneId, + messages: Vec<(MessagePayload, OutboundMessageDetails)>, + ) -> Vec; + } + } + } + + pub use [<$chain _messages_api>]::*; + } + }; +} + +/// 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`). +#[macro_export] +macro_rules! decl_bridge_runtime_apis { + ($chain: ident) => { + bp_runtime::decl_bridge_finality_runtime_apis!($chain); + bp_runtime::decl_bridge_messages_runtime_apis!($chain); + }; +} diff --git a/primitives/runtime/src/extensions.rs b/primitives/runtime/src/extensions.rs new file mode 100644 index 00000000000..96ee9d1e6ec --- /dev/null +++ b/primitives/runtime/src/extensions.rs @@ -0,0 +1,144 @@ +// Copyright 2019-2021 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 . + +//! Primitives that may be used for creating signed extensions for indirect runtimes. + +use codec::{Compact, Decode, Encode}; +use impl_trait_for_tuples::impl_for_tuples; +use scale_info::{StaticTypeInfo, TypeInfo}; +use sp_runtime::{ + traits::{DispatchInfoOf, SignedExtension}, + transaction_validity::TransactionValidityError, +}; +use sp_std::{fmt::Debug, marker::PhantomData}; + +/// Trait that describes some properties of a `SignedExtension` that are needed in order to send a +/// transaction to the chain. +pub trait SignedExtensionSchema: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo { + /// A type of the data encoded as part of the transaction. + type Payload: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; + /// Parameters which are part of the payload used to produce transaction signature, + /// but don't end up in the transaction itself (i.e. inherent part of the runtime). + type AdditionalSigned: Encode + Debug + Eq + Clone + StaticTypeInfo; +} + +// An implementation of `SignedExtensionSchema` using generic params. +#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)] +pub struct GenericSignedExtensionSchema(PhantomData<(P, S)>); + +impl SignedExtensionSchema for GenericSignedExtensionSchema +where + P: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, + S: Encode + Debug + Eq + Clone + StaticTypeInfo, +{ + type Payload = P; + type AdditionalSigned = S; +} + +/// The `SignedExtensionSchema` for `frame_system::CheckNonZeroSender`. +pub type CheckNonZeroSender = GenericSignedExtensionSchema<(), ()>; + +/// The `SignedExtensionSchema` for `frame_system::CheckSpecVersion`. +pub type CheckSpecVersion = GenericSignedExtensionSchema<(), u32>; + +/// The `SignedExtensionSchema` for `frame_system::CheckTxVersion`. +pub type CheckTxVersion = GenericSignedExtensionSchema<(), u32>; + +/// The `SignedExtensionSchema` for `frame_system::CheckGenesis`. +pub type CheckGenesis = GenericSignedExtensionSchema<(), Hash>; + +/// The `SignedExtensionSchema` for `frame_system::CheckEra`. +pub type CheckEra = GenericSignedExtensionSchema; + +/// The `SignedExtensionSchema` for `frame_system::CheckNonce`. +pub type CheckNonce = GenericSignedExtensionSchema, ()>; + +/// The `SignedExtensionSchema` for `frame_system::CheckWeight`. +pub type CheckWeight = GenericSignedExtensionSchema<(), ()>; + +/// The `SignedExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. +pub type ChargeTransactionPayment = GenericSignedExtensionSchema, ()>; + +/// The `SignedExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. +pub type BridgeRejectObsoleteHeadersAndMessages = GenericSignedExtensionSchema<(), ()>; + +/// The `SignedExtensionSchema` for `RefundBridgedParachainMessages`. +/// This schema is dedicated for `RefundBridgedParachainMessages` signed extension as +/// wildcard/placeholder, which relies on the scale encoding for `()` or `((), ())`, or `((), (), +/// ())` is the same. So runtime can contains any kind of tuple: +/// `(BridgeRefundBridgeHubRococoMessages)` +/// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWococoMessages)` +/// `(BridgeRefundParachainMessages1, ..., BridgeRefundParachainMessagesN)` +pub type RefundBridgedParachainMessagesSchema = GenericSignedExtensionSchema<(), ()>; + +#[impl_for_tuples(1, 12)] +impl SignedExtensionSchema for Tuple { + for_tuples!( type Payload = ( #( Tuple::Payload ),* ); ); + for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); ); +} + +/// A simplified version of signed extensions meant for producing signed transactions +/// and signed payloads in the client code. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub struct GenericSignedExtension { + pub payload: S::Payload, + #[codec(skip)] + // It may be set to `None` if extensions are decoded. We are never reconstructing transactions + // (and it makes no sense to do that) => decoded version of `SignedExtensions` is only used to + // read fields of the `payload`. And when resigning transaction, we're reconstructing + // `SignedExtensions` from the scratch. + additional_signed: Option, +} + +impl GenericSignedExtension { + pub fn new(payload: S::Payload, additional_signed: Option) -> Self { + Self { payload, additional_signed } + } +} + +impl SignedExtension for GenericSignedExtension +where + S: SignedExtensionSchema, + S::Payload: Send + Sync, + S::AdditionalSigned: Send + Sync, +{ + const IDENTIFIER: &'static str = "Not needed."; + type AccountId = (); + type Call = (); + type AdditionalSigned = S::AdditionalSigned; + type Pre = (); + + fn additional_signed(&self) -> Result { + // we shall not ever see this error in relay, because we are never signing decoded + // transactions. Instead we're constructing and signing new transactions. So the error code + // is kinda random here + self.additional_signed.clone().ok_or( + frame_support::unsigned::TransactionValidityError::Unknown( + frame_support::unsigned::UnknownTransaction::Custom(0xFF), + ), + ) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } +} diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs new file mode 100644 index 00000000000..df77745bc02 --- /dev/null +++ b/primitives/runtime/src/lib.rs @@ -0,0 +1,573 @@ +// Copyright 2019-2021 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 . + +//! Primitives that may be used at (bridges) runtime level. + +#![cfg_attr(not(feature = "std"), no_std)] + +use codec::{Decode, Encode, FullCodec, MaxEncodedLen}; +use frame_support::{ + log, pallet_prelude::DispatchResult, weights::Weight, PalletError, RuntimeDebug, StorageHasher, + StorageValue, +}; +use frame_system::RawOrigin; +use scale_info::TypeInfo; +use sp_core::storage::StorageKey; +use sp_runtime::traits::{BadOrigin, Header as HeaderT, UniqueSaturatedInto}; +use sp_std::{convert::TryFrom, fmt::Debug, ops::RangeInclusive, vec, vec::Vec}; + +pub use chain::{ + AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf, + HasherOf, HeaderOf, IndexOf, Parachain, SignatureOf, TransactionEraOf, UnderlyingChainOf, + UnderlyingChainProvider, +}; +pub use frame_support::storage::storage_prefix as storage_value_final_key; +use num_traits::{CheckedAdd, CheckedSub, One}; +pub use storage_proof::{ + record_all_keys as record_all_trie_keys, Error as StorageProofError, + ProofSize as StorageProofSize, RawStorageProof, StorageProofChecker, +}; +pub use storage_types::BoundedStorageValue; + +#[cfg(feature = "std")] +pub use storage_proof::craft_valid_storage_proof; + +pub mod extensions; +pub mod messages; + +mod chain; +mod storage_proof; +mod storage_types; + +// Re-export macro to aviod include paste dependency everywhere +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"; + +/// Kusama chain id. +pub const KUSAMA_CHAIN_ID: ChainId = *b"ksma"; + +/// Westend chain id. +pub const WESTEND_CHAIN_ID: ChainId = *b"wend"; + +/// Westend chain id. +pub const WESTMINT_CHAIN_ID: ChainId = *b"wmnt"; + +/// 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"; + +/// BridgeHubKusama chain id. +pub const BRIDGE_HUB_KUSAMA_CHAIN_ID: ChainId = *b"bhks"; + +/// BridgeHubPolkadot chain id. +pub const BRIDGE_HUB_POLKADOT_CHAIN_ID: ChainId = *b"bhwo"; + +/// Generic header Id. +#[derive( + RuntimeDebug, + Default, + Clone, + Encode, + Decode, + Copy, + Eq, + Hash, + MaxEncodedLen, + PartialEq, + PartialOrd, + Ord, + TypeInfo, +)] +pub struct HeaderId(pub Number, pub Hash); + +impl HeaderId { + /// Return header number. + pub fn number(&self) -> Number { + self.0 + } + + /// Return header hash. + pub fn hash(&self) -> Hash { + self.1 + } +} + +/// Header id used by the chain. +pub type HeaderIdOf = HeaderId, BlockNumberOf>; + +/// Generic header id provider. +pub trait HeaderIdProvider { + // Get the header id. + fn id(&self) -> HeaderId; + + // Get the header id for the parent block. + fn parent_id(&self) -> Option>; +} + +impl HeaderIdProvider
for Header { + fn id(&self) -> HeaderId { + HeaderId(*self.number(), self.hash()) + } + + fn parent_id(&self) -> Option> { + self.number() + .checked_sub(&One::one()) + .map(|parent_number| HeaderId(parent_number, *self.parent_hash())) + } +} + +/// Unique identifier of the chain. +/// +/// In addition to its main function (identifying the chain), this type may also be used to +/// identify module instance. We have a bunch of pallets that may be used in different bridges. E.g. +/// messages pallet may be deployed twice in the same runtime to bridge ThisChain with Chain1 and +/// Chain2. Sometimes we need to be able to identify deployed instance dynamically. This type may be +/// used for that. +pub type ChainId = [u8; 4]; + +/// Anything that has size. +pub trait Size { + /// Return size of this object (in bytes). + fn size(&self) -> u32; +} + +impl Size for () { + fn size(&self) -> u32 { + 0 + } +} + +impl Size for Vec { + fn size(&self) -> u32 { + self.len() as _ + } +} + +/// Pre-computed size. +pub struct PreComputedSize(pub usize); + +impl Size for PreComputedSize { + fn size(&self) -> u32 { + u32::try_from(self.0).unwrap_or(u32::MAX) + } +} + +/// Era of specific transaction. +#[derive(RuntimeDebug, Clone, Copy, PartialEq)] +pub enum TransactionEra { + /// Transaction is immortal. + Immortal, + /// Transaction is valid for a given number of blocks, starting from given block. + Mortal(HeaderId, u32), +} + +impl, BlockHash: Copy> + TransactionEra +{ + /// Prepare transaction era, based on mortality period and current best block number. + pub fn new( + best_block_id: HeaderId, + mortality_period: Option, + ) -> Self { + mortality_period + .map(|mortality_period| TransactionEra::Mortal(best_block_id, mortality_period)) + .unwrap_or(TransactionEra::Immortal) + } + + /// Create new immortal transaction era. + pub fn immortal() -> Self { + TransactionEra::Immortal + } + + /// Returns mortality period if transaction is mortal. + pub fn mortality_period(&self) -> Option { + match *self { + TransactionEra::Immortal => None, + TransactionEra::Mortal(_, period) => Some(period), + } + } + + /// Returns era that is used by FRAME-based runtimes. + pub fn frame_era(&self) -> sp_runtime::generic::Era { + match *self { + TransactionEra::Immortal => sp_runtime::generic::Era::immortal(), + // `unique_saturated_into` is fine here - mortality `u64::MAX` is not something we + // expect to see on any chain + TransactionEra::Mortal(header_id, period) => + sp_runtime::generic::Era::mortal(period as _, header_id.0.unique_saturated_into()), + } + } + + /// Returns header hash that needs to be included in the signature payload. + pub fn signed_payload(&self, genesis_hash: BlockHash) -> BlockHash { + match *self { + TransactionEra::Immortal => genesis_hash, + TransactionEra::Mortal(header_id, _) => header_id.1, + } + } +} + +/// This is a copy of the +/// `frame_support::storage::generator::StorageMap::storage_map_final_key` for maps based +/// on selected hasher. +/// +/// We're using it because to call `storage_map_final_key` directly, we need access to the runtime +/// and pallet instance, which (sometimes) is impossible. +pub fn storage_map_final_key( + pallet_prefix: &str, + map_name: &str, + key: &[u8], +) -> StorageKey { + let key_hashed = H::hash(key); + let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes()); + let storage_prefix_hashed = frame_support::Twox128::hash(map_name.as_bytes()); + + let mut final_key = Vec::with_capacity( + pallet_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len(), + ); + + final_key.extend_from_slice(&pallet_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key_hashed.as_ref()); + + 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`. +pub fn storage_value_key(pallet_prefix: &str, value_name: &str) -> StorageKey { + let pallet_hash = sp_io::hashing::twox_128(pallet_prefix.as_bytes()); + let storage_hash = sp_io::hashing::twox_128(value_name.as_bytes()); + + let mut final_key = vec![0u8; 32]; + final_key[..16].copy_from_slice(&pallet_hash); + final_key[16..].copy_from_slice(&storage_hash); + + StorageKey(final_key) +} + +/// Can be use to access the runtime storage key of a `StorageMap`. +pub trait StorageMapKeyProvider { + /// The name of the variable that holds the `StorageMap`. + const MAP_NAME: &'static str; + + /// The same as `StorageMap::Hasher1`. + type Hasher: StorageHasher; + /// The same as `StorageMap::Key1`. + type Key: FullCodec; + /// The same as `StorageMap::Value`. + type Value: FullCodec; + + /// This is a copy of the + /// `frame_support::storage::generator::StorageMap::storage_map_final_key`. + /// + /// We're using it because to call `storage_map_final_key` directly, we need access + /// to the runtime and pallet instance, which (sometimes) is impossible. + fn final_key(pallet_prefix: &str, key: &Self::Key) -> StorageKey { + storage_map_final_key::(pallet_prefix, Self::MAP_NAME, &key.encode()) + } +} + +/// Can be use to access the runtime storage key of a `StorageDoubleMap`. +pub trait StorageDoubleMapKeyProvider { + /// The name of the variable that holds the `StorageDoubleMap`. + const MAP_NAME: &'static str; + + /// The same as `StorageDoubleMap::Hasher1`. + type Hasher1: StorageHasher; + /// The same as `StorageDoubleMap::Key1`. + type Key1: FullCodec; + /// The same as `StorageDoubleMap::Hasher2`. + type Hasher2: StorageHasher; + /// The same as `StorageDoubleMap::Key2`. + type Key2: FullCodec; + /// The same as `StorageDoubleMap::Value`. + type Value: FullCodec; + + /// This is a copy of the + /// `frame_support::storage::generator::StorageDoubleMap::storage_double_map_final_key`. + /// + /// We're using it because to call `storage_double_map_final_key` directly, we need access + /// to the runtime and pallet instance, which (sometimes) is impossible. + fn final_key(pallet_prefix: &str, key1: &Self::Key1, key2: &Self::Key2) -> StorageKey { + let key1_hashed = Self::Hasher1::hash(&key1.encode()); + let key2_hashed = Self::Hasher2::hash(&key2.encode()); + let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes()); + let storage_prefix_hashed = frame_support::Twox128::hash(Self::MAP_NAME.as_bytes()); + + let mut final_key = Vec::with_capacity( + pallet_prefix_hashed.len() + + storage_prefix_hashed.len() + + key1_hashed.as_ref().len() + + key2_hashed.as_ref().len(), + ); + + final_key.extend_from_slice(&pallet_prefix_hashed[..]); + final_key.extend_from_slice(&storage_prefix_hashed[..]); + final_key.extend_from_slice(key1_hashed.as_ref()); + final_key.extend_from_slice(key2_hashed.as_ref()); + + StorageKey(final_key) + } +} + +/// Error generated by the `OwnedBridgeModule` trait. +#[derive(Encode, Decode, TypeInfo, PalletError)] +pub enum OwnedBridgeModuleError { + /// All pallet operations are halted. + Halted, +} + +/// Operating mode for a bridge module. +pub trait OperatingMode: Send + Copy + Debug + FullCodec { + // Returns true if the bridge module is halted. + fn is_halted(&self) -> bool; +} + +/// Basic operating modes for a bridges module (Normal/Halted). +#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +pub enum BasicOperatingMode { + /// Normal mode, when all operations are allowed. + Normal, + /// The pallet is halted. All operations (except operating mode change) are prohibited. + Halted, +} + +impl Default for BasicOperatingMode { + fn default() -> Self { + Self::Normal + } +} + +impl OperatingMode for BasicOperatingMode { + fn is_halted(&self) -> bool { + *self == BasicOperatingMode::Halted + } +} + +/// Bridge module that has owner and operating mode +pub trait OwnedBridgeModule { + /// The target that will be used when publishing logs related to this module. + const LOG_TARGET: &'static str; + + type OwnerStorage: StorageValue>; + type OperatingMode: OperatingMode; + type OperatingModeStorage: StorageValue; + + /// Check if the module is halted. + fn is_halted() -> bool { + Self::OperatingModeStorage::get().is_halted() + } + + /// Ensure that the origin is either root, or `PalletOwner`. + fn ensure_owner_or_root(origin: T::RuntimeOrigin) -> Result<(), BadOrigin> { + match origin.into() { + Ok(RawOrigin::Root) => Ok(()), + Ok(RawOrigin::Signed(ref signer)) + if Self::OwnerStorage::get().as_ref() == Some(signer) => + Ok(()), + _ => Err(BadOrigin), + } + } + + /// Ensure that the module is not halted. + fn ensure_not_halted() -> Result<(), OwnedBridgeModuleError> { + match Self::is_halted() { + true => Err(OwnedBridgeModuleError::Halted), + false => Ok(()), + } + } + + /// Change the owner of the module. + fn set_owner(origin: T::RuntimeOrigin, maybe_owner: Option) -> DispatchResult { + Self::ensure_owner_or_root(origin)?; + match maybe_owner { + Some(owner) => { + Self::OwnerStorage::put(&owner); + log::info!(target: Self::LOG_TARGET, "Setting pallet Owner to: {:?}", owner); + }, + None => { + Self::OwnerStorage::kill(); + log::info!(target: Self::LOG_TARGET, "Removed Owner of pallet."); + }, + } + + Ok(()) + } + + /// Halt or resume all/some module operations. + fn set_operating_mode( + origin: T::RuntimeOrigin, + operating_mode: Self::OperatingMode, + ) -> DispatchResult { + Self::ensure_owner_or_root(origin)?; + Self::OperatingModeStorage::put(operating_mode); + log::info!(target: Self::LOG_TARGET, "Setting operating mode to {:?}.", operating_mode); + Ok(()) + } +} + +/// All extra operations with weights that we need in bridges. +pub trait WeightExtraOps { + /// Checked division of individual components of two weights. + /// + /// Divides components and returns minimal division result. Returns `None` if one + /// of `other` weight components is zero. + fn min_components_checked_div(&self, other: Weight) -> Option; +} + +impl WeightExtraOps for Weight { + fn min_components_checked_div(&self, other: Weight) -> Option { + Some(sp_std::cmp::min( + self.ref_time().checked_div(other.ref_time())?, + self.proof_size().checked_div(other.proof_size())?, + )) + } +} + +/// Trait that provides a static `str`. +pub trait StaticStrProvider { + const STR: &'static str; +} + +#[macro_export] +macro_rules! generate_static_str_provider { + ($str:expr) => { + $crate::paste::item! { + pub struct []; + + impl $crate::StaticStrProvider for [] { + const STR: &'static str = stringify!($str); + } + } + }; +} + +#[derive(Encode, Decode, Clone, Eq, PartialEq, PalletError, TypeInfo)] +#[scale_info(skip_type_params(T))] +pub struct StrippableError { + _phantom_data: sp_std::marker::PhantomData, + #[codec(skip)] + #[cfg(feature = "std")] + message: String, +} + +impl From for StrippableError { + fn from(_err: T) -> Self { + Self { + _phantom_data: Default::default(), + #[cfg(feature = "std")] + message: format!("{:?}", _err), + } + } +} + +impl Debug for StrippableError { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + f.write_str(&self.message) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { + f.write_str("Stripped error") + } +} + +/// A trait defining helper methods for `RangeInclusive` (start..=end) +pub trait RangeInclusiveExt { + /// Computes the length of the `RangeInclusive`, checking for underflow and overflow. + fn checked_len(&self) -> Option; +} + +impl RangeInclusiveExt for RangeInclusive +where + Idx: CheckedSub + CheckedAdd + One, +{ + fn checked_len(&self) -> Option { + self.end() + .checked_sub(self.start()) + .and_then(|len| len.checked_add(&Idx::one())) + } +} + +#[cfg(test)] +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!( + storage_value_key("PalletTransactionPayment", "NextFeeMultiplier"), + StorageKey( + hex_literal::hex!( + "f0e954dfcca51a255ab12c60c789256a3f2edf3bdf381debe331ab7446addfdc" + ) + .to_vec() + ), + ); + } + + #[test] + fn generate_static_str_provider_works() { + generate_static_str_provider!(Test); + assert_eq!(StrTest::STR, "Test"); + } +} diff --git a/primitives/runtime/src/messages.rs b/primitives/runtime/src/messages.rs new file mode 100644 index 00000000000..9f7c8ab5ca4 --- /dev/null +++ b/primitives/runtime/src/messages.rs @@ -0,0 +1,35 @@ +// Copyright 2019-2021 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 . + +//! Primitives that may be used by different message delivery and dispatch mechanisms. + +use codec::{Decode, Encode}; +use frame_support::{weights::Weight, RuntimeDebug}; +use scale_info::TypeInfo; + +/// Message dispatch result. +#[derive(Encode, Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)] +pub struct MessageDispatchResult { + /// Unspent dispatch weight. This weight that will be deducted from total delivery transaction + /// weight, thus reducing the transaction cost. This shall not be zero in (at least) two cases: + /// + /// 1) if message has been dispatched successfully, but post-dispatch weight is less than + /// the weight, declared by the message sender; + /// 2) if message has not been dispatched at all. + pub unspent_weight: Weight, + /// Fine-grained result of single message dispatch (for better diagnostic purposes) + pub dispatch_level_result: DispatchLevelResult, +} diff --git a/primitives/runtime/src/storage_proof.rs b/primitives/runtime/src/storage_proof.rs new file mode 100644 index 00000000000..09641376666 --- /dev/null +++ b/primitives/runtime/src/storage_proof.rs @@ -0,0 +1,272 @@ +// Copyright 2019-2021 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 . + +//! Logic for checking Substrate storage proofs. + +use crate::StrippableError; +use codec::{Decode, Encode}; +use frame_support::PalletError; +use hash_db::{HashDB, Hasher, EMPTY_PREFIX}; +use scale_info::TypeInfo; +use sp_std::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec}; +use sp_trie::{ + read_trie_value, LayoutV1, MemoryDB, Recorder, StorageProof, Trie, TrieConfiguration, + TrieDBBuilder, TrieError, TrieHash, +}; + +/// Raw storage proof type (just raw trie nodes). +pub type RawStorageProof = Vec>; + +/// Storage proof size requirements. +/// +/// This is currently used by benchmarks when generating storage proofs. +#[derive(Clone, Copy, Debug)] +pub enum ProofSize { + /// The proof is expected to be minimal. If value size may be changed, then it is expected to + /// have given size. + Minimal(u32), + /// The proof is expected to have at least given size and grow by increasing value that is + /// stored in the trie. + HasLargeLeaf(u32), +} + +/// This struct is used to read storage values from a subset of a Merklized database. The "proof" +/// is a subset of the nodes in the Merkle structure of the database, so that it provides +/// authentication against a known Merkle root as well as the values in the +/// database themselves. +pub struct StorageProofChecker +where + H: Hasher, +{ + proof_nodes_count: usize, + root: H::Out, + db: MemoryDB, + recorder: Recorder>, +} + +impl StorageProofChecker +where + H: Hasher, +{ + /// Constructs a new storage proof checker. + /// + /// This returns an error if the given proof is invalid with respect to the given root. + pub fn new(root: H::Out, proof: RawStorageProof) -> Result { + // 1. we don't want extra items in the storage proof + // 2. `StorageProof` is storing all trie nodes in the `BTreeSet` + // + // => someone could simply add duplicate items to the proof and we won't be + // able to detect that by just using `StorageProof` + // + // => let's check it when we are converting our "raw proof" into `StorageProof` + let proof_nodes_count = proof.len(); + let proof = StorageProof::new(proof); + if proof_nodes_count != proof.iter_nodes().count() { + return Err(Error::DuplicateNodesInProof) + } + + let db = proof.into_memory_db(); + if !db.contains(&root, EMPTY_PREFIX) { + return Err(Error::StorageRootMismatch) + } + + let recorder = Recorder::default(); + let checker = StorageProofChecker { proof_nodes_count, root, db, recorder }; + Ok(checker) + } + + /// Returns error if the proof has some nodes that are left intact by previous `read_value` + /// calls. + pub fn ensure_no_unused_nodes(mut self) -> Result<(), Error> { + let visited_nodes = self + .recorder + .drain() + .into_iter() + .map(|record| record.data) + .collect::>(); + let visited_nodes_count = visited_nodes.len(); + if self.proof_nodes_count == visited_nodes_count { + Ok(()) + } else { + Err(Error::UnusedNodesInTheProof) + } + } + + /// Reads a value from the available subset of storage. If the value cannot be read due to an + /// incomplete or otherwise invalid proof, this function returns an error. + pub fn read_value(&mut self, key: &[u8]) -> Result>, Error> { + // LayoutV1 or LayoutV0 is identical for proof that only read values. + read_trie_value::, _>(&self.db, &self.root, key, Some(&mut self.recorder), None) + .map_err(|_| Error::StorageValueUnavailable) + } + + /// Reads and decodes a value from the available subset of storage. If the value cannot be read + /// due to an incomplete or otherwise invalid proof, this function returns an error. If value is + /// read, but decoding fails, this function returns an error. + pub fn read_and_decode_value(&mut self, key: &[u8]) -> Result, Error> { + self.read_value(key).and_then(|v| { + v.map(|v| T::decode(&mut &v[..]).map_err(|e| Error::StorageValueDecodeFailed(e.into()))) + .transpose() + }) + } + + /// Reads and decodes a value from the available subset of storage. If the value cannot be read + /// due to an incomplete or otherwise invalid proof, or if the value is `None`, this function + /// returns an error. If value is read, but decoding fails, this function returns an error. + pub fn read_and_decode_mandatory_value(&mut self, key: &[u8]) -> Result { + self.read_and_decode_value(key)?.ok_or(Error::StorageValueEmpty) + } + + /// Reads and decodes a value from the available subset of storage. If the value cannot be read + /// due to an incomplete or otherwise invalid proof, this function returns `Ok(None)`. + /// If value is read, but decoding fails, this function returns an error. + pub fn read_and_decode_opt_value(&mut self, key: &[u8]) -> Result, Error> { + match self.read_and_decode_value(key) { + Ok(outbound_lane_data) => Ok(outbound_lane_data), + Err(Error::StorageValueUnavailable) => Ok(None), + Err(e) => Err(e), + } + } +} + +/// Storage proof related errors. +#[derive(Encode, Decode, Clone, Eq, PartialEq, PalletError, Debug, TypeInfo)] +pub enum Error { + /// Duplicate trie nodes are found in the proof. + DuplicateNodesInProof, + /// Unused trie nodes are found in the proof. + UnusedNodesInTheProof, + /// Expected storage root is missing from the proof. + StorageRootMismatch, + /// Unable to reach expected storage value using provided trie nodes. + StorageValueUnavailable, + /// The storage value is `None`. + StorageValueEmpty, + /// Failed to decode storage value. + StorageValueDecodeFailed(StrippableError), +} + +/// Return valid storage proof and state root. +/// +/// NOTE: This should only be used for **testing**. +#[cfg(feature = "std")] +pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { + use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; + + let state_version = sp_runtime::StateVersion::default(); + + // construct storage proof + let backend = >::from(( + vec![ + (None, vec![(b"key1".to_vec(), Some(b"value1".to_vec()))]), + (None, vec![(b"key2".to_vec(), Some(b"value2".to_vec()))]), + (None, vec![(b"key3".to_vec(), Some(b"value3".to_vec()))]), + (None, vec![(b"key4".to_vec(), Some((42u64, 42u32, 42u16, 42u8).encode()))]), + // Value is too big to fit in a branch node + (None, vec![(b"key11".to_vec(), Some(vec![0u8; 32]))]), + ], + state_version, + )); + let root = backend.storage_root(std::iter::empty(), state_version).0; + let proof = + prove_read(backend, &[&b"key1"[..], &b"key2"[..], &b"key4"[..], &b"key22"[..]]).unwrap(); + + (root, proof.into_nodes().into_iter().collect()) +} + +/// Record all keys for a given root. +pub fn record_all_keys( + db: &DB, + root: &TrieHash, +) -> Result>> +where + DB: hash_db::HashDBRef, +{ + let mut recorder = Recorder::::new(); + let trie = TrieDBBuilder::::new(db, root).with_recorder(&mut recorder).build(); + for x in trie.iter()? { + let (key, _) = x?; + trie.get(&key)?; + } + + // recorder may record the same trie node multiple times and we don't want duplicate nodes + // in our proofs => let's deduplicate it by collecting to the BTreeSet first + Ok(recorder + .drain() + .into_iter() + .map(|n| n.data.to_vec()) + .collect::>() + .into_iter() + .collect()) +} + +#[cfg(test)] +pub mod tests { + use super::*; + use codec::Encode; + + #[test] + fn storage_proof_check() { + let (root, proof) = craft_valid_storage_proof(); + + // check proof in runtime + let mut checker = + >::new(root, proof.clone()).unwrap(); + assert_eq!(checker.read_value(b"key1"), Ok(Some(b"value1".to_vec()))); + assert_eq!(checker.read_value(b"key2"), Ok(Some(b"value2".to_vec()))); + assert_eq!(checker.read_value(b"key4"), Ok(Some((42u64, 42u32, 42u16, 42u8).encode()))); + assert_eq!(checker.read_value(b"key11111"), Err(Error::StorageValueUnavailable)); + assert_eq!(checker.read_value(b"key22"), Ok(None)); + assert_eq!(checker.read_and_decode_value(b"key4"), Ok(Some((42u64, 42u32, 42u16, 42u8))),); + assert!(matches!( + checker.read_and_decode_value::<[u8; 64]>(b"key4"), + Err(Error::StorageValueDecodeFailed(_)), + )); + + // checking proof against invalid commitment fails + assert_eq!( + >::new(sp_core::H256::random(), proof).err(), + Some(Error::StorageRootMismatch) + ); + } + + #[test] + fn proof_with_duplicate_items_is_rejected() { + let (root, mut proof) = craft_valid_storage_proof(); + proof.push(proof.first().unwrap().clone()); + + assert_eq!( + StorageProofChecker::::new(root, proof).map(drop), + Err(Error::DuplicateNodesInProof), + ); + } + + #[test] + fn proof_with_unused_items_is_rejected() { + let (root, proof) = craft_valid_storage_proof(); + + let mut checker = + StorageProofChecker::::new(root, proof.clone()).unwrap(); + checker.read_value(b"key1").unwrap(); + checker.read_value(b"key2").unwrap(); + checker.read_value(b"key4").unwrap(); + checker.read_value(b"key22").unwrap(); + assert_eq!(checker.ensure_no_unused_nodes(), Ok(())); + + let checker = StorageProofChecker::::new(root, proof).unwrap(); + assert_eq!(checker.ensure_no_unused_nodes(), Err(Error::UnusedNodesInTheProof)); + } +} diff --git a/primitives/runtime/src/storage_types.rs b/primitives/runtime/src/storage_types.rs new file mode 100644 index 00000000000..b37f779d00b --- /dev/null +++ b/primitives/runtime/src/storage_types.rs @@ -0,0 +1,90 @@ +// Copyright 2022 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 . + +//! Wrapper for a runtime storage value that checks if value exceeds given maximum +//! during conversion. + +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{traits::Get, RuntimeDebug}; +use scale_info::{Type, TypeInfo}; +use sp_std::{marker::PhantomData, ops::Deref}; + +/// Error that is returned when the value size exceeds maximal configured size. +#[derive(RuntimeDebug)] +pub struct MaximalSizeExceededError { + /// Size of the value. + pub value_size: usize, + /// Maximal configured size. + pub maximal_size: usize, +} + +/// A bounded runtime storage value. +#[derive(Clone, Decode, Encode, Eq, PartialEq)] +pub struct BoundedStorageValue { + value: V, + _phantom: PhantomData, +} + +impl sp_std::fmt::Debug for BoundedStorageValue { + fn fmt(&self, fmt: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + self.value.fmt(fmt) + } +} + +impl, V: Encode> BoundedStorageValue { + /// Construct `BoundedStorageValue` from the underlying `value` with all required checks. + /// + /// Returns error if value size exceeds given bounds. + pub fn try_from_inner(value: V) -> Result { + // this conversion is heavy (since we do encoding here), so we may want to optimize it later + // (e.g. by introducing custom Encode implementation, and turning `BoundedStorageValue` into + // `enum BoundedStorageValue { Decoded(V), Encoded(Vec) }`) + let value_size = value.encoded_size(); + let maximal_size = B::get() as usize; + if value_size > maximal_size { + Err(MaximalSizeExceededError { value_size, maximal_size }) + } else { + Ok(BoundedStorageValue { value, _phantom: Default::default() }) + } + } + + /// Convert into the inner type + pub fn into_inner(self) -> V { + self.value + } +} + +impl Deref for BoundedStorageValue { + type Target = V; + + fn deref(&self) -> &Self::Target { + &self.value + } +} + +impl TypeInfo for BoundedStorageValue { + type Identity = Self; + + fn type_info() -> Type { + V::type_info() + } +} + +impl, V: Encode> MaxEncodedLen for BoundedStorageValue { + fn max_encoded_len() -> usize { + B::get() as usize + } +} diff --git a/primitives/test-utils/Cargo.toml b/primitives/test-utils/Cargo.toml new file mode 100644 index 00000000000..5ed835857d1 --- /dev/null +++ b/primitives/test-utils/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "bp-test-utils" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +bp-header-chain = { path = "../header-chain", 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"] } +finality-grandpa = { version = "0.16.2", default-features = false } +sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-header-chain/std", + "codec/std", + "ed25519-dalek/std", + "finality-grandpa/std", + "sp-application-crypto/std", + "sp-consensus-grandpa/std", + "sp-runtime/std", + "sp-std/std", +] diff --git a/primitives/test-utils/src/keyring.rs b/primitives/test-utils/src/keyring.rs new file mode 100644 index 00000000000..b1782109668 --- /dev/null +++ b/primitives/test-utils/src/keyring.rs @@ -0,0 +1,94 @@ +// Copyright 2021 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 . + +//! Utilities for working with test accounts. + +use codec::Encode; +use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature}; +use finality_grandpa::voter_set::VoterSet; +use sp_consensus_grandpa::{AuthorityId, AuthorityList, AuthorityWeight}; +use sp_runtime::RuntimeDebug; +use sp_std::prelude::*; + +/// Set of test accounts with friendly names. +pub const ALICE: Account = Account(0); +pub const BOB: Account = Account(1); +pub const CHARLIE: Account = Account(2); +pub const DAVE: Account = Account(3); +pub const EVE: Account = Account(4); +pub const FERDIE: Account = Account(5); + +/// A test account which can be used to sign messages. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Account(pub u16); + +impl Account { + pub fn public(&self) -> PublicKey { + (&self.secret()).into() + } + + pub fn secret(&self) -> SecretKey { + 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.") + } + + pub fn sign(&self, msg: &[u8]) -> Signature { + use ed25519_dalek::Signer; + self.pair().sign(msg) + } +} + +impl From for AuthorityId { + fn from(p: Account) -> Self { + sp_application_crypto::UncheckedFrom::unchecked_from(p.public().to_bytes()) + } +} + +/// Get a valid set of voters for a Grandpa round. +pub fn voter_set() -> VoterSet { + VoterSet::new(authority_list()).unwrap() +} + +/// Convenience function to get a list of Grandpa authorities. +pub fn authority_list() -> AuthorityList { + test_keyring().iter().map(|(id, w)| (AuthorityId::from(*id), *w)).collect() +} + +/// Get the corresponding identities from the keyring for the "standard" authority set. +pub fn test_keyring() -> Vec<(Account, AuthorityWeight)> { + vec![(ALICE, 1), (BOB, 1), (CHARLIE, 1)] +} + +/// Get a list of "unique" accounts. +pub fn accounts(len: u16) -> Vec { + (0..len).map(Account).collect() +} diff --git a/primitives/test-utils/src/lib.rs b/primitives/test-utils/src/lib.rs new file mode 100644 index 00000000000..6bb4adbf450 --- /dev/null +++ b/primitives/test-utils/src/lib.rs @@ -0,0 +1,302 @@ +// Copyright 2021 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 . + +//! Utilities for testing runtime code. + +#![cfg_attr(not(feature = "std"), no_std)] + +use bp_header_chain::justification::{required_justification_precommits, GrandpaJustification}; +use codec::Encode; +use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, AuthorityWeight, SetId}; +use sp_runtime::traits::{Header as HeaderT, One, Zero}; +use sp_std::prelude::*; + +// Re-export all our test account utilities +pub use keyring::*; + +mod keyring; + +pub const TEST_GRANDPA_ROUND: u64 = 1; +pub const TEST_GRANDPA_SET_ID: SetId = 1; + +/// Configuration parameters when generating test GRANDPA justifications. +#[derive(Clone)] +pub struct JustificationGeneratorParams { + /// The header which we want to finalize. + pub header: H, + /// The GRANDPA round number for the current authority set. + pub round: u64, + /// The current authority set ID. + pub set_id: SetId, + /// The current GRANDPA authority set. + /// + /// The size of the set will determine the number of pre-commits in our justification. + pub authorities: Vec<(Account, AuthorityWeight)>, + /// The total number of precommit ancestors in the `votes_ancestries` field our justification. + /// + /// These may be distributed among many forks. + pub ancestors: u32, + /// The number of forks. + /// + /// Useful for creating a "worst-case" scenario in which each authority is on its own fork. + pub forks: u32, +} + +impl Default for JustificationGeneratorParams { + fn default() -> Self { + let required_signatures = required_justification_precommits(test_keyring().len() as _); + Self { + header: test_header(One::one()), + round: TEST_GRANDPA_ROUND, + set_id: TEST_GRANDPA_SET_ID, + authorities: test_keyring().into_iter().take(required_signatures as _).collect(), + ancestors: 2, + forks: 1, + } + } +} + +/// Make a valid GRANDPA justification with sensible defaults +pub fn make_default_justification(header: &H) -> GrandpaJustification { + let params = JustificationGeneratorParams:: { header: header.clone(), ..Default::default() }; + + make_justification_for_header(params) +} + +/// Generate justifications in a way where we are able to tune the number of pre-commits +/// and vote ancestries which are included in the justification. +/// +/// This is useful for benchmarkings where we want to generate valid justifications with +/// a specific number of pre-commits (tuned with the number of "authorities") and/or a specific +/// number of vote ancestries (tuned with the "votes" parameter). +/// +/// Note: This needs at least three authorities or else the verifier will complain about +/// being given an invalid commit. +pub fn make_justification_for_header( + params: JustificationGeneratorParams, +) -> GrandpaJustification { + let JustificationGeneratorParams { header, round, set_id, authorities, mut ancestors, forks } = + params; + let (target_hash, target_number) = (header.hash(), *header.number()); + let mut votes_ancestries = vec![]; + let mut precommits = vec![]; + + assert!(forks != 0, "Need at least one fork to have a chain.."); + assert!( + forks as usize <= authorities.len(), + "If we have more forks than authorities we can't create valid pre-commits for all the forks." + ); + + // Roughly, how many vote ancestries do we want per fork + let target_depth = (ancestors + forks - 1) / forks; + + let mut unsigned_precommits = vec![]; + for i in 0..forks { + let depth = if ancestors >= target_depth { + ancestors -= target_depth; + target_depth + } else { + ancestors + }; + + // Note: Adding 1 to account for the target header + let chain = generate_chain(i, depth + 1, &header); + + // We don't include our finality target header in the vote ancestries + for child in &chain[1..] { + votes_ancestries.push(child.clone()); + } + + // The header we need to use when pre-commiting is the one at the highest height + // on our chain. + let precommit_candidate = chain.last().map(|h| (h.hash(), *h.number())).unwrap(); + unsigned_precommits.push(precommit_candidate); + } + + for (i, (id, _weight)) in authorities.iter().enumerate() { + // Assign authorities to sign pre-commits in a round-robin fashion + let target = unsigned_precommits[i % forks as usize]; + let precommit = signed_precommit::(id, target, round, set_id); + + precommits.push(precommit); + } + + GrandpaJustification { + round, + commit: finality_grandpa::Commit { target_hash, target_number, precommits }, + votes_ancestries, + } +} + +fn generate_chain(fork_id: u32, depth: u32, ancestor: &H) -> Vec { + let mut headers = vec![ancestor.clone()]; + + for i in 1..depth { + let parent = &headers[(i - 1) as usize]; + let (hash, num) = (parent.hash(), *parent.number()); + + let mut header = test_header::(num + One::one()); + header.set_parent_hash(hash); + + // Modifying the digest so headers at the same height but in different forks have different + // hashes + header.digest_mut().logs.push(sp_runtime::DigestItem::Other(fork_id.encode())); + + headers.push(header); + } + + headers +} + +/// Create signed precommit with given target. +pub fn signed_precommit( + signer: &Account, + target: (H::Hash, H::Number), + round: u64, + set_id: SetId, +) -> finality_grandpa::SignedPrecommit { + let precommit = finality_grandpa::Precommit { target_hash: target.0, target_number: target.1 }; + + let encoded = sp_consensus_grandpa::localized_payload( + round, + set_id, + &finality_grandpa::Message::Precommit(precommit.clone()), + ); + + let signature = signer.sign(&encoded); + let raw_signature: Vec = signature.to_bytes().into(); + + // Need to wrap our signature and id types that they match what our `SignedPrecommit` is + // expecting + let signature = AuthoritySignature::try_from(raw_signature).expect( + "We know our Keypair is good, + so our signature must also be good.", + ); + let id = (*signer).into(); + + finality_grandpa::SignedPrecommit { precommit, signature, id } +} + +/// Get a header for testing. +/// +/// The correct parent hash will be used if given a non-zero header. +pub fn test_header(number: H::Number) -> H { + let default = |num| { + H::new(num, Default::default(), Default::default(), Default::default(), Default::default()) + }; + + let mut header = default(number); + if number != Zero::zero() { + let parent_hash = default(number - One::one()).hash(); + header.set_parent_hash(parent_hash); + } + + header +} + +/// Convenience function for generating a Header ID at a given block number. +pub fn header_id(index: u8) -> (H::Hash, H::Number) { + (test_header::(index.into()).hash(), index.into()) +} + +#[macro_export] +/// Adds methods for testing the `set_owner()` and `set_operating_mode()` for a pallet. +/// Some values are hardcoded like: +/// - `run_test()` +/// - `Pallet::` +/// - `PalletOwner::` +/// - `PalletOperatingMode::` +/// While this is not ideal, all the pallets use the same names, so it works for the moment. +/// We can revisit this in the future if anything changes. +macro_rules! generate_owned_bridge_module_tests { + ($normal_operating_mode: expr, $halted_operating_mode: expr) => { + #[test] + fn test_set_owner() { + run_test(|| { + PalletOwner::::put(1); + + // The root should be able to change the owner. + assert_ok!(Pallet::::set_owner(RuntimeOrigin::root(), Some(2))); + assert_eq!(PalletOwner::::get(), Some(2)); + + // The owner should be able to change the owner. + assert_ok!(Pallet::::set_owner(RuntimeOrigin::signed(2), Some(3))); + assert_eq!(PalletOwner::::get(), Some(3)); + + // Other users shouldn't be able to change the owner. + assert_noop!( + Pallet::::set_owner(RuntimeOrigin::signed(1), Some(4)), + DispatchError::BadOrigin + ); + assert_eq!(PalletOwner::::get(), Some(3)); + }); + } + + #[test] + fn test_set_operating_mode() { + run_test(|| { + PalletOwner::::put(1); + PalletOperatingMode::::put($normal_operating_mode); + + // The root should be able to halt the pallet. + assert_ok!(Pallet::::set_operating_mode( + RuntimeOrigin::root(), + $halted_operating_mode + )); + assert_eq!(PalletOperatingMode::::get(), $halted_operating_mode); + // The root should be able to resume the pallet. + assert_ok!(Pallet::::set_operating_mode( + RuntimeOrigin::root(), + $normal_operating_mode + )); + assert_eq!(PalletOperatingMode::::get(), $normal_operating_mode); + + // The owner should be able to halt the pallet. + assert_ok!(Pallet::::set_operating_mode( + RuntimeOrigin::signed(1), + $halted_operating_mode + )); + assert_eq!(PalletOperatingMode::::get(), $halted_operating_mode); + // The owner should be able to resume the pallet. + assert_ok!(Pallet::::set_operating_mode( + RuntimeOrigin::signed(1), + $normal_operating_mode + )); + assert_eq!(PalletOperatingMode::::get(), $normal_operating_mode); + + // Other users shouldn't be able to halt the pallet. + assert_noop!( + Pallet::::set_operating_mode( + RuntimeOrigin::signed(2), + $halted_operating_mode + ), + DispatchError::BadOrigin + ); + assert_eq!(PalletOperatingMode::::get(), $normal_operating_mode); + // Other users shouldn't be able to resume the pallet. + PalletOperatingMode::::put($halted_operating_mode); + assert_noop!( + Pallet::::set_operating_mode( + RuntimeOrigin::signed(2), + $normal_operating_mode + ), + DispatchError::BadOrigin + ); + assert_eq!(PalletOperatingMode::::get(), $halted_operating_mode); + }); + } + }; +} diff --git a/relays/bin-substrate/Cargo.toml b/relays/bin-substrate/Cargo.toml new file mode 100644 index 00000000000..7853b9cb599 --- /dev/null +++ b/relays/bin-substrate/Cargo.toml @@ -0,0 +1,73 @@ +[package] +name = "substrate-relay" +version = "1.0.1" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +anyhow = "1.0" +async-std = "1.9.0" +async-trait = "0.1" +codec = { package = "parity-scale-codec", version = "3.1.5" } +futures = "0.3.28" +hex = "0.4" +log = "0.4.17" +num-format = "0.4" +num-traits = "0.2" +rbtag = "0.3" +structopt = "0.3" +signal-hook = "0.3.15" +signal-hook-async-std = "0.2.2" +strum = { version = "0.24.1", features = ["derive"] } + +# Bridge dependencies +bp-header-chain = { path = "../../primitives/header-chain" } +bp-messages = { path = "../../primitives/messages" } +bp-parachains = { path = "../../primitives/parachains" } +bp-millau = { path = "../../primitives/chain-millau" } +bp-polkadot-core = { path = "../../primitives/polkadot-core" } +bp-rialto = { path = "../../primitives/chain-rialto" } +bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" } +bp-runtime = { path = "../../primitives/runtime" } +bridge-runtime-common = { path = "../../bin/runtime-common" } +millau-runtime = { path = "../../bin/millau/runtime" } +pallet-bridge-parachains = { path = "../../modules/parachains" } +parachains-relay = { path = "../parachains" } +relay-millau-client = { path = "../client-millau" } +relay-rialto-client = { path = "../client-rialto" } +relay-rialto-parachain-client = { path = "../client-rialto-parachain" } +relay-bridge-hub-kusama-client = { path = "../client-bridge-hub-kusama" } +relay-bridge-hub-polkadot-client = { path = "../client-bridge-hub-polkadot" } +relay-bridge-hub-rococo-client = { path = "../client-bridge-hub-rococo" } +relay-bridge-hub-wococo-client = { path = "../client-bridge-hub-wococo" } +relay-kusama-client = { path = "../client-kusama" } +relay-polkadot-client = { path = "../client-polkadot" } +relay-rococo-client = { path = "../client-rococo" } +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } +relay-westend-client = { path = "../client-westend" } +relay-wococo-client = { path = "../client-wococo" } +rialto-runtime = { path = "../../bin/rialto/runtime" } +substrate-relay-helper = { path = "../lib-substrate-relay" } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } + +# Polkadot Dependencies +polkadot-parachain = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-runtime-common = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } +xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } + + +[dev-dependencies] +bp-test-utils = { path = "../../primitives/test-utils" } +hex-literal = "0.4" +sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" } +tempfile = "3.5" +finality-grandpa = { version = "0.16.2" } diff --git a/relays/bin-substrate/src/bridges/kusama_polkadot/bridge_hub_kusama_messages_to_bridge_hub_polkadot.rs b/relays/bin-substrate/src/bridges/kusama_polkadot/bridge_hub_kusama_messages_to_bridge_hub_polkadot.rs new file mode 100644 index 00000000000..9abec22b981 --- /dev/null +++ b/relays/bin-substrate/src/bridges/kusama_polkadot/bridge_hub_kusama_messages_to_bridge_hub_polkadot.rs @@ -0,0 +1,65 @@ +// Copyright 2022 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 . + +//! BridgeHubKusama-to-BridgeHubPolkadot messages sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge}; +use relay_bridge_hub_kusama_client::BridgeHubKusama; +use relay_bridge_hub_polkadot_client::BridgeHubPolkadot; +use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; + +/// BridgeHubKusama-to-BridgeHubPolkadot messages bridge. +pub struct BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge {} + +impl CliBridgeBase for BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge { + type Source = BridgeHubKusama; + type Target = BridgeHubPolkadot; +} + +impl MessagesCliBridge for BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge { + type MessagesLane = BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLane; +} + +substrate_relay_helper::generate_receive_message_proof_call_builder!( + BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLane, + BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLaneReceiveMessagesProofCallBuilder, + relay_bridge_hub_polkadot_client::runtime::Call::BridgeKusamaMessages, + relay_bridge_hub_polkadot_client::runtime::BridgeKusamaMessagesCall::receive_messages_proof +); + +substrate_relay_helper::generate_receive_message_delivery_proof_call_builder!( + BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLane, + BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLaneReceiveMessagesDeliveryProofCallBuilder, + relay_bridge_hub_kusama_client::runtime::Call::BridgePolkadotMessages, + relay_bridge_hub_kusama_client::runtime::BridgePolkadotMessagesCall::receive_messages_delivery_proof +); + +/// BridgeHubKusama-to-BridgeHubPolkadot messages lane. +#[derive(Clone, Debug)] +pub struct BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLane; + +impl SubstrateMessageLane for BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLane { + type SourceChain = BridgeHubKusama; + type TargetChain = BridgeHubPolkadot; + + type ReceiveMessagesProofCallBuilder = + BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLaneReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLaneReceiveMessagesDeliveryProofCallBuilder; + + type SourceBatchCallBuilder = UtilityPalletBatchCallBuilder; + type TargetBatchCallBuilder = UtilityPalletBatchCallBuilder; +} diff --git a/relays/bin-substrate/src/bridges/kusama_polkadot/bridge_hub_polkadot_messages_to_bridge_hub_kusama.rs b/relays/bin-substrate/src/bridges/kusama_polkadot/bridge_hub_polkadot_messages_to_bridge_hub_kusama.rs new file mode 100644 index 00000000000..191a84b27c2 --- /dev/null +++ b/relays/bin-substrate/src/bridges/kusama_polkadot/bridge_hub_polkadot_messages_to_bridge_hub_kusama.rs @@ -0,0 +1,65 @@ +// Copyright 2022 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 . + +//! BridgeHubPolkadot-to-BridgeHubKusama messages sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge}; +use relay_bridge_hub_kusama_client::BridgeHubKusama; +use relay_bridge_hub_polkadot_client::BridgeHubPolkadot; +use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; + +/// BridgeHubPolkadot-to-BridgeHubKusama messages bridge. +pub struct BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge {} + +impl CliBridgeBase for BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge { + type Source = BridgeHubPolkadot; + type Target = BridgeHubKusama; +} + +impl MessagesCliBridge for BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge { + type MessagesLane = BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLane; +} + +substrate_relay_helper::generate_receive_message_proof_call_builder!( + BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLane, + BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLaneReceiveMessagesProofCallBuilder, + relay_bridge_hub_kusama_client::runtime::Call::BridgePolkadotMessages, + relay_bridge_hub_kusama_client::runtime::BridgePolkadotMessagesCall::receive_messages_proof +); + +substrate_relay_helper::generate_receive_message_delivery_proof_call_builder!( + BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLane, + BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLaneReceiveMessagesDeliveryProofCallBuilder, + relay_bridge_hub_polkadot_client::runtime::Call::BridgeKusamaMessages, + relay_bridge_hub_polkadot_client::runtime::BridgeKusamaMessagesCall::receive_messages_delivery_proof +); + +/// BridgeHubPolkadot-to-BridgeHubKusama messages lane. +#[derive(Clone, Debug)] +pub struct BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLane; + +impl SubstrateMessageLane for BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLane { + type SourceChain = BridgeHubPolkadot; + type TargetChain = BridgeHubKusama; + + type ReceiveMessagesProofCallBuilder = + BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLaneReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLaneReceiveMessagesDeliveryProofCallBuilder; + + type SourceBatchCallBuilder = UtilityPalletBatchCallBuilder; + type TargetBatchCallBuilder = UtilityPalletBatchCallBuilder; +} diff --git a/relays/bin-substrate/src/bridges/kusama_polkadot/kusama_headers_to_bridge_hub_polkadot.rs b/relays/bin-substrate/src/bridges/kusama_polkadot/kusama_headers_to_bridge_hub_polkadot.rs new file mode 100644 index 00000000000..1cfaf922692 --- /dev/null +++ b/relays/bin-substrate/src/bridges/kusama_polkadot/kusama_headers_to_bridge_hub_polkadot.rs @@ -0,0 +1,72 @@ +// Copyright 2022 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 . + +//! Kusama-to-BridgeHubPolkadot headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, RelayToRelayHeadersCliBridge}; + +use async_trait::async_trait; +use relay_substrate_client::{AccountKeyPairOf, Client}; +use substrate_relay_helper::{ + finality::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline}, + TransactionParams, +}; + +/// Description of Kusama -> PolkadotBridgeHub finalized headers bridge. +#[derive(Clone, Debug)] +pub struct KusamaFinalityToBridgeHubPolkadot; + +substrate_relay_helper::generate_submit_finality_proof_call_builder!( + KusamaFinalityToBridgeHubPolkadot, + KusamaFinalityToBridgeHubPolkadotCallBuilder, + relay_bridge_hub_polkadot_client::runtime::Call::BridgeKusamaGrandpa, + relay_bridge_hub_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof +); + +#[async_trait] +impl SubstrateFinalitySyncPipeline for KusamaFinalityToBridgeHubPolkadot { + type SourceChain = relay_kusama_client::Kusama; + type TargetChain = relay_bridge_hub_polkadot_client::BridgeHubPolkadot; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = KusamaFinalityToBridgeHubPolkadotCallBuilder; + + async fn start_relay_guards( + target_client: &Client, + _transaction_params: &TransactionParams>, + enable_version_guard: bool, + ) -> relay_substrate_client::Result<()> { + if enable_version_guard { + relay_substrate_client::guard::abort_on_spec_version_change( + target_client.clone(), + target_client.simple_runtime_version().await?.spec_version, + ); + } + Ok(()) + } +} + +/// `Kusama` to BridgeHub `Polkadot` bridge definition. +pub struct KusamaToBridgeHubPolkadotCliBridge {} + +impl CliBridgeBase for KusamaToBridgeHubPolkadotCliBridge { + type Source = relay_kusama_client::Kusama; + type Target = relay_bridge_hub_polkadot_client::BridgeHubPolkadot; +} + +impl RelayToRelayHeadersCliBridge for KusamaToBridgeHubPolkadotCliBridge { + type Finality = KusamaFinalityToBridgeHubPolkadot; +} diff --git a/relays/bin-substrate/src/bridges/kusama_polkadot/kusama_parachains_to_bridge_hub_polkadot.rs b/relays/bin-substrate/src/bridges/kusama_polkadot/kusama_parachains_to_bridge_hub_polkadot.rs new file mode 100644 index 00000000000..e5936640cb3 --- /dev/null +++ b/relays/bin-substrate/src/bridges/kusama_polkadot/kusama_parachains_to_bridge_hub_polkadot.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2021 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 . + +//! Kusama-to-BridgeHubPolkadot parachains sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use relay_substrate_client::{CallOf, HeaderIdOf}; +use substrate_relay_helper::parachains::{ + SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, +}; + +/// Kusama-to-BridgeHubPolkadot parachain sync description. +#[derive(Clone, Debug)] +pub struct BridgeHubKusamaToBridgeHubPolkadot; + +impl SubstrateParachainsPipeline for BridgeHubKusamaToBridgeHubPolkadot { + type SourceParachain = relay_bridge_hub_kusama_client::BridgeHubKusama; + type SourceRelayChain = relay_kusama_client::Kusama; + type TargetChain = relay_bridge_hub_polkadot_client::BridgeHubPolkadot; + + type SubmitParachainHeadsCallBuilder = BridgeHubKusamaToBridgeHubPolkadotCallBuilder; +} + +pub struct BridgeHubKusamaToBridgeHubPolkadotCallBuilder; +impl SubmitParachainHeadsCallBuilder + for BridgeHubKusamaToBridgeHubPolkadotCallBuilder +{ + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> CallOf { + relay_bridge_hub_polkadot_client::runtime::Call::BridgeKusamaParachain( + relay_bridge_hub_polkadot_client::runtime::BridgeParachainCall::submit_parachain_heads { + at_relay_block: (at_relay_block.0, at_relay_block.1), + parachains, + parachain_heads_proof, + }, + ) + } +} + +/// Kusama-to-BridgeHubPolkadot parachain sync description for the CLI. +pub struct BridgeHubKusamaToBridgeHubPolkadotCliBridge {} + +impl ParachainToRelayHeadersCliBridge for BridgeHubKusamaToBridgeHubPolkadotCliBridge { + type SourceRelay = relay_kusama_client::Kusama; + type ParachainFinality = BridgeHubKusamaToBridgeHubPolkadot; + type RelayFinality = + crate::bridges::kusama_polkadot::kusama_headers_to_bridge_hub_polkadot::KusamaFinalityToBridgeHubPolkadot; +} + +impl CliBridgeBase for BridgeHubKusamaToBridgeHubPolkadotCliBridge { + type Source = relay_bridge_hub_kusama_client::BridgeHubKusama; + type Target = relay_bridge_hub_polkadot_client::BridgeHubPolkadot; +} + +impl MessagesCliBridge for BridgeHubKusamaToBridgeHubPolkadotCliBridge { + type MessagesLane = + crate::bridges::kusama_polkadot::bridge_hub_kusama_messages_to_bridge_hub_polkadot::BridgeHubKusamaMessagesToBridgeHubPolkadotMessageLane; +} diff --git a/relays/bin-substrate/src/bridges/kusama_polkadot/mod.rs b/relays/bin-substrate/src/bridges/kusama_polkadot/mod.rs new file mode 100644 index 00000000000..65cd8d9ded6 --- /dev/null +++ b/relays/bin-substrate/src/bridges/kusama_polkadot/mod.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2021 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 . + +//! Declaration of all bridges between Kusama Bridge Hub and Polkadot Bridge Hub. + +pub mod bridge_hub_kusama_messages_to_bridge_hub_polkadot; +pub mod bridge_hub_polkadot_messages_to_bridge_hub_kusama; +pub mod kusama_headers_to_bridge_hub_polkadot; +pub mod kusama_parachains_to_bridge_hub_polkadot; +pub mod polkadot_headers_to_bridge_hub_kusama; +pub mod polkadot_parachains_to_bridge_hub_kusama; diff --git a/relays/bin-substrate/src/bridges/kusama_polkadot/polkadot_headers_to_bridge_hub_kusama.rs b/relays/bin-substrate/src/bridges/kusama_polkadot/polkadot_headers_to_bridge_hub_kusama.rs new file mode 100644 index 00000000000..6827c24768c --- /dev/null +++ b/relays/bin-substrate/src/bridges/kusama_polkadot/polkadot_headers_to_bridge_hub_kusama.rs @@ -0,0 +1,72 @@ +// Copyright 2022 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-to-KusamaBridgeHub headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, RelayToRelayHeadersCliBridge}; + +use async_trait::async_trait; +use relay_substrate_client::{AccountKeyPairOf, Client}; +use substrate_relay_helper::{ + finality::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline}, + TransactionParams, +}; + +/// Description of Polkadot -> KusamaBridgeHub finalized headers bridge. +#[derive(Clone, Debug)] +pub struct PolkadotFinalityToBridgeHubKusama; + +substrate_relay_helper::generate_submit_finality_proof_call_builder!( + PolkadotFinalityToBridgeHubKusama, + PolkadotFinalityToBridgeHubKusamaCallBuilder, + relay_bridge_hub_kusama_client::runtime::Call::BridgePolkadotGrandpa, + relay_bridge_hub_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof +); + +#[async_trait] +impl SubstrateFinalitySyncPipeline for PolkadotFinalityToBridgeHubKusama { + type SourceChain = relay_polkadot_client::Polkadot; + type TargetChain = relay_bridge_hub_kusama_client::BridgeHubKusama; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = PolkadotFinalityToBridgeHubKusamaCallBuilder; + + async fn start_relay_guards( + target_client: &Client, + _transaction_params: &TransactionParams>, + enable_version_guard: bool, + ) -> relay_substrate_client::Result<()> { + if enable_version_guard { + relay_substrate_client::guard::abort_on_spec_version_change( + target_client.clone(), + target_client.simple_runtime_version().await?.spec_version, + ); + } + Ok(()) + } +} + +/// `Polkadot` to BridgeHub `Kusama` bridge definition. +pub struct PolkadotToBridgeHubKusamaCliBridge {} + +impl CliBridgeBase for PolkadotToBridgeHubKusamaCliBridge { + type Source = relay_polkadot_client::Polkadot; + type Target = relay_bridge_hub_kusama_client::BridgeHubKusama; +} + +impl RelayToRelayHeadersCliBridge for PolkadotToBridgeHubKusamaCliBridge { + type Finality = PolkadotFinalityToBridgeHubKusama; +} diff --git a/relays/bin-substrate/src/bridges/kusama_polkadot/polkadot_parachains_to_bridge_hub_kusama.rs b/relays/bin-substrate/src/bridges/kusama_polkadot/polkadot_parachains_to_bridge_hub_kusama.rs new file mode 100644 index 00000000000..f2a7f7309cf --- /dev/null +++ b/relays/bin-substrate/src/bridges/kusama_polkadot/polkadot_parachains_to_bridge_hub_kusama.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2021 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-to-BridgeHubKusama parachains sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use relay_substrate_client::{CallOf, HeaderIdOf}; +use substrate_relay_helper::parachains::{ + SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, +}; + +/// Polkadot-to-BridgeHubKusama parachain sync description. +#[derive(Clone, Debug)] +pub struct BridgeHubPolkadotToBridgeHubKusama; + +impl SubstrateParachainsPipeline for BridgeHubPolkadotToBridgeHubKusama { + type SourceParachain = relay_bridge_hub_polkadot_client::BridgeHubPolkadot; + type SourceRelayChain = relay_polkadot_client::Polkadot; + type TargetChain = relay_bridge_hub_kusama_client::BridgeHubKusama; + + type SubmitParachainHeadsCallBuilder = BridgeHubPolkadotToBridgeHubKusamaCallBuilder; +} + +pub struct BridgeHubPolkadotToBridgeHubKusamaCallBuilder; +impl SubmitParachainHeadsCallBuilder + for BridgeHubPolkadotToBridgeHubKusamaCallBuilder +{ + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> CallOf { + relay_bridge_hub_kusama_client::runtime::Call::BridgePolkadotParachain( + bp_parachains::BridgeParachainCall::submit_parachain_heads { + at_relay_block: (at_relay_block.0, at_relay_block.1), + parachains, + parachain_heads_proof, + }, + ) + } +} + +/// Polkadot-to-BridgeHubKusama parachain sync description for the CLI. +pub struct BridgeHubPolkadotToBridgeHubKusamaCliBridge {} + +impl ParachainToRelayHeadersCliBridge for BridgeHubPolkadotToBridgeHubKusamaCliBridge { + type SourceRelay = relay_polkadot_client::Polkadot; + type ParachainFinality = BridgeHubPolkadotToBridgeHubKusama; + type RelayFinality = + crate::bridges::kusama_polkadot::polkadot_headers_to_bridge_hub_kusama::PolkadotFinalityToBridgeHubKusama; +} + +impl CliBridgeBase for BridgeHubPolkadotToBridgeHubKusamaCliBridge { + type Source = relay_bridge_hub_polkadot_client::BridgeHubPolkadot; + type Target = relay_bridge_hub_kusama_client::BridgeHubKusama; +} + +impl MessagesCliBridge for BridgeHubPolkadotToBridgeHubKusamaCliBridge { + type MessagesLane = + crate::bridges::kusama_polkadot::bridge_hub_polkadot_messages_to_bridge_hub_kusama::BridgeHubPolkadotMessagesToBridgeHubKusamaMessageLane; +} diff --git a/relays/bin-substrate/src/bridges/mod.rs b/relays/bin-substrate/src/bridges/mod.rs new file mode 100644 index 00000000000..62e69cc0e5f --- /dev/null +++ b/relays/bin-substrate/src/bridges/mod.rs @@ -0,0 +1,23 @@ +// Copyright 2019-2021 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 . + +//! Declaration of all bridges that the relay is able to serve. + +pub mod kusama_polkadot; +pub mod rialto_millau; +pub mod rialto_parachain_millau; +pub mod rococo_wococo; +pub mod westend_millau; diff --git a/relays/bin-substrate/src/bridges/rialto_millau/millau_headers_to_rialto.rs b/relays/bin-substrate/src/bridges/rialto_millau/millau_headers_to_rialto.rs new file mode 100644 index 00000000000..f805b29c6a9 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_millau/millau_headers_to_rialto.rs @@ -0,0 +1,56 @@ +// Copyright 2019-2021 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 . + +//! Millau-to-Rialto headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}; +use substrate_relay_helper::finality::{ + engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder, + SubstrateFinalitySyncPipeline, +}; + +/// Description of Millau -> Rialto finalized headers bridge. +#[derive(Clone, Debug)] +pub struct MillauFinalityToRialto; + +impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto { + type SourceChain = relay_millau_client::Millau; + type TargetChain = relay_rialto_client::Rialto; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder< + Self, + rialto_runtime::Runtime, + rialto_runtime::MillauGrandpaInstance, + >; +} + +//// `Millau` to `Rialto` bridge definition. +pub struct MillauToRialtoCliBridge {} + +impl CliBridgeBase for MillauToRialtoCliBridge { + type Source = relay_millau_client::Millau; + type Target = relay_rialto_client::Rialto; +} + +impl RelayToRelayHeadersCliBridge for MillauToRialtoCliBridge { + type Finality = MillauFinalityToRialto; +} + +impl MessagesCliBridge for MillauToRialtoCliBridge { + type MessagesLane = + crate::bridges::rialto_millau::millau_messages_to_rialto::MillauMessagesToRialto; +} diff --git a/relays/bin-substrate/src/bridges/rialto_millau/millau_messages_to_rialto.rs b/relays/bin-substrate/src/bridges/rialto_millau/millau_messages_to_rialto.rs new file mode 100644 index 00000000000..e6a2ef1a856 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_millau/millau_messages_to_rialto.rs @@ -0,0 +1,47 @@ +// Copyright 2019-2021 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 . + +//! Millau-to-Rialto messages sync entrypoint. + +use relay_millau_client::Millau; +use relay_rialto_client::Rialto; +use substrate_relay_helper::messages_lane::{ + DirectReceiveMessagesDeliveryProofCallBuilder, DirectReceiveMessagesProofCallBuilder, + SubstrateMessageLane, +}; + +/// Description of Millau -> Rialto messages bridge. +#[derive(Clone, Debug)] +pub struct MillauMessagesToRialto; + +impl SubstrateMessageLane for MillauMessagesToRialto { + type SourceChain = Millau; + type TargetChain = Rialto; + + type ReceiveMessagesProofCallBuilder = DirectReceiveMessagesProofCallBuilder< + Self, + rialto_runtime::Runtime, + rialto_runtime::WithMillauMessagesInstance, + >; + type ReceiveMessagesDeliveryProofCallBuilder = DirectReceiveMessagesDeliveryProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WithRialtoMessagesInstance, + >; + + type SourceBatchCallBuilder = (); + type TargetBatchCallBuilder = (); +} diff --git a/relays/bin-substrate/src/bridges/rialto_millau/mod.rs b/relays/bin-substrate/src/bridges/rialto_millau/mod.rs new file mode 100644 index 00000000000..2353b58ce61 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_millau/mod.rs @@ -0,0 +1,22 @@ +// Copyright 2019-2021 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 . + +//! Declaration of all bridges between Rialto and Millau. + +pub mod millau_headers_to_rialto; +pub mod millau_messages_to_rialto; +pub mod rialto_headers_to_millau; +pub mod rialto_messages_to_millau; diff --git a/relays/bin-substrate/src/bridges/rialto_millau/rialto_headers_to_millau.rs b/relays/bin-substrate/src/bridges/rialto_millau/rialto_headers_to_millau.rs new file mode 100644 index 00000000000..7c979f52795 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_millau/rialto_headers_to_millau.rs @@ -0,0 +1,56 @@ +// Copyright 2019-2021 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 . + +//! Rialto-to-Millau headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}; +use substrate_relay_helper::finality::{ + engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder, + SubstrateFinalitySyncPipeline, +}; + +/// Description of Millau -> Rialto finalized headers bridge. +#[derive(Clone, Debug)] +pub struct RialtoFinalityToMillau; + +impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau { + type SourceChain = relay_rialto_client::Rialto; + type TargetChain = relay_millau_client::Millau; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::RialtoGrandpaInstance, + >; +} + +//// `Rialto` to `Millau` bridge definition. +pub struct RialtoToMillauCliBridge {} + +impl CliBridgeBase for RialtoToMillauCliBridge { + type Source = relay_rialto_client::Rialto; + type Target = relay_millau_client::Millau; +} + +impl RelayToRelayHeadersCliBridge for RialtoToMillauCliBridge { + type Finality = RialtoFinalityToMillau; +} + +impl MessagesCliBridge for RialtoToMillauCliBridge { + type MessagesLane = + crate::bridges::rialto_millau::rialto_messages_to_millau::RialtoMessagesToMillau; +} diff --git a/relays/bin-substrate/src/bridges/rialto_millau/rialto_messages_to_millau.rs b/relays/bin-substrate/src/bridges/rialto_millau/rialto_messages_to_millau.rs new file mode 100644 index 00000000000..b45239fb9a9 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_millau/rialto_messages_to_millau.rs @@ -0,0 +1,47 @@ +// Copyright 2019-2021 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 . + +//! Rialto-to-Millau messages sync entrypoint. + +use relay_millau_client::Millau; +use relay_rialto_client::Rialto; +use substrate_relay_helper::messages_lane::{ + DirectReceiveMessagesDeliveryProofCallBuilder, DirectReceiveMessagesProofCallBuilder, + SubstrateMessageLane, +}; + +/// Description of Rialto -> Millau messages bridge. +#[derive(Clone, Debug)] +pub struct RialtoMessagesToMillau; + +impl SubstrateMessageLane for RialtoMessagesToMillau { + type SourceChain = Rialto; + type TargetChain = Millau; + + type ReceiveMessagesProofCallBuilder = DirectReceiveMessagesProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WithRialtoMessagesInstance, + >; + type ReceiveMessagesDeliveryProofCallBuilder = DirectReceiveMessagesDeliveryProofCallBuilder< + Self, + rialto_runtime::Runtime, + rialto_runtime::WithMillauMessagesInstance, + >; + + type SourceBatchCallBuilder = (); + type TargetBatchCallBuilder = (); +} diff --git a/relays/bin-substrate/src/bridges/rialto_parachain_millau/millau_headers_to_rialto_parachain.rs b/relays/bin-substrate/src/bridges/rialto_parachain_millau/millau_headers_to_rialto_parachain.rs new file mode 100644 index 00000000000..d1c090c0797 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_parachain_millau/millau_headers_to_rialto_parachain.rs @@ -0,0 +1,76 @@ +// Copyright 2019-2021 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 . + +//! Millau-to-RialtoParachain headers sync entrypoint. + +// Copyright 2019-2021 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 . + +//! Millau-to-RialtoParachain headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}; +use substrate_relay_helper::finality::{ + engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline, +}; + +substrate_relay_helper::generate_submit_finality_proof_call_builder!( + MillauFinalityToRialtoParachain, + MillauFinalityToRialtoParachainCallBuilder, + relay_rialto_parachain_client::RuntimeCall::BridgeMillauGrandpa, + relay_rialto_parachain_client::BridgeGrandpaCall::submit_finality_proof +); + +/// Description of Millau -> Rialto finalized headers bridge. +#[derive(Clone, Debug)] +pub struct MillauFinalityToRialtoParachain; + +impl SubstrateFinalitySyncPipeline for MillauFinalityToRialtoParachain { + type SourceChain = relay_millau_client::Millau; + type TargetChain = relay_rialto_parachain_client::RialtoParachain; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = MillauFinalityToRialtoParachainCallBuilder; +} + +//// `Millau` to `RialtoParachain` bridge definition. +pub struct MillauToRialtoParachainCliBridge {} + +impl CliBridgeBase for MillauToRialtoParachainCliBridge { + type Source = relay_millau_client::Millau; + type Target = relay_rialto_parachain_client::RialtoParachain; +} + +impl RelayToRelayHeadersCliBridge for MillauToRialtoParachainCliBridge { + type Finality = MillauFinalityToRialtoParachain; +} + +impl MessagesCliBridge for MillauToRialtoParachainCliBridge { + type MessagesLane = + crate::bridges::rialto_parachain_millau::millau_messages_to_rialto_parachain::MillauMessagesToRialtoParachain; +} diff --git a/relays/bin-substrate/src/bridges/rialto_parachain_millau/millau_messages_to_rialto_parachain.rs b/relays/bin-substrate/src/bridges/rialto_parachain_millau/millau_messages_to_rialto_parachain.rs new file mode 100644 index 00000000000..8fedd22a40a --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_parachain_millau/millau_messages_to_rialto_parachain.rs @@ -0,0 +1,51 @@ +// Copyright 2019-2021 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 . + +//! Millau-to-RialtoParachain messages sync entrypoint. + +use relay_millau_client::Millau; +use relay_rialto_parachain_client::RialtoParachain; +use substrate_relay_helper::{ + messages_lane::{DirectReceiveMessagesDeliveryProofCallBuilder, SubstrateMessageLane}, + UtilityPalletBatchCallBuilder, +}; + +substrate_relay_helper::generate_receive_message_proof_call_builder!( + MillauMessagesToRialtoParachain, + MillauMessagesToRialtoParachainReceiveMessagesProofCallBuilder, + relay_rialto_parachain_client::RuntimeCall::BridgeMillauMessages, + relay_rialto_parachain_client::BridgeMessagesCall::receive_messages_proof +); + +/// Description of Millau -> RialtoParachain messages bridge. +#[derive(Clone, Debug)] +pub struct MillauMessagesToRialtoParachain; + +impl SubstrateMessageLane for MillauMessagesToRialtoParachain { + type SourceChain = Millau; + type TargetChain = RialtoParachain; + + type ReceiveMessagesProofCallBuilder = + MillauMessagesToRialtoParachainReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = DirectReceiveMessagesDeliveryProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WithRialtoParachainMessagesInstance, + >; + + type SourceBatchCallBuilder = UtilityPalletBatchCallBuilder; + type TargetBatchCallBuilder = (); +} diff --git a/relays/bin-substrate/src/bridges/rialto_parachain_millau/mod.rs b/relays/bin-substrate/src/bridges/rialto_parachain_millau/mod.rs new file mode 100644 index 00000000000..f0613d1511e --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_parachain_millau/mod.rs @@ -0,0 +1,22 @@ +// Copyright 2019-2021 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 . + +//! Declaration of all bridges between Rialto Parachain and Millau. + +pub mod millau_headers_to_rialto_parachain; +pub mod millau_messages_to_rialto_parachain; +pub mod rialto_parachain_messages_to_millau; +pub mod rialto_parachains_to_millau; diff --git a/relays/bin-substrate/src/bridges/rialto_parachain_millau/rialto_parachain_messages_to_millau.rs b/relays/bin-substrate/src/bridges/rialto_parachain_millau/rialto_parachain_messages_to_millau.rs new file mode 100644 index 00000000000..e19953eac55 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_parachain_millau/rialto_parachain_messages_to_millau.rs @@ -0,0 +1,51 @@ +// Copyright 2019-2021 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 . + +//! RialtoParachain-to-Millau messages sync entrypoint. + +use relay_millau_client::Millau; +use relay_rialto_parachain_client::RialtoParachain; +use substrate_relay_helper::{ + messages_lane::{DirectReceiveMessagesProofCallBuilder, SubstrateMessageLane}, + UtilityPalletBatchCallBuilder, +}; + +substrate_relay_helper::generate_receive_message_delivery_proof_call_builder!( + RialtoParachainMessagesToMillau, + RialtoParachainMessagesToMillauReceiveMessagesDeliveryProofCallBuilder, + relay_rialto_parachain_client::RuntimeCall::BridgeMillauMessages, + relay_rialto_parachain_client::BridgeMessagesCall::receive_messages_delivery_proof +); + +/// Description of RialtoParachain -> Millau messages bridge. +#[derive(Clone, Debug)] +pub struct RialtoParachainMessagesToMillau; + +impl SubstrateMessageLane for RialtoParachainMessagesToMillau { + type SourceChain = RialtoParachain; + type TargetChain = Millau; + + type ReceiveMessagesProofCallBuilder = DirectReceiveMessagesProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WithRialtoParachainMessagesInstance, + >; + type ReceiveMessagesDeliveryProofCallBuilder = + RialtoParachainMessagesToMillauReceiveMessagesDeliveryProofCallBuilder; + + type SourceBatchCallBuilder = (); + type TargetBatchCallBuilder = UtilityPalletBatchCallBuilder; +} diff --git a/relays/bin-substrate/src/bridges/rialto_parachain_millau/rialto_parachains_to_millau.rs b/relays/bin-substrate/src/bridges/rialto_parachain_millau/rialto_parachains_to_millau.rs new file mode 100644 index 00000000000..04f2b5aa7c7 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rialto_parachain_millau/rialto_parachains_to_millau.rs @@ -0,0 +1,65 @@ +// Copyright 2019-2021 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 . + +//! Rialto-to-Millau parachains sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}; +use relay_millau_client::Millau; +use relay_rialto_client::Rialto; +use relay_rialto_parachain_client::RialtoParachain; +use substrate_relay_helper::parachains::{ + DirectSubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, +}; + +/// Rialto-to-Millau parachains sync description. +#[derive(Clone, Debug)] +pub struct RialtoParachainsToMillau; + +impl SubstrateParachainsPipeline for RialtoParachainsToMillau { + type SourceParachain = RialtoParachain; + type SourceRelayChain = Rialto; + type TargetChain = Millau; + + type SubmitParachainHeadsCallBuilder = RialtoParachainsToMillauSubmitParachainHeadsCallBuilder; +} + +/// `submit_parachain_heads` call builder for Rialto-to-Millau parachains sync pipeline. +pub type RialtoParachainsToMillauSubmitParachainHeadsCallBuilder = + DirectSubmitParachainHeadsCallBuilder< + RialtoParachainsToMillau, + millau_runtime::Runtime, + millau_runtime::WithRialtoParachainsInstance, + >; + +//// `RialtoParachain` to `Millau` bridge definition. +pub struct RialtoParachainToMillauCliBridge {} + +impl CliBridgeBase for RialtoParachainToMillauCliBridge { + type Source = RialtoParachain; + type Target = Millau; +} + +impl ParachainToRelayHeadersCliBridge for RialtoParachainToMillauCliBridge { + type SourceRelay = Rialto; + type ParachainFinality = RialtoParachainsToMillau; + type RelayFinality = + crate::bridges::rialto_millau::rialto_headers_to_millau::RialtoFinalityToMillau; +} + +impl MessagesCliBridge for RialtoParachainToMillauCliBridge { + type MessagesLane = + crate::bridges::rialto_parachain_millau::rialto_parachain_messages_to_millau::RialtoParachainMessagesToMillau; +} diff --git a/relays/bin-substrate/src/bridges/rococo_wococo/bridge_hub_rococo_messages_to_bridge_hub_wococo.rs b/relays/bin-substrate/src/bridges/rococo_wococo/bridge_hub_rococo_messages_to_bridge_hub_wococo.rs new file mode 100644 index 00000000000..9e4b5b15fd6 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rococo_wococo/bridge_hub_rococo_messages_to_bridge_hub_wococo.rs @@ -0,0 +1,64 @@ +// Copyright 2022 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 . + +//! BridgeHubRococo-to-BridgeHubWococo messages sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge}; +use relay_bridge_hub_rococo_client::BridgeHubRococo; +use relay_bridge_hub_wococo_client::BridgeHubWococo; +use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; + +pub struct BridgeHubRococoToBridgeHubWococoMessagesCliBridge {} + +impl CliBridgeBase for BridgeHubRococoToBridgeHubWococoMessagesCliBridge { + type Source = BridgeHubRococo; + type Target = BridgeHubWococo; +} + +impl MessagesCliBridge for BridgeHubRococoToBridgeHubWococoMessagesCliBridge { + type MessagesLane = BridgeHubRococoMessagesToBridgeHubWococoMessageLane; +} + +substrate_relay_helper::generate_receive_message_proof_call_builder!( + BridgeHubRococoMessagesToBridgeHubWococoMessageLane, + BridgeHubRococoMessagesToBridgeHubWococoMessageLaneReceiveMessagesProofCallBuilder, + relay_bridge_hub_wococo_client::runtime::Call::BridgeRococoMessages, + relay_bridge_hub_wococo_client::runtime::BridgeRococoMessagesCall::receive_messages_proof +); + +substrate_relay_helper::generate_receive_message_delivery_proof_call_builder!( + BridgeHubRococoMessagesToBridgeHubWococoMessageLane, + BridgeHubRococoMessagesToBridgeHubWococoMessageLaneReceiveMessagesDeliveryProofCallBuilder, + relay_bridge_hub_rococo_client::runtime::Call::BridgeWococoMessages, + relay_bridge_hub_rococo_client::runtime::BridgeWococoMessagesCall::receive_messages_delivery_proof +); + +/// Description of BridgeHubRococo -> BridgeHubWococo messages bridge. +#[derive(Clone, Debug)] +pub struct BridgeHubRococoMessagesToBridgeHubWococoMessageLane; + +impl SubstrateMessageLane for BridgeHubRococoMessagesToBridgeHubWococoMessageLane { + type SourceChain = BridgeHubRococo; + type TargetChain = BridgeHubWococo; + + type ReceiveMessagesProofCallBuilder = + BridgeHubRococoMessagesToBridgeHubWococoMessageLaneReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + BridgeHubRococoMessagesToBridgeHubWococoMessageLaneReceiveMessagesDeliveryProofCallBuilder; + + type SourceBatchCallBuilder = UtilityPalletBatchCallBuilder; + type TargetBatchCallBuilder = UtilityPalletBatchCallBuilder; +} diff --git a/relays/bin-substrate/src/bridges/rococo_wococo/bridge_hub_wococo_messages_to_bridge_hub_rococo.rs b/relays/bin-substrate/src/bridges/rococo_wococo/bridge_hub_wococo_messages_to_bridge_hub_rococo.rs new file mode 100644 index 00000000000..fb5a81c021e --- /dev/null +++ b/relays/bin-substrate/src/bridges/rococo_wococo/bridge_hub_wococo_messages_to_bridge_hub_rococo.rs @@ -0,0 +1,64 @@ +// Copyright 2022 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 . + +//! BridgeHubWococo-to-BridgeHubRococo messages sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge}; +use relay_bridge_hub_rococo_client::BridgeHubRococo; +use relay_bridge_hub_wococo_client::BridgeHubWococo; +use substrate_relay_helper::{messages_lane::SubstrateMessageLane, UtilityPalletBatchCallBuilder}; + +pub struct BridgeHubWococoToBridgeHubRococoMessagesCliBridge {} + +impl CliBridgeBase for BridgeHubWococoToBridgeHubRococoMessagesCliBridge { + type Source = BridgeHubWococo; + type Target = BridgeHubRococo; +} + +impl MessagesCliBridge for BridgeHubWococoToBridgeHubRococoMessagesCliBridge { + type MessagesLane = BridgeHubWococoMessagesToBridgeHubRococoMessageLane; +} + +substrate_relay_helper::generate_receive_message_proof_call_builder!( + BridgeHubWococoMessagesToBridgeHubRococoMessageLane, + BridgeHubWococoMessagesToBridgeHubRococoMessageLaneReceiveMessagesProofCallBuilder, + relay_bridge_hub_rococo_client::runtime::Call::BridgeWococoMessages, + relay_bridge_hub_rococo_client::runtime::BridgeWococoMessagesCall::receive_messages_proof +); + +substrate_relay_helper::generate_receive_message_delivery_proof_call_builder!( + BridgeHubWococoMessagesToBridgeHubRococoMessageLane, + BridgeHubWococoMessagesToBridgeHubRococoMessageLaneReceiveMessagesDeliveryProofCallBuilder, + relay_bridge_hub_wococo_client::runtime::Call::BridgeRococoMessages, + relay_bridge_hub_wococo_client::runtime::BridgeRococoMessagesCall::receive_messages_delivery_proof +); + +/// Description of BridgeHubWococo -> BridgeHubRococo messages bridge. +#[derive(Clone, Debug)] +pub struct BridgeHubWococoMessagesToBridgeHubRococoMessageLane; + +impl SubstrateMessageLane for BridgeHubWococoMessagesToBridgeHubRococoMessageLane { + type SourceChain = BridgeHubWococo; + type TargetChain = BridgeHubRococo; + + type ReceiveMessagesProofCallBuilder = + BridgeHubWococoMessagesToBridgeHubRococoMessageLaneReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + BridgeHubWococoMessagesToBridgeHubRococoMessageLaneReceiveMessagesDeliveryProofCallBuilder; + + type SourceBatchCallBuilder = UtilityPalletBatchCallBuilder; + type TargetBatchCallBuilder = UtilityPalletBatchCallBuilder; +} diff --git a/relays/bin-substrate/src/bridges/rococo_wococo/mod.rs b/relays/bin-substrate/src/bridges/rococo_wococo/mod.rs new file mode 100644 index 00000000000..64330a92252 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rococo_wococo/mod.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2021 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 . + +//! Declaration of all bridges between Rococo Bridge Hub and Wococo Bridge Hub. + +pub mod bridge_hub_rococo_messages_to_bridge_hub_wococo; +pub mod bridge_hub_wococo_messages_to_bridge_hub_rococo; +pub mod rococo_headers_to_bridge_hub_wococo; +pub mod rococo_parachains_to_bridge_hub_wococo; +pub mod wococo_headers_to_bridge_hub_rococo; +pub mod wococo_parachains_to_bridge_hub_rococo; diff --git a/relays/bin-substrate/src/bridges/rococo_wococo/rococo_headers_to_bridge_hub_wococo.rs b/relays/bin-substrate/src/bridges/rococo_wococo/rococo_headers_to_bridge_hub_wococo.rs new file mode 100644 index 00000000000..2272144311c --- /dev/null +++ b/relays/bin-substrate/src/bridges/rococo_wococo/rococo_headers_to_bridge_hub_wococo.rs @@ -0,0 +1,72 @@ +// Copyright 2022 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 . + +//! Rococo-to-Wococo bridge hubs headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, RelayToRelayHeadersCliBridge}; + +use async_trait::async_trait; +use relay_substrate_client::{AccountKeyPairOf, Client}; +use substrate_relay_helper::{ + finality::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline}, + TransactionParams, +}; + +/// Description of Rococo -> Wococo finalized headers bridge. +#[derive(Clone, Debug)] +pub struct RococoFinalityToBridgeHubWococo; + +substrate_relay_helper::generate_submit_finality_proof_call_builder!( + RococoFinalityToBridgeHubWococo, + RococoFinalityToBridgeHubWococoCallBuilder, + relay_bridge_hub_wococo_client::runtime::Call::BridgeRococoGrandpa, + relay_bridge_hub_wococo_client::runtime::BridgeRococoGrandpaCall::submit_finality_proof +); + +#[async_trait] +impl SubstrateFinalitySyncPipeline for RococoFinalityToBridgeHubWococo { + type SourceChain = relay_rococo_client::Rococo; + type TargetChain = relay_bridge_hub_wococo_client::BridgeHubWococo; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = RococoFinalityToBridgeHubWococoCallBuilder; + + async fn start_relay_guards( + target_client: &Client, + _transaction_params: &TransactionParams>, + enable_version_guard: bool, + ) -> relay_substrate_client::Result<()> { + if enable_version_guard { + relay_substrate_client::guard::abort_on_spec_version_change( + target_client.clone(), + target_client.simple_runtime_version().await?.spec_version, + ); + } + Ok(()) + } +} + +/// `Rococo` to BridgeHub `Wococo` bridge definition. +pub struct RococoToBridgeHubWococoCliBridge {} + +impl CliBridgeBase for RococoToBridgeHubWococoCliBridge { + type Source = relay_rococo_client::Rococo; + type Target = relay_bridge_hub_wococo_client::BridgeHubWococo; +} + +impl RelayToRelayHeadersCliBridge for RococoToBridgeHubWococoCliBridge { + type Finality = RococoFinalityToBridgeHubWococo; +} diff --git a/relays/bin-substrate/src/bridges/rococo_wococo/rococo_parachains_to_bridge_hub_wococo.rs b/relays/bin-substrate/src/bridges/rococo_wococo/rococo_parachains_to_bridge_hub_wococo.rs new file mode 100644 index 00000000000..78b4ff35a7d --- /dev/null +++ b/relays/bin-substrate/src/bridges/rococo_wococo/rococo_parachains_to_bridge_hub_wococo.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2021 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 . + +//! Wococo-to-Rococo parachains sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use relay_substrate_client::{CallOf, HeaderIdOf}; +use substrate_relay_helper::parachains::{ + SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, +}; + +/// BridgeHub-to-BridgeHub parachain sync description. +#[derive(Clone, Debug)] +pub struct BridgeHubRococoToBridgeHubWococo; + +impl SubstrateParachainsPipeline for BridgeHubRococoToBridgeHubWococo { + type SourceParachain = relay_bridge_hub_rococo_client::BridgeHubRococo; + type SourceRelayChain = relay_rococo_client::Rococo; + type TargetChain = relay_bridge_hub_wococo_client::BridgeHubWococo; + + type SubmitParachainHeadsCallBuilder = BridgeHubRococoToBridgeHubWococoCallBuilder; +} + +pub struct BridgeHubRococoToBridgeHubWococoCallBuilder; +impl SubmitParachainHeadsCallBuilder + for BridgeHubRococoToBridgeHubWococoCallBuilder +{ + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> CallOf { + relay_bridge_hub_wococo_client::runtime::Call::BridgeRococoParachain( + relay_bridge_hub_wococo_client::runtime::BridgeParachainCall::submit_parachain_heads { + at_relay_block: (at_relay_block.0, at_relay_block.1), + parachains, + parachain_heads_proof, + }, + ) + } +} + +/// `BridgeHubParachain` to `BridgeHubParachain` bridge definition. +pub struct BridgeHubRococoToBridgeHubWococoCliBridge {} + +impl ParachainToRelayHeadersCliBridge for BridgeHubRococoToBridgeHubWococoCliBridge { + type SourceRelay = relay_rococo_client::Rococo; + type ParachainFinality = BridgeHubRococoToBridgeHubWococo; + type RelayFinality = + crate::bridges::rococo_wococo::rococo_headers_to_bridge_hub_wococo::RococoFinalityToBridgeHubWococo; +} + +impl CliBridgeBase for BridgeHubRococoToBridgeHubWococoCliBridge { + type Source = relay_bridge_hub_rococo_client::BridgeHubRococo; + type Target = relay_bridge_hub_wococo_client::BridgeHubWococo; +} + +impl MessagesCliBridge for BridgeHubRococoToBridgeHubWococoCliBridge { + type MessagesLane = + crate::bridges::rococo_wococo::bridge_hub_rococo_messages_to_bridge_hub_wococo::BridgeHubRococoMessagesToBridgeHubWococoMessageLane; +} diff --git a/relays/bin-substrate/src/bridges/rococo_wococo/wococo_headers_to_bridge_hub_rococo.rs b/relays/bin-substrate/src/bridges/rococo_wococo/wococo_headers_to_bridge_hub_rococo.rs new file mode 100644 index 00000000000..39043009582 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rococo_wococo/wococo_headers_to_bridge_hub_rococo.rs @@ -0,0 +1,72 @@ +// Copyright 2022 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 . + +//! Wococo-to-Rococo bridge hubs headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, RelayToRelayHeadersCliBridge}; + +use async_trait::async_trait; +use relay_substrate_client::{AccountKeyPairOf, Client}; +use substrate_relay_helper::{ + finality::{engine::Grandpa as GrandpaFinalityEngine, SubstrateFinalitySyncPipeline}, + TransactionParams, +}; + +/// Description of Wococo -> Rococo finalized headers bridge. +#[derive(Clone, Debug)] +pub struct WococoFinalityToBridgeHubRococo; + +substrate_relay_helper::generate_submit_finality_proof_call_builder!( + WococoFinalityToBridgeHubRococo, + WococoFinalityToBridgeHubRococoCallBuilder, + relay_bridge_hub_rococo_client::runtime::Call::BridgeWococoGrandpa, + relay_bridge_hub_rococo_client::runtime::BridgeWococoGrandpaCall::submit_finality_proof +); + +#[async_trait] +impl SubstrateFinalitySyncPipeline for WococoFinalityToBridgeHubRococo { + type SourceChain = relay_wococo_client::Wococo; + type TargetChain = relay_bridge_hub_rococo_client::BridgeHubRococo; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = WococoFinalityToBridgeHubRococoCallBuilder; + + async fn start_relay_guards( + target_client: &Client, + _transaction_params: &TransactionParams>, + enable_version_guard: bool, + ) -> relay_substrate_client::Result<()> { + if enable_version_guard { + relay_substrate_client::guard::abort_on_spec_version_change( + target_client.clone(), + target_client.simple_runtime_version().await?.spec_version, + ); + } + Ok(()) + } +} + +/// `Wococo` to BridgeHub `Rococo` bridge definition. +pub struct WococoToBridgeHubRococoCliBridge {} + +impl CliBridgeBase for WococoToBridgeHubRococoCliBridge { + type Source = relay_wococo_client::Wococo; + type Target = relay_bridge_hub_rococo_client::BridgeHubRococo; +} + +impl RelayToRelayHeadersCliBridge for WococoToBridgeHubRococoCliBridge { + type Finality = WococoFinalityToBridgeHubRococo; +} diff --git a/relays/bin-substrate/src/bridges/rococo_wococo/wococo_parachains_to_bridge_hub_rococo.rs b/relays/bin-substrate/src/bridges/rococo_wococo/wococo_parachains_to_bridge_hub_rococo.rs new file mode 100644 index 00000000000..bc76e377c92 --- /dev/null +++ b/relays/bin-substrate/src/bridges/rococo_wococo/wococo_parachains_to_bridge_hub_rococo.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2021 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 . + +//! Rococo-to-Wococo parachains sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use relay_substrate_client::{CallOf, HeaderIdOf}; +use substrate_relay_helper::parachains::{ + SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, +}; + +/// BridgeHub-to-BridgeHub parachain sync description. +#[derive(Clone, Debug)] +pub struct BridgeHubWococoToBridgeHubRococo; + +impl SubstrateParachainsPipeline for BridgeHubWococoToBridgeHubRococo { + type SourceParachain = relay_bridge_hub_wococo_client::BridgeHubWococo; + type SourceRelayChain = relay_wococo_client::Wococo; + type TargetChain = relay_bridge_hub_rococo_client::BridgeHubRococo; + + type SubmitParachainHeadsCallBuilder = BridgeHubWococoToBridgeHubRococoCallBuilder; +} + +pub struct BridgeHubWococoToBridgeHubRococoCallBuilder; +impl SubmitParachainHeadsCallBuilder + for BridgeHubWococoToBridgeHubRococoCallBuilder +{ + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> CallOf { + relay_bridge_hub_rococo_client::runtime::Call::BridgeWococoParachain( + bp_parachains::BridgeParachainCall::submit_parachain_heads { + at_relay_block: (at_relay_block.0, at_relay_block.1), + parachains, + parachain_heads_proof, + }, + ) + } +} + +/// `BridgeHubParachain` to `BridgeHubParachain` bridge definition. +pub struct BridgeHubWococoToBridgeHubRococoCliBridge {} + +impl ParachainToRelayHeadersCliBridge for BridgeHubWococoToBridgeHubRococoCliBridge { + type SourceRelay = relay_wococo_client::Wococo; + type ParachainFinality = BridgeHubWococoToBridgeHubRococo; + type RelayFinality = + crate::bridges::rococo_wococo::wococo_headers_to_bridge_hub_rococo::WococoFinalityToBridgeHubRococo; +} + +impl CliBridgeBase for BridgeHubWococoToBridgeHubRococoCliBridge { + type Source = relay_bridge_hub_wococo_client::BridgeHubWococo; + type Target = relay_bridge_hub_rococo_client::BridgeHubRococo; +} + +impl MessagesCliBridge for BridgeHubWococoToBridgeHubRococoCliBridge { + type MessagesLane = + crate::bridges::rococo_wococo::bridge_hub_wococo_messages_to_bridge_hub_rococo::BridgeHubWococoMessagesToBridgeHubRococoMessageLane; +} diff --git a/relays/bin-substrate/src/bridges/westend_millau/mod.rs b/relays/bin-substrate/src/bridges/westend_millau/mod.rs new file mode 100644 index 00000000000..10bc19241ce --- /dev/null +++ b/relays/bin-substrate/src/bridges/westend_millau/mod.rs @@ -0,0 +1,20 @@ +// Copyright 2019-2021 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 . + +//! Declaration of all bridges between Westend and Millau. + +pub mod westend_headers_to_millau; +pub mod westend_parachains_to_millau; diff --git a/relays/bin-substrate/src/bridges/westend_millau/westend_headers_to_millau.rs b/relays/bin-substrate/src/bridges/westend_millau/westend_headers_to_millau.rs new file mode 100644 index 00000000000..2a253756c2b --- /dev/null +++ b/relays/bin-substrate/src/bridges/westend_millau/westend_headers_to_millau.rs @@ -0,0 +1,51 @@ +// Copyright 2019-2021 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 . + +//! Westend-to-Millau headers sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, RelayToRelayHeadersCliBridge}; +use substrate_relay_helper::finality::{ + engine::Grandpa as GrandpaFinalityEngine, DirectSubmitGrandpaFinalityProofCallBuilder, + SubstrateFinalitySyncPipeline, +}; + +/// Description of Westend -> Millau finalized headers bridge. +#[derive(Clone, Debug)] +pub struct WestendFinalityToMillau; + +impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau { + type SourceChain = relay_westend_client::Westend; + type TargetChain = relay_millau_client::Millau; + + type FinalityEngine = GrandpaFinalityEngine; + type SubmitFinalityProofCallBuilder = DirectSubmitGrandpaFinalityProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WestendGrandpaInstance, + >; +} + +//// `Westend` to `Millau` bridge definition. +pub struct WestendToMillauCliBridge {} + +impl CliBridgeBase for WestendToMillauCliBridge { + type Source = relay_westend_client::Westend; + type Target = relay_millau_client::Millau; +} + +impl RelayToRelayHeadersCliBridge for WestendToMillauCliBridge { + type Finality = WestendFinalityToMillau; +} diff --git a/relays/bin-substrate/src/bridges/westend_millau/westend_parachains_to_millau.rs b/relays/bin-substrate/src/bridges/westend_millau/westend_parachains_to_millau.rs new file mode 100644 index 00000000000..0556ecab368 --- /dev/null +++ b/relays/bin-substrate/src/bridges/westend_millau/westend_parachains_to_millau.rs @@ -0,0 +1,59 @@ +// Copyright 2019-2021 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 . + +//! Westend-to-Millau parachains sync entrypoint. + +use crate::cli::bridge::{CliBridgeBase, ParachainToRelayHeadersCliBridge}; +use relay_millau_client::Millau; +use relay_westend_client::{Westend, Westmint}; +use substrate_relay_helper::parachains::{ + DirectSubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, +}; + +/// Westend-to-Millau parachains sync description. +#[derive(Clone, Debug)] +pub struct WestendParachainsToMillau; + +impl SubstrateParachainsPipeline for WestendParachainsToMillau { + type SourceParachain = Westmint; + type SourceRelayChain = Westend; + type TargetChain = Millau; + + type SubmitParachainHeadsCallBuilder = WestendParachainsToMillauSubmitParachainHeadsCallBuilder; +} + +/// `submit_parachain_heads` call builder for Rialto-to-Millau parachains sync pipeline. +pub type WestendParachainsToMillauSubmitParachainHeadsCallBuilder = + DirectSubmitParachainHeadsCallBuilder< + WestendParachainsToMillau, + millau_runtime::Runtime, + millau_runtime::WithWestendParachainsInstance, + >; + +//// `WestendParachain` to `Millau` bridge definition. +pub struct WestmintToMillauCliBridge {} + +impl ParachainToRelayHeadersCliBridge for WestmintToMillauCliBridge { + type SourceRelay = Westend; + type ParachainFinality = WestendParachainsToMillau; + type RelayFinality = + crate::bridges::westend_millau::westend_headers_to_millau::WestendFinalityToMillau; +} + +impl CliBridgeBase for WestmintToMillauCliBridge { + type Source = Westmint; + type Target = Millau; +} diff --git a/relays/bin-substrate/src/chains/kusama.rs b/relays/bin-substrate/src/chains/kusama.rs new file mode 100644 index 00000000000..6d5a4764f91 --- /dev/null +++ b/relays/bin-substrate/src/chains/kusama.rs @@ -0,0 +1,32 @@ +// Copyright 2022 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 . + +//! Kusama + Kusama parachains specification for CLI. + +use crate::cli::CliChain; +use relay_bridge_hub_kusama_client::BridgeHubKusama; +use relay_kusama_client::Kusama; +use relay_substrate_client::SimpleRuntimeVersion; + +impl CliChain for Kusama { + const RUNTIME_VERSION: Option = None; +} + +impl CliChain for BridgeHubKusama { + // TODO: fix me (https://github.com/paritytech/parity-bridges-common/issues/1945) + const RUNTIME_VERSION: Option = + Some(SimpleRuntimeVersion { spec_version: 4242, transaction_version: 42 }); +} diff --git a/relays/bin-substrate/src/chains/millau.rs b/relays/bin-substrate/src/chains/millau.rs new file mode 100644 index 00000000000..44416195c6a --- /dev/null +++ b/relays/bin-substrate/src/chains/millau.rs @@ -0,0 +1,39 @@ +// Copyright 2019-2021 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 . + +//! Millau chain specification for CLI. + +use crate::cli::{encode_message::CliEncodeMessage, CliChain}; +use bp_runtime::EncodedOrDecodedCall; +use relay_millau_client::Millau; +use relay_substrate_client::SimpleRuntimeVersion; + +impl CliEncodeMessage for Millau { + fn encode_execute_xcm( + message: xcm::VersionedXcm, + ) -> anyhow::Result> { + Ok(millau_runtime::RuntimeCall::XcmPallet(millau_runtime::XcmCall::execute { + message: Box::new(message), + max_weight: Self::estimate_execute_xcm_weight(), + }) + .into()) + } +} + +impl CliChain for Millau { + const RUNTIME_VERSION: Option = + Some(SimpleRuntimeVersion::from_runtime_version(&millau_runtime::VERSION)); +} diff --git a/relays/bin-substrate/src/chains/mod.rs b/relays/bin-substrate/src/chains/mod.rs new file mode 100644 index 00000000000..b1a91ed1e85 --- /dev/null +++ b/relays/bin-substrate/src/chains/mod.rs @@ -0,0 +1,110 @@ +// Copyright 2019-2021 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 . + +//! Chain-specific relayer configuration. + +mod kusama; +mod millau; +mod polkadot; +mod rialto; +mod rialto_parachain; +mod rococo; +mod westend; +mod wococo; + +#[cfg(test)] +mod tests { + use crate::cli::encode_message; + use bp_messages::source_chain::TargetHeaderChain; + use bp_runtime::Chain as _; + use codec::Encode; + use relay_millau_client::Millau; + use relay_rialto_client::Rialto; + use relay_substrate_client::{ChainWithTransactions, SignParam, UnsignedTransaction}; + + #[test] + fn maximal_rialto_to_millau_message_size_is_computed_correctly() { + use rialto_runtime::millau_messages::MillauAsTargetHeaderChain; + + let maximal_message_size = encode_message::compute_maximal_message_size( + bp_rialto::Rialto::max_extrinsic_size(), + bp_millau::Millau::max_extrinsic_size(), + ); + + let message = vec![42; maximal_message_size as _]; + assert_eq!(MillauAsTargetHeaderChain::verify_message(&message), Ok(())); + + let message = vec![42; (maximal_message_size + 1) as _]; + assert!(MillauAsTargetHeaderChain::verify_message(&message).is_err()); + } + + #[test] + fn maximal_size_remark_to_rialto_is_generated_correctly() { + assert!( + bridge_runtime_common::messages::target::maximal_incoming_message_size( + bp_rialto::Rialto::max_extrinsic_size() + ) > bp_millau::Millau::max_extrinsic_size(), + "We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large", + ) + } + #[test] + fn rialto_tx_extra_bytes_constant_is_correct() { + let rialto_call = rialto_runtime::RuntimeCall::System(rialto_runtime::SystemCall::remark { + remark: vec![], + }); + let rialto_tx = Rialto::sign_transaction( + SignParam { + spec_version: 1, + transaction_version: 1, + genesis_hash: Default::default(), + signer: sp_keyring::AccountKeyring::Alice.pair(), + }, + UnsignedTransaction::new(rialto_call.clone().into(), 0), + ) + .unwrap(); + let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len(); + assert!( + bp_rialto::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, + "Hardcoded number of extra bytes in Rialto transaction {} is lower than actual value: {}", + bp_rialto::TX_EXTRA_BYTES, + extra_bytes_in_transaction, + ); + } + + #[test] + fn millau_tx_extra_bytes_constant_is_correct() { + let millau_call = millau_runtime::RuntimeCall::System(millau_runtime::SystemCall::remark { + remark: vec![], + }); + let millau_tx = Millau::sign_transaction( + SignParam { + spec_version: 0, + transaction_version: 0, + genesis_hash: Default::default(), + signer: sp_keyring::AccountKeyring::Alice.pair(), + }, + UnsignedTransaction::new(millau_call.clone().into(), 0), + ) + .unwrap(); + let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len(); + assert!( + bp_millau::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, + "Hardcoded number of extra bytes in Millau transaction {} is lower than actual value: {}", + bp_millau::TX_EXTRA_BYTES, + extra_bytes_in_transaction, + ); + } +} diff --git a/relays/bin-substrate/src/chains/polkadot.rs b/relays/bin-substrate/src/chains/polkadot.rs new file mode 100644 index 00000000000..4fe5a48398b --- /dev/null +++ b/relays/bin-substrate/src/chains/polkadot.rs @@ -0,0 +1,32 @@ +// Copyright 2022 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 + Polkadot parachains specification for CLI. + +use crate::cli::CliChain; +use relay_bridge_hub_polkadot_client::BridgeHubPolkadot; +use relay_polkadot_client::Polkadot; +use relay_substrate_client::SimpleRuntimeVersion; + +impl CliChain for Polkadot { + const RUNTIME_VERSION: Option = None; +} + +impl CliChain for BridgeHubPolkadot { + // TODO: fix me (https://github.com/paritytech/parity-bridges-common/issues/1945) + const RUNTIME_VERSION: Option = + Some(SimpleRuntimeVersion { spec_version: 4242, transaction_version: 42 }); +} diff --git a/relays/bin-substrate/src/chains/rialto.rs b/relays/bin-substrate/src/chains/rialto.rs new file mode 100644 index 00000000000..34a448ae4cb --- /dev/null +++ b/relays/bin-substrate/src/chains/rialto.rs @@ -0,0 +1,39 @@ +// Copyright 2019-2021 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 . + +//! Rialto chain specification for CLI. + +use crate::cli::{encode_message::CliEncodeMessage, CliChain}; +use bp_runtime::EncodedOrDecodedCall; +use relay_rialto_client::Rialto; +use relay_substrate_client::SimpleRuntimeVersion; + +impl CliEncodeMessage for Rialto { + fn encode_execute_xcm( + message: xcm::VersionedXcm, + ) -> anyhow::Result> { + Ok(rialto_runtime::RuntimeCall::XcmPallet(rialto_runtime::XcmCall::execute { + message: Box::new(message), + max_weight: Self::estimate_execute_xcm_weight(), + }) + .into()) + } +} + +impl CliChain for Rialto { + const RUNTIME_VERSION: Option = + Some(SimpleRuntimeVersion::from_runtime_version(&rialto_runtime::VERSION)); +} diff --git a/relays/bin-substrate/src/chains/rialto_parachain.rs b/relays/bin-substrate/src/chains/rialto_parachain.rs new file mode 100644 index 00000000000..8ea2c1ffd43 --- /dev/null +++ b/relays/bin-substrate/src/chains/rialto_parachain.rs @@ -0,0 +1,42 @@ +// Copyright 2019-2021 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 . + +//! Rialto parachain specification for CLI. + +use crate::cli::{encode_message::CliEncodeMessage, CliChain}; +use bp_runtime::EncodedOrDecodedCall; +use relay_rialto_parachain_client::RialtoParachain; +use relay_substrate_client::SimpleRuntimeVersion; + +impl CliEncodeMessage for RialtoParachain { + fn encode_execute_xcm( + message: xcm::VersionedXcm, + ) -> anyhow::Result> { + type RuntimeCall = relay_rialto_parachain_client::RuntimeCall; + type XcmCall = relay_rialto_parachain_client::runtime_types::pallet_xcm::pallet::Call; + + let xcm_call = XcmCall::execute { + message: Box::new(unsafe { std::mem::transmute(message) }), + max_weight: Self::estimate_execute_xcm_weight(), + }; + + Ok(RuntimeCall::PolkadotXcm(xcm_call).into()) + } +} + +impl CliChain for RialtoParachain { + const RUNTIME_VERSION: Option = None; +} diff --git a/relays/bin-substrate/src/chains/rococo.rs b/relays/bin-substrate/src/chains/rococo.rs new file mode 100644 index 00000000000..c0041c53ddb --- /dev/null +++ b/relays/bin-substrate/src/chains/rococo.rs @@ -0,0 +1,31 @@ +// Copyright 2022 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 . + +//! Rococo + Rococo parachains specification for CLI. + +use crate::cli::CliChain; +use relay_bridge_hub_rococo_client::BridgeHubRococo; +use relay_rococo_client::Rococo; +use relay_substrate_client::SimpleRuntimeVersion; + +impl CliChain for Rococo { + const RUNTIME_VERSION: Option = None; +} + +impl CliChain for BridgeHubRococo { + const RUNTIME_VERSION: Option = + Some(SimpleRuntimeVersion { spec_version: 9381, transaction_version: 2 }); +} diff --git a/relays/bin-substrate/src/chains/westend.rs b/relays/bin-substrate/src/chains/westend.rs new file mode 100644 index 00000000000..9cf639e9874 --- /dev/null +++ b/relays/bin-substrate/src/chains/westend.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2021 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 . + +//! Westend chain specification for CLI. + +use crate::cli::CliChain; +use relay_substrate_client::SimpleRuntimeVersion; +use relay_westend_client::{Westend, Westmint}; + +impl CliChain for Westend { + const RUNTIME_VERSION: Option = None; +} + +impl CliChain for Westmint { + const RUNTIME_VERSION: Option = None; +} diff --git a/relays/bin-substrate/src/chains/wococo.rs b/relays/bin-substrate/src/chains/wococo.rs new file mode 100644 index 00000000000..73b3884c289 --- /dev/null +++ b/relays/bin-substrate/src/chains/wococo.rs @@ -0,0 +1,31 @@ +// Copyright 2022 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 . + +//! Wococo + Wococo parachains specification for CLI. + +use crate::cli::CliChain; +use relay_bridge_hub_wococo_client::BridgeHubWococo; +use relay_substrate_client::SimpleRuntimeVersion; +use relay_wococo_client::Wococo; + +impl CliChain for Wococo { + const RUNTIME_VERSION: Option = None; +} + +impl CliChain for BridgeHubWococo { + const RUNTIME_VERSION: Option = + Some(SimpleRuntimeVersion { spec_version: 9381, transaction_version: 2 }); +} diff --git a/relays/bin-substrate/src/cli/bridge.rs b/relays/bin-substrate/src/cli/bridge.rs new file mode 100644 index 00000000000..62c71183a48 --- /dev/null +++ b/relays/bin-substrate/src/cli/bridge.rs @@ -0,0 +1,87 @@ +// Copyright 2019-2021 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 . + +use crate::cli::CliChain; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use relay_substrate_client::{Chain, ChainWithTransactions, Parachain, RelayChain}; +use strum::{EnumString, EnumVariantNames}; +use substrate_relay_helper::{ + finality::SubstrateFinalitySyncPipeline, messages_lane::SubstrateMessageLane, + parachains::SubstrateParachainsPipeline, +}; + +#[derive(Debug, PartialEq, Eq, EnumString, EnumVariantNames)] +#[strum(serialize_all = "kebab_case")] +/// Supported full bridges (headers + messages). +pub enum FullBridge { + MillauToRialto, + RialtoToMillau, + MillauToRialtoParachain, + RialtoParachainToMillau, + BridgeHubRococoToBridgeHubWococo, + BridgeHubWococoToBridgeHubRococo, + BridgeHubKusamaToBridgeHubPolkadot, + BridgeHubPolkadotToBridgeHubKusama, +} + +/// Minimal bridge representation that can be used from the CLI. +/// It connects a source chain to a target chain. +pub trait CliBridgeBase: Sized { + /// The source chain. + type Source: Chain + CliChain; + /// The target chain. + type Target: ChainWithTransactions + CliChain; +} + +/// Bridge representation that can be used from the CLI for relaying headers +/// from a relay chain to a relay chain. +pub trait RelayToRelayHeadersCliBridge: CliBridgeBase { + /// Finality proofs synchronization pipeline. + type Finality: SubstrateFinalitySyncPipeline< + SourceChain = Self::Source, + TargetChain = Self::Target, + >; +} + +/// Bridge representation that can be used from the CLI for relaying headers +/// from a parachain to a relay chain. +pub trait ParachainToRelayHeadersCliBridge: CliBridgeBase +where + Self::Source: Parachain, +{ + // The `CliBridgeBase` type represents the parachain in this situation. + // We need to add an extra type for the relay chain. + type SourceRelay: Chain + + CliChain + + RelayChain; + /// Finality proofs synchronization pipeline (source parachain -> target). + type ParachainFinality: SubstrateParachainsPipeline< + SourceRelayChain = Self::SourceRelay, + SourceParachain = Self::Source, + TargetChain = Self::Target, + >; + /// Finality proofs synchronization pipeline (source relay chain -> target). + type RelayFinality: SubstrateFinalitySyncPipeline< + SourceChain = Self::SourceRelay, + TargetChain = Self::Target, + >; +} + +/// Bridge representation that can be used from the CLI for relaying messages. +pub trait MessagesCliBridge: CliBridgeBase { + /// The Source -> Destination messages synchronization pipeline. + type MessagesLane: SubstrateMessageLane; +} diff --git a/relays/bin-substrate/src/cli/chain_schema.rs b/relays/bin-substrate/src/cli/chain_schema.rs new file mode 100644 index 00000000000..bbc95d7dcdb --- /dev/null +++ b/relays/bin-substrate/src/cli/chain_schema.rs @@ -0,0 +1,370 @@ +// Copyright 2019-2022 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 . + +use relay_substrate_client::{AccountKeyPairOf, ChainWithTransactions}; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames}; + +use crate::cli::CliChain; +pub use relay_substrate_client::{ChainRuntimeVersion, SimpleRuntimeVersion}; +use substrate_relay_helper::TransactionParams; + +#[doc = "Runtime version params."] +#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, EnumVariantNames)] +pub enum RuntimeVersionType { + /// Auto query version from chain + Auto, + /// Custom `spec_version` and `transaction_version` + Custom, + /// Read version from bundle dependencies directly. + Bundle, +} + +/// Create chain-specific set of runtime version parameters. +#[macro_export] +macro_rules! declare_chain_runtime_version_params_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + bp_runtime::paste::item! { + #[doc = $chain " runtime version params."] + #[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy)] + pub struct [<$chain RuntimeVersionParams>] { + #[doc = "The type of runtime version for chain " $chain] + #[structopt(long, default_value = "Bundle")] + pub [<$chain_prefix _version_mode>]: RuntimeVersionType, + #[doc = "The custom sepc_version for chain " $chain] + #[structopt(long)] + pub [<$chain_prefix _spec_version>]: Option, + #[doc = "The custom transaction_version for chain " $chain] + #[structopt(long)] + pub [<$chain_prefix _transaction_version>]: Option, + } + + impl [<$chain RuntimeVersionParams>] { + /// Converts self into `ChainRuntimeVersion`. + pub fn into_runtime_version( + self, + bundle_runtime_version: Option, + ) -> anyhow::Result { + Ok(match self.[<$chain_prefix _version_mode>] { + RuntimeVersionType::Auto => ChainRuntimeVersion::Auto, + RuntimeVersionType::Custom => { + let custom_spec_version = self.[<$chain_prefix _spec_version>] + .ok_or_else(|| anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?; + let custom_transaction_version = self.[<$chain_prefix _transaction_version>] + .ok_or_else(|| anyhow::Error::msg(format!("The {}-transaction-version is required when choose custom mode", stringify!($chain_prefix))))?; + ChainRuntimeVersion::Custom( + SimpleRuntimeVersion { + spec_version: custom_spec_version, + transaction_version: custom_transaction_version + } + ) + }, + RuntimeVersionType::Bundle => match bundle_runtime_version { + Some(runtime_version) => ChainRuntimeVersion::Custom(runtime_version), + None => ChainRuntimeVersion::Auto + }, + }) + } + } + } + }; +} + +/// Create chain-specific set of runtime version parameters. +#[macro_export] +macro_rules! declare_chain_connection_params_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + bp_runtime::paste::item! { + #[doc = $chain " connection params."] + #[derive(StructOpt, Debug, PartialEq, Eq, Clone)] + pub struct [<$chain ConnectionParams>] { + #[doc = "Connect to " $chain " node at given host."] + #[structopt(long, default_value = "127.0.0.1")] + pub [<$chain_prefix _host>]: String, + #[doc = "Connect to " $chain " node websocket server at given port."] + #[structopt(long, default_value = "9944")] + pub [<$chain_prefix _port>]: u16, + #[doc = "Use secure websocket connection."] + #[structopt(long)] + pub [<$chain_prefix _secure>]: bool, + #[doc = "Custom runtime version"] + #[structopt(flatten)] + pub [<$chain_prefix _runtime_version>]: [<$chain RuntimeVersionParams>], + } + + impl [<$chain ConnectionParams>] { + /// Convert connection params into Substrate client. + #[allow(dead_code)] + pub async fn into_client( + self, + ) -> anyhow::Result> { + let chain_runtime_version = self + .[<$chain_prefix _runtime_version>] + .into_runtime_version(Chain::RUNTIME_VERSION)?; + Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams { + host: self.[<$chain_prefix _host>], + port: self.[<$chain_prefix _port>], + secure: self.[<$chain_prefix _secure>], + chain_runtime_version, + }) + .await + ) + } + } + } + }; +} + +/// Helper trait to override transaction parameters differently. +pub trait TransactionParamsProvider { + /// Returns `true` if transaction parameters are defined by this provider. + fn is_defined(&self) -> bool; + /// Returns transaction parameters. + fn transaction_params( + &self, + ) -> anyhow::Result>>; + + /// Returns transaction parameters, defined by `self` provider or, if they're not defined, + /// defined by `other` provider. + fn transaction_params_or( + &self, + other: &T, + ) -> anyhow::Result>> { + if self.is_defined() { + self.transaction_params::() + } else { + other.transaction_params::() + } + } +} + +/// Create chain-specific set of signing parameters. +#[macro_export] +macro_rules! declare_chain_signing_params_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + bp_runtime::paste::item! { + #[doc = $chain " signing params."] + #[derive(StructOpt, Debug, PartialEq, Eq, Clone)] + pub struct [<$chain SigningParams>] { + #[doc = "The SURI of secret key to use when transactions are submitted to the " $chain " node."] + #[structopt(long)] + pub [<$chain_prefix _signer>]: Option, + #[doc = "The password for the SURI of secret key to use when transactions are submitted to the " $chain " node."] + #[structopt(long)] + pub [<$chain_prefix _signer_password>]: Option, + + #[doc = "Path to the file, that contains SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer option."] + #[structopt(long)] + pub [<$chain_prefix _signer_file>]: Option, + #[doc = "Path to the file, that password for the SURI of secret key to use when transactions are submitted to the " $chain " node. Can be overridden with " $chain_prefix "_signer_password option."] + #[structopt(long)] + pub [<$chain_prefix _signer_password_file>]: Option, + + #[doc = "Transactions mortality period, in blocks. MUST be a power of two in [4; 65536] range. MAY NOT be larger than `BlockHashCount` parameter of the chain system module."] + #[structopt(long)] + pub [<$chain_prefix _transactions_mortality>]: Option, + } + + impl [<$chain SigningParams>] { + /// Return transactions mortality. + #[allow(dead_code)] + pub fn transactions_mortality(&self) -> anyhow::Result> { + self.[<$chain_prefix _transactions_mortality>] + .map(|transactions_mortality| { + if !(4..=65536).contains(&transactions_mortality) + || !transactions_mortality.is_power_of_two() + { + Err(anyhow::format_err!( + "Transactions mortality {} is not a power of two in a [4; 65536] range", + transactions_mortality, + )) + } else { + Ok(transactions_mortality) + } + }) + .transpose() + } + + /// Parse signing params into chain-specific KeyPair. + #[allow(dead_code)] + pub fn to_keypair(&self) -> anyhow::Result> { + let suri = match (self.[<$chain_prefix _signer>].as_ref(), self.[<$chain_prefix _signer_file>].as_ref()) { + (Some(suri), _) => suri.to_owned(), + (None, Some(suri_file)) => std::fs::read_to_string(suri_file) + .map_err(|err| anyhow::format_err!( + "Failed to read SURI from file {:?}: {}", + suri_file, + err, + ))?, + (None, None) => return Err(anyhow::format_err!( + "One of options must be specified: '{}' or '{}'", + stringify!([<$chain_prefix _signer>]), + stringify!([<$chain_prefix _signer_file>]), + )), + }; + + let suri_password = match ( + self.[<$chain_prefix _signer_password>].as_ref(), + self.[<$chain_prefix _signer_password_file>].as_ref(), + ) { + (Some(suri_password), _) => Some(suri_password.to_owned()), + (None, Some(suri_password_file)) => std::fs::read_to_string(suri_password_file) + .map(Some) + .map_err(|err| anyhow::format_err!( + "Failed to read SURI password from file {:?}: {}", + suri_password_file, + err, + ))?, + _ => None, + }; + + use sp_core::crypto::Pair; + + AccountKeyPairOf::::from_string( + &suri, + suri_password.as_deref() + ).map_err(|e| anyhow::format_err!("{:?}", e)) + } + } + + #[allow(dead_code)] + impl TransactionParamsProvider for [<$chain SigningParams>] { + fn is_defined(&self) -> bool { + self.[<$chain_prefix _signer>].is_some() || self.[<$chain_prefix _signer_file>].is_some() + } + + fn transaction_params(&self) -> anyhow::Result>> { + Ok(TransactionParams { + mortality: self.transactions_mortality()?, + signer: self.to_keypair::()?, + }) + } + } + } + }; +} + +/// Create chain-specific set of configuration objects: connection parameters, +/// signing parameters and bridge initialization parameters. +#[macro_export] +macro_rules! declare_chain_cli_schema { + ($chain:ident, $chain_prefix:ident) => { + $crate::declare_chain_runtime_version_params_cli_schema!($chain, $chain_prefix); + $crate::declare_chain_connection_params_cli_schema!($chain, $chain_prefix); + $crate::declare_chain_signing_params_cli_schema!($chain, $chain_prefix); + }; +} + +declare_chain_cli_schema!(Source, source); +declare_chain_cli_schema!(Target, target); +declare_chain_cli_schema!(Relaychain, relaychain); +declare_chain_cli_schema!(Parachain, parachain); + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::Pair; + + #[test] + fn reads_suri_from_file() { + const ALICE: &str = "//Alice"; + const BOB: &str = "//Bob"; + const ALICE_PASSWORD: &str = "alice_password"; + const BOB_PASSWORD: &str = "bob_password"; + + let alice: sp_core::sr25519::Pair = Pair::from_string(ALICE, Some(ALICE_PASSWORD)).unwrap(); + let bob: sp_core::sr25519::Pair = Pair::from_string(BOB, Some(BOB_PASSWORD)).unwrap(); + let bob_with_alice_password = + sp_core::sr25519::Pair::from_string(BOB, Some(ALICE_PASSWORD)).unwrap(); + + let temp_dir = tempfile::tempdir().unwrap(); + let mut suri_file_path = temp_dir.path().to_path_buf(); + let mut password_file_path = temp_dir.path().to_path_buf(); + suri_file_path.push("suri"); + password_file_path.push("password"); + std::fs::write(&suri_file_path, BOB.as_bytes()).unwrap(); + std::fs::write(&password_file_path, BOB_PASSWORD.as_bytes()).unwrap(); + + // when both seed and password are read from file + assert_eq!( + TargetSigningParams { + target_signer: Some(ALICE.into()), + target_signer_password: Some(ALICE_PASSWORD.into()), + + target_signer_file: None, + target_signer_password_file: None, + + target_transactions_mortality: None, + } + .to_keypair::() + .map(|p| p.public()) + .map_err(drop), + Ok(alice.public()), + ); + + // when both seed and password are read from file + assert_eq!( + TargetSigningParams { + target_signer: None, + target_signer_password: None, + + target_signer_file: Some(suri_file_path.clone()), + target_signer_password_file: Some(password_file_path.clone()), + + target_transactions_mortality: None, + } + .to_keypair::() + .map(|p| p.public()) + .map_err(drop), + Ok(bob.public()), + ); + + // when password are is overriden by cli option + assert_eq!( + TargetSigningParams { + target_signer: None, + target_signer_password: Some(ALICE_PASSWORD.into()), + + target_signer_file: Some(suri_file_path.clone()), + target_signer_password_file: Some(password_file_path.clone()), + + target_transactions_mortality: None, + } + .to_keypair::() + .map(|p| p.public()) + .map_err(drop), + Ok(bob_with_alice_password.public()), + ); + + // when both seed and password are overriden by cli options + assert_eq!( + TargetSigningParams { + target_signer: Some(ALICE.into()), + target_signer_password: Some(ALICE_PASSWORD.into()), + + target_signer_file: Some(suri_file_path), + target_signer_password_file: Some(password_file_path), + + target_transactions_mortality: None, + } + .to_keypair::() + .map(|p| p.public()) + .map_err(drop), + Ok(alice.public()), + ); + } +} diff --git a/relays/bin-substrate/src/cli/encode_message.rs b/relays/bin-substrate/src/cli/encode_message.rs new file mode 100644 index 00000000000..9abf8b2df6d --- /dev/null +++ b/relays/bin-substrate/src/cli/encode_message.rs @@ -0,0 +1,151 @@ +// Copyright 2019-2021 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 . + +use crate::cli::{ExplicitOrMaximal, HexBytes}; +use bp_runtime::EncodedOrDecodedCall; +use codec::Encode; +use frame_support::weights::Weight; +use relay_substrate_client::Chain; +use structopt::StructOpt; + +/// All possible messages that may be delivered to generic Substrate chain. +/// +/// Note this enum may be used in the context of both Source (as part of `encode-call`) +/// and Target chain (as part of `encode-message/send-message`). +#[derive(StructOpt, Debug, PartialEq, Eq)] +pub enum Message { + /// Raw bytes for the message. + Raw { + /// Raw message bytes. + data: HexBytes, + }, + /// Message with given size. + Sized { + /// Sized of the message. + size: ExplicitOrMaximal, + }, +} + +/// Raw, SCALE-encoded message payload used in expected deployment. +pub type RawMessage = Vec; + +pub trait CliEncodeMessage: Chain { + /// Encode an `execute` XCM call of the XCM pallet. + fn encode_execute_xcm( + message: xcm::VersionedXcm, + ) -> anyhow::Result>; + + /// Estimate value of `max_weight` argument for the `execute` XCM call of the XCM pallet. + fn estimate_execute_xcm_weight() -> Weight { + // we are only executing XCM on our testnets and 1/100 of max extrinsic weight is ok + Self::max_extrinsic_weight() / 100 + } +} + +/// Encode message payload passed through CLI flags. +pub(crate) fn encode_message( + message: &Message, +) -> anyhow::Result { + Ok(match message { + Message::Raw { ref data } => data.0.clone(), + Message::Sized { ref size } => { + let expected_xcm_size = match *size { + ExplicitOrMaximal::Explicit(size) => size, + ExplicitOrMaximal::Maximal => compute_maximal_message_size( + Source::max_extrinsic_size(), + Target::max_extrinsic_size(), + ), + }; + + // there's no way to craft XCM of the given size - we'll be using `ExpectPallet` + // instruction, which has byte vector inside + let mut current_vec_size = expected_xcm_size; + let xcm = loop { + let xcm = xcm::VersionedXcm::<()>::V3( + vec![xcm::v3::Instruction::ExpectPallet { + index: 0, + name: vec![42; current_vec_size as usize], + module_name: vec![], + crate_major: 0, + min_crate_minor: 0, + }] + .into(), + ); + if xcm.encode().len() <= expected_xcm_size as usize { + break xcm + } + + current_vec_size -= 1; + }; + xcm.encode() + }, + }) +} + +/// Compute maximal message size, given max extrinsic size at source and target chains. +pub(crate) fn compute_maximal_message_size( + maximal_source_extrinsic_size: u32, + maximal_target_extrinsic_size: u32, +) -> u32 { + // assume that both signed extensions and other arguments fit 1KB + let service_tx_bytes_on_source_chain = 1024; + let maximal_source_extrinsic_size = + maximal_source_extrinsic_size - service_tx_bytes_on_source_chain; + let maximal_message_size = + bridge_runtime_common::messages::target::maximal_incoming_message_size( + maximal_target_extrinsic_size, + ); + if maximal_message_size > maximal_source_extrinsic_size { + maximal_source_extrinsic_size + } else { + maximal_message_size + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cli::send_message::decode_xcm; + use bp_runtime::Chain; + use relay_millau_client::Millau; + use relay_rialto_client::Rialto; + + #[test] + fn encode_explicit_size_message_works() { + let msg = encode_message::(&Message::Sized { + size: ExplicitOrMaximal::Explicit(100), + }) + .unwrap(); + assert_eq!(msg.len(), 100); + // check that it decodes to valid xcm + let _ = decode_xcm::<()>(msg).unwrap(); + } + + #[test] + fn encode_maximal_size_message_works() { + let maximal_size = compute_maximal_message_size( + Rialto::max_extrinsic_size(), + Millau::max_extrinsic_size(), + ); + + let msg = + encode_message::(&Message::Sized { size: ExplicitOrMaximal::Maximal }) + .unwrap(); + assert_eq!(msg.len(), maximal_size as usize); + // check that it decodes to valid xcm + let _ = decode_xcm::<()>(msg).unwrap(); + } +} diff --git a/relays/bin-substrate/src/cli/init_bridge.rs b/relays/bin-substrate/src/cli/init_bridge.rs new file mode 100644 index 00000000000..95cd02f6c6f --- /dev/null +++ b/relays/bin-substrate/src/cli/init_bridge.rs @@ -0,0 +1,221 @@ +// Copyright 2019-2021 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 . + +use async_trait::async_trait; +use codec::Encode; + +use crate::{ + bridges::{ + rialto_millau::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + }, + rialto_parachain_millau::millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rococo_wococo::{ + rococo_headers_to_bridge_hub_wococo::RococoToBridgeHubWococoCliBridge, + wococo_headers_to_bridge_hub_rococo::WococoToBridgeHubRococoCliBridge, + }, + westend_millau::westend_headers_to_millau::WestendToMillauCliBridge, + }, + cli::{bridge::CliBridgeBase, chain_schema::*}, +}; +use bp_runtime::Chain as ChainBase; +use relay_substrate_client::{AccountKeyPairOf, Chain, UnsignedTransaction}; +use sp_core::Pair; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames, VariantNames}; +use substrate_relay_helper::finality::engine::{Engine, Grandpa as GrandpaFinalityEngine}; + +/// Initialize bridge pallet. +#[derive(StructOpt)] +pub struct InitBridge { + /// A bridge instance to initialize. + #[structopt(possible_values = InitBridgeName::VARIANTS, case_insensitive = true)] + bridge: InitBridgeName, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + /// Generates all required data, but does not submit extrinsic + #[structopt(long)] + dry_run: bool, +} + +#[derive(Debug, EnumString, EnumVariantNames)] +#[strum(serialize_all = "kebab_case")] +/// Bridge to initialize. +pub enum InitBridgeName { + MillauToRialto, + RialtoToMillau, + WestendToMillau, + MillauToRialtoParachain, + RococoToBridgeHubWococo, + WococoToBridgeHubRococo, +} + +#[async_trait] +trait BridgeInitializer: CliBridgeBase +where + ::AccountId: From< as Pair>::Public>, +{ + type Engine: Engine; + + /// Get the encoded call to init the bridge. + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call; + + /// Initialize the bridge. + async fn init_bridge(data: InitBridge) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let target_client = data.target.into_client::().await?; + let target_sign = data.target_sign.to_keypair::()?; + let dry_run = data.dry_run; + + substrate_relay_helper::finality::initialize::initialize::( + source_client, + target_client.clone(), + target_sign, + move |transaction_nonce, initialization_data| { + let call = Self::encode_init_bridge(initialization_data); + log::info!( + target: "bridge", + "Initialize bridge call encoded as hex string: {:?}", + format!("0x{}", hex::encode(call.encode())) + ); + Ok(UnsignedTransaction::new(call.into(), transaction_nonce)) + }, + dry_run, + ) + .await; + + Ok(()) + } +} + +impl BridgeInitializer for MillauToRialtoCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + rialto_runtime::SudoCall::sudo { + call: Box::new(rialto_runtime::BridgeGrandpaCall::initialize { init_data }.into()), + } + .into() + } +} + +impl BridgeInitializer for MillauToRialtoParachainCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + type RuntimeCall = relay_rialto_parachain_client::RuntimeCall; + type BridgeGrandpaCall = relay_rialto_parachain_client::BridgeGrandpaCall; + type SudoCall = relay_rialto_parachain_client::SudoCall; + + let initialize_call = + RuntimeCall::BridgeMillauGrandpa(BridgeGrandpaCall::initialize { init_data }); + + RuntimeCall::Sudo(SudoCall::sudo { call: Box::new(initialize_call) }) + } +} + +impl BridgeInitializer for RialtoToMillauCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + let initialize_call = millau_runtime::BridgeGrandpaCall::< + millau_runtime::Runtime, + millau_runtime::RialtoGrandpaInstance, + >::initialize { + init_data, + }; + millau_runtime::SudoCall::sudo { call: Box::new(initialize_call.into()) }.into() + } +} + +impl BridgeInitializer for WestendToMillauCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + // at Westend -> Millau initialization we're not using sudo, because otherwise + // our deployments may fail, because we need to initialize both Rialto -> Millau + // and Westend -> Millau bridge. => since there's single possible sudo account, + // one of transaction may fail with duplicate nonce error + millau_runtime::BridgeGrandpaCall::< + millau_runtime::Runtime, + millau_runtime::WestendGrandpaInstance, + >::initialize { + init_data, + } + .into() + } +} + +impl BridgeInitializer for RococoToBridgeHubWococoCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + relay_bridge_hub_wococo_client::runtime::Call::BridgeRococoGrandpa( + relay_bridge_hub_wococo_client::runtime::BridgeRococoGrandpaCall::initialize { + init_data, + }, + ) + } +} + +impl BridgeInitializer for WococoToBridgeHubRococoCliBridge { + type Engine = GrandpaFinalityEngine; + + fn encode_init_bridge( + init_data: >::InitializationData, + ) -> ::Call { + relay_bridge_hub_rococo_client::runtime::Call::BridgeWococoGrandpa( + relay_bridge_hub_rococo_client::runtime::BridgeWococoGrandpaCall::initialize { + init_data, + }, + ) + } +} + +impl InitBridge { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self.bridge { + InitBridgeName::MillauToRialto => MillauToRialtoCliBridge::init_bridge(self), + InitBridgeName::RialtoToMillau => RialtoToMillauCliBridge::init_bridge(self), + InitBridgeName::WestendToMillau => WestendToMillauCliBridge::init_bridge(self), + InitBridgeName::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::init_bridge(self), + InitBridgeName::RococoToBridgeHubWococo => + RococoToBridgeHubWococoCliBridge::init_bridge(self), + InitBridgeName::WococoToBridgeHubRococo => + WococoToBridgeHubRococoCliBridge::init_bridge(self), + } + .await + } +} diff --git a/relays/bin-substrate/src/cli/mod.rs b/relays/bin-substrate/src/cli/mod.rs new file mode 100644 index 00000000000..a5b90744067 --- /dev/null +++ b/relays/bin-substrate/src/cli/mod.rs @@ -0,0 +1,355 @@ +// Copyright 2019-2021 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 . + +//! Deal with CLI args of substrate-to-substrate relay. + +use std::convert::TryInto; + +use async_std::prelude::*; +use codec::{Decode, Encode}; +use futures::{select, FutureExt}; +use rbtag::BuildInfo; +use signal_hook::consts::*; +use signal_hook_async_std::Signals; +use structopt::{clap::arg_enum, StructOpt}; +use strum::{EnumString, EnumVariantNames}; + +use bp_messages::LaneId; +use relay_substrate_client::SimpleRuntimeVersion; + +pub(crate) mod bridge; +pub(crate) mod encode_message; +pub(crate) mod send_message; + +mod chain_schema; +mod init_bridge; +mod register_parachain; +mod relay_headers; +mod relay_headers_and_messages; +mod relay_messages; +mod relay_parachains; +mod resubmit_transactions; + +/// The target that will be used when publishing logs related to this pallet. +pub const LOG_TARGET: &str = "bridge"; + +/// Parse relay CLI args. +pub fn parse_args() -> Command { + Command::from_args() +} + +/// Substrate-to-Substrate bridge utilities. +#[derive(StructOpt)] +#[structopt(about = "Substrate-to-Substrate relay")] +pub enum Command { + /// Start headers relay between two chains. + /// + /// The on-chain bridge component should have been already initialized with + /// `init-bridge` sub-command. + RelayHeaders(relay_headers::RelayHeaders), + /// Start messages relay between two chains. + /// + /// Ties up to `Messages` pallets on both chains and starts relaying messages. + /// Requires the header relay to be already running. + RelayMessages(relay_messages::RelayMessages), + /// Start headers and messages relay between two Substrate chains. + /// + /// This high-level relay internally starts four low-level relays: two `RelayHeaders` + /// and two `RelayMessages` relays. Headers are only relayed when they are required by + /// the message relays - i.e. when there are messages or confirmations that needs to be + /// relayed between chains. + RelayHeadersAndMessages(Box), + /// Initialize on-chain bridge pallet with current header data. + /// + /// Sends initialization transaction to bootstrap the bridge with current finalized block data. + InitBridge(init_bridge::InitBridge), + /// Send custom message over the bridge. + /// + /// Allows interacting with the bridge by sending messages over `Messages` component. + /// The message is being sent to the source chain, delivered to the target chain and dispatched + /// there. + SendMessage(send_message::SendMessage), + /// Resubmit transactions with increased tip if they are stalled. + ResubmitTransactions(resubmit_transactions::ResubmitTransactions), + /// Register parachain. + RegisterParachain(register_parachain::RegisterParachain), + /// + RelayParachains(relay_parachains::RelayParachains), +} + +impl Command { + // Initialize logger depending on the command. + fn init_logger(&self) { + use relay_utils::initialize::{initialize_logger, initialize_relay}; + + match self { + Self::RelayHeaders(_) | + Self::RelayMessages(_) | + Self::RelayHeadersAndMessages(_) | + Self::InitBridge(_) => { + initialize_relay(); + }, + _ => { + initialize_logger(false); + }, + } + } + + /// Run the command. + async fn do_run(self) -> anyhow::Result<()> { + match self { + Self::RelayHeaders(arg) => arg.run().await?, + Self::RelayMessages(arg) => arg.run().await?, + Self::RelayHeadersAndMessages(arg) => arg.run().await?, + Self::InitBridge(arg) => arg.run().await?, + Self::SendMessage(arg) => arg.run().await?, + Self::ResubmitTransactions(arg) => arg.run().await?, + Self::RegisterParachain(arg) => arg.run().await?, + Self::RelayParachains(arg) => arg.run().await?, + } + Ok(()) + } + + /// Run the command. + pub async fn run(self) { + self.init_logger(); + + let exit_signals = match Signals::new([SIGINT, SIGTERM]) { + Ok(signals) => signals, + Err(e) => { + log::error!(target: LOG_TARGET, "Could not register exit signals: {}", e); + return + }, + }; + let run = self.do_run().fuse(); + futures::pin_mut!(exit_signals, run); + + select! { + signal = exit_signals.next().fuse() => { + log::info!(target: LOG_TARGET, "Received exit signal {:?}", signal); + }, + result = run => { + if let Err(e) = result { + log::error!(target: LOG_TARGET, "substrate-relay: {}", e); + } + }, + } + } +} + +arg_enum! { + #[derive(Debug)] + /// The origin to use when dispatching the message on the target chain. + /// + /// - `Target` uses account existing on the target chain (requires target private key). + /// - `Origin` uses account derived from the source-chain account. + pub enum Origins { + Target, + Source, + } +} + +/// Generic balance type. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Balance(pub u128); + +impl std::fmt::Display for Balance { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + use num_format::{Locale, ToFormattedString}; + write!(fmt, "{}", self.0.to_formatted_string(&Locale::en)) + } +} + +impl std::str::FromStr for Balance { + type Err = ::Err; + + fn from_str(s: &str) -> Result { + Ok(Self(s.parse()?)) + } +} + +impl Balance { + /// Cast balance to `u64` type, panicking if it's too large. + pub fn cast(&self) -> u64 { + self.0.try_into().expect("Balance is too high for this chain.") + } +} + +// Bridge-supported network definition. +/// +/// Used to abstract away CLI commands. +pub trait CliChain: relay_substrate_client::Chain { + /// Current version of the chain runtime, known to relay. + /// + /// can be `None` if relay is not going to submit transactions to that chain. + const RUNTIME_VERSION: Option; +} + +/// Lane id. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct HexLaneId(pub [u8; 4]); + +impl From for LaneId { + fn from(lane_id: HexLaneId) -> LaneId { + LaneId(lane_id.0) + } +} + +impl std::str::FromStr for HexLaneId { + type Err = hex::FromHexError; + + fn from_str(s: &str) -> Result { + let mut lane_id = [0u8; 4]; + hex::decode_to_slice(s, &mut lane_id)?; + Ok(HexLaneId(lane_id)) + } +} + +/// Nicer formatting for raw bytes vectors. +#[derive(Default, Encode, Decode, PartialEq, Eq)] +pub struct HexBytes(pub Vec); + +impl std::str::FromStr for HexBytes { + type Err = hex::FromHexError; + + fn from_str(s: &str) -> Result { + Ok(Self(hex::decode(s)?)) + } +} + +impl std::fmt::Debug for HexBytes { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "0x{self}") + } +} + +impl std::fmt::Display for HexBytes { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(fmt, "{}", hex::encode(&self.0)) + } +} + +/// Prometheus metrics params. +#[derive(Clone, Debug, PartialEq, StructOpt)] +pub struct PrometheusParams { + /// Do not expose a Prometheus metric endpoint. + #[structopt(long)] + pub no_prometheus: bool, + /// Expose Prometheus endpoint at given interface. + #[structopt(long, default_value = "127.0.0.1")] + pub prometheus_host: String, + /// Expose Prometheus endpoint at given port. + #[structopt(long, default_value = "9616")] + pub prometheus_port: u16, +} + +/// Struct to get git commit info and build time. +#[derive(BuildInfo)] +struct SubstrateRelayBuildInfo; + +impl SubstrateRelayBuildInfo { + /// Get git commit in form ``. + pub fn get_git_commit() -> String { + // on gitlab we use images without git installed, so we can't use `rbtag` there + // locally we don't have `CI_*` env variables, so we can't rely on them + // => we are using `CI_*` env variables or else `rbtag` + let maybe_sha_from_ci = option_env!("CI_COMMIT_SHORT_SHA"); + maybe_sha_from_ci + .map(|short_sha| { + // we assume that on CI the copy is always clean + format!("{short_sha}-clean") + }) + .unwrap_or_else(|| SubstrateRelayBuildInfo.get_build_commit().into()) + } +} + +impl PrometheusParams { + /// Tries to convert CLI metrics params into metrics params, used by the relay. + pub fn into_metrics_params(self) -> anyhow::Result { + let metrics_address = if !self.no_prometheus { + Some(relay_utils::metrics::MetricsAddress { + host: self.prometheus_host, + port: self.prometheus_port, + }) + } else { + None + }; + + let relay_version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"); + let relay_commit = SubstrateRelayBuildInfo::get_git_commit(); + relay_utils::metrics::MetricsParams::new( + metrics_address, + relay_version.into(), + relay_commit, + ) + .map_err(|e| anyhow::format_err!("{:?}", e)) + } +} + +/// Either explicit or maximal allowed value. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ExplicitOrMaximal { + /// User has explicitly specified argument value. + Explicit(V), + /// Maximal allowed value for this argument. + Maximal, +} + +impl std::str::FromStr for ExplicitOrMaximal +where + V::Err: std::fmt::Debug, +{ + type Err = String; + + fn from_str(s: &str) -> Result { + if s.to_lowercase() == "max" { + return Ok(ExplicitOrMaximal::Maximal) + } + + V::from_str(s) + .map(ExplicitOrMaximal::Explicit) + .map_err(|e| format!("Failed to parse '{e:?}'. Expected 'max' or explicit value")) + } +} + +#[doc = "Runtime version params."] +#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, EnumVariantNames)] +pub enum RuntimeVersionType { + /// Auto query version from chain + Auto, + /// Custom `spec_version` and `transaction_version` + Custom, + /// Read version from bundle dependencies directly. + Bundle, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn hex_bytes_display_matches_from_str_for_clap() { + // given + let hex = HexBytes(vec![1, 2, 3, 4]); + let display = format!("{hex}"); + + // when + let hex2: HexBytes = display.parse().unwrap(); + + // then + assert_eq!(hex.0, hex2.0); + } +} diff --git a/relays/bin-substrate/src/cli/register_parachain.rs b/relays/bin-substrate/src/cli/register_parachain.rs new file mode 100644 index 00000000000..320277590bc --- /dev/null +++ b/relays/bin-substrate/src/cli/register_parachain.rs @@ -0,0 +1,324 @@ +// Copyright 2019-2021 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 . + +use crate::cli::{chain_schema::*, Balance}; + +use codec::Encode; +use frame_support::Twox64Concat; +use num_traits::Zero; +use polkadot_parachain::primitives::{ + HeadData as ParaHeadData, Id as ParaId, ValidationCode as ParaValidationCode, +}; +use polkadot_runtime_common::{ + paras_registrar::Call as ParaRegistrarCall, slots::Call as ParaSlotsCall, +}; +use polkadot_runtime_parachains::paras::ParaLifecycle; +use relay_substrate_client::{AccountIdOf, CallOf, Chain, Client, UnsignedTransaction}; +use relay_utils::{TrackedTransactionStatus, TransactionTracker}; +use rialto_runtime::SudoCall; +use sp_core::{ + storage::{well_known_keys::CODE, StorageKey}, + Pair, +}; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames, VariantNames}; + +/// Name of the `NextFreeParaId` value in the `polkadot_runtime_common::paras_registrar` pallet. +const NEXT_FREE_PARA_ID_STORAGE_NAME: &str = "NextFreeParaId"; +/// Name of the `ParaLifecycles` map in the `polkadot_runtime_parachains::paras` pallet. +const PARAS_LIFECYCLES_STORAGE_NAME: &str = "ParaLifecycles"; + +/// Register parachain. +#[derive(StructOpt, Debug, PartialEq, Eq)] +pub struct RegisterParachain { + /// A parachain to register. + #[structopt(possible_values = Parachain::VARIANTS, case_insensitive = true)] + parachain: Parachain, + /// Parachain deposit. + #[structopt(long, default_value = "0")] + deposit: Balance, + /// Lease begin. + #[structopt(long, default_value = "0")] + lease_begin: u32, + /// Lease end. + #[structopt(long, default_value = "256")] + lease_end: u32, + #[structopt(flatten)] + relay_connection: RelaychainConnectionParams, + #[structopt(flatten)] + relay_sign: RelaychainSigningParams, + #[structopt(flatten)] + para_connection: ParachainConnectionParams, +} + +/// Parachain to register. +#[derive(Debug, EnumString, EnumVariantNames, PartialEq, Eq)] +#[strum(serialize_all = "kebab_case")] +pub enum Parachain { + RialtoParachain, +} + +macro_rules! select_bridge { + ($bridge: expr, $generic: tt) => { + match $bridge { + Parachain::RialtoParachain => { + type Relaychain = relay_rialto_client::Rialto; + type Parachain = relay_rialto_parachain_client::RialtoParachain; + + use bp_rialto::{PARAS_PALLET_NAME, PARAS_REGISTRAR_PALLET_NAME}; + + $generic + }, + } + }; +} + +impl RegisterParachain { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + select_bridge!(self.parachain, { + let relay_client = self.relay_connection.into_client::().await?; + let relay_sign = self.relay_sign.to_keypair::()?; + let para_client = self.para_connection.into_client::().await?; + + // hopefully we're the only actor that is registering parachain right now + // => read next parachain id + let para_id_key = bp_runtime::storage_value_final_key( + PARAS_REGISTRAR_PALLET_NAME.as_bytes(), + NEXT_FREE_PARA_ID_STORAGE_NAME.as_bytes(), + ); + let para_id: ParaId = relay_client + .storage_value(StorageKey(para_id_key.to_vec()), None) + .await? + .unwrap_or(polkadot_primitives::v4::LOWEST_PUBLIC_ID) + .max(polkadot_primitives::v4::LOWEST_PUBLIC_ID); + log::info!(target: "bridge", "Going to reserve parachain id: {:?}", para_id); + + // step 1: reserve a parachain id + let relay_sudo_account: AccountIdOf = relay_sign.public().into(); + let reserve_parachain_id_call: CallOf = + ParaRegistrarCall::reserve {}.into(); + let reserve_result = relay_client + .submit_and_watch_signed_extrinsic(&relay_sign, move |_, transaction_nonce| { + Ok(UnsignedTransaction::new( + reserve_parachain_id_call.into(), + transaction_nonce, + )) + }) + .await? + .wait() + .await; + if reserve_result == TrackedTransactionStatus::Lost { + return Err(anyhow::format_err!( + "Failed to finalize `reserve-parachain-id` transaction" + )) + } + log::info!(target: "bridge", "Reserved parachain id: {:?}", para_id); + + // step 2: register parathread + let para_genesis_header = para_client.header_by_number(Zero::zero()).await?; + let para_code = para_client + .raw_storage_value(StorageKey(CODE.to_vec()), Some(para_genesis_header.hash())) + .await? + .ok_or_else(|| { + anyhow::format_err!("Cannot fetch validation code of {}", Parachain::NAME) + })? + .0; + log::info!( + target: "bridge", + "Going to register parachain {:?}: genesis len = {} code len = {}", + para_id, + para_genesis_header.encode().len(), + para_code.len(), + ); + let register_parathread_call: CallOf = ParaRegistrarCall::register { + id: para_id, + genesis_head: ParaHeadData(para_genesis_header.encode()), + validation_code: ParaValidationCode(para_code), + } + .into(); + let register_result = relay_client + .submit_and_watch_signed_extrinsic(&relay_sign, move |_, transaction_nonce| { + Ok(UnsignedTransaction::new(register_parathread_call.into(), transaction_nonce)) + }) + .await? + .wait() + .await; + if register_result == TrackedTransactionStatus::Lost { + return Err(anyhow::format_err!( + "Failed to finalize `register-parathread` transaction" + )) + } + log::info!(target: "bridge", "Registered parachain: {:?}. Waiting for onboarding", para_id); + + // wait until parathread is onboarded + let para_state_key = bp_runtime::storage_map_final_key::( + PARAS_PALLET_NAME, + PARAS_LIFECYCLES_STORAGE_NAME, + ¶_id.encode(), + ); + wait_para_state( + &relay_client, + ¶_state_key.0, + &[ParaLifecycle::Onboarding, ParaLifecycle::Parathread], + ParaLifecycle::Parathread, + ) + .await?; + + // step 3: force parachain leases + let lease_begin = self.lease_begin; + let lease_end = self.lease_end; + let para_deposit = self.deposit.cast().into(); + log::info!( + target: "bridge", + "Going to force leases of parachain {:?}: [{}; {}]", + para_id, + lease_begin, + lease_end, + ); + let force_lease_call: CallOf = SudoCall::sudo { + call: Box::new( + ParaSlotsCall::force_lease { + para: para_id, + leaser: relay_sudo_account.clone(), + amount: para_deposit, + period_begin: lease_begin, + period_count: lease_end.saturating_sub(lease_begin).saturating_add(1), + } + .into(), + ), + } + .into(); + relay_client + .submit_signed_extrinsic(&relay_sign, move |_, transaction_nonce| { + Ok(UnsignedTransaction::new(force_lease_call.into(), transaction_nonce)) + }) + .await?; + log::info!(target: "bridge", "Registered parachain leases: {:?}. Waiting for onboarding", para_id); + + // wait until parachain is onboarded + wait_para_state( + &relay_client, + ¶_state_key.0, + &[ + ParaLifecycle::Onboarding, + ParaLifecycle::UpgradingParathread, + ParaLifecycle::Parathread, + ], + ParaLifecycle::Parachain, + ) + .await?; + + Ok(()) + }) + } +} + +/// Wait until parachain state is changed. +async fn wait_para_state( + relay_client: &Client, + para_state_key: &[u8], + from_states: &[ParaLifecycle], + to_state: ParaLifecycle, +) -> anyhow::Result<()> { + loop { + let para_state: ParaLifecycle = relay_client + .storage_value(StorageKey(para_state_key.to_vec()), None) + .await? + .ok_or_else(|| { + anyhow::format_err!( + "Cannot fetch next free parachain lifecycle from the runtime storage of {}", + Relaychain::NAME, + ) + })?; + if para_state == to_state { + log::info!(target: "bridge", "Parachain state is now: {:?}", to_state); + return Ok(()) + } + if !from_states.contains(¶_state) { + return Err(anyhow::format_err!("Invalid parachain lifecycle: {:?}", para_state)) + } + + log::info!(target: "bridge", "Parachain state: {:?}. Waiting for {:?}", para_state, to_state); + async_std::task::sleep(Relaychain::AVERAGE_BLOCK_INTERVAL).await; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn register_rialto_parachain() { + let register_parachain = RegisterParachain::from_iter(vec![ + "register-parachain", + "rialto-parachain", + "--parachain-host", + "127.0.0.1", + "--parachain-port", + "11949", + "--relaychain-host", + "127.0.0.1", + "--relaychain-port", + "9944", + "--relaychain-signer", + "//Alice", + "--deposit", + "42", + "--lease-begin", + "100", + "--lease-end", + "200", + ]); + + assert_eq!( + register_parachain, + RegisterParachain { + parachain: Parachain::RialtoParachain, + deposit: Balance(42), + lease_begin: 100, + lease_end: 200, + relay_connection: RelaychainConnectionParams { + relaychain_host: "127.0.0.1".into(), + relaychain_port: 9944, + relaychain_secure: false, + relaychain_runtime_version: RelaychainRuntimeVersionParams { + relaychain_version_mode: RuntimeVersionType::Bundle, + relaychain_spec_version: None, + relaychain_transaction_version: None, + } + }, + relay_sign: RelaychainSigningParams { + relaychain_signer: Some("//Alice".into()), + relaychain_signer_password: None, + relaychain_signer_file: None, + relaychain_signer_password_file: None, + relaychain_transactions_mortality: None, + }, + para_connection: ParachainConnectionParams { + parachain_host: "127.0.0.1".into(), + parachain_port: 11949, + parachain_secure: false, + parachain_runtime_version: ParachainRuntimeVersionParams { + parachain_version_mode: RuntimeVersionType::Bundle, + parachain_spec_version: None, + parachain_transaction_version: None, + } + }, + } + ); + } +} diff --git a/relays/bin-substrate/src/cli/relay_headers.rs b/relays/bin-substrate/src/cli/relay_headers.rs new file mode 100644 index 00000000000..fbe360d3cd7 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers.rs @@ -0,0 +1,145 @@ +// Copyright 2019-2021 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 . + +use async_trait::async_trait; +use relay_substrate_client::{AccountIdOf, AccountKeyPairOf}; +use sp_core::Pair; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames, VariantNames}; + +use crate::bridges::{ + kusama_polkadot::{ + kusama_headers_to_bridge_hub_polkadot::KusamaToBridgeHubPolkadotCliBridge, + polkadot_headers_to_bridge_hub_kusama::PolkadotToBridgeHubKusamaCliBridge, + }, + rialto_millau::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + }, + rialto_parachain_millau::millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rococo_wococo::{ + rococo_headers_to_bridge_hub_wococo::RococoToBridgeHubWococoCliBridge, + wococo_headers_to_bridge_hub_rococo::WococoToBridgeHubRococoCliBridge, + }, + westend_millau::westend_headers_to_millau::WestendToMillauCliBridge, +}; +use relay_utils::metrics::{GlobalMetrics, StandaloneMetric}; +use substrate_relay_helper::finality::SubstrateFinalitySyncPipeline; + +use crate::cli::{bridge::*, chain_schema::*, PrometheusParams}; + +/// Start headers relayer process. +#[derive(StructOpt)] +pub struct RelayHeaders { + /// A bridge instance to relay headers for. + #[structopt(possible_values = RelayHeadersBridge::VARIANTS, case_insensitive = true)] + bridge: RelayHeadersBridge, + /// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set) + /// are relayed. + #[structopt(long)] + only_mandatory_headers: bool, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + #[structopt(flatten)] + prometheus_params: PrometheusParams, +} + +#[derive(Debug, EnumString, EnumVariantNames)] +#[strum(serialize_all = "kebab_case")] +/// Headers relay bridge. +pub enum RelayHeadersBridge { + MillauToRialto, + RialtoToMillau, + WestendToMillau, + MillauToRialtoParachain, + RococoToBridgeHubWococo, + WococoToBridgeHubRococo, + KusamaToBridgeHubPolkadot, + PolkadotToBridgeHubKusama, +} + +#[async_trait] +trait HeadersRelayer: RelayToRelayHeadersCliBridge +where + AccountIdOf: From< as Pair>::Public>, +{ + /// Relay headers. + async fn relay_headers(data: RelayHeaders) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let target_client = data.target.into_client::().await?; + let target_transactions_mortality = data.target_sign.target_transactions_mortality; + let target_sign = data.target_sign.to_keypair::()?; + + let metrics_params: relay_utils::metrics::MetricsParams = + data.prometheus_params.into_metrics_params()?; + GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; + + let target_transactions_params = substrate_relay_helper::TransactionParams { + signer: target_sign, + mortality: target_transactions_mortality, + }; + Self::Finality::start_relay_guards( + &target_client, + &target_transactions_params, + target_client.can_start_version_guard(), + ) + .await?; + + substrate_relay_helper::finality::run::( + source_client, + target_client, + data.only_mandatory_headers, + target_transactions_params, + metrics_params, + ) + .await + } +} + +impl HeadersRelayer for MillauToRialtoCliBridge {} +impl HeadersRelayer for RialtoToMillauCliBridge {} +impl HeadersRelayer for WestendToMillauCliBridge {} +impl HeadersRelayer for MillauToRialtoParachainCliBridge {} +impl HeadersRelayer for RococoToBridgeHubWococoCliBridge {} +impl HeadersRelayer for WococoToBridgeHubRococoCliBridge {} +impl HeadersRelayer for KusamaToBridgeHubPolkadotCliBridge {} +impl HeadersRelayer for PolkadotToBridgeHubKusamaCliBridge {} + +impl RelayHeaders { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self.bridge { + RelayHeadersBridge::MillauToRialto => MillauToRialtoCliBridge::relay_headers(self), + RelayHeadersBridge::RialtoToMillau => RialtoToMillauCliBridge::relay_headers(self), + RelayHeadersBridge::WestendToMillau => WestendToMillauCliBridge::relay_headers(self), + RelayHeadersBridge::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::relay_headers(self), + RelayHeadersBridge::RococoToBridgeHubWococo => + RococoToBridgeHubWococoCliBridge::relay_headers(self), + RelayHeadersBridge::WococoToBridgeHubRococo => + WococoToBridgeHubRococoCliBridge::relay_headers(self), + RelayHeadersBridge::KusamaToBridgeHubPolkadot => + KusamaToBridgeHubPolkadotCliBridge::relay_headers(self), + RelayHeadersBridge::PolkadotToBridgeHubKusama => + PolkadotToBridgeHubKusamaCliBridge::relay_headers(self), + } + .await + } +} diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs new file mode 100644 index 00000000000..5384c8ff9e9 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs @@ -0,0 +1,715 @@ +// Copyright 2019-2022 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 . + +//! Complex 2-ways headers+messages relays support. +//! +//! To add new complex relay between `ChainA` and `ChainB`, you must: +//! +//! 1) ensure that there's a `declare_chain_cli_schema!(...)` for both chains. +//! 2) add `declare_chain_to_chain_bridge_schema!(...)` or +//! `declare_chain_to_parachain_bridge_schema` for the bridge. +//! 3) declare a new struct for the added bridge and implement the `Full2WayBridge` trait for it. + +#[macro_use] +mod parachain_to_parachain; +#[macro_use] +mod relay_to_relay; +#[macro_use] +mod relay_to_parachain; + +use async_trait::async_trait; +use std::{marker::PhantomData, sync::Arc}; +use structopt::StructOpt; + +use futures::{FutureExt, TryFutureExt}; +use relay_to_parachain::*; +use relay_to_relay::*; + +use crate::{ + bridges::{ + rialto_millau::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + }, + rialto_parachain_millau::{ + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, + }, + rococo_wococo::{ + rococo_parachains_to_bridge_hub_wococo::BridgeHubRococoToBridgeHubWococoCliBridge, + wococo_parachains_to_bridge_hub_rococo::BridgeHubWococoToBridgeHubRococoCliBridge, + }, + }, + cli::{ + bridge::{ + CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge, + RelayToRelayHeadersCliBridge, + }, + chain_schema::*, + relay_headers_and_messages::parachain_to_parachain::ParachainToParachainBridge, + CliChain, HexLaneId, PrometheusParams, + }, + declare_chain_cli_schema, +}; +use bp_messages::LaneId; +use bp_runtime::BalanceOf; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithMessages, + ChainWithTransactions, Client, Parachain, +}; +use relay_utils::metrics::MetricsParams; +use sp_core::Pair; +use substrate_relay_helper::{ + messages_lane::MessagesRelayParams, on_demand::OnDemandRelay, TaggedAccount, TransactionParams, +}; + +/// Parameters that have the same names across all bridges. +#[derive(Debug, PartialEq, StructOpt)] +pub struct HeadersAndMessagesSharedParams { + /// Hex-encoded lane identifiers that should be served by the complex relay. + #[structopt(long, default_value = "00000000")] + pub lane: Vec, + /// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set) + /// are relayed. + #[structopt(long)] + pub only_mandatory_headers: bool, + #[structopt(flatten)] + pub prometheus_params: PrometheusParams, +} + +/// Bridge parameters, shared by all bridge types. +pub struct Full2WayBridgeCommonParams< + Left: ChainWithTransactions + CliChain, + Right: ChainWithTransactions + CliChain, +> { + /// Shared parameters. + pub shared: HeadersAndMessagesSharedParams, + /// Parameters of the left chain. + pub left: BridgeEndCommonParams, + /// Parameters of the right chain. + pub right: BridgeEndCommonParams, + + /// Common metric parameters. + pub metrics_params: MetricsParams, +} + +impl + Full2WayBridgeCommonParams +{ + /// Creates new bridge parameters from its components. + pub fn new>( + shared: HeadersAndMessagesSharedParams, + left: BridgeEndCommonParams, + right: BridgeEndCommonParams, + ) -> anyhow::Result { + // Create metrics registry. + let metrics_params = shared.prometheus_params.clone().into_metrics_params()?; + let metrics_params = relay_utils::relay_metrics(metrics_params).into_params(); + + Ok(Self { shared, left, right, metrics_params }) + } +} + +/// Parameters that are associated with one side of the bridge. +pub struct BridgeEndCommonParams { + /// Chain client. + pub client: Client, + /// Transactions signer. + pub sign: AccountKeyPairOf, + /// Transactions mortality. + pub transactions_mortality: Option, + /// Accounts, which balances are exposed as metrics by the relay process. + pub accounts: Vec>>, +} + +/// All data of the bidirectional complex relay. +struct FullBridge< + 'a, + Source: ChainWithTransactions + CliChain, + Target: ChainWithTransactions + CliChain, + Bridge: MessagesCliBridge, +> { + source: &'a mut BridgeEndCommonParams, + target: &'a mut BridgeEndCommonParams, + metrics_params: &'a MetricsParams, + _phantom_data: PhantomData, +} + +impl< + 'a, + Source: ChainWithTransactions + CliChain, + Target: ChainWithTransactions + CliChain, + Bridge: MessagesCliBridge, + > FullBridge<'a, Source, Target, Bridge> +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom> + Into, +{ + /// Construct complex relay given it components. + fn new( + source: &'a mut BridgeEndCommonParams, + target: &'a mut BridgeEndCommonParams, + metrics_params: &'a MetricsParams, + ) -> Self { + Self { source, target, metrics_params, _phantom_data: Default::default() } + } + + /// Returns message relay parameters. + fn messages_relay_params( + &self, + source_to_target_headers_relay: Arc>, + target_to_source_headers_relay: Arc>, + lane_id: LaneId, + ) -> MessagesRelayParams { + MessagesRelayParams { + source_client: self.source.client.clone(), + source_transaction_params: TransactionParams { + signer: self.source.sign.clone(), + mortality: self.source.transactions_mortality, + }, + target_client: self.target.client.clone(), + target_transaction_params: TransactionParams { + signer: self.target.sign.clone(), + mortality: self.target.transactions_mortality, + }, + source_to_target_headers_relay: Some(source_to_target_headers_relay), + target_to_source_headers_relay: Some(target_to_source_headers_relay), + lane_id, + metrics_params: self.metrics_params.clone().disable(), + } + } +} + +// All supported chains. +declare_chain_cli_schema!(Millau, millau); +declare_chain_cli_schema!(Rialto, rialto); +declare_chain_cli_schema!(RialtoParachain, rialto_parachain); +declare_chain_cli_schema!(Rococo, rococo); +declare_chain_cli_schema!(BridgeHubRococo, bridge_hub_rococo); +declare_chain_cli_schema!(Wococo, wococo); +declare_chain_cli_schema!(BridgeHubWococo, bridge_hub_wococo); +// Means to override signers of different layer transactions. +declare_chain_cli_schema!(MillauHeadersToRialto, millau_headers_to_rialto); +declare_chain_cli_schema!(MillauHeadersToRialtoParachain, millau_headers_to_rialto_parachain); +declare_chain_cli_schema!(RialtoHeadersToMillau, rialto_headers_to_millau); +declare_chain_cli_schema!(RialtoParachainsToMillau, rialto_parachains_to_millau); +declare_chain_cli_schema!(RococoHeadersToBridgeHubWococo, rococo_headers_to_bridge_hub_wococo); +declare_chain_cli_schema!( + RococoParachainsToBridgeHubWococo, + rococo_parachains_to_bridge_hub_wococo +); +declare_chain_cli_schema!(WococoHeadersToBridgeHubRococo, wococo_headers_to_bridge_hub_rococo); +declare_chain_cli_schema!( + WococoParachainsToBridgeHubRococo, + wococo_parachains_to_bridge_hub_rococo +); +// All supported bridges. +declare_relay_to_relay_bridge_schema!(Millau, Rialto); +declare_relay_to_parachain_bridge_schema!(Millau, RialtoParachain, Rialto); +declare_parachain_to_parachain_bridge_schema!(BridgeHubRococo, Rococo, BridgeHubWococo, Wococo); + +/// Base portion of the bidirectional complex relay. +/// +/// This main purpose of extracting this trait is that in different relays the implementation +/// of `start_on_demand_headers_relayers` method will be different. But the number of +/// implementations is limited to relay <> relay, parachain <> relay and parachain <> parachain. +/// This trait allows us to reuse these implementations in different bridges. +#[async_trait] +trait Full2WayBridgeBase: Sized + Send + Sync { + /// The CLI params for the bridge. + type Params; + /// The left relay chain. + type Left: ChainWithTransactions + CliChain; + /// The right destination chain (it can be a relay or a parachain). + type Right: ChainWithTransactions + CliChain; + + /// Reference to common relay parameters. + fn common(&self) -> &Full2WayBridgeCommonParams; + + /// Mutable reference to common relay parameters. + fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams; + + /// Start on-demand headers relays. + async fn start_on_demand_headers_relayers( + &mut self, + ) -> anyhow::Result<( + Arc>, + Arc>, + )>; +} + +/// Bidirectional complex relay. +#[async_trait] +trait Full2WayBridge: Sized + Sync +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom> + Into, + BalanceOf: TryFrom> + Into, +{ + /// Base portion of the bidirectional complex relay. + type Base: Full2WayBridgeBase; + + /// The left relay chain. + type Left: ChainWithTransactions + ChainWithBalances + ChainWithMessages + CliChain; + /// The right relay chain. + type Right: ChainWithTransactions + ChainWithBalances + ChainWithMessages + CliChain; + + /// Left to Right bridge. + type L2R: MessagesCliBridge; + /// Right to Left bridge + type R2L: MessagesCliBridge; + + /// Construct new bridge. + fn new(params: ::Params) -> anyhow::Result; + + /// Reference to the base relay portion. + fn base(&self) -> &Self::Base; + + /// Mutable reference to the base relay portion. + fn mut_base(&mut self) -> &mut Self::Base; + + /// Creates and returns Left to Right complex relay. + fn left_to_right(&mut self) -> FullBridge { + let common = self.mut_base().mut_common(); + FullBridge::<_, _, Self::L2R>::new( + &mut common.left, + &mut common.right, + &common.metrics_params, + ) + } + + /// Creates and returns Right to Left complex relay. + fn right_to_left(&mut self) -> FullBridge { + let common = self.mut_base().mut_common(); + FullBridge::<_, _, Self::R2L>::new( + &mut common.right, + &mut common.left, + &common.metrics_params, + ) + } + + /// Start complex relay. + async fn run(&mut self) -> anyhow::Result<()> { + // Register standalone metrics. + { + let common = self.mut_base().mut_common(); + common.left.accounts.push(TaggedAccount::Messages { + id: common.left.sign.public().into(), + bridged_chain: Self::Right::NAME.to_string(), + }); + common.right.accounts.push(TaggedAccount::Messages { + id: common.right.sign.public().into(), + bridged_chain: Self::Left::NAME.to_string(), + }); + } + + // start on-demand header relays + let (left_to_right_on_demand_headers, right_to_left_on_demand_headers) = + self.mut_base().start_on_demand_headers_relayers().await?; + + // add balance-related metrics + let lanes = self + .base() + .common() + .shared + .lane + .iter() + .cloned() + .map(Into::into) + .collect::>(); + { + let common = self.mut_base().mut_common(); + substrate_relay_helper::messages_metrics::add_relay_balances_metrics::<_, Self::Right>( + common.left.client.clone(), + &mut common.metrics_params, + &common.left.accounts, + &lanes, + ) + .await?; + substrate_relay_helper::messages_metrics::add_relay_balances_metrics::<_, Self::Left>( + common.right.client.clone(), + &mut common.metrics_params, + &common.right.accounts, + &lanes, + ) + .await?; + } + + // Need 2x capacity since we consider both directions for each lane + let mut message_relays = Vec::with_capacity(lanes.len() * 2); + for lane in lanes { + let left_to_right_messages = substrate_relay_helper::messages_lane::run::< + ::MessagesLane, + >(self.left_to_right().messages_relay_params( + left_to_right_on_demand_headers.clone(), + right_to_left_on_demand_headers.clone(), + lane, + )) + .map_err(|e| anyhow::format_err!("{}", e)) + .boxed(); + message_relays.push(left_to_right_messages); + + let right_to_left_messages = substrate_relay_helper::messages_lane::run::< + ::MessagesLane, + >(self.right_to_left().messages_relay_params( + right_to_left_on_demand_headers.clone(), + left_to_right_on_demand_headers.clone(), + lane, + )) + .map_err(|e| anyhow::format_err!("{}", e)) + .boxed(); + message_relays.push(right_to_left_messages); + } + + relay_utils::relay_metrics(self.base().common().metrics_params.clone()) + .expose() + .await + .map_err(|e| anyhow::format_err!("{}", e))?; + + futures::future::select_all(message_relays).await.0 + } +} + +/// Millau <> Rialto complex relay. +pub struct MillauRialtoFull2WayBridge { + base: ::Base, +} + +#[async_trait] +impl Full2WayBridge for MillauRialtoFull2WayBridge { + type Base = RelayToRelayBridge; + type Left = relay_millau_client::Millau; + type Right = relay_rialto_client::Rialto; + type L2R = MillauToRialtoCliBridge; + type R2L = RialtoToMillauCliBridge; + + fn new(base: Self::Base) -> anyhow::Result { + Ok(Self { base }) + } + + fn base(&self) -> &Self::Base { + &self.base + } + + fn mut_base(&mut self) -> &mut Self::Base { + &mut self.base + } +} + +/// Millau <> RialtoParachain complex relay. +pub struct MillauRialtoParachainFull2WayBridge { + base: ::Base, +} + +#[async_trait] +impl Full2WayBridge for MillauRialtoParachainFull2WayBridge { + type Base = RelayToParachainBridge; + type Left = relay_millau_client::Millau; + type Right = relay_rialto_parachain_client::RialtoParachain; + type L2R = MillauToRialtoParachainCliBridge; + type R2L = RialtoParachainToMillauCliBridge; + + fn new(base: Self::Base) -> anyhow::Result { + Ok(Self { base }) + } + + fn base(&self) -> &Self::Base { + &self.base + } + + fn mut_base(&mut self) -> &mut Self::Base { + &mut self.base + } +} + +/// BridgeHubRococo <> BridgeHubWococo complex relay. +pub struct BridgeHubRococoBridgeHubWococoFull2WayBridge { + base: ::Base, +} + +#[async_trait] +impl Full2WayBridge for BridgeHubRococoBridgeHubWococoFull2WayBridge { + type Base = ParachainToParachainBridge; + type Left = relay_bridge_hub_rococo_client::BridgeHubRococo; + type Right = relay_bridge_hub_wococo_client::BridgeHubWococo; + type L2R = BridgeHubRococoToBridgeHubWococoCliBridge; + type R2L = BridgeHubWococoToBridgeHubRococoCliBridge; + + fn new(base: Self::Base) -> anyhow::Result { + Ok(Self { base }) + } + + fn base(&self) -> &Self::Base { + &self.base + } + + fn mut_base(&mut self) -> &mut Self::Base { + &mut self.base + } +} + +/// Complex headers+messages relay. +#[derive(Debug, PartialEq, StructOpt)] +pub enum RelayHeadersAndMessages { + /// Millau <> Rialto relay. + MillauRialto(MillauRialtoHeadersAndMessages), + /// Millau <> RialtoParachain relay. + MillauRialtoParachain(MillauRialtoParachainHeadersAndMessages), + /// BridgeHubRococo <> BridgeHubWococo relay. + BridgeHubRococoBridgeHubWococo(BridgeHubRococoBridgeHubWococoHeadersAndMessages), +} + +impl RelayHeadersAndMessages { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self { + RelayHeadersAndMessages::MillauRialto(params) => + MillauRialtoFull2WayBridge::new(params.into_bridge().await?)?.run().await, + RelayHeadersAndMessages::MillauRialtoParachain(params) => + MillauRialtoParachainFull2WayBridge::new(params.into_bridge().await?)? + .run() + .await, + RelayHeadersAndMessages::BridgeHubRococoBridgeHubWococo(params) => + BridgeHubRococoBridgeHubWococoFull2WayBridge::new(params.into_bridge().await?)? + .run() + .await, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_parse_relay_to_relay_options() { + // when + let res = RelayHeadersAndMessages::from_iter(vec![ + "relay-headers-and-messages", + "millau-rialto", + "--millau-host", + "millau-node-alice", + "--millau-port", + "9944", + "--millau-signer", + "//Charlie", + "--millau-transactions-mortality", + "64", + "--rialto-host", + "rialto-node-alice", + "--rialto-port", + "9944", + "--rialto-signer", + "//Charlie", + "--rialto-transactions-mortality", + "64", + "--lane", + "00000000", + "--lane", + "73776170", + "--prometheus-host", + "0.0.0.0", + ]); + + // then + assert_eq!( + res, + RelayHeadersAndMessages::MillauRialto(MillauRialtoHeadersAndMessages { + shared: HeadersAndMessagesSharedParams { + lane: vec![ + HexLaneId([0x00, 0x00, 0x00, 0x00]), + HexLaneId([0x73, 0x77, 0x61, 0x70]) + ], + only_mandatory_headers: false, + prometheus_params: PrometheusParams { + no_prometheus: false, + prometheus_host: "0.0.0.0".into(), + prometheus_port: 9616, + }, + }, + left: MillauConnectionParams { + millau_host: "millau-node-alice".into(), + millau_port: 9944, + millau_secure: false, + millau_runtime_version: MillauRuntimeVersionParams { + millau_version_mode: RuntimeVersionType::Bundle, + millau_spec_version: None, + millau_transaction_version: None, + }, + }, + left_sign: MillauSigningParams { + millau_signer: Some("//Charlie".into()), + millau_signer_password: None, + millau_signer_file: None, + millau_signer_password_file: None, + millau_transactions_mortality: Some(64), + }, + left_headers_to_right_sign_override: MillauHeadersToRialtoSigningParams { + millau_headers_to_rialto_signer: None, + millau_headers_to_rialto_signer_password: None, + millau_headers_to_rialto_signer_file: None, + millau_headers_to_rialto_signer_password_file: None, + millau_headers_to_rialto_transactions_mortality: None, + }, + right: RialtoConnectionParams { + rialto_host: "rialto-node-alice".into(), + rialto_port: 9944, + rialto_secure: false, + rialto_runtime_version: RialtoRuntimeVersionParams { + rialto_version_mode: RuntimeVersionType::Bundle, + rialto_spec_version: None, + rialto_transaction_version: None, + }, + }, + right_sign: RialtoSigningParams { + rialto_signer: Some("//Charlie".into()), + rialto_signer_password: None, + rialto_signer_file: None, + rialto_signer_password_file: None, + rialto_transactions_mortality: Some(64), + }, + right_headers_to_left_sign_override: RialtoHeadersToMillauSigningParams { + rialto_headers_to_millau_signer: None, + rialto_headers_to_millau_signer_password: None, + rialto_headers_to_millau_signer_file: None, + rialto_headers_to_millau_signer_password_file: None, + rialto_headers_to_millau_transactions_mortality: None, + }, + }), + ); + } + + #[test] + fn should_parse_relay_to_parachain_options() { + // when + let res = RelayHeadersAndMessages::from_iter(vec![ + "relay-headers-and-messages", + "millau-rialto-parachain", + "--millau-host", + "millau-node-alice", + "--millau-port", + "9944", + "--millau-signer", + "//Iden", + "--rialto-headers-to-millau-signer", + "//Ken", + "--millau-transactions-mortality", + "64", + "--rialto-parachain-host", + "rialto-parachain-collator-charlie", + "--rialto-parachain-port", + "9944", + "--rialto-parachain-signer", + "//George", + "--rialto-parachain-transactions-mortality", + "64", + "--rialto-host", + "rialto-node-alice", + "--rialto-port", + "9944", + "--lane", + "00000000", + "--prometheus-host", + "0.0.0.0", + ]); + + // then + assert_eq!( + res, + RelayHeadersAndMessages::MillauRialtoParachain( + MillauRialtoParachainHeadersAndMessages { + shared: HeadersAndMessagesSharedParams { + lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])], + only_mandatory_headers: false, + prometheus_params: PrometheusParams { + no_prometheus: false, + prometheus_host: "0.0.0.0".into(), + prometheus_port: 9616, + }, + }, + left: MillauConnectionParams { + millau_host: "millau-node-alice".into(), + millau_port: 9944, + millau_secure: false, + millau_runtime_version: MillauRuntimeVersionParams { + millau_version_mode: RuntimeVersionType::Bundle, + millau_spec_version: None, + millau_transaction_version: None, + }, + }, + left_sign: MillauSigningParams { + millau_signer: Some("//Iden".into()), + millau_signer_password: None, + millau_signer_file: None, + millau_signer_password_file: None, + millau_transactions_mortality: Some(64), + }, + left_headers_to_right_sign_override: + MillauHeadersToRialtoParachainSigningParams { + millau_headers_to_rialto_parachain_signer: None, + millau_headers_to_rialto_parachain_signer_password: None, + millau_headers_to_rialto_parachain_signer_file: None, + millau_headers_to_rialto_parachain_signer_password_file: None, + millau_headers_to_rialto_parachain_transactions_mortality: None, + }, + right: RialtoParachainConnectionParams { + rialto_parachain_host: "rialto-parachain-collator-charlie".into(), + rialto_parachain_port: 9944, + rialto_parachain_secure: false, + rialto_parachain_runtime_version: RialtoParachainRuntimeVersionParams { + rialto_parachain_version_mode: RuntimeVersionType::Bundle, + rialto_parachain_spec_version: None, + rialto_parachain_transaction_version: None, + }, + }, + right_sign: RialtoParachainSigningParams { + rialto_parachain_signer: Some("//George".into()), + rialto_parachain_signer_password: None, + rialto_parachain_signer_file: None, + rialto_parachain_signer_password_file: None, + rialto_parachain_transactions_mortality: Some(64), + }, + right_relay_headers_to_left_sign_override: RialtoHeadersToMillauSigningParams { + rialto_headers_to_millau_signer: Some("//Ken".into()), + rialto_headers_to_millau_signer_password: None, + rialto_headers_to_millau_signer_file: None, + rialto_headers_to_millau_signer_password_file: None, + rialto_headers_to_millau_transactions_mortality: None, + }, + right_parachains_to_left_sign_override: RialtoParachainsToMillauSigningParams { + rialto_parachains_to_millau_signer: None, + rialto_parachains_to_millau_signer_password: None, + rialto_parachains_to_millau_signer_file: None, + rialto_parachains_to_millau_signer_password_file: None, + rialto_parachains_to_millau_transactions_mortality: None, + }, + right_relay: RialtoConnectionParams { + rialto_host: "rialto-node-alice".into(), + rialto_port: 9944, + rialto_secure: false, + rialto_runtime_version: RialtoRuntimeVersionParams { + rialto_version_mode: RuntimeVersionType::Bundle, + rialto_spec_version: None, + rialto_transaction_version: None, + }, + }, + } + ), + ); + } +} diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages/parachain_to_parachain.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages/parachain_to_parachain.rs new file mode 100644 index 00000000000..b4c858e566b --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages/parachain_to_parachain.rs @@ -0,0 +1,275 @@ +// Copyright 2019-2022 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 . + +use async_trait::async_trait; +use std::sync::Arc; + +use crate::cli::{ + bridge::{CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge}, + relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams}, + CliChain, +}; +use bp_polkadot_core::parachains::ParaHash; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, Chain, ChainWithTransactions, Client, Parachain, +}; +use sp_core::Pair; +use substrate_relay_helper::{ + finality::SubstrateFinalitySyncPipeline, + on_demand::{ + headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, + }, + TaggedAccount, TransactionParams, +}; + +/// A base relay between two parachain from different consensus systems. +/// +/// Such relay starts 2 messages relay. It also starts 2 on-demand header relays and 2 on-demand +/// parachain heads relay. +pub struct ParachainToParachainBridge< + L2R: MessagesCliBridge + ParachainToRelayHeadersCliBridge, + R2L: MessagesCliBridge + ParachainToRelayHeadersCliBridge, +> where + ::Source: Parachain, + ::Source: Parachain, +{ + /// Parameters that are shared by all bridge types. + pub common: + Full2WayBridgeCommonParams<::Target, ::Target>, + /// Client of the left relay chain. + pub left_relay: Client<::SourceRelay>, + /// Client of the right relay chain. + pub right_relay: Client<::SourceRelay>, + + /// Override for right_relay->left headers signer. + pub right_headers_to_left_transaction_params: + TransactionParams::Target>>, + /// Override for left_relay->right headers signer. + pub left_headers_to_right_transaction_params: + TransactionParams::Target>>, + + /// Override for right->left parachains signer. + pub right_parachains_to_left_transaction_params: + TransactionParams::Target>>, + /// Override for left->right parachains signer. + pub left_parachains_to_right_transaction_params: + TransactionParams::Target>>, +} + +macro_rules! declare_parachain_to_parachain_bridge_schema { + // left-parachain, relay-chain-of-left-parachain, right-parachain, relay-chain-of-right-parachain + ($left_parachain:ident, $left_chain:ident, $right_parachain:ident, $right_chain:ident) => { + bp_runtime::paste::item! { + #[doc = $left_parachain ", " $left_chain ", " $right_parachain " and " $right_chain " headers+parachains+messages relay params."] + #[derive(Debug, PartialEq, StructOpt)] + pub struct [<$left_parachain $right_parachain HeadersAndMessages>] { + // shared parameters + #[structopt(flatten)] + shared: HeadersAndMessagesSharedParams, + + #[structopt(flatten)] + left: [<$left_parachain ConnectionParams>], + #[structopt(flatten)] + left_relay: [<$left_chain ConnectionParams>], + + // default signer, which is always used to sign messages relay transactions on the left chain + #[structopt(flatten)] + left_sign: [<$left_parachain SigningParams>], + + #[structopt(flatten)] + right: [<$right_parachain ConnectionParams>], + #[structopt(flatten)] + right_relay: [<$right_chain ConnectionParams>], + + // default signer, which is always used to sign messages relay transactions on the right chain + #[structopt(flatten)] + right_sign: [<$right_parachain SigningParams>], + + // override for right_relay->left-parachain headers signer + #[structopt(flatten)] + right_relay_headers_to_left_sign_override: [<$right_chain HeadersTo $left_parachain SigningParams>], + // override for left_relay->right-parachain headers signer + #[structopt(flatten)] + left_relay_headers_to_right_sign_override: [<$left_chain HeadersTo $right_parachain SigningParams>], + + // override for right->left parachains signer + #[structopt(flatten)] + right_parachains_to_left_sign_override: [<$right_chain ParachainsTo $left_parachain SigningParams>], + // override for left->right parachains signer + #[structopt(flatten)] + left_parachains_to_right_sign_override: [<$left_chain ParachainsTo $right_parachain SigningParams>], + } + + impl [<$left_parachain $right_parachain HeadersAndMessages>] { + async fn into_bridge< + Left: ChainWithTransactions + CliChain + Parachain, + LeftRelay: CliChain, + Right: ChainWithTransactions + CliChain + Parachain, + RightRelay: CliChain, + L2R: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + >( + self, + ) -> anyhow::Result> { + Ok(ParachainToParachainBridge { + common: Full2WayBridgeCommonParams::new::( + self.shared, + BridgeEndCommonParams { + client: self.left.into_client::().await?, + sign: self.left_sign.to_keypair::()?, + transactions_mortality: self.left_sign.transactions_mortality()?, + accounts: vec![], + }, + BridgeEndCommonParams { + client: self.right.into_client::().await?, + sign: self.right_sign.to_keypair::()?, + transactions_mortality: self.right_sign.transactions_mortality()?, + accounts: vec![], + }, + )?, + left_relay: self.left_relay.into_client::().await?, + right_relay: self.right_relay.into_client::().await?, + right_headers_to_left_transaction_params: self + .right_relay_headers_to_left_sign_override + .transaction_params_or::(&self.left_sign)?, + left_headers_to_right_transaction_params: self + .left_relay_headers_to_right_sign_override + .transaction_params_or::(&self.right_sign)?, + right_parachains_to_left_transaction_params: self + .right_parachains_to_left_sign_override + .transaction_params_or::(&self.left_sign)?, + left_parachains_to_right_transaction_params: self + .left_parachains_to_right_sign_override + .transaction_params_or::(&self.right_sign)?, + }) + } + } + } + }; +} + +#[async_trait] +impl< + Left: Chain + ChainWithTransactions + CliChain + Parachain, + Right: Chain + ChainWithTransactions + CliChain + Parachain, + LeftRelay: Chain + + CliChain, + RightRelay: Chain + + CliChain, + L2R: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + > Full2WayBridgeBase for ParachainToParachainBridge +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, +{ + type Params = ParachainToParachainBridge; + type Left = Left; + type Right = Right; + + fn common(&self) -> &Full2WayBridgeCommonParams { + &self.common + } + + fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams { + &mut self.common + } + + async fn start_on_demand_headers_relayers( + &mut self, + ) -> anyhow::Result<( + Arc>, + Arc>, + )> { + self.common.left.accounts.push(TaggedAccount::Headers { + id: self.right_headers_to_left_transaction_params.signer.public().into(), + bridged_chain: RightRelay::NAME.to_string(), + }); + self.common.left.accounts.push(TaggedAccount::Parachains { + id: self.right_parachains_to_left_transaction_params.signer.public().into(), + bridged_chain: RightRelay::NAME.to_string(), + }); + self.common.right.accounts.push(TaggedAccount::Headers { + id: self.left_headers_to_right_transaction_params.signer.public().into(), + bridged_chain: Left::NAME.to_string(), + }); + self.common.right.accounts.push(TaggedAccount::Parachains { + id: self.left_parachains_to_right_transaction_params.signer.public().into(), + bridged_chain: LeftRelay::NAME.to_string(), + }); + + ::RelayFinality::start_relay_guards( + &self.common.right.client, + &self.left_headers_to_right_transaction_params, + self.common.right.client.can_start_version_guard(), + ) + .await?; + ::RelayFinality::start_relay_guards( + &self.common.left.client, + &self.right_headers_to_left_transaction_params, + self.common.left.client.can_start_version_guard(), + ) + .await?; + + let left_relay_to_right_on_demand_headers = + OnDemandHeadersRelay::<::RelayFinality>::new( + self.left_relay.clone(), + self.common.right.client.clone(), + self.left_headers_to_right_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + Some(self.common.metrics_params.clone()), + ); + let right_relay_to_left_on_demand_headers = + OnDemandHeadersRelay::<::RelayFinality>::new( + self.right_relay.clone(), + self.common.left.client.clone(), + self.right_headers_to_left_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + Some(self.common.metrics_params.clone()), + ); + + let left_to_right_on_demand_parachains = OnDemandParachainsRelay::< + ::ParachainFinality, + >::new( + self.left_relay.clone(), + self.common.right.client.clone(), + self.left_parachains_to_right_transaction_params.clone(), + Arc::new(left_relay_to_right_on_demand_headers), + ); + let right_to_left_on_demand_parachains = OnDemandParachainsRelay::< + ::ParachainFinality, + >::new( + self.right_relay.clone(), + self.common.left.client.clone(), + self.right_parachains_to_left_transaction_params.clone(), + Arc::new(right_relay_to_left_on_demand_headers), + ); + + Ok(( + Arc::new(left_to_right_on_demand_parachains), + Arc::new(right_to_left_on_demand_parachains), + )) + } +} diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs new file mode 100644 index 00000000000..d632cce08e9 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_parachain.rs @@ -0,0 +1,248 @@ +// Copyright 2019-2022 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 . + +use async_trait::async_trait; +use std::sync::Arc; + +use crate::cli::{ + bridge::{ + CliBridgeBase, MessagesCliBridge, ParachainToRelayHeadersCliBridge, + RelayToRelayHeadersCliBridge, + }, + relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams}, + CliChain, +}; +use bp_polkadot_core::parachains::ParaHash; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, Chain, ChainWithTransactions, Client, Parachain, +}; +use sp_core::Pair; +use substrate_relay_helper::{ + finality::SubstrateFinalitySyncPipeline, + on_demand::{ + headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, + }, + TaggedAccount, TransactionParams, +}; + +/// A base relay between standalone (relay) chain and a parachain from another consensus system. +/// +/// Such relay starts 2 messages relay. It also starts 2 on-demand header relays and 1 on-demand +/// parachain heads relay. +pub struct RelayToParachainBridge< + L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge, + R2L: MessagesCliBridge + ParachainToRelayHeadersCliBridge, +> where + ::Source: Parachain, +{ + /// Parameters that are shared by all bridge types. + pub common: + Full2WayBridgeCommonParams<::Target, ::Target>, + /// Client of the right relay chain. + pub right_relay: Client<::SourceRelay>, + + /// Override for right_relay->left headers signer. + pub right_headers_to_left_transaction_params: + TransactionParams::Target>>, + /// Override for right->left parachains signer. + pub right_parachains_to_left_transaction_params: + TransactionParams::Target>>, + /// Override for left->right headers signer. + pub left_headers_to_right_transaction_params: + TransactionParams::Target>>, +} + +macro_rules! declare_relay_to_parachain_bridge_schema { + // chain, parachain, relay-chain-of-parachain + ($left_chain:ident, $right_parachain:ident, $right_chain:ident) => { + bp_runtime::paste::item! { + #[doc = $left_chain ", " $right_parachain " and " $right_chain " headers+parachains+messages relay params."] + #[derive(Debug, PartialEq, StructOpt)] + pub struct [<$left_chain $right_parachain HeadersAndMessages>] { + // shared parameters + #[structopt(flatten)] + shared: HeadersAndMessagesSharedParams, + + #[structopt(flatten)] + left: [<$left_chain ConnectionParams>], + + // default signer, which is always used to sign messages relay transactions on the left chain + #[structopt(flatten)] + left_sign: [<$left_chain SigningParams>], + + #[structopt(flatten)] + right: [<$right_parachain ConnectionParams>], + #[structopt(flatten)] + right_relay: [<$right_chain ConnectionParams>], + + // default signer, which is always used to sign messages relay transactions on the right chain + #[structopt(flatten)] + right_sign: [<$right_parachain SigningParams>], + + // override for right_relay->left headers signer + #[structopt(flatten)] + right_relay_headers_to_left_sign_override: [<$right_chain HeadersTo $left_chain SigningParams>], + // override for left->right headers signer + #[structopt(flatten)] + left_headers_to_right_sign_override: [<$left_chain HeadersTo $right_parachain SigningParams>], + + // override for right->left parachains signer + #[structopt(flatten)] + right_parachains_to_left_sign_override: [<$right_chain ParachainsTo $left_chain SigningParams>], + } + + impl [<$left_chain $right_parachain HeadersAndMessages>] { + async fn into_bridge< + Left: ChainWithTransactions + CliChain, + Right: ChainWithTransactions + CliChain + Parachain, + RightRelay: CliChain, + L2R: CliBridgeBase + MessagesCliBridge + RelayToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + >( + self, + ) -> anyhow::Result> { + Ok(RelayToParachainBridge { + common: Full2WayBridgeCommonParams::new::( + self.shared, + BridgeEndCommonParams { + client: self.left.into_client::().await?, + sign: self.left_sign.to_keypair::()?, + transactions_mortality: self.left_sign.transactions_mortality()?, + accounts: vec![], + }, + BridgeEndCommonParams { + client: self.right.into_client::().await?, + sign: self.right_sign.to_keypair::()?, + transactions_mortality: self.right_sign.transactions_mortality()?, + accounts: vec![], + }, + )?, + right_relay: self.right_relay.into_client::().await?, + right_headers_to_left_transaction_params: self + .right_relay_headers_to_left_sign_override + .transaction_params_or::( + &self.left_sign, + )?, + right_parachains_to_left_transaction_params: self + .right_parachains_to_left_sign_override + .transaction_params_or::( + &self.left_sign, + )?, + left_headers_to_right_transaction_params: self + .left_headers_to_right_sign_override + .transaction_params_or::(&self.right_sign)?, + }) + } + } + } + }; +} + +#[async_trait] +impl< + Left: ChainWithTransactions + CliChain, + Right: Chain + ChainWithTransactions + CliChain + Parachain, + RightRelay: Chain + + CliChain, + L2R: CliBridgeBase + + MessagesCliBridge + + RelayToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + ParachainToRelayHeadersCliBridge, + > Full2WayBridgeBase for RelayToParachainBridge +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, +{ + type Params = RelayToParachainBridge; + type Left = Left; + type Right = Right; + + fn common(&self) -> &Full2WayBridgeCommonParams { + &self.common + } + + fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams { + &mut self.common + } + + async fn start_on_demand_headers_relayers( + &mut self, + ) -> anyhow::Result<( + Arc>, + Arc>, + )> { + self.common.left.accounts.push(TaggedAccount::Headers { + id: self.right_headers_to_left_transaction_params.signer.public().into(), + bridged_chain: RightRelay::NAME.to_string(), + }); + self.common.left.accounts.push(TaggedAccount::Parachains { + id: self.right_parachains_to_left_transaction_params.signer.public().into(), + bridged_chain: RightRelay::NAME.to_string(), + }); + self.common.right.accounts.push(TaggedAccount::Headers { + id: self.left_headers_to_right_transaction_params.signer.public().into(), + bridged_chain: Left::NAME.to_string(), + }); + + ::Finality::start_relay_guards( + &self.common.right.client, + &self.left_headers_to_right_transaction_params, + self.common.right.client.can_start_version_guard(), + ) + .await?; + ::RelayFinality::start_relay_guards( + &self.common.left.client, + &self.right_headers_to_left_transaction_params, + self.common.left.client.can_start_version_guard(), + ) + .await?; + + let left_to_right_on_demand_headers = + OnDemandHeadersRelay::<::Finality>::new( + self.common.left.client.clone(), + self.common.right.client.clone(), + self.left_headers_to_right_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + None, + ); + let right_relay_to_left_on_demand_headers = + OnDemandHeadersRelay::<::RelayFinality>::new( + self.right_relay.clone(), + self.common.left.client.clone(), + self.right_headers_to_left_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + Some(self.common.metrics_params.clone()), + ); + let right_to_left_on_demand_parachains = OnDemandParachainsRelay::< + ::ParachainFinality, + >::new( + self.right_relay.clone(), + self.common.left.client.clone(), + self.right_parachains_to_left_transaction_params.clone(), + Arc::new(right_relay_to_left_on_demand_headers), + ); + + Ok(( + Arc::new(left_to_right_on_demand_headers), + Arc::new(right_to_left_on_demand_parachains), + )) + } +} diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs new file mode 100644 index 00000000000..fce80492fc0 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages/relay_to_relay.rs @@ -0,0 +1,189 @@ +// Copyright 2019-2022 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 . + +use async_trait::async_trait; +use std::sync::Arc; + +use crate::cli::{ + bridge::{CliBridgeBase, MessagesCliBridge, RelayToRelayHeadersCliBridge}, + relay_headers_and_messages::{Full2WayBridgeBase, Full2WayBridgeCommonParams}, + CliChain, +}; +use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, ChainWithTransactions}; +use sp_core::Pair; +use substrate_relay_helper::{ + finality::SubstrateFinalitySyncPipeline, + on_demand::{headers::OnDemandHeadersRelay, OnDemandRelay}, + TaggedAccount, TransactionParams, +}; + +/// A base relay between two standalone (relay) chains. +/// +/// Such relay starts 2 messages relay and 2 on-demand header relays. +pub struct RelayToRelayBridge< + L2R: MessagesCliBridge + RelayToRelayHeadersCliBridge, + R2L: MessagesCliBridge + RelayToRelayHeadersCliBridge, +> { + /// Parameters that are shared by all bridge types. + pub common: + Full2WayBridgeCommonParams<::Target, ::Target>, + /// Override for right->left headers signer. + pub right_to_left_transaction_params: + TransactionParams::Target>>, + /// Override for left->right headers signer. + pub left_to_right_transaction_params: + TransactionParams::Target>>, +} + +macro_rules! declare_relay_to_relay_bridge_schema { + ($left_chain:ident, $right_chain:ident) => { + bp_runtime::paste::item! { + #[doc = $left_chain " and " $right_chain " headers+messages relay params."] + #[derive(Debug, PartialEq, StructOpt)] + pub struct [<$left_chain $right_chain HeadersAndMessages>] { + #[structopt(flatten)] + shared: HeadersAndMessagesSharedParams, + // default signer, which is always used to sign messages relay transactions on the left chain + #[structopt(flatten)] + left: [<$left_chain ConnectionParams>], + // override for right->left headers signer + #[structopt(flatten)] + right_headers_to_left_sign_override: [<$right_chain HeadersTo $left_chain SigningParams>], + #[structopt(flatten)] + left_sign: [<$left_chain SigningParams>], + // default signer, which is always used to sign messages relay transactions on the right chain + #[structopt(flatten)] + right: [<$right_chain ConnectionParams>], + // override for left->right headers signer + #[structopt(flatten)] + left_headers_to_right_sign_override: [<$left_chain HeadersTo $right_chain SigningParams>], + #[structopt(flatten)] + right_sign: [<$right_chain SigningParams>], + } + + impl [<$left_chain $right_chain HeadersAndMessages>] { + async fn into_bridge< + Left: ChainWithTransactions + CliChain, + Right: ChainWithTransactions + CliChain, + L2R: CliBridgeBase + MessagesCliBridge + RelayToRelayHeadersCliBridge, + R2L: CliBridgeBase + MessagesCliBridge + RelayToRelayHeadersCliBridge, + >( + self, + ) -> anyhow::Result> { + Ok(RelayToRelayBridge { + common: Full2WayBridgeCommonParams::new::( + self.shared, + BridgeEndCommonParams { + client: self.left.into_client::().await?, + sign: self.left_sign.to_keypair::()?, + transactions_mortality: self.left_sign.transactions_mortality()?, + accounts: vec![], + }, + BridgeEndCommonParams { + client: self.right.into_client::().await?, + sign: self.right_sign.to_keypair::()?, + transactions_mortality: self.right_sign.transactions_mortality()?, + accounts: vec![], + }, + )?, + right_to_left_transaction_params: self + .right_headers_to_left_sign_override + .transaction_params_or::(&self.left_sign)?, + left_to_right_transaction_params: self + .left_headers_to_right_sign_override + .transaction_params_or::(&self.right_sign)?, + }) + } + } + } + }; +} + +#[async_trait] +impl< + Left: ChainWithTransactions + CliChain, + Right: ChainWithTransactions + CliChain, + L2R: CliBridgeBase + + MessagesCliBridge + + RelayToRelayHeadersCliBridge, + R2L: CliBridgeBase + + MessagesCliBridge + + RelayToRelayHeadersCliBridge, + > Full2WayBridgeBase for RelayToRelayBridge +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, +{ + type Params = RelayToRelayBridge; + type Left = Left; + type Right = Right; + + fn common(&self) -> &Full2WayBridgeCommonParams { + &self.common + } + + fn mut_common(&mut self) -> &mut Full2WayBridgeCommonParams { + &mut self.common + } + + async fn start_on_demand_headers_relayers( + &mut self, + ) -> anyhow::Result<( + Arc>, + Arc>, + )> { + self.common.right.accounts.push(TaggedAccount::Headers { + id: self.left_to_right_transaction_params.signer.public().into(), + bridged_chain: Self::Left::NAME.to_string(), + }); + self.common.left.accounts.push(TaggedAccount::Headers { + id: self.right_to_left_transaction_params.signer.public().into(), + bridged_chain: Self::Right::NAME.to_string(), + }); + + ::Finality::start_relay_guards( + &self.common.right.client, + &self.left_to_right_transaction_params, + self.common.right.client.can_start_version_guard(), + ) + .await?; + ::Finality::start_relay_guards( + &self.common.left.client, + &self.right_to_left_transaction_params, + self.common.left.client.can_start_version_guard(), + ) + .await?; + + let left_to_right_on_demand_headers = + OnDemandHeadersRelay::<::Finality>::new( + self.common.left.client.clone(), + self.common.right.client.clone(), + self.left_to_right_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + None, + ); + let right_to_left_on_demand_headers = + OnDemandHeadersRelay::<::Finality>::new( + self.common.right.client.clone(), + self.common.left.client.clone(), + self.right_to_left_transaction_params.clone(), + self.common.shared.only_mandatory_headers, + None, + ); + + Ok((Arc::new(left_to_right_on_demand_headers), Arc::new(right_to_left_on_demand_headers))) + } +} diff --git a/relays/bin-substrate/src/cli/relay_messages.rs b/relays/bin-substrate/src/cli/relay_messages.rs new file mode 100644 index 00000000000..1624524e4a5 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_messages.rs @@ -0,0 +1,133 @@ +// Copyright 2019-2021 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 . + +use async_trait::async_trait; +use sp_core::Pair; +use structopt::StructOpt; +use strum::VariantNames; + +use crate::bridges::{ + kusama_polkadot::{ + bridge_hub_kusama_messages_to_bridge_hub_polkadot::BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge, + bridge_hub_polkadot_messages_to_bridge_hub_kusama::BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge, + }, + rialto_millau::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + }, + rialto_parachain_millau::{ + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, + }, + rococo_wococo::{ + bridge_hub_rococo_messages_to_bridge_hub_wococo::BridgeHubRococoToBridgeHubWococoMessagesCliBridge, + bridge_hub_wococo_messages_to_bridge_hub_rococo::BridgeHubWococoToBridgeHubRococoMessagesCliBridge, + }, +}; +use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, BalanceOf, ChainWithTransactions}; +use substrate_relay_helper::{messages_lane::MessagesRelayParams, TransactionParams}; + +use crate::cli::{bridge::*, chain_schema::*, CliChain, HexLaneId, PrometheusParams}; + +/// Start messages relayer process. +#[derive(StructOpt)] +pub struct RelayMessages { + /// A bridge instance to relay messages for. + #[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)] + bridge: FullBridge, + /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. + #[structopt(long, default_value = "00000000")] + lane: HexLaneId, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + source_sign: SourceSigningParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + #[structopt(flatten)] + prometheus_params: PrometheusParams, +} + +#[async_trait] +trait MessagesRelayer: MessagesCliBridge +where + Self::Source: ChainWithTransactions + CliChain, + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom>, +{ + async fn relay_messages(data: RelayMessages) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let source_sign = data.source_sign.to_keypair::()?; + let source_transactions_mortality = data.source_sign.transactions_mortality()?; + let target_client = data.target.into_client::().await?; + let target_sign = data.target_sign.to_keypair::()?; + let target_transactions_mortality = data.target_sign.transactions_mortality()?; + + substrate_relay_helper::messages_lane::run::(MessagesRelayParams { + source_client, + source_transaction_params: TransactionParams { + signer: source_sign, + mortality: source_transactions_mortality, + }, + target_client, + target_transaction_params: TransactionParams { + signer: target_sign, + mortality: target_transactions_mortality, + }, + source_to_target_headers_relay: None, + target_to_source_headers_relay: None, + lane_id: data.lane.into(), + metrics_params: data.prometheus_params.into_metrics_params()?, + }) + .await + .map_err(|e| anyhow::format_err!("{}", e)) + } +} + +impl MessagesRelayer for MillauToRialtoCliBridge {} +impl MessagesRelayer for RialtoToMillauCliBridge {} +impl MessagesRelayer for MillauToRialtoParachainCliBridge {} +impl MessagesRelayer for RialtoParachainToMillauCliBridge {} +impl MessagesRelayer for BridgeHubRococoToBridgeHubWococoMessagesCliBridge {} +impl MessagesRelayer for BridgeHubWococoToBridgeHubRococoMessagesCliBridge {} +impl MessagesRelayer for BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge {} +impl MessagesRelayer for BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge {} + +impl RelayMessages { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self.bridge { + FullBridge::MillauToRialto => MillauToRialtoCliBridge::relay_messages(self), + FullBridge::RialtoToMillau => RialtoToMillauCliBridge::relay_messages(self), + FullBridge::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::relay_messages(self), + FullBridge::RialtoParachainToMillau => + RialtoParachainToMillauCliBridge::relay_messages(self), + FullBridge::BridgeHubRococoToBridgeHubWococo => + BridgeHubRococoToBridgeHubWococoMessagesCliBridge::relay_messages(self), + FullBridge::BridgeHubWococoToBridgeHubRococo => + BridgeHubWococoToBridgeHubRococoMessagesCliBridge::relay_messages(self), + FullBridge::BridgeHubKusamaToBridgeHubPolkadot => + BridgeHubKusamaToBridgeHubPolkadotMessagesCliBridge::relay_messages(self), + FullBridge::BridgeHubPolkadotToBridgeHubKusama => + BridgeHubPolkadotToBridgeHubKusamaMessagesCliBridge::relay_messages(self), + } + .await + } +} diff --git a/relays/bin-substrate/src/cli/relay_parachains.rs b/relays/bin-substrate/src/cli/relay_parachains.rs new file mode 100644 index 00000000000..8c2aa1cc8c1 --- /dev/null +++ b/relays/bin-substrate/src/cli/relay_parachains.rs @@ -0,0 +1,143 @@ +// Copyright 2019-2021 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 . + +use crate::bridges::{ + kusama_polkadot::{ + kusama_parachains_to_bridge_hub_polkadot::BridgeHubKusamaToBridgeHubPolkadotCliBridge, + polkadot_parachains_to_bridge_hub_kusama::BridgeHubPolkadotToBridgeHubKusamaCliBridge, + }, + rialto_parachain_millau::rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, + rococo_wococo::{ + rococo_parachains_to_bridge_hub_wococo::BridgeHubRococoToBridgeHubWococoCliBridge, + wococo_parachains_to_bridge_hub_rococo::BridgeHubWococoToBridgeHubRococoCliBridge, + }, + westend_millau::westend_parachains_to_millau::WestmintToMillauCliBridge, +}; +use async_std::sync::Mutex; +use async_trait::async_trait; +use parachains_relay::parachains_loop::{AvailableHeader, SourceClient, TargetClient}; +use relay_substrate_client::Parachain; +use relay_utils::metrics::{GlobalMetrics, StandaloneMetric}; +use std::sync::Arc; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames, VariantNames}; +use substrate_relay_helper::{ + parachains::{source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter}, + TransactionParams, +}; + +use crate::cli::{ + bridge::{CliBridgeBase, ParachainToRelayHeadersCliBridge}, + chain_schema::*, + PrometheusParams, +}; + +/// Start parachain heads relayer process. +#[derive(StructOpt)] +pub struct RelayParachains { + /// A bridge instance to relay parachains heads for. + #[structopt(possible_values = RelayParachainsBridge::VARIANTS, case_insensitive = true)] + bridge: RelayParachainsBridge, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + #[structopt(flatten)] + prometheus_params: PrometheusParams, +} + +/// Parachain heads relay bridge. +#[derive(Debug, EnumString, EnumVariantNames)] +#[strum(serialize_all = "kebab_case")] +pub enum RelayParachainsBridge { + RialtoToMillau, + WestendToMillau, + RococoToBridgeHubWococo, + WococoToBridgeHubRococo, + KusamaToBridgeHubPolkadot, + PolkadotToBridgeHubKusama, +} + +#[async_trait] +trait ParachainsRelayer: ParachainToRelayHeadersCliBridge +where + ParachainsSource: + SourceClient>, + ParachainsTarget: + TargetClient>, + ::Source: Parachain, +{ + async fn relay_parachains(data: RelayParachains) -> anyhow::Result<()> { + let source_client = data.source.into_client::().await?; + let source_client = ParachainsSource::::new( + source_client, + Arc::new(Mutex::new(AvailableHeader::Missing)), + ); + + let target_transaction_params = TransactionParams { + signer: data.target_sign.to_keypair::()?, + mortality: data.target_sign.target_transactions_mortality, + }; + let target_client = data.target.into_client::().await?; + let target_client = ParachainsTarget::::new( + target_client.clone(), + target_transaction_params, + ); + + let metrics_params: relay_utils::metrics::MetricsParams = + data.prometheus_params.into_metrics_params()?; + GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; + + parachains_relay::parachains_loop::run( + source_client, + target_client, + metrics_params, + futures::future::pending(), + ) + .await + .map_err(|e| anyhow::format_err!("{}", e)) + } +} + +impl ParachainsRelayer for RialtoParachainToMillauCliBridge {} +impl ParachainsRelayer for WestmintToMillauCliBridge {} +impl ParachainsRelayer for BridgeHubRococoToBridgeHubWococoCliBridge {} +impl ParachainsRelayer for BridgeHubWococoToBridgeHubRococoCliBridge {} +impl ParachainsRelayer for BridgeHubKusamaToBridgeHubPolkadotCliBridge {} +impl ParachainsRelayer for BridgeHubPolkadotToBridgeHubKusamaCliBridge {} + +impl RelayParachains { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self.bridge { + RelayParachainsBridge::RialtoToMillau => + RialtoParachainToMillauCliBridge::relay_parachains(self), + RelayParachainsBridge::WestendToMillau => + WestmintToMillauCliBridge::relay_parachains(self), + RelayParachainsBridge::RococoToBridgeHubWococo => + BridgeHubRococoToBridgeHubWococoCliBridge::relay_parachains(self), + RelayParachainsBridge::WococoToBridgeHubRococo => + BridgeHubWococoToBridgeHubRococoCliBridge::relay_parachains(self), + RelayParachainsBridge::KusamaToBridgeHubPolkadot => + BridgeHubKusamaToBridgeHubPolkadotCliBridge::relay_parachains(self), + RelayParachainsBridge::PolkadotToBridgeHubKusama => + BridgeHubPolkadotToBridgeHubKusamaCliBridge::relay_parachains(self), + } + .await + } +} diff --git a/relays/bin-substrate/src/cli/resubmit_transactions.rs b/relays/bin-substrate/src/cli/resubmit_transactions.rs new file mode 100644 index 00000000000..c5b20e939c1 --- /dev/null +++ b/relays/bin-substrate/src/cli/resubmit_transactions.rs @@ -0,0 +1,560 @@ +// Copyright 2019-2021 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 . + +use crate::cli::{chain_schema::*, Balance}; + +use bp_runtime::HeaderIdProvider; +use codec::{Decode, Encode}; +use num_traits::{One, Zero}; +use relay_substrate_client::{ + AccountKeyPairOf, BlockWithJustification, Chain, ChainWithTransactions, Client, + Error as SubstrateError, HeaderIdOf, HeaderOf, SignParam, +}; +use relay_utils::FailedClient; +use sp_core::Bytes; +use sp_runtime::{ + traits::{Hash, Header as HeaderT}, + transaction_validity::TransactionPriority, +}; +use structopt::StructOpt; +use strum::{EnumString, EnumVariantNames, VariantNames}; +use substrate_relay_helper::TransactionParams; + +/// Start resubmit transactions process. +#[derive(StructOpt)] +pub struct ResubmitTransactions { + /// A bridge instance to relay headers for. + #[structopt(possible_values = RelayChain::VARIANTS, case_insensitive = true)] + chain: RelayChain, + #[structopt(flatten)] + target: TargetConnectionParams, + #[structopt(flatten)] + target_sign: TargetSigningParams, + /// Number of blocks we see before considering queued transaction as stalled. + #[structopt(long, default_value = "5")] + stalled_blocks: u32, + /// Tip limit. We'll never submit transaction with larger tip. + #[structopt(long)] + tip_limit: Balance, + /// Tip increase step. We'll be checking updated transaction priority by increasing its tip by + /// this step. + #[structopt(long)] + tip_step: Balance, + /// Priority selection strategy. + #[structopt(subcommand)] + strategy: PrioritySelectionStrategy, +} + +/// Chain, which transactions we're going to track && resubmit. +#[derive(Debug, EnumString, EnumVariantNames)] +#[strum(serialize_all = "kebab_case")] +pub enum RelayChain { + Millau, +} + +/// Strategy to use for priority selection. +#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy)] +pub enum PrioritySelectionStrategy { + /// Strategy selects tip that changes transaction priority to be better than priority of + /// the first transaction of previous block. + /// + /// It only makes sense to use this strategy for Millau transactions. Millau has transactions + /// that are close to block limits, so if there are any other queued transactions, 'large' + /// transaction won't fit the block && will be postponed. To avoid this, we change its priority + /// to some large value, making it best transaction => it'll be 'mined' first. + MakeItBestTransaction, + /// Strategy selects tip that changes transaction priority to be better than priority of + /// selected queued transaction. + /// + /// When we first see stalled transaction, we make it better than worst 1/4 of queued + /// transactions. If it is still stalled, we'll make it better than 1/3 of queued transactions, + /// ... + MakeItBetterThanQueuedTransaction, +} + +macro_rules! select_bridge { + ($bridge: expr, $generic: tt) => { + match $bridge { + RelayChain::Millau => { + type Target = relay_millau_client::Millau; + + $generic + }, + } + }; +} + +impl ResubmitTransactions { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + select_bridge!(self.chain, { + let relay_loop_name = format!("ResubmitTransactions{}", Target::NAME); + let client = self.target.into_client::().await?; + let transaction_params = TransactionParams { + signer: self.target_sign.to_keypair::()?, + mortality: self.target_sign.target_transactions_mortality, + }; + + relay_utils::relay_loop((), client) + .run(relay_loop_name, move |_, client, _| { + run_until_connection_lost( + client, + transaction_params.clone(), + Context { + strategy: self.strategy, + best_header: HeaderOf::::new( + Default::default(), + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ), + transaction: None, + resubmitted: 0, + stalled_for: Zero::zero(), + stalled_for_limit: self.stalled_blocks as _, + tip_step: self.tip_step.cast() as _, + tip_limit: self.tip_limit.cast() as _, + }, + ) + }) + .await + .map_err(Into::into) + }) + } +} + +impl PrioritySelectionStrategy { + /// Select target priority. + async fn select_target_priority( + &self, + client: &Client, + context: &Context, + ) -> Result, SubstrateError> { + match *self { + PrioritySelectionStrategy::MakeItBestTransaction => + read_previous_block_best_priority(client, context).await, + PrioritySelectionStrategy::MakeItBetterThanQueuedTransaction => + select_priority_from_queue(client, context).await, + } + } +} + +#[derive(Debug)] +struct Context { + /// Priority selection strategy. + strategy: PrioritySelectionStrategy, + /// Best known block header. + best_header: C::Header, + /// Hash of the (potentially) stalled transaction. + transaction: Option, + /// How many times we have resubmitted this `transaction`? + resubmitted: u32, + /// This transaction is in pool for `stalled_for` wakeup intervals. + stalled_for: C::BlockNumber, + /// When `stalled_for` reaching this limit, transaction is considered stalled. + stalled_for_limit: C::BlockNumber, + /// Tip step interval. + tip_step: C::Balance, + /// Maximal tip. + tip_limit: C::Balance, +} + +impl Context { + /// Return true if transaction has stalled. + fn is_stalled(&self) -> bool { + self.stalled_for >= self.stalled_for_limit + } + + /// Notice resubmitted transaction. + fn notice_resubmitted_transaction(mut self, transaction: C::Hash) -> Self { + self.transaction = Some(transaction); + self.stalled_for = Zero::zero(); + self.resubmitted += 1; + self + } + + /// Notice transaction from the transaction pool. + fn notice_transaction(mut self, transaction: C::Hash) -> Self { + if self.transaction == Some(transaction) { + self.stalled_for += One::one(); + } else { + self.transaction = Some(transaction); + self.stalled_for = One::one(); + self.resubmitted = 0; + } + self + } +} + +/// Run resubmit transactions loop. +async fn run_until_connection_lost( + client: Client, + transaction_params: TransactionParams>, + mut context: Context, +) -> Result<(), FailedClient> { + loop { + async_std::task::sleep(C::AVERAGE_BLOCK_INTERVAL).await; + + let result = run_loop_iteration(client.clone(), transaction_params.clone(), context).await; + context = match result { + Ok(context) => context, + Err(error) => { + log::error!( + target: "bridge", + "Resubmit {} transactions loop has failed with error: {:?}", + C::NAME, + error, + ); + return Err(FailedClient::Target) + }, + }; + } +} + +/// Run single loop iteration. +async fn run_loop_iteration( + client: Client, + transaction_params: TransactionParams>, + mut context: Context, +) -> Result, SubstrateError> { + // correct best header is required for all other actions + context.best_header = client.best_header().await?; + + // check if there's queued transaction, signed by given author + let original_transaction = + match lookup_signer_transaction(&client, &transaction_params.signer).await? { + Some(original_transaction) => original_transaction, + None => { + log::trace!(target: "bridge", "No {} transactions from required signer in the txpool", C::NAME); + return Ok(context) + }, + }; + let original_transaction_hash = C::Hasher::hash(&original_transaction.encode()); + let context = context.notice_transaction(original_transaction_hash); + + // if transaction hasn't been mined for `stalled_blocks`, we'll need to resubmit it + if !context.is_stalled() { + log::trace!( + target: "bridge", + "{} transaction {:?} is not yet stalled ({:?}/{:?})", + C::NAME, + context.transaction, + context.stalled_for, + context.stalled_for_limit, + ); + return Ok(context) + } + + // select priority for updated transaction + let target_priority = match context.strategy.select_target_priority(&client, &context).await? { + Some(target_priority) => target_priority, + None => { + log::trace!(target: "bridge", "Failed to select target priority"); + return Ok(context) + }, + }; + + // update transaction tip + let (is_updated, updated_transaction) = update_transaction_tip( + &client, + &transaction_params, + context.best_header.id(), + original_transaction, + context.tip_step, + context.tip_limit, + target_priority, + ) + .await?; + + if !is_updated { + log::trace!(target: "bridge", "{} transaction tip can not be updated. Reached limit?", C::NAME); + return Ok(context) + } + + let updated_transaction = updated_transaction.encode(); + let updated_transaction_hash = C::Hasher::hash(&updated_transaction); + client.submit_unsigned_extrinsic(Bytes(updated_transaction)).await?; + + log::info!( + target: "bridge", + "Replaced {} transaction {} with {} in txpool", + C::NAME, + original_transaction_hash, + updated_transaction_hash, + ); + + Ok(context.notice_resubmitted_transaction(updated_transaction_hash)) +} + +/// Search transaction pool for transaction, signed by given key pair. +async fn lookup_signer_transaction( + client: &Client, + key_pair: &AccountKeyPairOf, +) -> Result, SubstrateError> { + let pending_transactions = client.pending_extrinsics().await?; + for pending_transaction in pending_transactions { + let pending_transaction = C::SignedTransaction::decode(&mut &pending_transaction.0[..]) + .map_err(SubstrateError::ResponseParseFailed)?; + if !C::is_signed_by(key_pair, &pending_transaction) { + continue + } + + return Ok(Some(pending_transaction)) + } + + Ok(None) +} + +/// Read priority of best signed transaction of previous block. +async fn read_previous_block_best_priority( + client: &Client, + context: &Context, +) -> Result, SubstrateError> { + let best_block = client.get_block(Some(context.best_header.hash())).await?; + let best_transaction = best_block + .extrinsics() + .iter() + .filter_map(|xt| C::SignedTransaction::decode(&mut &xt[..]).ok()) + .find(|xt| C::is_signed(xt)); + match best_transaction { + Some(best_transaction) => Ok(Some( + client + .validate_transaction(*context.best_header.parent_hash(), best_transaction) + .await?? + .priority, + )), + None => Ok(None), + } +} + +/// Select priority of some queued transaction. +async fn select_priority_from_queue( + client: &Client, + context: &Context, +) -> Result, SubstrateError> { + // select transaction from the queue + let queued_transactions = client.pending_extrinsics().await?; + let selected_transaction = match select_transaction_from_queue(queued_transactions, context) { + Some(selected_transaction) => selected_transaction, + None => return Ok(None), + }; + + let selected_transaction = C::SignedTransaction::decode(&mut &selected_transaction[..]) + .map_err(SubstrateError::ResponseParseFailed)?; + let target_priority = client + .validate_transaction(context.best_header.hash(), selected_transaction) + .await?? + .priority; + Ok(Some(target_priority)) +} + +/// Select transaction with target priority from the vec of queued transactions. +fn select_transaction_from_queue( + mut queued_transactions: Vec, + context: &Context, +) -> Option { + if queued_transactions.is_empty() { + return None + } + + // the more times we resubmit transaction (`context.resubmitted`), the closer we move + // to the front of the transaction queue + let total_transactions = queued_transactions.len(); + let resubmitted_factor = context.resubmitted; + let divisor = + 1usize.saturating_add(1usize.checked_shl(resubmitted_factor).unwrap_or(usize::MAX)); + let transactions_to_skip = total_transactions / divisor; + + Some( + queued_transactions + .swap_remove(std::cmp::min(total_transactions - 1, transactions_to_skip)), + ) +} + +/// Try to find appropriate tip for transaction so that its priority is larger than given. +async fn update_transaction_tip( + client: &Client, + transaction_params: &TransactionParams>, + at_block: HeaderIdOf, + tx: C::SignedTransaction, + tip_step: C::Balance, + tip_limit: C::Balance, + target_priority: TransactionPriority, +) -> Result<(bool, C::SignedTransaction), SubstrateError> { + let stx = format!("{tx:?}"); + let mut current_priority = client.validate_transaction(at_block.1, tx.clone()).await??.priority; + let mut unsigned_tx = C::parse_transaction(tx).ok_or_else(|| { + SubstrateError::Custom(format!("Failed to parse {} transaction {stx}", C::NAME,)) + })?; + let old_tip = unsigned_tx.tip; + + let runtime_version = client.simple_runtime_version().await?; + while current_priority < target_priority { + let next_tip = unsigned_tx.tip + tip_step; + if next_tip > tip_limit { + break + } + + log::trace!( + target: "bridge", + "{} transaction priority with tip={:?}: {}. Target priority: {}", + C::NAME, + unsigned_tx.tip, + current_priority, + target_priority, + ); + + unsigned_tx.tip = next_tip; + current_priority = client + .validate_transaction( + at_block.1, + C::sign_transaction( + SignParam { + spec_version: runtime_version.spec_version, + transaction_version: runtime_version.transaction_version, + genesis_hash: *client.genesis_hash(), + signer: transaction_params.signer.clone(), + }, + unsigned_tx.clone(), + )?, + ) + .await?? + .priority; + } + + log::debug!( + target: "bridge", + "{} transaction tip has changed from {:?} to {:?}", + C::NAME, + old_tip, + unsigned_tx.tip, + ); + + Ok(( + old_tip != unsigned_tx.tip, + C::sign_transaction( + SignParam { + spec_version: runtime_version.spec_version, + transaction_version: runtime_version.transaction_version, + genesis_hash: *client.genesis_hash(), + signer: transaction_params.signer.clone(), + }, + unsigned_tx.era(relay_substrate_client::TransactionEra::new( + at_block, + transaction_params.mortality, + )), + )?, + )) +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_rialto::Hash; + use relay_rialto_client::Rialto; + + fn context() -> Context { + Context { + strategy: PrioritySelectionStrategy::MakeItBestTransaction, + best_header: HeaderOf::::new( + Default::default(), + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ), + transaction: None, + resubmitted: 0, + stalled_for: Zero::zero(), + stalled_for_limit: 3, + tip_step: 100, + tip_limit: 1000, + } + } + + #[test] + fn context_works() { + let mut context = context(); + + // when transaction is noticed 2/3 times, it isn't stalled + context = context.notice_transaction(Default::default()); + assert!(!context.is_stalled()); + assert_eq!(context.stalled_for, 1); + assert_eq!(context.resubmitted, 0); + context = context.notice_transaction(Default::default()); + assert!(!context.is_stalled()); + assert_eq!(context.stalled_for, 2); + assert_eq!(context.resubmitted, 0); + + // when transaction is noticed for 3rd time in a row, it is considered stalled + context = context.notice_transaction(Default::default()); + assert!(context.is_stalled()); + assert_eq!(context.stalled_for, 3); + assert_eq!(context.resubmitted, 0); + + // and after we resubmit it, we forget previous transaction + context = context.notice_resubmitted_transaction(Hash::from([1; 32])); + assert_eq!(context.transaction, Some(Hash::from([1; 32]))); + assert_eq!(context.resubmitted, 1); + assert_eq!(context.stalled_for, 0); + } + + #[test] + fn select_transaction_from_queue_works_with_empty_queue() { + assert_eq!(select_transaction_from_queue(vec![], &context()), None); + } + + #[test] + fn select_transaction_from_queue_works() { + let mut context = context(); + let queued_transactions = vec![ + Bytes(vec![1]), + Bytes(vec![2]), + Bytes(vec![3]), + Bytes(vec![4]), + Bytes(vec![5]), + Bytes(vec![6]), + ]; + + // when we resubmit tx for the first time, 1/2 of queue is skipped + assert_eq!( + select_transaction_from_queue(queued_transactions.clone(), &context), + Some(Bytes(vec![4])), + ); + + // when we resubmit tx for the second time, 1/3 of queue is skipped + context = context.notice_resubmitted_transaction(Hash::from([1; 32])); + assert_eq!( + select_transaction_from_queue(queued_transactions.clone(), &context), + Some(Bytes(vec![3])), + ); + + // when we resubmit tx for the third time, 1/5 of queue is skipped + context = context.notice_resubmitted_transaction(Hash::from([2; 32])); + assert_eq!( + select_transaction_from_queue(queued_transactions.clone(), &context), + Some(Bytes(vec![2])), + ); + + // when we resubmit tx for the second time, 1/9 of queue is skipped + context = context.notice_resubmitted_transaction(Hash::from([3; 32])); + assert_eq!( + select_transaction_from_queue(queued_transactions, &context), + Some(Bytes(vec![1])), + ); + } +} diff --git a/relays/bin-substrate/src/cli/send_message.rs b/relays/bin-substrate/src/cli/send_message.rs new file mode 100644 index 00000000000..8f76e501f69 --- /dev/null +++ b/relays/bin-substrate/src/cli/send_message.rs @@ -0,0 +1,187 @@ +// Copyright 2019-2021 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 . + +use crate::{ + bridges::{ + rialto_millau::{ + millau_headers_to_rialto::MillauToRialtoCliBridge, + rialto_headers_to_millau::RialtoToMillauCliBridge, + }, + rialto_parachain_millau::{ + millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge, + rialto_parachains_to_millau::RialtoParachainToMillauCliBridge, + }, + }, + cli::{ + bridge::{FullBridge, MessagesCliBridge}, + chain_schema::*, + encode_message::{self, CliEncodeMessage, RawMessage}, + CliChain, + }, +}; +use async_trait::async_trait; +use codec::{Decode, Encode}; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, Chain, ChainBase, ChainWithTransactions, UnsignedTransaction, +}; +use sp_core::Pair; +use sp_runtime::AccountId32; +use std::fmt::Display; +use structopt::StructOpt; +use strum::VariantNames; + +/// Send bridge message. +#[derive(StructOpt)] +pub struct SendMessage { + /// A bridge instance to encode call for. + #[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)] + bridge: FullBridge, + #[structopt(flatten)] + source: SourceConnectionParams, + #[structopt(flatten)] + source_sign: SourceSigningParams, + /// Message type. + #[structopt(subcommand)] + message: crate::cli::encode_message::Message, +} + +#[async_trait] +trait MessageSender: MessagesCliBridge +where + Self::Source: ChainBase + ChainWithTransactions + CliChain + CliEncodeMessage, + ::Balance: Display + From + Into, + ::Call: Sync, + ::SignedTransaction: Sync, + AccountIdOf: From< as Pair>::Public>, + AccountId32: From< as Pair>::Public>, +{ + async fn send_message(data: SendMessage) -> anyhow::Result<()> { + let payload = encode_message::encode_message::(&data.message)?; + + let source_client = data.source.into_client::().await?; + let source_sign = data.source_sign.to_keypair::()?; + + let payload_len = payload.encoded_size(); + let send_message_call = Self::Source::encode_execute_xcm(decode_xcm(payload)?)?; + + source_client + .submit_signed_extrinsic(&source_sign, move |_, transaction_nonce| { + let unsigned = UnsignedTransaction::new(send_message_call, transaction_nonce); + log::info!( + target: "bridge", + "Sending message to {}. Size: {}", + Self::Target::NAME, + payload_len, + ); + Ok(unsigned) + }) + .await?; + + Ok(()) + } +} + +impl MessageSender for MillauToRialtoCliBridge {} +impl MessageSender for RialtoToMillauCliBridge {} +impl MessageSender for MillauToRialtoParachainCliBridge {} +impl MessageSender for RialtoParachainToMillauCliBridge {} + +impl SendMessage { + /// Run the command. + pub async fn run(self) -> anyhow::Result<()> { + match self.bridge { + FullBridge::MillauToRialto => MillauToRialtoCliBridge::send_message(self), + FullBridge::RialtoToMillau => RialtoToMillauCliBridge::send_message(self), + FullBridge::MillauToRialtoParachain => + MillauToRialtoParachainCliBridge::send_message(self), + FullBridge::RialtoParachainToMillau => + RialtoParachainToMillauCliBridge::send_message(self), + FullBridge::BridgeHubRococoToBridgeHubWococo => unimplemented!( + "Sending message from BridgeHubRococo to BridgeHubWococo is not supported" + ), + FullBridge::BridgeHubWococoToBridgeHubRococo => unimplemented!( + "Sending message from BridgeHubWococo to BridgeHubRococo is not supported" + ), + FullBridge::BridgeHubKusamaToBridgeHubPolkadot => unimplemented!( + "Sending message from BridgeHubKusama to BridgeHubPolkadot is not supported" + ), + FullBridge::BridgeHubPolkadotToBridgeHubKusama => unimplemented!( + "Sending message from BridgeHubPolkadot to BridgeHubKusama is not supported" + ), + } + .await + } +} + +/// Decode SCALE encoded raw XCM message. +pub(crate) fn decode_xcm(message: RawMessage) -> anyhow::Result> { + Decode::decode(&mut &message[..]) + .map_err(|e| anyhow::format_err!("Failed to decode XCM program: {:?}", e)) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::cli::{ExplicitOrMaximal, HexBytes}; + + #[test] + fn send_raw_rialto_to_millau() { + // given + let send_message = SendMessage::from_iter(vec![ + "send-message", + "rialto-to-millau", + "--source-port", + "1234", + "--source-signer", + "//Alice", + "raw", + "dead", + ]); + + // then + assert_eq!(send_message.bridge, FullBridge::RialtoToMillau); + assert_eq!(send_message.source.source_port, 1234); + assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into())); + assert_eq!( + send_message.message, + crate::cli::encode_message::Message::Raw { data: HexBytes(vec![0xDE, 0xAD]) } + ); + } + + #[test] + fn send_sized_rialto_to_millau() { + // given + let send_message = SendMessage::from_iter(vec![ + "send-message", + "rialto-to-millau", + "--source-port", + "1234", + "--source-signer", + "//Alice", + "sized", + "max", + ]); + + // then + assert_eq!(send_message.bridge, FullBridge::RialtoToMillau); + assert_eq!(send_message.source.source_port, 1234); + assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into())); + assert_eq!( + send_message.message, + crate::cli::encode_message::Message::Sized { size: ExplicitOrMaximal::Maximal } + ); + } +} diff --git a/relays/bin-substrate/src/main.rs b/relays/bin-substrate/src/main.rs new file mode 100644 index 00000000000..33a423b0766 --- /dev/null +++ b/relays/bin-substrate/src/main.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2021 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 . + +//! Substrate-to-substrate relay entrypoint. + +#![warn(missing_docs)] + +mod bridges; +mod chains; +mod cli; + +fn main() { + let command = cli::parse_args(); + let run = command.run(); + async_std::task::block_on(run); +} diff --git a/relays/client-bridge-hub-kusama/Cargo.toml b/relays/client-bridge-hub-kusama/Cargo.toml new file mode 100644 index 00000000000..96650710f67 --- /dev/null +++ b/relays/client-bridge-hub-kusama/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "relay-bridge-hub-kusama-client" +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", features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +relay-substrate-client = { path = "../client-substrate" } + +# Bridge dependencies + +bp-bridge-hub-kusama = { path = "../../primitives/chain-bridge-hub-kusama" } +bp-bridge-hub-polkadot = { path = "../../primitives/chain-bridge-hub-polkadot" } +bp-header-chain = { path = "../../primitives/header-chain" } +bp-messages = { path = "../../primitives/messages" } +bp-parachains = { path = "../../primitives/parachains" } +bp-runtime = { path = "../../primitives/runtime" } +bp-polkadot = { path = "../../primitives/chain-polkadot" } + +bridge-runtime-common = { path = "../../bin/runtime-common" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-bridge-hub-kusama/src/lib.rs b/relays/client-bridge-hub-kusama/src/lib.rs new file mode 100644 index 00000000000..6549a32ca79 --- /dev/null +++ b/relays/client-bridge-hub-kusama/src/lib.rs @@ -0,0 +1,162 @@ +// Copyright 2022 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 . + +//! Types used to connect to the BridgeHub-Kusama-Substrate parachain. + +use bp_bridge_hub_kusama::{BridgeHubSignedExtension, AVERAGE_BLOCK_INTERVAL}; +use bp_messages::MessageNonce; +use bp_runtime::ChainId; +use codec::Encode; +use relay_substrate_client::{ + Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions, ChainWithUtilityPallet, + Error as SubstrateError, MockedRuntimeUtilityPallet, SignParam, UnderlyingChainProvider, + UnsignedTransaction, +}; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use std::time::Duration; + +/// Re-export runtime wrapper +pub mod runtime_wrapper; +pub use runtime_wrapper as runtime; + +/// Kusama chain definition +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct BridgeHubKusama; + +impl UnderlyingChainProvider for BridgeHubKusama { + type Chain = bp_bridge_hub_kusama::BridgeHubKusama; +} + +impl Chain for BridgeHubKusama { + const ID: ChainId = bp_runtime::BRIDGE_HUB_KUSAMA_CHAIN_ID; + const NAME: &'static str = "BridgeHubKusama"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_bridge_hub_kusama::BEST_FINALIZED_BRIDGE_HUB_KUSAMA_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = AVERAGE_BLOCK_INTERVAL; + + type SignedBlock = bp_bridge_hub_kusama::SignedBlock; + type Call = runtime::Call; +} + +impl ChainWithBalances for BridgeHubKusama { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + bp_bridge_hub_kusama::AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +impl ChainWithUtilityPallet for BridgeHubKusama { + type UtilityPallet = MockedRuntimeUtilityPallet; +} + +impl ChainWithTransactions for BridgeHubKusama { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = runtime::UncheckedExtrinsic; + + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { + let raw_payload = SignedPayload::new( + unsigned.call, + runtime::SignedExtension::from_params( + param.spec_version, + param.transaction_version, + unsigned.era, + param.genesis_hash, + unsigned.nonce, + unsigned.tip, + ), + )?; + + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); + let (call, extra, _) = raw_payload.deconstruct(); + + Ok(runtime::UncheckedExtrinsic::new_signed( + call, + signer.into_account().into(), + signature.into(), + extra, + )) + } + + fn is_signed(tx: &Self::SignedTransaction) -> bool { + tx.signature.is_some() + } + + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { + tx.signature + .as_ref() + .map(|(address, _, _)| { + *address == bp_bridge_hub_kusama::Address::Id(signer.public().into()) + }) + .unwrap_or(false) + } + + fn parse_transaction(tx: Self::SignedTransaction) -> Option> { + let extra = &tx.signature.as_ref()?.2; + Some(UnsignedTransaction::new(tx.function, extra.nonce()).tip(extra.tip())) + } +} + +impl ChainWithMessages for BridgeHubKusama { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_bridge_hub_kusama::WITH_BRIDGE_HUB_KUSAMA_MESSAGES_PALLET_NAME; + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = + Some(bp_bridge_hub_kusama::WITH_BRIDGE_HUB_KUSAMA_RELAYERS_PALLET_NAME); + + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_bridge_hub_kusama::TO_BRIDGE_HUB_KUSAMA_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_bridge_hub_kusama::FROM_BRIDGE_HUB_KUSAMA_MESSAGE_DETAILS_METHOD; + + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_bridge_hub_kusama::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_bridge_hub_kusama::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; +} + +#[cfg(test)] +mod tests { + use super::*; + use relay_substrate_client::TransactionEra; + + #[test] + fn parse_transaction_works() { + let unsigned = UnsignedTransaction { + call: runtime::Call::System(relay_substrate_client::calls::SystemCall::remark( + b"Hello world!".to_vec(), + )) + .into(), + nonce: 777, + tip: 888, + era: TransactionEra::immortal(), + }; + let signed_transaction = BridgeHubKusama::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 32].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) + .unwrap(); + let parsed_transaction = BridgeHubKusama::parse_transaction(signed_transaction).unwrap(); + assert_eq!(parsed_transaction, unsigned); + } +} diff --git a/relays/client-bridge-hub-kusama/src/runtime_wrapper.rs b/relays/client-bridge-hub-kusama/src/runtime_wrapper.rs new file mode 100644 index 00000000000..18bdafc0f04 --- /dev/null +++ b/relays/client-bridge-hub-kusama/src/runtime_wrapper.rs @@ -0,0 +1,74 @@ +// Copyright 2019-2021 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 . + +//! Types that are specific to the BridgeHubKusama runtime. +// TODO: regenerate me using `runtime-codegen` tool? (https://github.com/paritytech/parity-bridges-common/issues/1945) + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +pub use bp_bridge_hub_kusama::SignedExtension; +pub use bp_header_chain::BridgeGrandpaCallOf; +pub use bp_parachains::BridgeParachainCall; +pub use bridge_runtime_common::messages::BridgeMessagesCallOf; +pub use relay_substrate_client::calls::{SystemCall, UtilityCall}; + +/// Unchecked BridgeHubKusama extrinsic. +pub type UncheckedExtrinsic = bp_bridge_hub_kusama::UncheckedExtrinsic; + +// The indirect pallet call used to sync `Polkadot` GRANDPA finality to `BHKusama`. +pub type BridgePolkadotGrandpaCall = BridgeGrandpaCallOf; +// The indirect pallet call used to sync `BridgeHubPolkadot` messages to `BHKusama`. +pub type BridgePolkadotMessagesCall = + BridgeMessagesCallOf; + +/// `BridgeHubKusama` Runtime `Call` enum. +/// +/// The enum represents a subset of possible `Call`s we can send to `BridgeHubKusama` 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 +/// `BridgeHubKusama` `construct_runtime`, so that we maintain SCALE-compatibility. +#[allow(clippy::large_enum_variant)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum Call { + #[cfg(test)] + #[codec(index = 0)] + System(SystemCall), + /// Utility pallet. + #[codec(index = 40)] + Utility(UtilityCall), + + /// Polkadot bridge pallet. + // TODO: the index is wrong (https://github.com/paritytech/parity-bridges-common/issues/1945) + #[codec(index = 41)] + BridgePolkadotGrandpa(BridgePolkadotGrandpaCall), + /// Polkadot parachain bridge pallet. + // TODO: the index is wrong (https://github.com/paritytech/parity-bridges-common/issues/1945) + #[codec(index = 42)] + BridgePolkadotParachain(BridgeParachainCall), + /// Polkadot messages bridge pallet. + // TODO: the index is wrong (https://github.com/paritytech/parity-bridges-common/issues/1945) + #[codec(index = 46)] + BridgePolkadotMessages(BridgePolkadotMessagesCall), +} + +impl From> for Call { + fn from(call: UtilityCall) -> Call { + Call::Utility(call) + } +} diff --git a/relays/client-bridge-hub-polkadot/Cargo.toml b/relays/client-bridge-hub-polkadot/Cargo.toml new file mode 100644 index 00000000000..6126a8f2b3f --- /dev/null +++ b/relays/client-bridge-hub-polkadot/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "relay-bridge-hub-polkadot-client" +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", features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +relay-substrate-client = { path = "../client-substrate" } + +# Bridge dependencies + +bp-bridge-hub-kusama = { path = "../../primitives/chain-bridge-hub-kusama" } +bp-bridge-hub-polkadot = { path = "../../primitives/chain-bridge-hub-polkadot" } +bp-header-chain = { path = "../../primitives/header-chain" } +bp-messages = { path = "../../primitives/messages" } +bp-parachains = { path = "../../primitives/parachains" } +bp-kusama = { path = "../../primitives/chain-kusama" } +bp-runtime = { path = "../../primitives/runtime" } + +bridge-runtime-common = { path = "../../bin/runtime-common" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[dev-dependencies] +bp-polkadot-core = { path = "../../primitives/polkadot-core" } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-bridge-hub-polkadot/src/lib.rs b/relays/client-bridge-hub-polkadot/src/lib.rs new file mode 100644 index 00000000000..6428b055dd5 --- /dev/null +++ b/relays/client-bridge-hub-polkadot/src/lib.rs @@ -0,0 +1,160 @@ +// Copyright 2022 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 . + +//! Types used to connect to the BridgeHub-Polkadot-Substrate parachain. + +use bp_bridge_hub_polkadot::{BridgeHubSignedExtension, AVERAGE_BLOCK_INTERVAL}; +use bp_messages::MessageNonce; +use bp_runtime::ChainId; +use codec::Encode; +use relay_substrate_client::{ + Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions, ChainWithUtilityPallet, + Error as SubstrateError, MockedRuntimeUtilityPallet, SignParam, UnderlyingChainProvider, + UnsignedTransaction, +}; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use std::time::Duration; + +/// Re-export runtime wrapper +pub mod runtime_wrapper; +pub use runtime_wrapper as runtime; + +/// Polkadot chain definition +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct BridgeHubPolkadot; + +impl UnderlyingChainProvider for BridgeHubPolkadot { + type Chain = bp_bridge_hub_polkadot::BridgeHubPolkadot; +} + +impl Chain for BridgeHubPolkadot { + const ID: ChainId = bp_runtime::BRIDGE_HUB_POLKADOT_CHAIN_ID; + const NAME: &'static str = "BridgeHubPolkadot"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_bridge_hub_polkadot::BEST_FINALIZED_BRIDGE_HUB_POLKADOT_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = AVERAGE_BLOCK_INTERVAL; + + type SignedBlock = bp_bridge_hub_polkadot::SignedBlock; + type Call = runtime::Call; +} + +impl ChainWithBalances for BridgeHubPolkadot { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + bp_bridge_hub_polkadot::AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +impl ChainWithUtilityPallet for BridgeHubPolkadot { + type UtilityPallet = MockedRuntimeUtilityPallet; +} + +impl ChainWithTransactions for BridgeHubPolkadot { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = runtime::UncheckedExtrinsic; + + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { + let raw_payload = SignedPayload::new( + unsigned.call, + runtime::SignedExtension::from_params( + param.spec_version, + param.transaction_version, + unsigned.era, + param.genesis_hash, + unsigned.nonce, + unsigned.tip, + ), + )?; + + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); + let (call, extra, _) = raw_payload.deconstruct(); + + Ok(runtime::UncheckedExtrinsic::new_signed( + call, + signer.into_account().into(), + signature.into(), + extra, + )) + } + + fn is_signed(tx: &Self::SignedTransaction) -> bool { + tx.signature.is_some() + } + + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { + tx.signature + .as_ref() + .map(|(address, _, _)| { + *address == bp_bridge_hub_polkadot::Address::Id(signer.public().into()) + }) + .unwrap_or(false) + } + + fn parse_transaction(tx: Self::SignedTransaction) -> Option> { + let extra = &tx.signature.as_ref()?.2; + Some(UnsignedTransaction::new(tx.function, extra.nonce()).tip(extra.tip())) + } +} + +impl ChainWithMessages for BridgeHubPolkadot { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_bridge_hub_polkadot::WITH_BRIDGE_HUB_POLKADOT_MESSAGES_PALLET_NAME; + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = + Some(bp_bridge_hub_polkadot::WITH_BRIDGE_HUB_POLKADOT_RELAYERS_PALLET_NAME); + + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_bridge_hub_polkadot::TO_BRIDGE_HUB_POLKADOT_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_bridge_hub_polkadot::FROM_BRIDGE_HUB_POLKADOT_MESSAGE_DETAILS_METHOD; + + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_bridge_hub_polkadot::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_bridge_hub_polkadot::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; +} + +#[cfg(test)] +mod tests { + use super::*; + use relay_substrate_client::TransactionEra; + + #[test] + fn parse_transaction_works() { + let unsigned = UnsignedTransaction { + call: runtime::Call::System(runtime::SystemCall::remark(b"Hello world!".to_vec())) + .into(), + nonce: 777, + tip: 888, + era: TransactionEra::immortal(), + }; + let signed_transaction = BridgeHubPolkadot::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 32].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) + .unwrap(); + let parsed_transaction = BridgeHubPolkadot::parse_transaction(signed_transaction).unwrap(); + assert_eq!(parsed_transaction, unsigned); + } +} diff --git a/relays/client-bridge-hub-polkadot/src/runtime_wrapper.rs b/relays/client-bridge-hub-polkadot/src/runtime_wrapper.rs new file mode 100644 index 00000000000..5afac61dbb3 --- /dev/null +++ b/relays/client-bridge-hub-polkadot/src/runtime_wrapper.rs @@ -0,0 +1,119 @@ +// Copyright 2019-2021 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 . + +//! Types that are specific to the BridgeHubPolkadot runtime. +// TODO: regenerate me using `runtime-codegen` tool? (https://github.com/paritytech/parity-bridges-common/issues/1945) + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +pub use bp_bridge_hub_polkadot::SignedExtension; +pub use bp_header_chain::BridgeGrandpaCallOf; +pub use bp_parachains::BridgeParachainCall; +pub use bridge_runtime_common::messages::BridgeMessagesCallOf; +pub use relay_substrate_client::calls::{SystemCall, UtilityCall}; + +/// Unchecked BridgeHubPolkadot extrinsic. +pub type UncheckedExtrinsic = bp_bridge_hub_polkadot::UncheckedExtrinsic; + +// The indirect pallet call used to sync `Kusama` GRANDPA finality to `BHPolkadot`. +pub type BridgeKusamaGrandpaCall = BridgeGrandpaCallOf; +// The indirect pallet call used to sync `BridgeHubKusama` messages to `BridgeHubPolkadot`. +pub type BridgeKusamaMessagesCall = BridgeMessagesCallOf; + +/// `BridgeHubPolkadot` Runtime `Call` enum. +/// +/// The enum represents a subset of possible `Call`s we can send to `BridgeHubPolkadot` 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 +/// `BridgeHubPolkadot` `construct_runtime`, so that we maintain SCALE-compatibility. +#[allow(clippy::large_enum_variant)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum Call { + #[cfg(test)] + #[codec(index = 0)] + System(SystemCall), + /// Utility pallet. + #[codec(index = 40)] + Utility(UtilityCall), + + /// Kusama bridge pallet. + // TODO: the index is wrong (https://github.com/paritytech/parity-bridges-common/issues/1945) + #[codec(index = 43)] + BridgeKusamaGrandpa(BridgeKusamaGrandpaCall), + /// Kusama parachain bridge pallet. + // TODO: the index is wrong (https://github.com/paritytech/parity-bridges-common/issues/1945) + #[codec(index = 44)] + BridgeKusamaParachain(BridgeParachainCall), + /// Kusama messages bridge pallet. + // TODO: the index is wrong (https://github.com/paritytech/parity-bridges-common/issues/1945) + #[codec(index = 45)] + BridgeKusamaMessages(BridgeKusamaMessagesCall), +} + +impl From> for Call { + fn from(call: UtilityCall) -> Call { + Call::Utility(call) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_runtime::BasicOperatingMode; + use sp_consensus_grandpa::AuthorityList; + use sp_core::hexdisplay::HexDisplay; + use sp_runtime::traits::Header; + use std::str::FromStr; + + pub type RelayBlockNumber = bp_polkadot_core::BlockNumber; + pub type RelayBlockHasher = bp_polkadot_core::Hasher; + pub type RelayBlockHeader = sp_runtime::generic::Header; + + #[test] + fn encode_decode_calls() { + let header = RelayBlockHeader::new( + 75, + bp_polkadot_core::Hash::from_str( + "0xd2c0afaab32de0cb8f7f0d89217e37c5ea302c1ffb5a7a83e10d20f12c32874d", + ) + .expect("invalid value"), + bp_polkadot_core::Hash::from_str( + "0x92b965f0656a4e0e5fc0167da2d4b5ee72b3be2c1583c4c1e5236c8c12aa141b", + ) + .expect("invalid value"), + bp_polkadot_core::Hash::from_str( + "0xae4a25acf250d72ed02c149ecc7dd3c9ee976d41a2888fc551de8064521dc01d", + ) + .expect("invalid value"), + Default::default(), + ); + let init_data = bp_header_chain::InitializationData { + header: Box::new(header), + authority_list: AuthorityList::default(), + set_id: 6, + operating_mode: BasicOperatingMode::Normal, + }; + let call = BridgeKusamaGrandpaCall::initialize { init_data }; + let tx = Call::BridgeKusamaGrandpa(call); + + // encode call as hex string + let hex_encoded_call = format!("0x{:?}", HexDisplay::from(&Encode::encode(&tx))); + assert_eq!(hex_encoded_call, "0x2b01ae4a25acf250d72ed02c149ecc7dd3c9ee976d41a2888fc551de8064521dc01d2d0192b965f0656a4e0e5fc0167da2d4b5ee72b3be2c1583c4c1e5236c8c12aa141bd2c0afaab32de0cb8f7f0d89217e37c5ea302c1ffb5a7a83e10d20f12c32874d0000060000000000000000"); + } +} diff --git a/relays/client-bridge-hub-rococo/Cargo.toml b/relays/client-bridge-hub-rococo/Cargo.toml new file mode 100644 index 00000000000..48df2e56cf0 --- /dev/null +++ b/relays/client-bridge-hub-rococo/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "relay-bridge-hub-rococo-client" +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", features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +relay-substrate-client = { path = "../client-substrate" } + +# Bridge dependencies + +bp-bridge-hub-rococo = { path = "../../primitives/chain-bridge-hub-rococo" } +bp-bridge-hub-wococo = { path = "../../primitives/chain-bridge-hub-wococo" } +bp-header-chain = { path = "../../primitives/header-chain" } +bp-messages = { path = "../../primitives/messages" } +bp-parachains = { path = "../../primitives/parachains" } +bp-runtime = { path = "../../primitives/runtime" } +bp-wococo = { path = "../../primitives/chain-wococo" } + +bridge-runtime-common = { path = "../../bin/runtime-common" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-bridge-hub-rococo/src/lib.rs b/relays/client-bridge-hub-rococo/src/lib.rs new file mode 100644 index 00000000000..bc2ec3aca41 --- /dev/null +++ b/relays/client-bridge-hub-rococo/src/lib.rs @@ -0,0 +1,162 @@ +// Copyright 2022 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 . + +//! Types used to connect to the BridgeHub-Rococo-Substrate parachain. + +use bp_bridge_hub_rococo::{BridgeHubSignedExtension, AVERAGE_BLOCK_INTERVAL}; +use bp_messages::MessageNonce; +use bp_runtime::ChainId; +use codec::Encode; +use relay_substrate_client::{ + Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions, ChainWithUtilityPallet, + Error as SubstrateError, MockedRuntimeUtilityPallet, SignParam, UnderlyingChainProvider, + UnsignedTransaction, +}; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use std::time::Duration; + +/// Re-export runtime wrapper +pub mod runtime_wrapper; +pub use runtime_wrapper as runtime; + +/// Rococo chain definition +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct BridgeHubRococo; + +impl UnderlyingChainProvider for BridgeHubRococo { + type Chain = bp_bridge_hub_rococo::BridgeHubRococo; +} + +impl Chain for BridgeHubRococo { + const ID: ChainId = bp_runtime::BRIDGE_HUB_ROCOCO_CHAIN_ID; + const NAME: &'static str = "BridgeHubRococo"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_bridge_hub_rococo::BEST_FINALIZED_BRIDGE_HUB_ROCOCO_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = AVERAGE_BLOCK_INTERVAL; + + type SignedBlock = bp_bridge_hub_rococo::SignedBlock; + type Call = runtime::Call; +} + +impl ChainWithBalances for BridgeHubRococo { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + bp_bridge_hub_rococo::AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +impl ChainWithUtilityPallet for BridgeHubRococo { + type UtilityPallet = MockedRuntimeUtilityPallet; +} + +impl ChainWithTransactions for BridgeHubRococo { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = runtime::UncheckedExtrinsic; + + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { + let raw_payload = SignedPayload::new( + unsigned.call, + runtime::SignedExtension::from_params( + param.spec_version, + param.transaction_version, + unsigned.era, + param.genesis_hash, + unsigned.nonce, + unsigned.tip, + ), + )?; + + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); + let (call, extra, _) = raw_payload.deconstruct(); + + Ok(runtime::UncheckedExtrinsic::new_signed( + call, + signer.into_account().into(), + signature.into(), + extra, + )) + } + + fn is_signed(tx: &Self::SignedTransaction) -> bool { + tx.signature.is_some() + } + + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { + tx.signature + .as_ref() + .map(|(address, _, _)| { + *address == bp_bridge_hub_rococo::Address::Id(signer.public().into()) + }) + .unwrap_or(false) + } + + fn parse_transaction(tx: Self::SignedTransaction) -> Option> { + let extra = &tx.signature.as_ref()?.2; + Some(UnsignedTransaction::new(tx.function, extra.nonce()).tip(extra.tip())) + } +} + +impl ChainWithMessages for BridgeHubRococo { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_MESSAGES_PALLET_NAME; + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = + Some(bp_bridge_hub_rococo::WITH_BRIDGE_HUB_ROCOCO_RELAYERS_PALLET_NAME); + + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_bridge_hub_rococo::TO_BRIDGE_HUB_ROCOCO_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_bridge_hub_rococo::FROM_BRIDGE_HUB_ROCOCO_MESSAGE_DETAILS_METHOD; + + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_bridge_hub_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; +} + +#[cfg(test)] +mod tests { + use super::*; + use relay_substrate_client::TransactionEra; + + #[test] + fn parse_transaction_works() { + let unsigned = UnsignedTransaction { + call: runtime::Call::System(relay_substrate_client::calls::SystemCall::remark( + b"Hello world!".to_vec(), + )) + .into(), + nonce: 777, + tip: 888, + era: TransactionEra::immortal(), + }; + let signed_transaction = BridgeHubRococo::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 32].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) + .unwrap(); + let parsed_transaction = BridgeHubRococo::parse_transaction(signed_transaction).unwrap(); + assert_eq!(parsed_transaction, unsigned); + } +} diff --git a/relays/client-bridge-hub-rococo/src/runtime_wrapper.rs b/relays/client-bridge-hub-rococo/src/runtime_wrapper.rs new file mode 100644 index 00000000000..26e0bd9da5e --- /dev/null +++ b/relays/client-bridge-hub-rococo/src/runtime_wrapper.rs @@ -0,0 +1,69 @@ +// Copyright 2019-2021 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 . + +//! Types that are specific to the BridgeHubRococo runtime. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +pub use bp_bridge_hub_rococo::SignedExtension; +pub use bp_header_chain::BridgeGrandpaCallOf; +pub use bp_parachains::BridgeParachainCall; +pub use bridge_runtime_common::messages::BridgeMessagesCallOf; +pub use relay_substrate_client::calls::{SystemCall, UtilityCall}; + +/// Unchecked BridgeHubRococo extrinsic. +pub type UncheckedExtrinsic = bp_bridge_hub_rococo::UncheckedExtrinsic; + +// The indirect pallet call used to sync `Wococo` GRANDPA finality to `BHRococo`. +pub type BridgeWococoGrandpaCall = BridgeGrandpaCallOf; +// The indirect pallet call used to sync `BridgeHubWococo` messages to `BHRococo`. +pub type BridgeWococoMessagesCall = BridgeMessagesCallOf; + +/// `BridgeHubRococo` Runtime `Call` enum. +/// +/// The enum represents a subset of possible `Call`s we can send to `BridgeHubRococo` 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 +/// `BridgeHubRococo` `construct_runtime`, so that we maintain SCALE-compatibility. +#[allow(clippy::large_enum_variant)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum Call { + #[cfg(test)] + #[codec(index = 0)] + System(SystemCall), + /// Utility pallet. + #[codec(index = 40)] + Utility(UtilityCall), + + /// Wococo bridge pallet. + #[codec(index = 41)] + BridgeWococoGrandpa(BridgeWococoGrandpaCall), + /// Wococo parachain bridge pallet. + #[codec(index = 42)] + BridgeWococoParachain(BridgeParachainCall), + /// Wococo messages bridge pallet. + #[codec(index = 46)] + BridgeWococoMessages(BridgeWococoMessagesCall), +} + +impl From> for Call { + fn from(call: UtilityCall) -> Call { + Call::Utility(call) + } +} diff --git a/relays/client-bridge-hub-wococo/Cargo.toml b/relays/client-bridge-hub-wococo/Cargo.toml new file mode 100644 index 00000000000..d4578fcd488 --- /dev/null +++ b/relays/client-bridge-hub-wococo/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "relay-bridge-hub-wococo-client" +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", features = ["derive"] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +relay-substrate-client = { path = "../client-substrate" } + +# Bridge dependencies + +bp-bridge-hub-rococo = { path = "../../primitives/chain-bridge-hub-rococo" } +bp-bridge-hub-wococo = { path = "../../primitives/chain-bridge-hub-wococo" } +bp-header-chain = { path = "../../primitives/header-chain" } +bp-messages = { path = "../../primitives/messages" } +bp-parachains = { path = "../../primitives/parachains" } +bp-rococo = { path = "../../primitives/chain-rococo" } +bp-runtime = { path = "../../primitives/runtime" } + +bridge-runtime-common = { path = "../../bin/runtime-common" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[dev-dependencies] +bp-polkadot-core = { path = "../../primitives/polkadot-core" } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-bridge-hub-wococo/src/lib.rs b/relays/client-bridge-hub-wococo/src/lib.rs new file mode 100644 index 00000000000..c9acc47dd95 --- /dev/null +++ b/relays/client-bridge-hub-wococo/src/lib.rs @@ -0,0 +1,160 @@ +// Copyright 2022 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 . + +//! Types used to connect to the BridgeHub-Wococo-Substrate parachain. + +use bp_bridge_hub_wococo::{BridgeHubSignedExtension, AVERAGE_BLOCK_INTERVAL}; +use bp_messages::MessageNonce; +use bp_runtime::ChainId; +use codec::Encode; +use relay_substrate_client::{ + Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions, ChainWithUtilityPallet, + Error as SubstrateError, MockedRuntimeUtilityPallet, SignParam, UnderlyingChainProvider, + UnsignedTransaction, +}; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use std::time::Duration; + +/// Re-export runtime wrapper +pub mod runtime_wrapper; +pub use runtime_wrapper as runtime; + +/// Wococo chain definition +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct BridgeHubWococo; + +impl UnderlyingChainProvider for BridgeHubWococo { + type Chain = bp_bridge_hub_wococo::BridgeHubWococo; +} + +impl Chain for BridgeHubWococo { + const ID: ChainId = bp_runtime::BRIDGE_HUB_WOCOCO_CHAIN_ID; + const NAME: &'static str = "BridgeHubWococo"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_bridge_hub_wococo::BEST_FINALIZED_BRIDGE_HUB_WOCOCO_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = AVERAGE_BLOCK_INTERVAL; + + type SignedBlock = bp_bridge_hub_wococo::SignedBlock; + type Call = runtime::Call; +} + +impl ChainWithBalances for BridgeHubWococo { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + bp_bridge_hub_wococo::AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +impl ChainWithUtilityPallet for BridgeHubWococo { + type UtilityPallet = MockedRuntimeUtilityPallet; +} + +impl ChainWithTransactions for BridgeHubWococo { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = runtime::UncheckedExtrinsic; + + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { + let raw_payload = SignedPayload::new( + unsigned.call, + runtime::SignedExtension::from_params( + param.spec_version, + param.transaction_version, + unsigned.era, + param.genesis_hash, + unsigned.nonce, + unsigned.tip, + ), + )?; + + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); + let (call, extra, _) = raw_payload.deconstruct(); + + Ok(runtime::UncheckedExtrinsic::new_signed( + call, + signer.into_account().into(), + signature.into(), + extra, + )) + } + + fn is_signed(tx: &Self::SignedTransaction) -> bool { + tx.signature.is_some() + } + + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { + tx.signature + .as_ref() + .map(|(address, _, _)| { + *address == bp_bridge_hub_wococo::Address::Id(signer.public().into()) + }) + .unwrap_or(false) + } + + fn parse_transaction(tx: Self::SignedTransaction) -> Option> { + let extra = &tx.signature.as_ref()?.2; + Some(UnsignedTransaction::new(tx.function, extra.nonce()).tip(extra.tip())) + } +} + +impl ChainWithMessages for BridgeHubWococo { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_MESSAGES_PALLET_NAME; + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = + Some(bp_bridge_hub_wococo::WITH_BRIDGE_HUB_WOCOCO_RELAYERS_PALLET_NAME); + + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_bridge_hub_wococo::TO_BRIDGE_HUB_WOCOCO_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_bridge_hub_wococo::FROM_BRIDGE_HUB_WOCOCO_MESSAGE_DETAILS_METHOD; + + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_bridge_hub_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_bridge_hub_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; +} + +#[cfg(test)] +mod tests { + use super::*; + use relay_substrate_client::TransactionEra; + + #[test] + fn parse_transaction_works() { + let unsigned = UnsignedTransaction { + call: runtime::Call::System(runtime::SystemCall::remark(b"Hello world!".to_vec())) + .into(), + nonce: 777, + tip: 888, + era: TransactionEra::immortal(), + }; + let signed_transaction = BridgeHubWococo::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 32].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) + .unwrap(); + let parsed_transaction = BridgeHubWococo::parse_transaction(signed_transaction).unwrap(); + assert_eq!(parsed_transaction, unsigned); + } +} diff --git a/relays/client-bridge-hub-wococo/src/runtime_wrapper.rs b/relays/client-bridge-hub-wococo/src/runtime_wrapper.rs new file mode 100644 index 00000000000..b9803955922 --- /dev/null +++ b/relays/client-bridge-hub-wococo/src/runtime_wrapper.rs @@ -0,0 +1,115 @@ +// Copyright 2019-2021 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 . + +//! Types that are specific to the BridgeHubWococo runtime. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; + +pub use bp_bridge_hub_wococo::SignedExtension; +pub use bp_header_chain::BridgeGrandpaCallOf; +pub use bp_parachains::BridgeParachainCall; +pub use bridge_runtime_common::messages::BridgeMessagesCallOf; +pub use relay_substrate_client::calls::{SystemCall, UtilityCall}; + +/// Unchecked BridgeHubWococo extrinsic. +pub type UncheckedExtrinsic = bp_bridge_hub_wococo::UncheckedExtrinsic; + +// The indirect pallet call used to sync `Rococo` GRANDPA finality to `BHWococo`. +pub type BridgeRococoGrandpaCall = BridgeGrandpaCallOf; +// The indirect pallet call used to sync `BridgeHubRococo` messages to `BridgeHubWococo`. +pub type BridgeRococoMessagesCall = BridgeMessagesCallOf; + +/// `BridgeHubWococo` Runtime `Call` enum. +/// +/// The enum represents a subset of possible `Call`s we can send to `BridgeHubWococo` 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 +/// `BridgeHubWococo` `construct_runtime`, so that we maintain SCALE-compatibility. +#[allow(clippy::large_enum_variant)] +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +pub enum Call { + #[cfg(test)] + #[codec(index = 0)] + System(SystemCall), + /// Utility pallet. + #[codec(index = 40)] + Utility(UtilityCall), + + /// Rococo bridge pallet. + #[codec(index = 43)] + BridgeRococoGrandpa(BridgeRococoGrandpaCall), + /// Rococo parachain bridge pallet. + #[codec(index = 44)] + BridgeRococoParachain(BridgeParachainCall), + /// Rococo messages bridge pallet. + #[codec(index = 45)] + BridgeRococoMessages(BridgeRococoMessagesCall), +} + +impl From> for Call { + fn from(call: UtilityCall) -> Call { + Call::Utility(call) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_runtime::BasicOperatingMode; + use sp_consensus_grandpa::AuthorityList; + use sp_core::hexdisplay::HexDisplay; + use sp_runtime::traits::Header; + use std::str::FromStr; + + pub type RelayBlockNumber = bp_polkadot_core::BlockNumber; + pub type RelayBlockHasher = bp_polkadot_core::Hasher; + pub type RelayBlockHeader = sp_runtime::generic::Header; + + #[test] + fn encode_decode_calls() { + let header = RelayBlockHeader::new( + 75, + bp_polkadot_core::Hash::from_str( + "0xd2c0afaab32de0cb8f7f0d89217e37c5ea302c1ffb5a7a83e10d20f12c32874d", + ) + .expect("invalid value"), + bp_polkadot_core::Hash::from_str( + "0x92b965f0656a4e0e5fc0167da2d4b5ee72b3be2c1583c4c1e5236c8c12aa141b", + ) + .expect("invalid value"), + bp_polkadot_core::Hash::from_str( + "0xae4a25acf250d72ed02c149ecc7dd3c9ee976d41a2888fc551de8064521dc01d", + ) + .expect("invalid value"), + Default::default(), + ); + let init_data = bp_header_chain::InitializationData { + header: Box::new(header), + authority_list: AuthorityList::default(), + set_id: 6, + operating_mode: BasicOperatingMode::Normal, + }; + let call = BridgeRococoGrandpaCall::initialize { init_data }; + let tx = Call::BridgeRococoGrandpa(call); + + // encode call as hex string + let hex_encoded_call = format!("0x{:?}", HexDisplay::from(&Encode::encode(&tx))); + assert_eq!(hex_encoded_call, "0x2b01ae4a25acf250d72ed02c149ecc7dd3c9ee976d41a2888fc551de8064521dc01d2d0192b965f0656a4e0e5fc0167da2d4b5ee72b3be2c1583c4c1e5236c8c12aa141bd2c0afaab32de0cb8f7f0d89217e37c5ea302c1ffb5a7a83e10d20f12c32874d0000060000000000000000"); + } +} diff --git a/relays/client-kusama/Cargo.toml b/relays/client-kusama/Cargo.toml new file mode 100644 index 00000000000..302f530eb4e --- /dev/null +++ b/relays/client-kusama/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "relay-kusama-client" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-kusama = { path = "../../primitives/chain-kusama" } +bp-runtime = { path = "../../primitives/runtime" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-kusama/src/lib.rs b/relays/client-kusama/src/lib.rs new file mode 100644 index 00000000000..99a52b4baf4 --- /dev/null +++ b/relays/client-kusama/src/lib.rs @@ -0,0 +1,60 @@ +// Copyright 2019-2021 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 . + +//! Types used to connect to the Kusama chain. + +use bp_kusama::AccountInfoStorageMapKeyProvider; +use bp_runtime::ChainId; +use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider}; +use sp_core::storage::StorageKey; +use std::time::Duration; + +/// Kusama header id. +pub type HeaderId = relay_utils::HeaderId; + +/// Kusama header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; + +/// Kusama chain definition +#[derive(Debug, Clone, Copy)] +pub struct Kusama; + +impl UnderlyingChainProvider for Kusama { + type Chain = bp_kusama::Kusama; +} + +impl Chain for Kusama { + const ID: ChainId = bp_runtime::KUSAMA_CHAIN_ID; + const NAME: &'static str = "Kusama"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); + + type SignedBlock = bp_kusama::SignedBlock; + type Call = (); +} + +impl ChainWithBalances for Kusama { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +impl RelayChain for Kusama { + const PARAS_PALLET_NAME: &'static str = bp_kusama::PARAS_PALLET_NAME; + // TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945) + const PARACHAINS_FINALITY_PALLET_NAME: &'static str = "BridgeKusamaParachain"; +} diff --git a/relays/client-millau/Cargo.toml b/relays/client-millau/Cargo.toml new file mode 100644 index 00000000000..fe5482e5b67 --- /dev/null +++ b/relays/client-millau/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "relay-millau-client" +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" } +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } + +# Supported Chains + +bp-messages = { path = "../../primitives/messages" } +bp-millau = { path = "../../primitives/chain-millau" } +bp-runtime = { path = "../../primitives/runtime" } +millau-runtime = { path = "../../bin/millau/runtime" } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-millau/src/lib.rs b/relays/client-millau/src/lib.rs new file mode 100644 index 00000000000..ce42d004bb8 --- /dev/null +++ b/relays/client-millau/src/lib.rs @@ -0,0 +1,188 @@ +// Copyright 2019-2021 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 . + +//! Types used to connect to the Millau-Substrate chain. + +use bp_messages::MessageNonce; +use bp_runtime::ChainId; +use codec::{Compact, Decode, Encode}; +use relay_substrate_client::{ + BalanceOf, Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions, + ChainWithUtilityPallet, Error as SubstrateError, FullRuntimeUtilityPallet, IndexOf, SignParam, + UnderlyingChainProvider, UnsignedTransaction, +}; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use std::time::Duration; + +/// Millau header id. +pub type HeaderId = relay_utils::HeaderId; + +/// Millau chain definition. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Millau; + +impl UnderlyingChainProvider for Millau { + type Chain = bp_millau::Millau; +} + +impl ChainWithMessages for Millau { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; + // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): change the name + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = Some("BridgeRelayers"); + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_millau::FROM_MILLAU_MESSAGE_DETAILS_METHOD; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; +} + +impl Chain for Millau { + const ID: ChainId = bp_runtime::MILLAU_CHAIN_ID; + const NAME: &'static str = "Millau"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); + + type SignedBlock = millau_runtime::SignedBlock; + type Call = millau_runtime::RuntimeCall; +} + +impl ChainWithBalances for Millau { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + use frame_support::storage::generator::StorageMap; + StorageKey(frame_system::Account::::storage_map_final_key( + account_id, + )) + } +} + +impl ChainWithTransactions for Millau { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = millau_runtime::UncheckedExtrinsic; + + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { + let raw_payload = SignedPayload::from_raw( + unsigned.call.clone(), + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(unsigned.era.frame_era()), + frame_system::CheckNonce::::from(unsigned.nonce), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(unsigned.tip), + millau_runtime::BridgeRejectObsoleteHeadersAndMessages, + millau_runtime::BridgeRefundRialtoParachainMessages::default(), + ), + ( + (), + param.spec_version, + param.transaction_version, + param.genesis_hash, + unsigned.era.signed_payload(param.genesis_hash), + (), + (), + (), + (), + () + ), + ); + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); + let (call, extra, _) = raw_payload.deconstruct(); + + Ok(millau_runtime::UncheckedExtrinsic::new_signed( + call.into_decoded()?, + signer.into_account(), + signature.into(), + extra, + )) + } + + fn is_signed(tx: &Self::SignedTransaction) -> bool { + tx.signature.is_some() + } + + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { + tx.signature + .as_ref() + .map(|(address, _, _)| { + *address == millau_runtime::Address::from(*signer.public().as_array_ref()) + }) + .unwrap_or(false) + } + + fn parse_transaction(tx: Self::SignedTransaction) -> Option> { + let extra = &tx.signature.as_ref()?.2; + Some( + UnsignedTransaction::new( + tx.function.into(), + Compact::>::decode(&mut &extra.5.encode()[..]).ok()?.into(), + ) + .tip(Compact::>::decode(&mut &extra.7.encode()[..]).ok()?.into()), + ) + } +} + +impl ChainWithUtilityPallet for Millau { + type UtilityPallet = FullRuntimeUtilityPallet; +} + +/// Millau signing params. +pub type SigningParams = sp_core::sr25519::Pair; + +/// Millau header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; + +#[cfg(test)] +mod tests { + use super::*; + use relay_substrate_client::TransactionEra; + + #[test] + fn parse_transaction_works() { + let unsigned = UnsignedTransaction { + call: millau_runtime::RuntimeCall::System(millau_runtime::SystemCall::remark { + remark: b"Hello world!".to_vec(), + }) + .into(), + nonce: 777, + tip: 888, + era: TransactionEra::immortal(), + }; + let signed_transaction = Millau::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 64].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) + .unwrap(); + let parsed_transaction = Millau::parse_transaction(signed_transaction).unwrap(); + assert_eq!(parsed_transaction, unsigned); + } +} diff --git a/relays/client-polkadot/Cargo.toml b/relays/client-polkadot/Cargo.toml new file mode 100644 index 00000000000..0d3a30949cb --- /dev/null +++ b/relays/client-polkadot/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "relay-polkadot-client" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-polkadot = { path = "../../primitives/chain-polkadot" } +bp-runtime = { path = "../../primitives/runtime" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-polkadot/src/lib.rs b/relays/client-polkadot/src/lib.rs new file mode 100644 index 00000000000..7f8615e0cd0 --- /dev/null +++ b/relays/client-polkadot/src/lib.rs @@ -0,0 +1,60 @@ +// Copyright 2019-2021 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 . + +//! Types used to connect to the Polkadot chain. + +use bp_polkadot::AccountInfoStorageMapKeyProvider; +use bp_runtime::ChainId; +use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider}; +use sp_core::storage::StorageKey; +use std::time::Duration; + +/// Polkadot header id. +pub type HeaderId = relay_utils::HeaderId; + +/// Polkadot header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; + +/// Polkadot chain definition +#[derive(Debug, Clone, Copy)] +pub struct Polkadot; + +impl UnderlyingChainProvider for Polkadot { + type Chain = bp_polkadot::Polkadot; +} + +impl Chain for Polkadot { + const ID: ChainId = bp_runtime::POLKADOT_CHAIN_ID; + const NAME: &'static str = "Polkadot"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); + + type SignedBlock = bp_polkadot::SignedBlock; + type Call = (); +} + +impl ChainWithBalances for Polkadot { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +impl RelayChain for Polkadot { + const PARAS_PALLET_NAME: &'static str = bp_polkadot::PARAS_PALLET_NAME; + // TODO: check me (https://github.com/paritytech/parity-bridges-common/issues/1945) + const PARACHAINS_FINALITY_PALLET_NAME: &'static str = "BridgePolkadotParachain"; +} diff --git a/relays/client-rialto-parachain/Cargo.toml b/relays/client-rialto-parachain/Cargo.toml new file mode 100644 index 00000000000..4450dee3711 --- /dev/null +++ b/relays/client-rialto-parachain/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "relay-rialto-parachain-client" +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" } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +subxt = { version = "0.27.1", default-features = false, features = [] } + +# Bridge dependencies + +bp-bridge-hub-cumulus = { path = "../../primitives/chain-bridge-hub-cumulus" } +bp-header-chain = { path = "../../primitives/header-chain" } +bp-messages = { path = "../../primitives/messages" } +bp-millau = { path = "../../primitives/chain-millau" } +bp-polkadot-core = { path = "../../primitives/polkadot-core" } +bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" } +bp-runtime = { path = "../../primitives/runtime" } + +bridge-runtime-common = { path = "../../bin/runtime-common" } +relay-substrate-client = { path = "../client-substrate" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-weights = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-rialto-parachain/src/codegen_runtime.rs b/relays/client-rialto-parachain/src/codegen_runtime.rs new file mode 100644 index 00000000000..3ea4a0ac2b5 --- /dev/null +++ b/relays/client-rialto-parachain/src/codegen_runtime.rs @@ -0,0 +1,10210 @@ +// Copyright 2019-2023 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 . + +//! Autogenerated runtime API +//! THIS FILE WAS AUTOGENERATED USING parity-bridges-common::runtime-codegen +//! EXECUTED COMMAND: target/debug/runtime-codegen --from-node-url http://localhost:20433 + +#[allow(dead_code, unused_imports, non_camel_case_types)] +#[allow(clippy::all)] +pub mod api { + use super::api as root_mod; + pub static PALLETS: [&str; 16usize] = [ + "System", + "Timestamp", + "Sudo", + "TransactionPayment", + "ParachainSystem", + "ParachainInfo", + "Balances", + "Aura", + "AuraExt", + "XcmpQueue", + "PolkadotXcm", + "CumulusXcm", + "DmpQueue", + "BridgeRelayers", + "BridgeMillauGrandpa", + "BridgeMillauMessages", + ]; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum Event { + #[codec(index = 0)] + System(system::Event), + #[codec(index = 2)] + Sudo(sudo::Event), + #[codec(index = 3)] + TransactionPayment(transaction_payment::Event), + #[codec(index = 20)] + ParachainSystem(parachain_system::Event), + #[codec(index = 30)] + Balances(balances::Event), + #[codec(index = 50)] + XcmpQueue(xcmp_queue::Event), + #[codec(index = 51)] + PolkadotXcm(polkadot_xcm::Event), + #[codec(index = 52)] + CumulusXcm(cumulus_xcm::Event), + #[codec(index = 53)] + DmpQueue(dmp_queue::Event), + #[codec(index = 54)] + BridgeRelayers(bridge_relayers::Event), + #[codec(index = 55)] + BridgeMillauGrandpa(bridge_millau_grandpa::Event), + #[codec(index = 56)] + BridgeMillauMessages(bridge_millau_messages::Event), + } + pub mod system { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Remark { + pub remark: ::std::vec::Vec<::core::primitive::u8>, + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct SetHeapPages { + pub pages: ::core::primitive::u64, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetCode { + pub code: ::std::vec::Vec<::core::primitive::u8>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetCodeWithoutChecks { + pub code: ::std::vec::Vec<::core::primitive::u8>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetStorage { + pub items: ::std::vec::Vec<( + ::std::vec::Vec<::core::primitive::u8>, + ::std::vec::Vec<::core::primitive::u8>, + )>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct KillStorage { + pub keys: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct KillPrefix { + pub prefix: ::std::vec::Vec<::core::primitive::u8>, + pub subkeys: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct RemarkWithEvent { + pub remark: ::std::vec::Vec<::core::primitive::u8>, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Make some on-chain remark."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- `O(1)`"] + pub fn remark( + &self, + remark: ::std::vec::Vec<::core::primitive::u8>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "System", + "remark", + Remark { remark }, + [ + 101u8, 80u8, 195u8, 226u8, 224u8, 247u8, 60u8, 128u8, 3u8, 101u8, 51u8, + 147u8, 96u8, 126u8, 76u8, 230u8, 194u8, 227u8, 191u8, 73u8, 160u8, + 146u8, 87u8, 147u8, 243u8, 28u8, 228u8, 116u8, 224u8, 181u8, 129u8, + 160u8, + ], + ) + } + #[doc = "Set the number of pages in the WebAssembly environment's heap."] + pub fn set_heap_pages( + &self, + pages: ::core::primitive::u64, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "System", + "set_heap_pages", + SetHeapPages { pages }, + [ + 43u8, 103u8, 128u8, 49u8, 156u8, 136u8, 11u8, 204u8, 80u8, 6u8, 244u8, + 86u8, 171u8, 44u8, 140u8, 225u8, 142u8, 198u8, 43u8, 87u8, 26u8, 45u8, + 125u8, 222u8, 165u8, 254u8, 172u8, 158u8, 39u8, 178u8, 86u8, 87u8, + ], + ) + } + #[doc = "Set the new runtime code."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- `O(C + S)` where `C` length of `code` and `S` complexity of `can_set_code`"] + pub fn set_code( + &self, + code: ::std::vec::Vec<::core::primitive::u8>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "System", + "set_code", + SetCode { code }, + [ + 27u8, 104u8, 244u8, 205u8, 188u8, 254u8, 121u8, 13u8, 106u8, 120u8, + 244u8, 108u8, 97u8, 84u8, 100u8, 68u8, 26u8, 69u8, 93u8, 128u8, 107u8, + 4u8, 3u8, 142u8, 13u8, 134u8, 196u8, 62u8, 113u8, 181u8, 14u8, 40u8, + ], + ) + } + #[doc = "Set the new runtime code without doing any checks of the given `code`."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- `O(C)` where `C` length of `code`"] + pub fn set_code_without_checks( + &self, + code: ::std::vec::Vec<::core::primitive::u8>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "System", + "set_code_without_checks", + SetCodeWithoutChecks { code }, + [ + 102u8, 160u8, 125u8, 235u8, 30u8, 23u8, 45u8, 239u8, 112u8, 148u8, + 159u8, 158u8, 42u8, 93u8, 206u8, 94u8, 80u8, 250u8, 66u8, 195u8, 60u8, + 40u8, 142u8, 169u8, 183u8, 80u8, 80u8, 96u8, 3u8, 231u8, 99u8, 216u8, + ], + ) + } + #[doc = "Set some items of storage."] + pub fn set_storage( + &self, + items: ::std::vec::Vec<( + ::std::vec::Vec<::core::primitive::u8>, + ::std::vec::Vec<::core::primitive::u8>, + )>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "System", + "set_storage", + SetStorage { items }, + [ + 74u8, 43u8, 106u8, 255u8, 50u8, 151u8, 192u8, 155u8, 14u8, 90u8, 19u8, + 45u8, 165u8, 16u8, 235u8, 242u8, 21u8, 131u8, 33u8, 172u8, 119u8, 78u8, + 140u8, 10u8, 107u8, 202u8, 122u8, 235u8, 181u8, 191u8, 22u8, 116u8, + ], + ) + } + #[doc = "Kill some items from storage."] + pub fn kill_storage( + &self, + keys: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "System", + "kill_storage", + KillStorage { keys }, + [ + 174u8, 174u8, 13u8, 174u8, 75u8, 138u8, 128u8, 235u8, 222u8, 216u8, + 85u8, 18u8, 198u8, 1u8, 138u8, 70u8, 19u8, 108u8, 209u8, 41u8, 228u8, + 67u8, 130u8, 230u8, 160u8, 207u8, 11u8, 180u8, 139u8, 242u8, 41u8, + 15u8, + ], + ) + } + #[doc = "Kill all storage items with a key that starts with the given prefix."] + #[doc = ""] + #[doc = "**NOTE:** We rely on the Root origin to provide us the number of subkeys under"] + #[doc = "the prefix we are removing to accurately calculate the weight of this function."] + pub fn kill_prefix( + &self, + prefix: ::std::vec::Vec<::core::primitive::u8>, + subkeys: ::core::primitive::u32, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "System", + "kill_prefix", + KillPrefix { prefix, subkeys }, + [ + 203u8, 116u8, 217u8, 42u8, 154u8, 215u8, 77u8, 217u8, 13u8, 22u8, + 193u8, 2u8, 128u8, 115u8, 179u8, 115u8, 187u8, 218u8, 129u8, 34u8, + 80u8, 4u8, 173u8, 120u8, 92u8, 35u8, 237u8, 112u8, 201u8, 207u8, 200u8, + 48u8, + ], + ) + } + #[doc = "Make some on-chain remark and emit event."] + pub fn remark_with_event( + &self, + remark: ::std::vec::Vec<::core::primitive::u8>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "System", + "remark_with_event", + RemarkWithEvent { remark }, + [ + 123u8, 225u8, 180u8, 179u8, 144u8, 74u8, 27u8, 85u8, 101u8, 75u8, + 134u8, 44u8, 181u8, 25u8, 183u8, 158u8, 14u8, 213u8, 56u8, 225u8, + 136u8, 88u8, 26u8, 114u8, 178u8, 43u8, 176u8, 43u8, 240u8, 84u8, 116u8, + 46u8, + ], + ) + } + } + } + #[doc = "Event for the System pallet."] + pub type Event = runtime_types::frame_system::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An extrinsic completed successfully."] + pub struct ExtrinsicSuccess { + pub dispatch_info: runtime_types::frame_support::dispatch::DispatchInfo, + } + impl ::subxt::events::StaticEvent for ExtrinsicSuccess { + const PALLET: &'static str = "System"; + const EVENT: &'static str = "ExtrinsicSuccess"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An extrinsic failed."] + pub struct ExtrinsicFailed { + pub dispatch_error: runtime_types::sp_runtime::DispatchError, + pub dispatch_info: runtime_types::frame_support::dispatch::DispatchInfo, + } + impl ::subxt::events::StaticEvent for ExtrinsicFailed { + const PALLET: &'static str = "System"; + const EVENT: &'static str = "ExtrinsicFailed"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "`:code` was updated."] + pub struct CodeUpdated; + impl ::subxt::events::StaticEvent for CodeUpdated { + const PALLET: &'static str = "System"; + const EVENT: &'static str = "CodeUpdated"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A new account was created."] + pub struct NewAccount { + pub account: ::sp_core::crypto::AccountId32, + } + impl ::subxt::events::StaticEvent for NewAccount { + const PALLET: &'static str = "System"; + const EVENT: &'static str = "NewAccount"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An account was reaped."] + pub struct KilledAccount { + pub account: ::sp_core::crypto::AccountId32, + } + impl ::subxt::events::StaticEvent for KilledAccount { + const PALLET: &'static str = "System"; + const EVENT: &'static str = "KilledAccount"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "On on-chain remark happened."] + pub struct Remarked { + pub sender: ::sp_core::crypto::AccountId32, + pub hash: ::subxt::utils::H256, + } + impl ::subxt::events::StaticEvent for Remarked { + const PALLET: &'static str = "System"; + const EVENT: &'static str = "Remarked"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " The full account information for a particular account ID."] + pub fn account( + &self, + _0: impl ::std::borrow::Borrow<::sp_core::crypto::AccountId32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::frame_system::AccountInfo< + ::core::primitive::u32, + runtime_types::pallet_balances::types::AccountData< + ::core::primitive::u128, + >, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "Account", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 248u8, 178u8, 160u8, 222u8, 45u8, 231u8, 115u8, 164u8, 98u8, 184u8, + 174u8, 206u8, 149u8, 190u8, 175u8, 34u8, 202u8, 230u8, 69u8, 218u8, + 83u8, 43u8, 170u8, 41u8, 106u8, 77u8, 233u8, 97u8, 114u8, 14u8, 155u8, + 131u8, + ], + ) + } + #[doc = " The full account information for a particular account ID."] + pub fn account_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::frame_system::AccountInfo< + ::core::primitive::u32, + runtime_types::pallet_balances::types::AccountData< + ::core::primitive::u128, + >, + >, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "Account", + Vec::new(), + [ + 248u8, 178u8, 160u8, 222u8, 45u8, 231u8, 115u8, 164u8, 98u8, 184u8, + 174u8, 206u8, 149u8, 190u8, 175u8, 34u8, 202u8, 230u8, 69u8, 218u8, + 83u8, 43u8, 170u8, 41u8, 106u8, 77u8, 233u8, 97u8, 114u8, 14u8, 155u8, + 131u8, + ], + ) + } + #[doc = " Total extrinsics count for the current block."] + pub fn extrinsic_count( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "ExtrinsicCount", + vec![], + [ + 223u8, 60u8, 201u8, 120u8, 36u8, 44u8, 180u8, 210u8, 242u8, 53u8, + 222u8, 154u8, 123u8, 176u8, 249u8, 8u8, 225u8, 28u8, 232u8, 4u8, 136u8, + 41u8, 151u8, 82u8, 189u8, 149u8, 49u8, 166u8, 139u8, 9u8, 163u8, 231u8, + ], + ) + } + #[doc = " The current weight for the block."] + pub fn block_weight( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::frame_support::dispatch::PerDispatchClass< + ::sp_weights::Weight, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "BlockWeight", + vec![], + [ + 120u8, 67u8, 71u8, 163u8, 36u8, 202u8, 52u8, 106u8, 143u8, 155u8, + 144u8, 87u8, 142u8, 241u8, 232u8, 183u8, 56u8, 235u8, 27u8, 237u8, + 20u8, 202u8, 33u8, 85u8, 189u8, 0u8, 28u8, 52u8, 198u8, 40u8, 219u8, + 54u8, + ], + ) + } + #[doc = " Total length (in bytes) for all extrinsics put together, for the current block."] + pub fn all_extrinsics_len( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "AllExtrinsicsLen", + vec![], + [ + 202u8, 145u8, 209u8, 225u8, 40u8, 220u8, 174u8, 74u8, 93u8, 164u8, + 254u8, 248u8, 254u8, 192u8, 32u8, 117u8, 96u8, 149u8, 53u8, 145u8, + 219u8, 64u8, 234u8, 18u8, 217u8, 200u8, 203u8, 141u8, 145u8, 28u8, + 134u8, 60u8, + ], + ) + } + #[doc = " Map of block numbers to block hashes."] + pub fn block_hash( + &self, + _0: impl ::std::borrow::Borrow<::core::primitive::u32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::subxt::utils::H256>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "BlockHash", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Twox64Concat, + )], + [ + 50u8, 112u8, 176u8, 239u8, 175u8, 18u8, 205u8, 20u8, 241u8, 195u8, + 21u8, 228u8, 186u8, 57u8, 200u8, 25u8, 38u8, 44u8, 106u8, 20u8, 168u8, + 80u8, 76u8, 235u8, 12u8, 51u8, 137u8, 149u8, 200u8, 4u8, 220u8, 237u8, + ], + ) + } + #[doc = " Map of block numbers to block hashes."] + pub fn block_hash_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::subxt::utils::H256>, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "BlockHash", + Vec::new(), + [ + 50u8, 112u8, 176u8, 239u8, 175u8, 18u8, 205u8, 20u8, 241u8, 195u8, + 21u8, 228u8, 186u8, 57u8, 200u8, 25u8, 38u8, 44u8, 106u8, 20u8, 168u8, + 80u8, 76u8, 235u8, 12u8, 51u8, 137u8, 149u8, 200u8, 4u8, 220u8, 237u8, + ], + ) + } + #[doc = " Extrinsics data for the current block (maps an extrinsic's index to its data)."] + pub fn extrinsic_data( + &self, + _0: impl ::std::borrow::Borrow<::core::primitive::u32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "ExtrinsicData", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Twox64Concat, + )], + [ + 210u8, 224u8, 211u8, 186u8, 118u8, 210u8, 185u8, 194u8, 238u8, 211u8, + 254u8, 73u8, 67u8, 184u8, 31u8, 229u8, 168u8, 125u8, 98u8, 23u8, 241u8, + 59u8, 49u8, 86u8, 126u8, 9u8, 114u8, 163u8, 160u8, 62u8, 50u8, 67u8, + ], + ) + } + #[doc = " Extrinsics data for the current block (maps an extrinsic's index to its data)."] + pub fn extrinsic_data_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "ExtrinsicData", + Vec::new(), + [ + 210u8, 224u8, 211u8, 186u8, 118u8, 210u8, 185u8, 194u8, 238u8, 211u8, + 254u8, 73u8, 67u8, 184u8, 31u8, 229u8, 168u8, 125u8, 98u8, 23u8, 241u8, + 59u8, 49u8, 86u8, 126u8, 9u8, 114u8, 163u8, 160u8, 62u8, 50u8, 67u8, + ], + ) + } + #[doc = " The current block number being processed. Set by `execute_block`."] + pub fn number( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "Number", + vec![], + [ + 228u8, 96u8, 102u8, 190u8, 252u8, 130u8, 239u8, 172u8, 126u8, 235u8, + 246u8, 139u8, 208u8, 15u8, 88u8, 245u8, 141u8, 232u8, 43u8, 204u8, + 36u8, 87u8, 211u8, 141u8, 187u8, 68u8, 236u8, 70u8, 193u8, 235u8, + 164u8, 191u8, + ], + ) + } + #[doc = " Hash of the previous block."] + pub fn parent_hash( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::subxt::utils::H256>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "ParentHash", + vec![], + [ + 232u8, 206u8, 177u8, 119u8, 38u8, 57u8, 233u8, 50u8, 225u8, 49u8, + 169u8, 176u8, 210u8, 51u8, 231u8, 176u8, 234u8, 186u8, 188u8, 112u8, + 15u8, 152u8, 195u8, 232u8, 201u8, 97u8, 208u8, 249u8, 9u8, 163u8, 69u8, + 36u8, + ], + ) + } + #[doc = " Digest of the current block, also part of the block header."] + pub fn digest( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::sp_runtime::generic::Digest>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "Digest", + vec![], + [ + 83u8, 141u8, 200u8, 132u8, 182u8, 55u8, 197u8, 122u8, 13u8, 159u8, + 31u8, 42u8, 60u8, 191u8, 89u8, 221u8, 242u8, 47u8, 199u8, 213u8, 48u8, + 216u8, 131u8, 168u8, 245u8, 82u8, 56u8, 190u8, 62u8, 69u8, 96u8, 37u8, + ], + ) + } + #[doc = " Events deposited for the current block."] + #[doc = ""] + #[doc = " NOTE: The item is unbound and should therefore never be read on chain."] + #[doc = " It could otherwise inflate the PoV size of a block."] + #[doc = ""] + #[doc = " Events have a large in-memory size. Box the events to not go out-of-memory"] + #[doc = " just in case someone still reads them from within the runtime."] + pub fn events( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec< + runtime_types::frame_system::EventRecord< + runtime_types::rialto_parachain_runtime::RuntimeEvent, + ::subxt::utils::H256, + >, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "Events", + vec![], + [ + 76u8, 19u8, 44u8, 121u8, 59u8, 168u8, 101u8, 101u8, 248u8, 3u8, 172u8, + 27u8, 249u8, 200u8, 147u8, 17u8, 4u8, 102u8, 186u8, 6u8, 152u8, 62u8, + 76u8, 195u8, 45u8, 188u8, 191u8, 30u8, 134u8, 78u8, 199u8, 93u8, + ], + ) + } + #[doc = " The number of events in the `Events` list."] + pub fn event_count( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "EventCount", + vec![], + [ + 236u8, 93u8, 90u8, 177u8, 250u8, 211u8, 138u8, 187u8, 26u8, 208u8, + 203u8, 113u8, 221u8, 233u8, 227u8, 9u8, 249u8, 25u8, 202u8, 185u8, + 161u8, 144u8, 167u8, 104u8, 127u8, 187u8, 38u8, 18u8, 52u8, 61u8, 66u8, + 112u8, + ], + ) + } + #[doc = " Mapping between a topic (represented by T::Hash) and a vector of indexes"] + #[doc = " of events in the `>` list."] + #[doc = ""] + #[doc = " All topic vectors have deterministic storage locations depending on the topic. This"] + #[doc = " allows light-clients to leverage the changes trie storage tracking mechanism and"] + #[doc = " in case of changes fetch the list of events of interest."] + #[doc = ""] + #[doc = " The value has the type `(T::BlockNumber, EventIndex)` because if we used only just"] + #[doc = " the `EventIndex` then in case if the topic has the same contents on the next block"] + #[doc = " no notification will be triggered thus the event might be lost."] + pub fn event_topics( + &self, + _0: impl ::std::borrow::Borrow<::subxt::utils::H256>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec<(::core::primitive::u32, ::core::primitive::u32)>, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "EventTopics", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 205u8, 90u8, 142u8, 190u8, 176u8, 37u8, 94u8, 82u8, 98u8, 1u8, 129u8, + 63u8, 246u8, 101u8, 130u8, 58u8, 216u8, 16u8, 139u8, 196u8, 154u8, + 111u8, 110u8, 178u8, 24u8, 44u8, 183u8, 176u8, 232u8, 82u8, 223u8, + 38u8, + ], + ) + } + #[doc = " Mapping between a topic (represented by T::Hash) and a vector of indexes"] + #[doc = " of events in the `>` list."] + #[doc = ""] + #[doc = " All topic vectors have deterministic storage locations depending on the topic. This"] + #[doc = " allows light-clients to leverage the changes trie storage tracking mechanism and"] + #[doc = " in case of changes fetch the list of events of interest."] + #[doc = ""] + #[doc = " The value has the type `(T::BlockNumber, EventIndex)` because if we used only just"] + #[doc = " the `EventIndex` then in case if the topic has the same contents on the next block"] + #[doc = " no notification will be triggered thus the event might be lost."] + pub fn event_topics_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec<(::core::primitive::u32, ::core::primitive::u32)>, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "EventTopics", + Vec::new(), + [ + 205u8, 90u8, 142u8, 190u8, 176u8, 37u8, 94u8, 82u8, 98u8, 1u8, 129u8, + 63u8, 246u8, 101u8, 130u8, 58u8, 216u8, 16u8, 139u8, 196u8, 154u8, + 111u8, 110u8, 178u8, 24u8, 44u8, 183u8, 176u8, 232u8, 82u8, 223u8, + 38u8, + ], + ) + } + #[doc = " Stores the `spec_version` and `spec_name` of when the last runtime upgrade happened."] + pub fn last_runtime_upgrade( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::frame_system::LastRuntimeUpgradeInfo, + >, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "LastRuntimeUpgrade", + vec![], + [ + 52u8, 37u8, 117u8, 111u8, 57u8, 130u8, 196u8, 14u8, 99u8, 77u8, 91u8, + 126u8, 178u8, 249u8, 78u8, 34u8, 9u8, 194u8, 92u8, 105u8, 113u8, 81u8, + 185u8, 127u8, 245u8, 184u8, 60u8, 29u8, 234u8, 182u8, 96u8, 196u8, + ], + ) + } + #[doc = " True if we have upgraded so that `type RefCount` is `u32`. False (default) if not."] + pub fn upgraded_to_u32_ref_count( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::bool>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "UpgradedToU32RefCount", + vec![], + [ + 171u8, 88u8, 244u8, 92u8, 122u8, 67u8, 27u8, 18u8, 59u8, 175u8, 175u8, + 178u8, 20u8, 150u8, 213u8, 59u8, 222u8, 141u8, 32u8, 107u8, 3u8, 114u8, + 83u8, 250u8, 180u8, 233u8, 152u8, 54u8, 187u8, 99u8, 131u8, 204u8, + ], + ) + } + #[doc = " True if we have upgraded so that AccountInfo contains three types of `RefCount`. False"] + #[doc = " (default) if not."] + pub fn upgraded_to_triple_ref_count( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::bool>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "UpgradedToTripleRefCount", + vec![], + [ + 90u8, 33u8, 56u8, 86u8, 90u8, 101u8, 89u8, 133u8, 203u8, 56u8, 201u8, + 210u8, 244u8, 232u8, 150u8, 18u8, 51u8, 105u8, 14u8, 230u8, 103u8, + 155u8, 246u8, 99u8, 53u8, 207u8, 225u8, 128u8, 186u8, 76u8, 40u8, + 185u8, + ], + ) + } + #[doc = " The execution phase of the block."] + pub fn execution_phase( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "System", + "ExecutionPhase", + vec![], + [ + 230u8, 183u8, 221u8, 135u8, 226u8, 223u8, 55u8, 104u8, 138u8, 224u8, + 103u8, 156u8, 222u8, 99u8, 203u8, 199u8, 164u8, 168u8, 193u8, 133u8, + 201u8, 155u8, 63u8, 95u8, 17u8, 206u8, 165u8, 123u8, 161u8, 33u8, + 172u8, 93u8, + ], + ) + } + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " Block & extrinsics weights: base values and limits."] + pub fn block_weights( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::frame_system::limits::BlockWeights, + >, + > { + ::subxt::constants::StaticConstantAddress::new( + "System", + "BlockWeights", + [ + 118u8, 253u8, 239u8, 217u8, 145u8, 115u8, 85u8, 86u8, 172u8, 248u8, + 139u8, 32u8, 158u8, 126u8, 172u8, 188u8, 197u8, 105u8, 145u8, 235u8, + 171u8, 50u8, 31u8, 225u8, 167u8, 187u8, 241u8, 87u8, 6u8, 17u8, 234u8, + 185u8, + ], + ) + } + #[doc = " The maximum length of a block (in bytes)."] + pub fn block_length( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::frame_system::limits::BlockLength, + >, + > { + ::subxt::constants::StaticConstantAddress::new( + "System", + "BlockLength", + [ + 116u8, 184u8, 225u8, 228u8, 207u8, 203u8, 4u8, 220u8, 234u8, 198u8, + 150u8, 108u8, 205u8, 87u8, 194u8, 131u8, 229u8, 51u8, 140u8, 4u8, 47u8, + 12u8, 200u8, 144u8, 153u8, 62u8, 51u8, 39u8, 138u8, 205u8, 203u8, + 236u8, + ], + ) + } + #[doc = " Maximum number of block number to block hash mappings to keep (oldest pruned first)."] + pub fn block_hash_count( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + > { + ::subxt::constants::StaticConstantAddress::new( + "System", + "BlockHashCount", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " The weight of runtime database operations the runtime can invoke."] + pub fn db_weight( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType, + > { + ::subxt::constants::StaticConstantAddress::new( + "System", + "DbWeight", + [ + 124u8, 162u8, 190u8, 149u8, 49u8, 177u8, 162u8, 231u8, 62u8, 167u8, + 199u8, 181u8, 43u8, 232u8, 185u8, 116u8, 195u8, 51u8, 233u8, 223u8, + 20u8, 129u8, 246u8, 13u8, 65u8, 180u8, 64u8, 9u8, 157u8, 59u8, 245u8, + 118u8, + ], + ) + } + #[doc = " Get the chain's current version."] + pub fn version( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType, + > { + ::subxt::constants::StaticConstantAddress::new( + "System", + "Version", + [ + 93u8, 98u8, 57u8, 243u8, 229u8, 8u8, 234u8, 231u8, 72u8, 230u8, 139u8, + 47u8, 63u8, 181u8, 17u8, 2u8, 220u8, 231u8, 104u8, 237u8, 185u8, 143u8, + 165u8, 253u8, 188u8, 76u8, 147u8, 12u8, 170u8, 26u8, 74u8, 200u8, + ], + ) + } + #[doc = " The designated SS58 prefix of this chain."] + #[doc = ""] + #[doc = " This replaces the \"ss58Format\" property declared in the chain spec. Reason is"] + #[doc = " that the runtime should know about the prefix in order to make use of it as"] + #[doc = " an identifier of the chain."] + pub fn ss58_prefix( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u16>, + > { + ::subxt::constants::StaticConstantAddress::new( + "System", + "SS58Prefix", + [ + 116u8, 33u8, 2u8, 170u8, 181u8, 147u8, 171u8, 169u8, 167u8, 227u8, + 41u8, 144u8, 11u8, 236u8, 82u8, 100u8, 74u8, 60u8, 184u8, 72u8, 169u8, + 90u8, 208u8, 135u8, 15u8, 117u8, 10u8, 123u8, 128u8, 193u8, 29u8, 70u8, + ], + ) + } + } + } + } + pub mod timestamp { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Set { + #[codec(compact)] + pub now: ::core::primitive::u64, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Set the current time."] + #[doc = ""] + #[doc = "This call should be invoked exactly once per block. It will panic at the finalization"] + #[doc = "phase, if this call hasn't been invoked by that time."] + #[doc = ""] + #[doc = "The timestamp should be greater than the previous one by the amount specified by"] + #[doc = "`MinimumPeriod`."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be `Inherent`."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- `O(1)` (Note that implementations of `OnTimestampSet` must also be `O(1)`)"] + #[doc = "- 1 storage read and 1 storage mutation (codec `O(1)`). (because of `DidUpdate::take` in"] + #[doc = " `on_finalize`)"] + #[doc = "- 1 event handler `on_timestamp_set`. Must be `O(1)`."] + pub fn set( + &self, + now: ::core::primitive::u64, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Timestamp", + "set", + Set { now }, + [ + 6u8, 97u8, 172u8, 236u8, 118u8, 238u8, 228u8, 114u8, 15u8, 115u8, + 102u8, 85u8, 66u8, 151u8, 16u8, 33u8, 187u8, 17u8, 166u8, 88u8, 127u8, + 214u8, 182u8, 51u8, 168u8, 88u8, 43u8, 101u8, 185u8, 8u8, 1u8, 28u8, + ], + ) + } + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " Current time for the current block."] + pub fn now( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u64>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Timestamp", + "Now", + vec![], + [ + 148u8, 53u8, 50u8, 54u8, 13u8, 161u8, 57u8, 150u8, 16u8, 83u8, 144u8, + 221u8, 59u8, 75u8, 158u8, 130u8, 39u8, 123u8, 106u8, 134u8, 202u8, + 185u8, 83u8, 85u8, 60u8, 41u8, 120u8, 96u8, 210u8, 34u8, 2u8, 250u8, + ], + ) + } + #[doc = " Did the timestamp get updated in this block?"] + pub fn did_update( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::bool>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Timestamp", + "DidUpdate", + vec![], + [ + 70u8, 13u8, 92u8, 186u8, 80u8, 151u8, 167u8, 90u8, 158u8, 232u8, 175u8, + 13u8, 103u8, 135u8, 2u8, 78u8, 16u8, 6u8, 39u8, 158u8, 167u8, 85u8, + 27u8, 47u8, 122u8, 73u8, 127u8, 26u8, 35u8, 168u8, 72u8, 204u8, + ], + ) + } + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " The minimum period between blocks. Beware that this is different to the *expected*"] + #[doc = " period that the block production apparatus provides. Your chosen consensus system will"] + #[doc = " generally work with this to determine a sensible block time. e.g. For Aura, it will be"] + #[doc = " double this period on default settings."] + pub fn minimum_period( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u64>, + > { + ::subxt::constants::StaticConstantAddress::new( + "Timestamp", + "MinimumPeriod", + [ + 128u8, 214u8, 205u8, 242u8, 181u8, 142u8, 124u8, 231u8, 190u8, 146u8, + 59u8, 226u8, 157u8, 101u8, 103u8, 117u8, 249u8, 65u8, 18u8, 191u8, + 103u8, 119u8, 53u8, 85u8, 81u8, 96u8, 220u8, 42u8, 184u8, 239u8, 42u8, + 246u8, + ], + ) + } + } + } + } + pub mod sudo { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Sudo { + pub call: ::std::boxed::Box, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SudoUncheckedWeight { + pub call: ::std::boxed::Box, + pub weight: ::sp_weights::Weight, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetKey { + pub new: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SudoAs { + pub who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + pub call: ::std::boxed::Box, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + pub fn sudo( + &self, + call: runtime_types::rialto_parachain_runtime::RuntimeCall, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Sudo", + "sudo", + Sudo { call: ::std::boxed::Box::new(call) }, + [ + 19u8, 178u8, 172u8, 30u8, 28u8, 209u8, 160u8, 61u8, 76u8, 239u8, 71u8, + 124u8, 21u8, 34u8, 233u8, 176u8, 100u8, 90u8, 198u8, 118u8, 117u8, 2u8, + 147u8, 7u8, 109u8, 1u8, 32u8, 35u8, 99u8, 0u8, 107u8, 145u8, + ], + ) + } + #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] + #[doc = "This function does not check the weight of the call, and instead allows the"] + #[doc = "Sudo user to specify the weight of the call."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + pub fn sudo_unchecked_weight( + &self, + call: runtime_types::rialto_parachain_runtime::RuntimeCall, + weight: ::sp_weights::Weight, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Sudo", + "sudo_unchecked_weight", + SudoUncheckedWeight { call: ::std::boxed::Box::new(call), weight }, + [ + 145u8, 160u8, 12u8, 105u8, 228u8, 240u8, 115u8, 105u8, 220u8, 99u8, + 215u8, 228u8, 115u8, 71u8, 109u8, 28u8, 149u8, 247u8, 159u8, 216u8, + 76u8, 71u8, 68u8, 87u8, 254u8, 146u8, 185u8, 174u8, 251u8, 209u8, 72u8, + 122u8, + ], + ) + } + #[doc = "Authenticates the current sudo key and sets the given AccountId (`new`) as the new sudo"] + #[doc = "key."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + pub fn set_key( + &self, + new: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Sudo", + "set_key", + SetKey { new }, + [ + 23u8, 224u8, 218u8, 169u8, 8u8, 28u8, 111u8, 199u8, 26u8, 88u8, 225u8, + 105u8, 17u8, 19u8, 87u8, 156u8, 97u8, 67u8, 89u8, 173u8, 70u8, 0u8, + 5u8, 246u8, 198u8, 135u8, 182u8, 180u8, 44u8, 9u8, 212u8, 95u8, + ], + ) + } + #[doc = "Authenticates the sudo key and dispatches a function call with `Signed` origin from"] + #[doc = "a given account."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + pub fn sudo_as( + &self, + who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + call: runtime_types::rialto_parachain_runtime::RuntimeCall, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Sudo", + "sudo_as", + SudoAs { who, call: ::std::boxed::Box::new(call) }, + [ + 229u8, 45u8, 129u8, 96u8, 54u8, 29u8, 159u8, 77u8, 210u8, 144u8, 29u8, + 97u8, 127u8, 133u8, 122u8, 110u8, 152u8, 194u8, 211u8, 246u8, 97u8, + 197u8, 187u8, 203u8, 46u8, 12u8, 104u8, 125u8, 15u8, 226u8, 28u8, + 183u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::pallet_sudo::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A sudo just took place. \\[result\\]"] + pub struct Sudid { + pub sudo_result: + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, + } + impl ::subxt::events::StaticEvent for Sudid { + const PALLET: &'static str = "Sudo"; + const EVENT: &'static str = "Sudid"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "The \\[sudoer\\] just switched identity; the old key is supplied if one existed."] + pub struct KeyChanged { + pub old_sudoer: ::core::option::Option<::sp_core::crypto::AccountId32>, + } + impl ::subxt::events::StaticEvent for KeyChanged { + const PALLET: &'static str = "Sudo"; + const EVENT: &'static str = "KeyChanged"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A sudo just took place. \\[result\\]"] + pub struct SudoAsDone { + pub sudo_result: + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, + } + impl ::subxt::events::StaticEvent for SudoAsDone { + const PALLET: &'static str = "Sudo"; + const EVENT: &'static str = "SudoAsDone"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " The `AccountId` of the sudo key."] + pub fn key( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::sp_core::crypto::AccountId32>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Sudo", + "Key", + vec![], + [ + 244u8, 73u8, 188u8, 136u8, 218u8, 163u8, 68u8, 179u8, 122u8, 173u8, + 34u8, 108u8, 137u8, 28u8, 182u8, 16u8, 196u8, 92u8, 138u8, 34u8, 102u8, + 80u8, 199u8, 88u8, 107u8, 207u8, 36u8, 22u8, 168u8, 167u8, 20u8, 142u8, + ], + ) + } + } + } + } + pub mod transaction_payment { + use super::{root_mod, runtime_types}; + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::pallet_transaction_payment::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee,"] + #[doc = "has been paid by `who`."] + pub struct TransactionFeePaid { + pub who: ::sp_core::crypto::AccountId32, + pub actual_fee: ::core::primitive::u128, + pub tip: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for TransactionFeePaid { + const PALLET: &'static str = "TransactionPayment"; + const EVENT: &'static str = "TransactionFeePaid"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + pub fn next_fee_multiplier( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::sp_arithmetic::fixed_point::FixedU128, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "TransactionPayment", + "NextFeeMultiplier", + vec![], + [ + 210u8, 0u8, 206u8, 165u8, 183u8, 10u8, 206u8, 52u8, 14u8, 90u8, 218u8, + 197u8, 189u8, 125u8, 113u8, 216u8, 52u8, 161u8, 45u8, 24u8, 245u8, + 237u8, 121u8, 41u8, 106u8, 29u8, 45u8, 129u8, 250u8, 203u8, 206u8, + 180u8, + ], + ) + } + pub fn storage_version( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::pallet_transaction_payment::Releases, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "TransactionPayment", + "StorageVersion", + vec![], + [ + 219u8, 243u8, 82u8, 176u8, 65u8, 5u8, 132u8, 114u8, 8u8, 82u8, 176u8, + 200u8, 97u8, 150u8, 177u8, 164u8, 166u8, 11u8, 34u8, 12u8, 12u8, 198u8, + 58u8, 191u8, 186u8, 221u8, 221u8, 119u8, 181u8, 253u8, 154u8, 228u8, + ], + ) + } + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " A fee mulitplier for `Operational` extrinsics to compute \"virtual tip\" to boost their"] + #[doc = " `priority`"] + #[doc = ""] + #[doc = " This value is multipled by the `final_fee` to obtain a \"virtual tip\" that is later"] + #[doc = " added to a tip component in regular `priority` calculations."] + #[doc = " It means that a `Normal` transaction can front-run a similarly-sized `Operational`"] + #[doc = " extrinsic (with no tip), by including a tip value greater than the virtual tip."] + #[doc = ""] + #[doc = " ```rust,ignore"] + #[doc = " // For `Normal`"] + #[doc = " let priority = priority_calc(tip);"] + #[doc = ""] + #[doc = " // For `Operational`"] + #[doc = " let virtual_tip = (inclusion_fee + tip) * OperationalFeeMultiplier;"] + #[doc = " let priority = priority_calc(tip + virtual_tip);"] + #[doc = " ```"] + #[doc = ""] + #[doc = " Note that since we use `final_fee` the multiplier applies also to the regular `tip`"] + #[doc = " sent with the transaction. So, not only does the transaction get a priority bump based"] + #[doc = " on the `inclusion_fee`, but we also amplify the impact of tips applied to `Operational`"] + #[doc = " transactions."] + pub fn operational_fee_multiplier( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u8>, + > { + ::subxt::constants::StaticConstantAddress::new( + "TransactionPayment", + "OperationalFeeMultiplier", + [ + 141u8, 130u8, 11u8, 35u8, 226u8, 114u8, 92u8, 179u8, 168u8, 110u8, + 28u8, 91u8, 221u8, 64u8, 4u8, 148u8, 201u8, 193u8, 185u8, 66u8, 226u8, + 114u8, 97u8, 79u8, 62u8, 212u8, 202u8, 114u8, 237u8, 228u8, 183u8, + 165u8, + ], + ) + } + } + } + } + pub mod parachain_system { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetValidationData { + pub data: + runtime_types::cumulus_primitives_parachain_inherent::ParachainInherentData, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SudoSendUpwardMessage { + pub message: ::std::vec::Vec<::core::primitive::u8>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct AuthorizeUpgrade { + pub code_hash: ::subxt::utils::H256, + pub check_version: ::core::primitive::bool, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct EnactAuthorizedUpgrade { + pub code: ::std::vec::Vec<::core::primitive::u8>, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Set the current validation data."] + #[doc = ""] + #[doc = "This should be invoked exactly once per block. It will panic at the finalization"] + #[doc = "phase if the call was not invoked."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be `Inherent`"] + #[doc = ""] + #[doc = "As a side effect, this function upgrades the current validation function"] + #[doc = "if the appropriate time has come."] + pub fn set_validation_data( + &self, + data : runtime_types :: cumulus_primitives_parachain_inherent :: ParachainInherentData, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "ParachainSystem", + "set_validation_data", + SetValidationData { data }, + [ + 200u8, 80u8, 163u8, 177u8, 184u8, 117u8, 61u8, 203u8, 244u8, 214u8, + 106u8, 151u8, 128u8, 131u8, 254u8, 120u8, 254u8, 76u8, 104u8, 39u8, + 215u8, 227u8, 233u8, 254u8, 26u8, 62u8, 17u8, 42u8, 19u8, 127u8, 108u8, + 242u8, + ], + ) + } + pub fn sudo_send_upward_message( + &self, + message: ::std::vec::Vec<::core::primitive::u8>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "ParachainSystem", + "sudo_send_upward_message", + SudoSendUpwardMessage { message }, + [ + 127u8, 79u8, 45u8, 183u8, 190u8, 205u8, 184u8, 169u8, 255u8, 191u8, + 86u8, 154u8, 134u8, 25u8, 249u8, 63u8, 47u8, 194u8, 108u8, 62u8, 60u8, + 170u8, 81u8, 240u8, 113u8, 48u8, 181u8, 171u8, 95u8, 63u8, 26u8, 222u8, + ], + ) + } + #[doc = "Authorize an upgrade to a given `code_hash` for the runtime. The runtime can be supplied"] + #[doc = "later."] + #[doc = ""] + #[doc = "The `check_version` parameter sets a boolean flag for whether or not the runtime's spec"] + #[doc = "version and name should be verified on upgrade. Since the authorization only has a hash,"] + #[doc = "it cannot actually perform the verification."] + #[doc = ""] + #[doc = "This call requires Root origin."] + pub fn authorize_upgrade( + &self, + code_hash: ::subxt::utils::H256, + check_version: ::core::primitive::bool, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "ParachainSystem", + "authorize_upgrade", + AuthorizeUpgrade { code_hash, check_version }, + [ + 208u8, 115u8, 62u8, 35u8, 70u8, 223u8, 65u8, 57u8, 216u8, 44u8, 169u8, + 249u8, 90u8, 112u8, 17u8, 208u8, 30u8, 131u8, 102u8, 131u8, 240u8, + 217u8, 230u8, 214u8, 145u8, 198u8, 55u8, 13u8, 217u8, 51u8, 178u8, + 141u8, + ], + ) + } + #[doc = "Provide the preimage (runtime binary) `code` for an upgrade that has been authorized."] + #[doc = ""] + #[doc = "If the authorization required a version check, this call will ensure the spec name"] + #[doc = "remains unchanged and that the spec version has increased."] + #[doc = ""] + #[doc = "Note that this function will not apply the new `code`, but only attempt to schedule the"] + #[doc = "upgrade with the Relay Chain."] + #[doc = ""] + #[doc = "All origins are allowed."] + pub fn enact_authorized_upgrade( + &self, + code: ::std::vec::Vec<::core::primitive::u8>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "ParachainSystem", + "enact_authorized_upgrade", + EnactAuthorizedUpgrade { code }, + [ + 43u8, 157u8, 1u8, 230u8, 134u8, 72u8, 230u8, 35u8, 159u8, 13u8, 201u8, + 134u8, 184u8, 94u8, 167u8, 13u8, 108u8, 157u8, 145u8, 166u8, 119u8, + 37u8, 51u8, 121u8, 252u8, 255u8, 48u8, 251u8, 126u8, 152u8, 247u8, 5u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::cumulus_pallet_parachain_system::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "The validation function has been scheduled to apply."] + pub struct ValidationFunctionStored; + impl ::subxt::events::StaticEvent for ValidationFunctionStored { + const PALLET: &'static str = "ParachainSystem"; + const EVENT: &'static str = "ValidationFunctionStored"; + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "The validation function was applied as of the contained relay chain block number."] + pub struct ValidationFunctionApplied { + pub relay_chain_block_num: ::core::primitive::u32, + } + impl ::subxt::events::StaticEvent for ValidationFunctionApplied { + const PALLET: &'static str = "ParachainSystem"; + const EVENT: &'static str = "ValidationFunctionApplied"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "The relay-chain aborted the upgrade process."] + pub struct ValidationFunctionDiscarded; + impl ::subxt::events::StaticEvent for ValidationFunctionDiscarded { + const PALLET: &'static str = "ParachainSystem"; + const EVENT: &'static str = "ValidationFunctionDiscarded"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An upgrade has been authorized."] + pub struct UpgradeAuthorized { + pub code_hash: ::subxt::utils::H256, + } + impl ::subxt::events::StaticEvent for UpgradeAuthorized { + const PALLET: &'static str = "ParachainSystem"; + const EVENT: &'static str = "UpgradeAuthorized"; + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Some downward messages have been received and will be processed."] + pub struct DownwardMessagesReceived { + pub count: ::core::primitive::u32, + } + impl ::subxt::events::StaticEvent for DownwardMessagesReceived { + const PALLET: &'static str = "ParachainSystem"; + const EVENT: &'static str = "DownwardMessagesReceived"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward messages were processed using the given weight."] + pub struct DownwardMessagesProcessed { + pub weight_used: ::sp_weights::Weight, + pub dmq_head: ::subxt::utils::H256, + } + impl ::subxt::events::StaticEvent for DownwardMessagesProcessed { + const PALLET: &'static str = "ParachainSystem"; + const EVENT: &'static str = "DownwardMessagesProcessed"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An upward message was sent to the relay chain."] + pub struct UpwardMessageSent { + pub message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + } + impl ::subxt::events::StaticEvent for UpwardMessageSent { + const PALLET: &'static str = "ParachainSystem"; + const EVENT: &'static str = "UpwardMessageSent"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " In case of a scheduled upgrade, this storage field contains the validation code to be applied."] + #[doc = ""] + #[doc = " As soon as the relay chain gives us the go-ahead signal, we will overwrite the [`:code`][well_known_keys::CODE]"] + #[doc = " which will result the next block process with the new validation code. This concludes the upgrade process."] + #[doc = ""] + #[doc = " [well_known_keys::CODE]: sp_core::storage::well_known_keys::CODE"] + pub fn pending_validation_code( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "PendingValidationCode", + vec![], + [ + 162u8, 35u8, 108u8, 76u8, 160u8, 93u8, 215u8, 84u8, 20u8, 249u8, 57u8, + 187u8, 88u8, 161u8, 15u8, 131u8, 213u8, 89u8, 140u8, 20u8, 227u8, + 204u8, 79u8, 176u8, 114u8, 119u8, 8u8, 7u8, 64u8, 15u8, 90u8, 92u8, + ], + ) + } + #[doc = " Validation code that is set by the parachain and is to be communicated to collator and"] + #[doc = " consequently the relay-chain."] + #[doc = ""] + #[doc = " This will be cleared in `on_initialize` of each new block if no other pallet already set"] + #[doc = " the value."] + pub fn new_validation_code( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "NewValidationCode", + vec![], + [ + 224u8, 174u8, 53u8, 106u8, 240u8, 49u8, 48u8, 79u8, 219u8, 74u8, 142u8, + 166u8, 92u8, 204u8, 244u8, 200u8, 43u8, 169u8, 177u8, 207u8, 190u8, + 106u8, 180u8, 65u8, 245u8, 131u8, 134u8, 4u8, 53u8, 45u8, 76u8, 3u8, + ], + ) + } + #[doc = " The [`PersistedValidationData`] set for this block."] + #[doc = " This value is expected to be set only once per block and it's never stored"] + #[doc = " in the trie."] + pub fn validation_data( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::polkadot_primitives::v4::PersistedValidationData< + ::subxt::utils::H256, + ::core::primitive::u32, + >, + >, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "ValidationData", + vec![], + [ + 112u8, 58u8, 240u8, 81u8, 219u8, 110u8, 244u8, 186u8, 251u8, 90u8, + 195u8, 217u8, 229u8, 102u8, 233u8, 24u8, 109u8, 96u8, 219u8, 72u8, + 139u8, 93u8, 58u8, 140u8, 40u8, 110u8, 167u8, 98u8, 199u8, 12u8, 138u8, + 131u8, + ], + ) + } + #[doc = " Were the validation data set to notify the relay chain?"] + pub fn did_set_validation_code( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::bool>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "DidSetValidationCode", + vec![], + [ + 89u8, 83u8, 74u8, 174u8, 234u8, 188u8, 149u8, 78u8, 140u8, 17u8, 92u8, + 165u8, 243u8, 87u8, 59u8, 97u8, 135u8, 81u8, 192u8, 86u8, 193u8, 187u8, + 113u8, 22u8, 108u8, 83u8, 242u8, 208u8, 174u8, 40u8, 49u8, 245u8, + ], + ) + } + #[doc = " The relay chain block number associated with the last parachain block."] + pub fn last_relay_chain_block_number( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "LastRelayChainBlockNumber", + vec![], + [ + 68u8, 121u8, 6u8, 159u8, 181u8, 94u8, 151u8, 215u8, 225u8, 244u8, 4u8, + 158u8, 216u8, 85u8, 55u8, 228u8, 197u8, 35u8, 200u8, 33u8, 29u8, 182u8, + 17u8, 83u8, 59u8, 63u8, 25u8, 180u8, 132u8, 23u8, 97u8, 252u8, + ], + ) + } + #[doc = " An option which indicates if the relay-chain restricts signalling a validation code upgrade."] + #[doc = " In other words, if this is `Some` and [`NewValidationCode`] is `Some` then the produced"] + #[doc = " candidate will be invalid."] + #[doc = ""] + #[doc = " This storage item is a mirror of the corresponding value for the current parachain from the"] + #[doc = " relay-chain. This value is ephemeral which means it doesn't hit the storage. This value is"] + #[doc = " set after the inherent."] + pub fn upgrade_restriction_signal( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::core::option::Option< + runtime_types::polkadot_primitives::v4::UpgradeRestriction, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "UpgradeRestrictionSignal", + vec![], + [ + 61u8, 3u8, 26u8, 6u8, 88u8, 114u8, 109u8, 63u8, 7u8, 115u8, 245u8, + 198u8, 73u8, 234u8, 28u8, 228u8, 126u8, 27u8, 151u8, 18u8, 133u8, 54u8, + 144u8, 149u8, 246u8, 43u8, 83u8, 47u8, 77u8, 238u8, 10u8, 196u8, + ], + ) + } + #[doc = " The state proof for the last relay parent block."] + #[doc = ""] + #[doc = " This field is meant to be updated each block with the validation data inherent. Therefore,"] + #[doc = " before processing of the inherent, e.g. in `on_initialize` this data may be stale."] + #[doc = ""] + #[doc = " This data is also absent from the genesis."] + pub fn relay_state_proof( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::sp_trie::storage_proof::StorageProof, + >, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "RelayStateProof", + vec![], + [ + 35u8, 124u8, 167u8, 221u8, 162u8, 145u8, 158u8, 186u8, 57u8, 154u8, + 225u8, 6u8, 176u8, 13u8, 178u8, 195u8, 209u8, 122u8, 221u8, 26u8, + 155u8, 126u8, 153u8, 246u8, 101u8, 221u8, 61u8, 145u8, 211u8, 236u8, + 48u8, 130u8, + ], + ) + } + #[doc = " The snapshot of some state related to messaging relevant to the current parachain as per"] + #[doc = " the relay parent."] + #[doc = ""] + #[doc = " This field is meant to be updated each block with the validation data inherent. Therefore,"] + #[doc = " before processing of the inherent, e.g. in `on_initialize` this data may be stale."] + #[doc = ""] + #[doc = " This data is also absent from the genesis."] pub fn relevant_messaging_state (& self ,) -> :: subxt :: storage :: address :: StaticStorageAddress :: < :: subxt :: metadata :: DecodeStaticType < runtime_types :: cumulus_pallet_parachain_system :: relay_state_snapshot :: MessagingStateSnapshot > , :: subxt :: storage :: address :: Yes , () , () >{ + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "RelevantMessagingState", + vec![], + [ + 68u8, 241u8, 114u8, 83u8, 200u8, 99u8, 8u8, 244u8, 110u8, 134u8, 106u8, + 153u8, 17u8, 90u8, 184u8, 157u8, 100u8, 140u8, 157u8, 83u8, 25u8, + 166u8, 173u8, 31u8, 221u8, 24u8, 236u8, 85u8, 176u8, 223u8, 237u8, + 65u8, + ], + ) + } + #[doc = " The parachain host configuration that was obtained from the relay parent."] + #[doc = ""] + #[doc = " This field is meant to be updated each block with the validation data inherent. Therefore,"] + #[doc = " before processing of the inherent, e.g. in `on_initialize` this data may be stale."] + #[doc = ""] + #[doc = " This data is also absent from the genesis."] + pub fn host_configuration( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::polkadot_primitives::v4::AbridgedHostConfiguration, + >, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "HostConfiguration", + vec![], + [ + 104u8, 200u8, 30u8, 202u8, 119u8, 204u8, 233u8, 20u8, 67u8, 199u8, + 47u8, 166u8, 254u8, 152u8, 10u8, 187u8, 240u8, 255u8, 148u8, 201u8, + 134u8, 41u8, 130u8, 201u8, 112u8, 65u8, 68u8, 103u8, 56u8, 123u8, + 178u8, 113u8, + ], + ) + } + #[doc = " The last downward message queue chain head we have observed."] + #[doc = ""] + #[doc = " This value is loaded before and saved after processing inbound downward messages carried"] + #[doc = " by the system inherent."] + pub fn last_dmq_mqc_head( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::cumulus_primitives_parachain_inherent::MessageQueueChain, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "LastDmqMqcHead", + vec![], + [ + 176u8, 255u8, 246u8, 125u8, 36u8, 120u8, 24u8, 44u8, 26u8, 64u8, 236u8, + 210u8, 189u8, 237u8, 50u8, 78u8, 45u8, 139u8, 58u8, 141u8, 112u8, + 253u8, 178u8, 198u8, 87u8, 71u8, 77u8, 248u8, 21u8, 145u8, 187u8, 52u8, + ], + ) + } + #[doc = " The message queue chain heads we have observed per each channel incoming channel."] + #[doc = ""] + #[doc = " This value is loaded before and saved after processing inbound downward messages carried"] + #[doc = " by the system inherent."] + pub fn last_hrmp_mqc_heads( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::subxt::utils::KeyedVec< + runtime_types::polkadot_parachain::primitives::Id, + runtime_types::cumulus_primitives_parachain_inherent::MessageQueueChain, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "LastHrmpMqcHeads", + vec![], + [ + 55u8, 179u8, 35u8, 16u8, 173u8, 0u8, 122u8, 179u8, 236u8, 98u8, 9u8, + 112u8, 11u8, 219u8, 241u8, 89u8, 131u8, 198u8, 64u8, 139u8, 103u8, + 158u8, 77u8, 107u8, 83u8, 236u8, 255u8, 208u8, 47u8, 61u8, 219u8, + 240u8, + ], + ) + } + #[doc = " Number of downward messages processed in a block."] + #[doc = ""] + #[doc = " This will be cleared in `on_initialize` of each new block."] + pub fn processed_downward_messages( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "ProcessedDownwardMessages", + vec![], + [ + 48u8, 177u8, 84u8, 228u8, 101u8, 235u8, 181u8, 27u8, 66u8, 55u8, 50u8, + 146u8, 245u8, 223u8, 77u8, 132u8, 178u8, 80u8, 74u8, 90u8, 166u8, 81u8, + 109u8, 25u8, 91u8, 69u8, 5u8, 69u8, 123u8, 197u8, 160u8, 146u8, + ], + ) + } + #[doc = " HRMP watermark that was set in a block."] + #[doc = ""] + #[doc = " This will be cleared in `on_initialize` of each new block."] + pub fn hrmp_watermark( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "HrmpWatermark", + vec![], + [ + 189u8, 59u8, 183u8, 195u8, 69u8, 185u8, 241u8, 226u8, 62u8, 204u8, + 230u8, 77u8, 102u8, 75u8, 86u8, 157u8, 249u8, 140u8, 219u8, 72u8, 94u8, + 64u8, 176u8, 72u8, 34u8, 205u8, 114u8, 103u8, 231u8, 233u8, 206u8, + 111u8, + ], + ) + } + #[doc = " HRMP messages that were sent in a block."] + #[doc = ""] + #[doc = " This will be cleared in `on_initialize` of each new block."] + pub fn hrmp_outbound_messages( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec< + runtime_types::polkadot_core_primitives::OutboundHrmpMessage< + runtime_types::polkadot_parachain::primitives::Id, + >, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "HrmpOutboundMessages", + vec![], + [ + 74u8, 86u8, 173u8, 248u8, 90u8, 230u8, 71u8, 225u8, 127u8, 164u8, + 221u8, 62u8, 146u8, 13u8, 73u8, 9u8, 98u8, 168u8, 6u8, 14u8, 97u8, + 166u8, 45u8, 70u8, 62u8, 210u8, 9u8, 32u8, 83u8, 18u8, 4u8, 201u8, + ], + ) + } + #[doc = " Upward messages that were sent in a block."] + #[doc = ""] + #[doc = " This will be cleared in `on_initialize` of each new block."] + pub fn upward_messages( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "UpwardMessages", + vec![], + [ + 129u8, 208u8, 187u8, 36u8, 48u8, 108u8, 135u8, 56u8, 204u8, 60u8, + 100u8, 158u8, 113u8, 238u8, 46u8, 92u8, 228u8, 41u8, 178u8, 177u8, + 208u8, 195u8, 148u8, 149u8, 127u8, 21u8, 93u8, 92u8, 29u8, 115u8, 10u8, + 248u8, + ], + ) + } + #[doc = " Upward messages that are still pending and not yet send to the relay chain."] + pub fn pending_upward_messages( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "PendingUpwardMessages", + vec![], + [ + 223u8, 46u8, 224u8, 227u8, 222u8, 119u8, 225u8, 244u8, 59u8, 87u8, + 127u8, 19u8, 217u8, 237u8, 103u8, 61u8, 6u8, 210u8, 107u8, 201u8, + 117u8, 25u8, 85u8, 248u8, 36u8, 231u8, 28u8, 202u8, 41u8, 140u8, 208u8, + 254u8, + ], + ) + } + #[doc = " The number of HRMP messages we observed in `on_initialize` and thus used that number for"] + #[doc = " announcing the weight of `on_initialize` and `on_finalize`."] + pub fn announced_hrmp_messages_per_candidate( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "AnnouncedHrmpMessagesPerCandidate", + vec![], + [ + 132u8, 61u8, 162u8, 129u8, 251u8, 243u8, 20u8, 144u8, 162u8, 73u8, + 237u8, 51u8, 248u8, 41u8, 127u8, 171u8, 180u8, 79u8, 137u8, 23u8, 66u8, + 134u8, 106u8, 222u8, 182u8, 154u8, 0u8, 145u8, 184u8, 156u8, 36u8, + 97u8, + ], + ) + } + #[doc = " The weight we reserve at the beginning of the block for processing XCMP messages. This"] + #[doc = " overrides the amount set in the Config trait."] + pub fn reserved_xcmp_weight_override( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::sp_weights::Weight>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "ReservedXcmpWeightOverride", + vec![], + [ + 180u8, 90u8, 34u8, 178u8, 1u8, 242u8, 211u8, 97u8, 100u8, 34u8, 39u8, + 42u8, 142u8, 249u8, 236u8, 194u8, 244u8, 164u8, 96u8, 54u8, 98u8, 46u8, + 92u8, 196u8, 185u8, 51u8, 231u8, 234u8, 249u8, 143u8, 244u8, 64u8, + ], + ) + } + #[doc = " The weight we reserve at the beginning of the block for processing DMP messages. This"] + #[doc = " overrides the amount set in the Config trait."] + pub fn reserved_dmp_weight_override( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::sp_weights::Weight>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "ReservedDmpWeightOverride", + vec![], + [ + 90u8, 122u8, 168u8, 240u8, 95u8, 195u8, 160u8, 109u8, 175u8, 170u8, + 227u8, 44u8, 139u8, 176u8, 32u8, 161u8, 57u8, 233u8, 56u8, 55u8, 123u8, + 168u8, 174u8, 96u8, 159u8, 62u8, 186u8, 186u8, 17u8, 70u8, 57u8, 246u8, + ], + ) + } + #[doc = " The next authorized upgrade, if there is one."] + pub fn authorized_upgrade( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::cumulus_pallet_parachain_system::CodeUpgradeAuthorization, + >, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "AuthorizedUpgrade", + vec![], + [ + 12u8, 212u8, 71u8, 191u8, 89u8, 101u8, 195u8, 3u8, 23u8, 180u8, 233u8, + 52u8, 53u8, 133u8, 207u8, 94u8, 58u8, 43u8, 221u8, 236u8, 161u8, 41u8, + 30u8, 194u8, 125u8, 2u8, 118u8, 152u8, 197u8, 49u8, 34u8, 33u8, + ], + ) + } + #[doc = " A custom head data that should be returned as result of `validate_block`."] + #[doc = ""] + #[doc = " See [`Pallet::set_custom_validation_head_data`] for more information."] + pub fn custom_validation_head_data( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainSystem", + "CustomValidationHeadData", + vec![], + [ + 189u8, 150u8, 234u8, 128u8, 111u8, 27u8, 173u8, 92u8, 109u8, 4u8, 98u8, + 103u8, 158u8, 19u8, 16u8, 5u8, 107u8, 135u8, 126u8, 170u8, 62u8, 64u8, + 149u8, 80u8, 33u8, 17u8, 83u8, 22u8, 176u8, 118u8, 26u8, 223u8, + ], + ) + } + } + } + } + pub mod parachain_info { + use super::{root_mod, runtime_types}; + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + pub fn parachain_id( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::polkadot_parachain::primitives::Id, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "ParachainInfo", + "ParachainId", + vec![], + [ + 151u8, 191u8, 241u8, 118u8, 192u8, 47u8, 166u8, 151u8, 217u8, 240u8, + 165u8, 232u8, 51u8, 113u8, 243u8, 1u8, 89u8, 240u8, 11u8, 1u8, 77u8, + 104u8, 12u8, 56u8, 17u8, 135u8, 214u8, 19u8, 114u8, 135u8, 66u8, 76u8, + ], + ) + } + } + } + } + pub mod balances { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct TransferAllowDeath { + pub dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + pub value: ::core::primitive::u128, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetBalanceDeprecated { + pub who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + pub new_free: ::core::primitive::u128, + #[codec(compact)] + pub old_reserved: ::core::primitive::u128, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ForceTransfer { + pub source: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + pub dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + pub value: ::core::primitive::u128, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct TransferKeepAlive { + pub dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + pub value: ::core::primitive::u128, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct TransferAll { + pub dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + pub keep_alive: ::core::primitive::bool, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ForceUnreserve { + pub who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + pub amount: ::core::primitive::u128, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct UpgradeAccounts { + pub who: ::std::vec::Vec<::sp_core::crypto::AccountId32>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Transfer { + pub dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + pub value: ::core::primitive::u128, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ForceSetBalance { + pub who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + pub new_free: ::core::primitive::u128, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Transfer some liquid free balance to another account."] + #[doc = ""] + #[doc = "`transfer_allow_death` will set the `FreeBalance` of the sender and receiver."] + #[doc = "If the sender's account is below the existential deposit as a result"] + #[doc = "of the transfer, the account will be reaped."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be `Signed` by the transactor."] + pub fn transfer_allow_death( + &self, + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + value: ::core::primitive::u128, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "transfer_allow_death", + TransferAllowDeath { dest, value }, + [ + 234u8, 130u8, 149u8, 36u8, 235u8, 112u8, 159u8, 189u8, 104u8, 148u8, + 108u8, 230u8, 25u8, 198u8, 71u8, 158u8, 112u8, 3u8, 162u8, 25u8, 145u8, + 252u8, 44u8, 63u8, 47u8, 34u8, 47u8, 158u8, 61u8, 14u8, 120u8, 255u8, + ], + ) + } + #[doc = "Set the regular balance of a given account; it also takes a reserved balance but this"] + #[doc = "must be the same as the account's current reserved balance."] + #[doc = ""] + #[doc = "The dispatch origin for this call is `root`."] + #[doc = ""] + #[doc = "WARNING: This call is DEPRECATED! Use `force_set_balance` instead."] + pub fn set_balance_deprecated( + &self, + who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + new_free: ::core::primitive::u128, + old_reserved: ::core::primitive::u128, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "set_balance_deprecated", + SetBalanceDeprecated { who, new_free, old_reserved }, + [ + 240u8, 107u8, 184u8, 206u8, 78u8, 106u8, 115u8, 152u8, 130u8, 56u8, + 156u8, 176u8, 105u8, 27u8, 176u8, 187u8, 49u8, 171u8, 229u8, 79u8, + 254u8, 248u8, 8u8, 162u8, 134u8, 12u8, 89u8, 100u8, 137u8, 102u8, + 132u8, 158u8, + ], + ) + } + #[doc = "Exactly as `transfer_allow_death`, except the origin must be root and the source account"] + #[doc = "may be specified."] + pub fn force_transfer( + &self, + source: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + value: ::core::primitive::u128, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "force_transfer", + ForceTransfer { source, dest, value }, + [ + 79u8, 174u8, 212u8, 108u8, 184u8, 33u8, 170u8, 29u8, 232u8, 254u8, + 195u8, 218u8, 221u8, 134u8, 57u8, 99u8, 6u8, 70u8, 181u8, 227u8, 56u8, + 239u8, 243u8, 158u8, 157u8, 245u8, 36u8, 162u8, 11u8, 237u8, 147u8, + 15u8, + ], + ) + } + #[doc = "Same as the [`transfer_allow_death`] call, but with a check that the transfer will not"] + #[doc = "kill the origin account."] + #[doc = ""] + #[doc = "99% of the time you want [`transfer_allow_death`] instead."] + #[doc = ""] + #[doc = "[`transfer_allow_death`]: struct.Pallet.html#method.transfer"] + pub fn transfer_keep_alive( + &self, + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + value: ::core::primitive::u128, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "transfer_keep_alive", + TransferKeepAlive { dest, value }, + [ + 112u8, 179u8, 75u8, 168u8, 193u8, 221u8, 9u8, 82u8, 190u8, 113u8, + 253u8, 13u8, 130u8, 134u8, 170u8, 216u8, 136u8, 111u8, 242u8, 220u8, + 202u8, 112u8, 47u8, 79u8, 73u8, 244u8, 226u8, 59u8, 240u8, 188u8, + 210u8, 208u8, + ], + ) + } + #[doc = "Transfer the entire transferable balance from the caller account."] + #[doc = ""] + #[doc = "NOTE: This function only attempts to transfer _transferable_ balances. This means that"] + #[doc = "any locked, reserved, or existential deposits (when `keep_alive` is `true`), will not be"] + #[doc = "transferred by this function. To ensure that this function results in a killed account,"] + #[doc = "you might need to prepare the account by removing any reference counters, storage"] + #[doc = "deposits, etc..."] + #[doc = ""] + #[doc = "The dispatch origin of this call must be Signed."] + #[doc = ""] + #[doc = "- `dest`: The recipient of the transfer."] + #[doc = "- `keep_alive`: A boolean to determine if the `transfer_all` operation should send all"] + #[doc = " of the funds the account has, causing the sender account to be killed (false), or"] + #[doc = " transfer everything except at least the existential deposit, which will guarantee to"] + #[doc = " keep the sender account alive (true)."] + pub fn transfer_all( + &self, + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + keep_alive: ::core::primitive::bool, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "transfer_all", + TransferAll { dest, keep_alive }, + [ + 46u8, 129u8, 29u8, 177u8, 221u8, 107u8, 245u8, 69u8, 238u8, 126u8, + 145u8, 26u8, 219u8, 208u8, 14u8, 80u8, 149u8, 1u8, 214u8, 63u8, 67u8, + 201u8, 144u8, 45u8, 129u8, 145u8, 174u8, 71u8, 238u8, 113u8, 208u8, + 34u8, + ], + ) + } + #[doc = "Unreserve some balance from a user by force."] + #[doc = ""] + #[doc = "Can only be called by ROOT."] + pub fn force_unreserve( + &self, + who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + amount: ::core::primitive::u128, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "force_unreserve", + ForceUnreserve { who, amount }, + [ + 160u8, 146u8, 137u8, 76u8, 157u8, 187u8, 66u8, 148u8, 207u8, 76u8, + 32u8, 254u8, 82u8, 215u8, 35u8, 161u8, 213u8, 52u8, 32u8, 98u8, 102u8, + 106u8, 234u8, 123u8, 6u8, 175u8, 184u8, 188u8, 174u8, 106u8, 176u8, + 78u8, + ], + ) + } + #[doc = "Upgrade a specified account."] + #[doc = ""] + #[doc = "- `origin`: Must be `Signed`."] + #[doc = "- `who`: The account to be upgraded."] + #[doc = ""] + #[doc = "This will waive the transaction fee if at least all but 10% of the accounts needed to"] + #[doc = "be upgraded. (We let some not have to be upgraded just in order to allow for the"] + #[doc = "possibililty of churn)."] + pub fn upgrade_accounts( + &self, + who: ::std::vec::Vec<::sp_core::crypto::AccountId32>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "upgrade_accounts", + UpgradeAccounts { who }, + [ + 164u8, 61u8, 119u8, 24u8, 165u8, 46u8, 197u8, 59u8, 39u8, 198u8, 228u8, + 96u8, 228u8, 45u8, 85u8, 51u8, 37u8, 5u8, 75u8, 40u8, 241u8, 163u8, + 86u8, 228u8, 151u8, 217u8, 47u8, 105u8, 203u8, 103u8, 207u8, 4u8, + ], + ) + } + #[doc = "Alias for `transfer_allow_death`, provided only for name-wise compatibility."] + #[doc = ""] + #[doc = "WARNING: DEPRECATED! Will be released in approximately 3 months."] + pub fn transfer( + &self, + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + value: ::core::primitive::u128, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "transfer", + Transfer { dest, value }, + [ + 111u8, 222u8, 32u8, 56u8, 171u8, 77u8, 252u8, 29u8, 194u8, 155u8, + 200u8, 192u8, 198u8, 81u8, 23u8, 115u8, 236u8, 91u8, 218u8, 114u8, + 107u8, 141u8, 138u8, 100u8, 237u8, 21u8, 58u8, 172u8, 3u8, 20u8, 216u8, + 38u8, + ], + ) + } + #[doc = "Set the regular balance of a given account."] + #[doc = ""] + #[doc = "The dispatch origin for this call is `root`."] + pub fn force_set_balance( + &self, + who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + new_free: ::core::primitive::u128, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "Balances", + "force_set_balance", + ForceSetBalance { who, new_free }, + [ + 237u8, 4u8, 41u8, 58u8, 62u8, 179u8, 160u8, 4u8, 50u8, 71u8, 178u8, + 36u8, 130u8, 130u8, 92u8, 229u8, 16u8, 245u8, 169u8, 109u8, 165u8, + 72u8, 94u8, 70u8, 196u8, 136u8, 37u8, 94u8, 140u8, 215u8, 125u8, 125u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::pallet_balances::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An account was created with some free balance."] + pub struct Endowed { + pub account: ::sp_core::crypto::AccountId32, + pub free_balance: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Endowed { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Endowed"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An account was removed whose balance was non-zero but below ExistentialDeposit,"] + #[doc = "resulting in an outright loss."] + pub struct DustLost { + pub account: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for DustLost { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "DustLost"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Transfer succeeded."] + pub struct Transfer { + pub from: ::sp_core::crypto::AccountId32, + pub to: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Transfer { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Transfer"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A balance was set by root."] + pub struct BalanceSet { + pub who: ::sp_core::crypto::AccountId32, + pub free: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for BalanceSet { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "BalanceSet"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some balance was reserved (moved from free to reserved)."] + pub struct Reserved { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Reserved { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Reserved"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some balance was unreserved (moved from reserved to free)."] + pub struct Unreserved { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Unreserved { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Unreserved"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some balance was moved from the reserve of the first account to the second account."] + #[doc = "Final argument indicates the destination balance type."] + pub struct ReserveRepatriated { + pub from: ::sp_core::crypto::AccountId32, + pub to: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + pub destination_status: + runtime_types::frame_support::traits::tokens::misc::BalanceStatus, + } + impl ::subxt::events::StaticEvent for ReserveRepatriated { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "ReserveRepatriated"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some amount was deposited (e.g. for transaction fees)."] + pub struct Deposit { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Deposit { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Deposit"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some amount was withdrawn from the account (e.g. for transaction fees)."] + pub struct Withdraw { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Withdraw { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Withdraw"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some amount was removed from the account (e.g. for misbehavior)."] + pub struct Slashed { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Slashed { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Slashed"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some amount was minted into an account."] + pub struct Minted { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Minted { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Minted"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some amount was burned from an account."] + pub struct Burned { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Burned { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Burned"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some amount was suspended from an account (it can be restored later)."] + pub struct Suspended { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Suspended { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Suspended"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some amount was restored into an account."] + pub struct Restored { + pub who: ::sp_core::crypto::AccountId32, + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Restored { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Restored"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An account was upgraded."] + pub struct Upgraded { + pub who: ::sp_core::crypto::AccountId32, + } + impl ::subxt::events::StaticEvent for Upgraded { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Upgraded"; + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Total issuance was increased by `amount`, creating a credit to be balanced."] + pub struct Issued { + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Issued { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Issued"; + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Total issuance was decreased by `amount`, creating a debt to be balanced."] + pub struct Rescinded { + pub amount: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for Rescinded { + const PALLET: &'static str = "Balances"; + const EVENT: &'static str = "Rescinded"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " The total units issued in the system."] + pub fn total_issuance( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u128>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "TotalIssuance", + vec![], + [ + 1u8, 206u8, 252u8, 237u8, 6u8, 30u8, 20u8, 232u8, 164u8, 115u8, 51u8, + 156u8, 156u8, 206u8, 241u8, 187u8, 44u8, 84u8, 25u8, 164u8, 235u8, + 20u8, 86u8, 242u8, 124u8, 23u8, 28u8, 140u8, 26u8, 73u8, 231u8, 51u8, + ], + ) + } + #[doc = " The total units of outstanding deactivated balance in the system."] + pub fn inactive_issuance( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u128>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "InactiveIssuance", + vec![], + [ + 74u8, 203u8, 111u8, 142u8, 225u8, 104u8, 173u8, 51u8, 226u8, 12u8, + 85u8, 135u8, 41u8, 206u8, 177u8, 238u8, 94u8, 246u8, 184u8, 250u8, + 140u8, 213u8, 91u8, 118u8, 163u8, 111u8, 211u8, 46u8, 204u8, 160u8, + 154u8, 21u8, + ], + ) + } + #[doc = " The Balances pallet example of storing the balance of an account."] + #[doc = ""] + #[doc = " # Example"] + #[doc = ""] + #[doc = " ```nocompile"] + #[doc = " impl pallet_balances::Config for Runtime {"] + #[doc = " type AccountStore = StorageMapShim, frame_system::Provider, AccountId, Self::AccountData>"] + #[doc = " }"] + #[doc = " ```"] + #[doc = ""] + #[doc = " You can also store the balance of an account in the `System` pallet."] + #[doc = ""] + #[doc = " # Example"] + #[doc = ""] + #[doc = " ```nocompile"] + #[doc = " impl pallet_balances::Config for Runtime {"] + #[doc = " type AccountStore = System"] + #[doc = " }"] + #[doc = " ```"] + #[doc = ""] + #[doc = " But this comes with tradeoffs, storing account balances in the system pallet stores"] + #[doc = " `frame_system` data alongside the account data contrary to storing account balances in the"] + #[doc = " `Balances` pallet, which uses a `StorageMap` to store balances data only."] + #[doc = " NOTE: This is only used in the case that this pallet is used to store balances."] + pub fn account( + &self, + _0: impl ::std::borrow::Borrow<::sp_core::crypto::AccountId32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::pallet_balances::types::AccountData<::core::primitive::u128>, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Account", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 109u8, 250u8, 18u8, 96u8, 139u8, 232u8, 4u8, 139u8, 133u8, 239u8, 30u8, + 237u8, 73u8, 209u8, 143u8, 160u8, 94u8, 248u8, 124u8, 43u8, 224u8, + 165u8, 11u8, 6u8, 176u8, 144u8, 189u8, 161u8, 174u8, 210u8, 56u8, + 225u8, + ], + ) + } + #[doc = " The Balances pallet example of storing the balance of an account."] + #[doc = ""] + #[doc = " # Example"] + #[doc = ""] + #[doc = " ```nocompile"] + #[doc = " impl pallet_balances::Config for Runtime {"] + #[doc = " type AccountStore = StorageMapShim, frame_system::Provider, AccountId, Self::AccountData>"] + #[doc = " }"] + #[doc = " ```"] + #[doc = ""] + #[doc = " You can also store the balance of an account in the `System` pallet."] + #[doc = ""] + #[doc = " # Example"] + #[doc = ""] + #[doc = " ```nocompile"] + #[doc = " impl pallet_balances::Config for Runtime {"] + #[doc = " type AccountStore = System"] + #[doc = " }"] + #[doc = " ```"] + #[doc = ""] + #[doc = " But this comes with tradeoffs, storing account balances in the system pallet stores"] + #[doc = " `frame_system` data alongside the account data contrary to storing account balances in the"] + #[doc = " `Balances` pallet, which uses a `StorageMap` to store balances data only."] + #[doc = " NOTE: This is only used in the case that this pallet is used to store balances."] + pub fn account_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::pallet_balances::types::AccountData<::core::primitive::u128>, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Account", + Vec::new(), + [ + 109u8, 250u8, 18u8, 96u8, 139u8, 232u8, 4u8, 139u8, 133u8, 239u8, 30u8, + 237u8, 73u8, 209u8, 143u8, 160u8, 94u8, 248u8, 124u8, 43u8, 224u8, + 165u8, 11u8, 6u8, 176u8, 144u8, 189u8, 161u8, 174u8, 210u8, 56u8, + 225u8, + ], + ) + } + #[doc = " Any liquidity locks on some account balances."] + #[doc = " NOTE: Should only be accessed when setting, changing and freeing a lock."] + pub fn locks( + &self, + _0: impl ::std::borrow::Borrow<::sp_core::crypto::AccountId32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::weak_bounded_vec::WeakBoundedVec< + runtime_types::pallet_balances::types::BalanceLock< + ::core::primitive::u128, + >, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Locks", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 216u8, 253u8, 87u8, 73u8, 24u8, 218u8, 35u8, 0u8, 244u8, 134u8, 195u8, + 58u8, 255u8, 64u8, 153u8, 212u8, 210u8, 232u8, 4u8, 122u8, 90u8, 212u8, + 136u8, 14u8, 127u8, 232u8, 8u8, 192u8, 40u8, 233u8, 18u8, 250u8, + ], + ) + } + #[doc = " Any liquidity locks on some account balances."] + #[doc = " NOTE: Should only be accessed when setting, changing and freeing a lock."] + pub fn locks_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::weak_bounded_vec::WeakBoundedVec< + runtime_types::pallet_balances::types::BalanceLock< + ::core::primitive::u128, + >, + >, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Locks", + Vec::new(), + [ + 216u8, 253u8, 87u8, 73u8, 24u8, 218u8, 35u8, 0u8, 244u8, 134u8, 195u8, + 58u8, 255u8, 64u8, 153u8, 212u8, 210u8, 232u8, 4u8, 122u8, 90u8, 212u8, + 136u8, 14u8, 127u8, 232u8, 8u8, 192u8, 40u8, 233u8, 18u8, 250u8, + ], + ) + } + #[doc = " Named reserves on some account balances."] + pub fn reserves( + &self, + _0: impl ::std::borrow::Borrow<::sp_core::crypto::AccountId32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::pallet_balances::types::ReserveData< + [::core::primitive::u8; 8usize], + ::core::primitive::u128, + >, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Reserves", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 17u8, 32u8, 191u8, 46u8, 76u8, 220u8, 101u8, 100u8, 42u8, 250u8, 128u8, + 167u8, 117u8, 44u8, 85u8, 96u8, 105u8, 216u8, 16u8, 147u8, 74u8, 55u8, + 183u8, 94u8, 160u8, 177u8, 26u8, 187u8, 71u8, 197u8, 187u8, 163u8, + ], + ) + } + #[doc = " Named reserves on some account balances."] + pub fn reserves_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::pallet_balances::types::ReserveData< + [::core::primitive::u8; 8usize], + ::core::primitive::u128, + >, + >, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Reserves", + Vec::new(), + [ + 17u8, 32u8, 191u8, 46u8, 76u8, 220u8, 101u8, 100u8, 42u8, 250u8, 128u8, + 167u8, 117u8, 44u8, 85u8, 96u8, 105u8, 216u8, 16u8, 147u8, 74u8, 55u8, + 183u8, 94u8, 160u8, 177u8, 26u8, 187u8, 71u8, 197u8, 187u8, 163u8, + ], + ) + } + #[doc = " Holds on account balances."] + pub fn holds( + &self, + _0: impl ::std::borrow::Borrow<::sp_core::crypto::AccountId32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::pallet_balances::types::IdAmount< + (), + ::core::primitive::u128, + >, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Holds", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 247u8, 81u8, 4u8, 220u8, 77u8, 205u8, 28u8, 131u8, 215u8, 74u8, 197u8, + 137u8, 113u8, 214u8, 249u8, 91u8, 81u8, 216u8, 8u8, 5u8, 233u8, 39u8, + 104u8, 250u8, 3u8, 228u8, 148u8, 78u8, 4u8, 34u8, 45u8, 143u8, + ], + ) + } + #[doc = " Holds on account balances."] + pub fn holds_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::pallet_balances::types::IdAmount< + (), + ::core::primitive::u128, + >, + >, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Holds", + Vec::new(), + [ + 247u8, 81u8, 4u8, 220u8, 77u8, 205u8, 28u8, 131u8, 215u8, 74u8, 197u8, + 137u8, 113u8, 214u8, 249u8, 91u8, 81u8, 216u8, 8u8, 5u8, 233u8, 39u8, + 104u8, 250u8, 3u8, 228u8, 148u8, 78u8, 4u8, 34u8, 45u8, 143u8, + ], + ) + } + #[doc = " Freeze locks on account balances."] + pub fn freezes( + &self, + _0: impl ::std::borrow::Borrow<::sp_core::crypto::AccountId32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::pallet_balances::types::IdAmount< + (), + ::core::primitive::u128, + >, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Freezes", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 211u8, 24u8, 237u8, 217u8, 47u8, 230u8, 147u8, 39u8, 112u8, 209u8, + 193u8, 47u8, 242u8, 13u8, 241u8, 0u8, 100u8, 45u8, 116u8, 130u8, 246u8, + 196u8, 50u8, 134u8, 135u8, 112u8, 206u8, 1u8, 12u8, 53u8, 106u8, 131u8, + ], + ) + } + #[doc = " Freeze locks on account balances."] + pub fn freezes_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::pallet_balances::types::IdAmount< + (), + ::core::primitive::u128, + >, + >, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "Balances", + "Freezes", + Vec::new(), + [ + 211u8, 24u8, 237u8, 217u8, 47u8, 230u8, 147u8, 39u8, 112u8, 209u8, + 193u8, 47u8, 242u8, 13u8, 241u8, 0u8, 100u8, 45u8, 116u8, 130u8, 246u8, + 196u8, 50u8, 134u8, 135u8, 112u8, 206u8, 1u8, 12u8, 53u8, 106u8, 131u8, + ], + ) + } + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " The minimum amount required to keep an account open."] + pub fn existential_deposit( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u128>, + > { + ::subxt::constants::StaticConstantAddress::new( + "Balances", + "ExistentialDeposit", + [ + 84u8, 157u8, 140u8, 4u8, 93u8, 57u8, 29u8, 133u8, 105u8, 200u8, 214u8, + 27u8, 144u8, 208u8, 218u8, 160u8, 130u8, 109u8, 101u8, 54u8, 210u8, + 136u8, 71u8, 63u8, 49u8, 237u8, 234u8, 15u8, 178u8, 98u8, 148u8, 156u8, + ], + ) + } + #[doc = " The maximum number of locks that should exist on an account."] + #[doc = " Not strictly enforced, but used for weight estimation."] + pub fn max_locks( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + > { + ::subxt::constants::StaticConstantAddress::new( + "Balances", + "MaxLocks", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " The maximum number of named reserves that can exist on an account."] + pub fn max_reserves( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + > { + ::subxt::constants::StaticConstantAddress::new( + "Balances", + "MaxReserves", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " The maximum number of holds that can exist on an account at any time."] + pub fn max_holds( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + > { + ::subxt::constants::StaticConstantAddress::new( + "Balances", + "MaxHolds", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " The maximum number of individual freeze locks that can exist on an account at any time."] + pub fn max_freezes( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + > { + ::subxt::constants::StaticConstantAddress::new( + "Balances", + "MaxFreezes", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + } + } + } + pub mod aura { + use super::{root_mod, runtime_types}; + } + pub mod aura_ext { + use super::{root_mod, runtime_types}; + } + pub mod xcmp_queue { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ServiceOverweight { + pub index: ::core::primitive::u64, + pub weight_limit: ::sp_weights::Weight, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SuspendXcmExecution; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ResumeXcmExecution; + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct UpdateSuspendThreshold { + pub new: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct UpdateDropThreshold { + pub new: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct UpdateResumeThreshold { + pub new: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct UpdateThresholdWeight { + pub new: ::sp_weights::Weight, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct UpdateWeightRestrictDecay { + pub new: ::sp_weights::Weight, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct UpdateXcmpMaxIndividualWeight { + pub new: ::sp_weights::Weight, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Services a single overweight XCM."] + #[doc = ""] + #[doc = "- `origin`: Must pass `ExecuteOverweightOrigin`."] + #[doc = "- `index`: The index of the overweight XCM to service"] + #[doc = "- `weight_limit`: The amount of weight that XCM execution may take."] + #[doc = ""] + #[doc = "Errors:"] + #[doc = "- `BadOverweightIndex`: XCM under `index` is not found in the `Overweight` storage map."] + #[doc = "- `BadXcm`: XCM under `index` cannot be properly decoded into a valid XCM format."] + #[doc = "- `WeightOverLimit`: XCM execution may use greater `weight_limit`."] + #[doc = ""] + #[doc = "Events:"] + #[doc = "- `OverweightServiced`: On success."] + pub fn service_overweight( + &self, + index: ::core::primitive::u64, + weight_limit: ::sp_weights::Weight, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "service_overweight", + ServiceOverweight { index, weight_limit }, + [ + 121u8, 236u8, 235u8, 23u8, 210u8, 238u8, 238u8, 122u8, 15u8, 86u8, + 34u8, 119u8, 105u8, 100u8, 214u8, 236u8, 117u8, 39u8, 254u8, 235u8, + 189u8, 15u8, 72u8, 74u8, 225u8, 134u8, 148u8, 126u8, 31u8, 203u8, + 144u8, 106u8, + ], + ) + } + #[doc = "Suspends all XCM executions for the XCMP queue, regardless of the sender's origin."] + #[doc = ""] + #[doc = "- `origin`: Must pass `ControllerOrigin`."] + pub fn suspend_xcm_execution( + &self, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "suspend_xcm_execution", + SuspendXcmExecution {}, + [ + 139u8, 76u8, 166u8, 86u8, 106u8, 144u8, 16u8, 47u8, 105u8, 185u8, 7u8, + 7u8, 63u8, 14u8, 250u8, 236u8, 99u8, 121u8, 101u8, 143u8, 28u8, 175u8, + 108u8, 197u8, 226u8, 43u8, 103u8, 92u8, 186u8, 12u8, 51u8, 153u8, + ], + ) + } + #[doc = "Resumes all XCM executions for the XCMP queue."] + #[doc = ""] + #[doc = "Note that this function doesn't change the status of the in/out bound channels."] + #[doc = ""] + #[doc = "- `origin`: Must pass `ControllerOrigin`."] + pub fn resume_xcm_execution( + &self, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "resume_xcm_execution", + ResumeXcmExecution {}, + [ + 67u8, 111u8, 47u8, 237u8, 79u8, 42u8, 90u8, 56u8, 245u8, 2u8, 20u8, + 23u8, 33u8, 121u8, 135u8, 50u8, 204u8, 147u8, 195u8, 80u8, 177u8, + 202u8, 8u8, 160u8, 164u8, 138u8, 64u8, 252u8, 178u8, 63u8, 102u8, + 245u8, + ], + ) + } + #[doc = "Overwrites the number of pages of messages which must be in the queue for the other side to be told to"] + #[doc = "suspend their sending."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.suspend_value`"] + pub fn update_suspend_threshold( + &self, + new: ::core::primitive::u32, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "update_suspend_threshold", + UpdateSuspendThreshold { new }, + [ + 155u8, 120u8, 9u8, 228u8, 110u8, 62u8, 233u8, 36u8, 57u8, 85u8, 19u8, + 67u8, 246u8, 88u8, 81u8, 116u8, 243u8, 236u8, 174u8, 130u8, 8u8, 246u8, + 254u8, 97u8, 155u8, 207u8, 123u8, 60u8, 164u8, 14u8, 196u8, 97u8, + ], + ) + } + #[doc = "Overwrites the number of pages of messages which must be in the queue after which we drop any further"] + #[doc = "messages from the channel."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.drop_threshold`"] + pub fn update_drop_threshold( + &self, + new: ::core::primitive::u32, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "update_drop_threshold", + UpdateDropThreshold { new }, + [ + 146u8, 177u8, 164u8, 96u8, 247u8, 182u8, 229u8, 175u8, 194u8, 101u8, + 186u8, 168u8, 94u8, 114u8, 172u8, 119u8, 35u8, 222u8, 175u8, 21u8, + 67u8, 61u8, 216u8, 144u8, 194u8, 10u8, 181u8, 62u8, 166u8, 198u8, + 138u8, 243u8, + ], + ) + } + #[doc = "Overwrites the number of pages of messages which the queue must be reduced to before it signals that"] + #[doc = "message sending may recommence after it has been suspended."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.resume_threshold`"] + pub fn update_resume_threshold( + &self, + new: ::core::primitive::u32, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "update_resume_threshold", + UpdateResumeThreshold { new }, + [ + 231u8, 128u8, 80u8, 179u8, 61u8, 50u8, 103u8, 209u8, 103u8, 55u8, + 101u8, 113u8, 150u8, 10u8, 202u8, 7u8, 0u8, 77u8, 58u8, 4u8, 227u8, + 17u8, 225u8, 112u8, 121u8, 203u8, 184u8, 113u8, 231u8, 156u8, 174u8, + 154u8, + ], + ) + } + #[doc = "Overwrites the amount of remaining weight under which we stop processing messages."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.threshold_weight`"] + pub fn update_threshold_weight( + &self, + new: ::sp_weights::Weight, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "update_threshold_weight", + UpdateThresholdWeight { new }, + [ + 14u8, 144u8, 112u8, 207u8, 195u8, 208u8, 184u8, 164u8, 94u8, 41u8, 8u8, + 58u8, 180u8, 80u8, 239u8, 39u8, 210u8, 159u8, 114u8, 169u8, 152u8, + 176u8, 26u8, 161u8, 32u8, 43u8, 250u8, 156u8, 56u8, 21u8, 43u8, 159u8, + ], + ) + } + #[doc = "Overwrites the speed to which the available weight approaches the maximum weight."] + #[doc = "A lower number results in a faster progression. A value of 1 makes the entire weight available initially."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.weight_restrict_decay`."] + pub fn update_weight_restrict_decay( + &self, + new: ::sp_weights::Weight, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "update_weight_restrict_decay", + UpdateWeightRestrictDecay { new }, + [ + 42u8, 53u8, 83u8, 191u8, 51u8, 227u8, 210u8, 193u8, 142u8, 218u8, + 244u8, 177u8, 19u8, 87u8, 148u8, 177u8, 231u8, 197u8, 196u8, 255u8, + 41u8, 130u8, 245u8, 139u8, 107u8, 212u8, 90u8, 161u8, 82u8, 248u8, + 160u8, 223u8, + ], + ) + } + #[doc = "Overwrite the maximum amount of weight any individual message may consume."] + #[doc = "Messages above this weight go into the overweight queue and may only be serviced explicitly."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.xcmp_max_individual_weight`."] + pub fn update_xcmp_max_individual_weight( + &self, + new: ::sp_weights::Weight, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "XcmpQueue", + "update_xcmp_max_individual_weight", + UpdateXcmpMaxIndividualWeight { new }, + [ + 148u8, 185u8, 89u8, 36u8, 152u8, 220u8, 248u8, 233u8, 236u8, 82u8, + 170u8, 111u8, 225u8, 142u8, 25u8, 211u8, 72u8, 248u8, 250u8, 14u8, + 45u8, 72u8, 78u8, 95u8, 92u8, 196u8, 245u8, 104u8, 112u8, 128u8, 27u8, + 109u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::cumulus_pallet_xcmp_queue::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some XCM was executed ok."] + pub struct Success { + pub message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + pub weight: ::sp_weights::Weight, + } + impl ::subxt::events::StaticEvent for Success { + const PALLET: &'static str = "XcmpQueue"; + const EVENT: &'static str = "Success"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some XCM failed."] + pub struct Fail { + pub message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + pub error: runtime_types::xcm::v3::traits::Error, + pub weight: ::sp_weights::Weight, + } + impl ::subxt::events::StaticEvent for Fail { + const PALLET: &'static str = "XcmpQueue"; + const EVENT: &'static str = "Fail"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Bad XCM version used."] + pub struct BadVersion { + pub message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + } + impl ::subxt::events::StaticEvent for BadVersion { + const PALLET: &'static str = "XcmpQueue"; + const EVENT: &'static str = "BadVersion"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Bad XCM format used."] + pub struct BadFormat { + pub message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + } + impl ::subxt::events::StaticEvent for BadFormat { + const PALLET: &'static str = "XcmpQueue"; + const EVENT: &'static str = "BadFormat"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An HRMP message was sent to a sibling parachain."] + pub struct XcmpMessageSent { + pub message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + } + impl ::subxt::events::StaticEvent for XcmpMessageSent { + const PALLET: &'static str = "XcmpQueue"; + const EVENT: &'static str = "XcmpMessageSent"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An XCM exceeded the individual message weight budget."] + pub struct OverweightEnqueued { + pub sender: runtime_types::polkadot_parachain::primitives::Id, + pub sent_at: ::core::primitive::u32, + pub index: ::core::primitive::u64, + pub required: ::sp_weights::Weight, + } + impl ::subxt::events::StaticEvent for OverweightEnqueued { + const PALLET: &'static str = "XcmpQueue"; + const EVENT: &'static str = "OverweightEnqueued"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An XCM from the overweight queue was executed with the given actual weight used."] + pub struct OverweightServiced { + pub index: ::core::primitive::u64, + pub used: ::sp_weights::Weight, + } + impl ::subxt::events::StaticEvent for OverweightServiced { + const PALLET: &'static str = "XcmpQueue"; + const EVENT: &'static str = "OverweightServiced"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " Status of the inbound XCMP channels."] + pub fn inbound_xcmp_status( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec< + runtime_types::cumulus_pallet_xcmp_queue::InboundChannelDetails, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "InboundXcmpStatus", + vec![], + [ + 183u8, 198u8, 237u8, 153u8, 132u8, 201u8, 87u8, 182u8, 121u8, 164u8, + 129u8, 241u8, 58u8, 192u8, 115u8, 152u8, 7u8, 33u8, 95u8, 51u8, 2u8, + 176u8, 144u8, 12u8, 125u8, 83u8, 92u8, 198u8, 211u8, 101u8, 28u8, 50u8, + ], + ) + } + #[doc = " Inbound aggregate XCMP messages. It can only be one per ParaId/block."] + pub fn inbound_xcmp_messages( + &self, + _0: impl ::std::borrow::Borrow, + _1: impl ::std::borrow::Borrow<::core::primitive::u32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "InboundXcmpMessages", + vec![ + ::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + ), + ::subxt::storage::address::StorageMapKey::new( + _1.borrow(), + ::subxt::storage::address::StorageHasher::Twox64Concat, + ), + ], + [ + 157u8, 232u8, 222u8, 97u8, 218u8, 96u8, 96u8, 90u8, 216u8, 205u8, 39u8, + 130u8, 109u8, 152u8, 127u8, 57u8, 54u8, 63u8, 104u8, 135u8, 33u8, + 175u8, 197u8, 166u8, 238u8, 22u8, 137u8, 162u8, 226u8, 199u8, 87u8, + 25u8, + ], + ) + } + #[doc = " Inbound aggregate XCMP messages. It can only be one per ParaId/block."] + pub fn inbound_xcmp_messages_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "InboundXcmpMessages", + Vec::new(), + [ + 157u8, 232u8, 222u8, 97u8, 218u8, 96u8, 96u8, 90u8, 216u8, 205u8, 39u8, + 130u8, 109u8, 152u8, 127u8, 57u8, 54u8, 63u8, 104u8, 135u8, 33u8, + 175u8, 197u8, 166u8, 238u8, 22u8, 137u8, 162u8, 226u8, 199u8, 87u8, + 25u8, + ], + ) + } + #[doc = " The non-empty XCMP channels in order of becoming non-empty, and the index of the first"] + #[doc = " and last outbound message. If the two indices are equal, then it indicates an empty"] + #[doc = " queue and there must be a non-`Ok` `OutboundStatus`. We assume queues grow no greater"] + #[doc = " than 65535 items. Queue indices for normal messages begin at one; zero is reserved in"] + #[doc = " case of the need to send a high-priority signal message this block."] + #[doc = " The bool is true if there is a signal message waiting to be sent."] + pub fn outbound_xcmp_status( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec< + runtime_types::cumulus_pallet_xcmp_queue::OutboundChannelDetails, + >, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "OutboundXcmpStatus", + vec![], + [ + 238u8, 120u8, 185u8, 141u8, 82u8, 159u8, 41u8, 68u8, 204u8, 15u8, 46u8, + 152u8, 144u8, 74u8, 250u8, 83u8, 71u8, 105u8, 54u8, 53u8, 226u8, 87u8, + 14u8, 202u8, 58u8, 160u8, 54u8, 162u8, 239u8, 248u8, 227u8, 116u8, + ], + ) + } + #[doc = " The messages outbound in a given XCMP channel."] + pub fn outbound_xcmp_messages( + &self, + _0: impl ::std::borrow::Borrow, + _1: impl ::std::borrow::Borrow<::core::primitive::u16>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "OutboundXcmpMessages", + vec![ + ::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + ), + ::subxt::storage::address::StorageMapKey::new( + _1.borrow(), + ::subxt::storage::address::StorageHasher::Twox64Concat, + ), + ], + [ + 50u8, 182u8, 237u8, 191u8, 106u8, 67u8, 54u8, 1u8, 17u8, 107u8, 70u8, + 90u8, 202u8, 8u8, 63u8, 184u8, 171u8, 111u8, 192u8, 196u8, 7u8, 31u8, + 186u8, 68u8, 31u8, 63u8, 71u8, 61u8, 83u8, 223u8, 79u8, 200u8, + ], + ) + } + #[doc = " The messages outbound in a given XCMP channel."] + pub fn outbound_xcmp_messages_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "OutboundXcmpMessages", + Vec::new(), + [ + 50u8, 182u8, 237u8, 191u8, 106u8, 67u8, 54u8, 1u8, 17u8, 107u8, 70u8, + 90u8, 202u8, 8u8, 63u8, 184u8, 171u8, 111u8, 192u8, 196u8, 7u8, 31u8, + 186u8, 68u8, 31u8, 63u8, 71u8, 61u8, 83u8, 223u8, 79u8, 200u8, + ], + ) + } + #[doc = " Any signal messages waiting to be sent."] + pub fn signal_messages( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "SignalMessages", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 156u8, 242u8, 186u8, 89u8, 177u8, 195u8, 90u8, 121u8, 94u8, 106u8, + 222u8, 78u8, 19u8, 162u8, 179u8, 96u8, 38u8, 113u8, 209u8, 148u8, 29u8, + 110u8, 106u8, 167u8, 162u8, 96u8, 221u8, 20u8, 33u8, 179u8, 168u8, + 142u8, + ], + ) + } + #[doc = " Any signal messages waiting to be sent."] + pub fn signal_messages_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::std::vec::Vec<::core::primitive::u8>>, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "SignalMessages", + Vec::new(), + [ + 156u8, 242u8, 186u8, 89u8, 177u8, 195u8, 90u8, 121u8, 94u8, 106u8, + 222u8, 78u8, 19u8, 162u8, 179u8, 96u8, 38u8, 113u8, 209u8, 148u8, 29u8, + 110u8, 106u8, 167u8, 162u8, 96u8, 221u8, 20u8, 33u8, 179u8, 168u8, + 142u8, + ], + ) + } + #[doc = " The configuration which controls the dynamics of the outbound queue."] + pub fn queue_config( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::cumulus_pallet_xcmp_queue::QueueConfigData, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "QueueConfig", + vec![], + [ + 154u8, 172u8, 227u8, 208u8, 130u8, 93u8, 173u8, 129u8, 33u8, 75u8, + 180u8, 100u8, 35u8, 154u8, 40u8, 188u8, 86u8, 53u8, 74u8, 118u8, 131u8, + 159u8, 240u8, 159u8, 185u8, 45u8, 165u8, 6u8, 90u8, 125u8, 77u8, 253u8, + ], + ) + } + #[doc = " The messages that exceeded max individual message weight budget."] + #[doc = ""] + #[doc = " These message stay in this storage map until they are manually dispatched via"] + #[doc = " `service_overweight`."] + pub fn overweight( + &self, + _0: impl ::std::borrow::Borrow<::core::primitive::u64>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<( + runtime_types::polkadot_parachain::primitives::Id, + ::core::primitive::u32, + ::std::vec::Vec<::core::primitive::u8>, + )>, + ::subxt::storage::address::Yes, + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "Overweight", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Twox64Concat, + )], + [ + 222u8, 249u8, 232u8, 110u8, 117u8, 229u8, 165u8, 164u8, 219u8, 219u8, + 149u8, 204u8, 25u8, 78u8, 204u8, 116u8, 111u8, 114u8, 120u8, 222u8, + 56u8, 77u8, 122u8, 147u8, 108u8, 15u8, 94u8, 161u8, 212u8, 50u8, 7u8, + 7u8, + ], + ) + } + #[doc = " The messages that exceeded max individual message weight budget."] + #[doc = ""] + #[doc = " These message stay in this storage map until they are manually dispatched via"] + #[doc = " `service_overweight`."] + pub fn overweight_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<( + runtime_types::polkadot_parachain::primitives::Id, + ::core::primitive::u32, + ::std::vec::Vec<::core::primitive::u8>, + )>, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "Overweight", + Vec::new(), + [ + 222u8, 249u8, 232u8, 110u8, 117u8, 229u8, 165u8, 164u8, 219u8, 219u8, + 149u8, 204u8, 25u8, 78u8, 204u8, 116u8, 111u8, 114u8, 120u8, 222u8, + 56u8, 77u8, 122u8, 147u8, 108u8, 15u8, 94u8, 161u8, 212u8, 50u8, 7u8, + 7u8, + ], + ) + } + #[doc = "Counter for the related counted storage map"] + pub fn counter_for_overweight( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "CounterForOverweight", + vec![], + [ + 148u8, 226u8, 248u8, 107u8, 165u8, 97u8, 218u8, 160u8, 127u8, 48u8, + 185u8, 251u8, 35u8, 137u8, 119u8, 251u8, 151u8, 167u8, 189u8, 66u8, + 80u8, 74u8, 134u8, 129u8, 222u8, 180u8, 51u8, 182u8, 50u8, 110u8, 10u8, + 43u8, + ], + ) + } + #[doc = " The number of overweight messages ever recorded in `Overweight`. Also doubles as the next"] + #[doc = " available free overweight index."] + pub fn overweight_count( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u64>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "OverweightCount", + vec![], + [ + 102u8, 180u8, 196u8, 148u8, 115u8, 62u8, 46u8, 238u8, 97u8, 116u8, + 117u8, 42u8, 14u8, 5u8, 72u8, 237u8, 230u8, 46u8, 150u8, 126u8, 89u8, + 64u8, 233u8, 166u8, 180u8, 137u8, 52u8, 233u8, 252u8, 255u8, 36u8, + 20u8, + ], + ) + } + #[doc = " Whether or not the XCMP queue is suspended from executing incoming XCMs or not."] + pub fn queue_suspended( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::bool>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "XcmpQueue", + "QueueSuspended", + vec![], + [ + 23u8, 37u8, 48u8, 112u8, 222u8, 17u8, 252u8, 65u8, 160u8, 217u8, 218u8, + 30u8, 2u8, 1u8, 204u8, 0u8, 251u8, 17u8, 138u8, 197u8, 164u8, 50u8, + 122u8, 0u8, 31u8, 238u8, 147u8, 213u8, 30u8, 132u8, 184u8, 215u8, + ], + ) + } + } + } + } + pub mod polkadot_xcm { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Send { + pub dest: ::std::boxed::Box, + pub message: ::std::boxed::Box, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct TeleportAssets { + pub dest: ::std::boxed::Box, + pub beneficiary: ::std::boxed::Box, + pub assets: ::std::boxed::Box, + pub fee_asset_item: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ReserveTransferAssets { + pub dest: ::std::boxed::Box, + pub beneficiary: ::std::boxed::Box, + pub assets: ::std::boxed::Box, + pub fee_asset_item: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Execute { + pub message: ::std::boxed::Box, + pub max_weight: ::sp_weights::Weight, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ForceXcmVersion { + pub location: + ::std::boxed::Box, + pub xcm_version: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ForceDefaultXcmVersion { + pub maybe_xcm_version: ::core::option::Option<::core::primitive::u32>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ForceSubscribeVersionNotify { + pub location: ::std::boxed::Box, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ForceUnsubscribeVersionNotify { + pub location: ::std::boxed::Box, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct LimitedReserveTransferAssets { + pub dest: ::std::boxed::Box, + pub beneficiary: ::std::boxed::Box, + pub assets: ::std::boxed::Box, + pub fee_asset_item: ::core::primitive::u32, + pub weight_limit: runtime_types::xcm::v3::WeightLimit, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct LimitedTeleportAssets { + pub dest: ::std::boxed::Box, + pub beneficiary: ::std::boxed::Box, + pub assets: ::std::boxed::Box, + pub fee_asset_item: ::core::primitive::u32, + pub weight_limit: runtime_types::xcm::v3::WeightLimit, + } + pub struct TransactionApi; + impl TransactionApi { + pub fn send( + &self, + dest: runtime_types::xcm::VersionedMultiLocation, + message: runtime_types::xcm::VersionedXcm, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "send", + Send { + dest: ::std::boxed::Box::new(dest), + message: ::std::boxed::Box::new(message), + }, + [ + 246u8, 35u8, 227u8, 112u8, 223u8, 7u8, 44u8, 186u8, 60u8, 225u8, 153u8, + 249u8, 104u8, 51u8, 123u8, 227u8, 143u8, 65u8, 232u8, 209u8, 178u8, + 104u8, 70u8, 56u8, 230u8, 14u8, 75u8, 83u8, 250u8, 160u8, 9u8, 39u8, + ], + ) + } + #[doc = "Teleport some assets from the local chain to some destination chain."] + #[doc = ""] + #[doc = "Fee payment on the destination side is made from the asset in the `assets` vector of"] + #[doc = "index `fee_asset_item`. The weight limit for fees is not provided and thus is unlimited,"] + #[doc = "with all fees taken as needed from the asset."] + #[doc = ""] + #[doc = "- `origin`: Must be capable of withdrawing the `assets` and executing XCM."] + #[doc = "- `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send"] + #[doc = " from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain."] + #[doc = "- `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be"] + #[doc = " an `AccountId32` value."] + #[doc = "- `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the"] + #[doc = " `dest` side. May not be empty."] + #[doc = "- `fee_asset_item`: The index into `assets` of the item which should be used to pay"] + #[doc = " fees."] + pub fn teleport_assets( + &self, + dest: runtime_types::xcm::VersionedMultiLocation, + beneficiary: runtime_types::xcm::VersionedMultiLocation, + assets: runtime_types::xcm::VersionedMultiAssets, + fee_asset_item: ::core::primitive::u32, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "teleport_assets", + TeleportAssets { + dest: ::std::boxed::Box::new(dest), + beneficiary: ::std::boxed::Box::new(beneficiary), + assets: ::std::boxed::Box::new(assets), + fee_asset_item, + }, + [ + 187u8, 42u8, 2u8, 96u8, 105u8, 125u8, 74u8, 53u8, 2u8, 21u8, 31u8, + 160u8, 201u8, 197u8, 157u8, 190u8, 40u8, 145u8, 5u8, 99u8, 194u8, 41u8, + 114u8, 60u8, 165u8, 186u8, 15u8, 226u8, 85u8, 113u8, 159u8, 136u8, + ], + ) + } + #[doc = "Transfer some assets from the local chain to the sovereign account of a destination"] + #[doc = "chain and forward a notification XCM."] + #[doc = ""] + #[doc = "Fee payment on the destination side is made from the asset in the `assets` vector of"] + #[doc = "index `fee_asset_item`. The weight limit for fees is not provided and thus is unlimited,"] + #[doc = "with all fees taken as needed from the asset."] + #[doc = ""] + #[doc = "- `origin`: Must be capable of withdrawing the `assets` and executing XCM."] + #[doc = "- `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send"] + #[doc = " from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain."] + #[doc = "- `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be"] + #[doc = " an `AccountId32` value."] + #[doc = "- `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the"] + #[doc = " `dest` side."] + #[doc = "- `fee_asset_item`: The index into `assets` of the item which should be used to pay"] + #[doc = " fees."] + pub fn reserve_transfer_assets( + &self, + dest: runtime_types::xcm::VersionedMultiLocation, + beneficiary: runtime_types::xcm::VersionedMultiLocation, + assets: runtime_types::xcm::VersionedMultiAssets, + fee_asset_item: ::core::primitive::u32, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "reserve_transfer_assets", + ReserveTransferAssets { + dest: ::std::boxed::Box::new(dest), + beneficiary: ::std::boxed::Box::new(beneficiary), + assets: ::std::boxed::Box::new(assets), + fee_asset_item, + }, + [ + 249u8, 177u8, 76u8, 204u8, 186u8, 165u8, 16u8, 186u8, 129u8, 239u8, + 65u8, 252u8, 9u8, 132u8, 32u8, 164u8, 117u8, 177u8, 40u8, 21u8, 196u8, + 246u8, 147u8, 2u8, 95u8, 110u8, 68u8, 162u8, 148u8, 9u8, 59u8, 170u8, + ], + ) + } + #[doc = "Execute an XCM message from a local, signed, origin."] + #[doc = ""] + #[doc = "An event is deposited indicating whether `msg` could be executed completely or only"] + #[doc = "partially."] + #[doc = ""] + #[doc = "No more than `max_weight` will be used in its attempted execution. If this is less than the"] + #[doc = "maximum amount of weight that the message could take to be executed, then no execution"] + #[doc = "attempt will be made."] + #[doc = ""] + #[doc = "NOTE: A successful return to this does *not* imply that the `msg` was executed successfully"] + #[doc = "to completion; only that *some* of it was executed."] + pub fn execute( + &self, + message: runtime_types::xcm::VersionedXcm, + max_weight: ::sp_weights::Weight, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "execute", + Execute { message: ::std::boxed::Box::new(message), max_weight }, + [ + 102u8, 41u8, 146u8, 29u8, 241u8, 205u8, 95u8, 153u8, 228u8, 141u8, + 11u8, 228u8, 13u8, 44u8, 75u8, 204u8, 174u8, 35u8, 155u8, 104u8, 204u8, + 82u8, 239u8, 98u8, 249u8, 187u8, 193u8, 1u8, 122u8, 88u8, 162u8, 200u8, + ], + ) + } + #[doc = "Extoll that a particular destination can be communicated with through a particular"] + #[doc = "version of XCM."] + #[doc = ""] + #[doc = "- `origin`: Must be Root."] + #[doc = "- `location`: The destination that is being described."] + #[doc = "- `xcm_version`: The latest version of XCM that `location` supports."] + pub fn force_xcm_version( + &self, + location: runtime_types::xcm::v3::multilocation::MultiLocation, + xcm_version: ::core::primitive::u32, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "force_xcm_version", + ForceXcmVersion { location: ::std::boxed::Box::new(location), xcm_version }, + [ + 68u8, 48u8, 95u8, 61u8, 152u8, 95u8, 213u8, 126u8, 209u8, 176u8, 230u8, + 160u8, 164u8, 42u8, 128u8, 62u8, 175u8, 3u8, 161u8, 170u8, 20u8, 31u8, + 216u8, 122u8, 31u8, 77u8, 64u8, 182u8, 121u8, 41u8, 23u8, 80u8, + ], + ) + } + #[doc = "Set a safe XCM version (the version that XCM should be encoded with if the most recent"] + #[doc = "version a destination can accept is unknown)."] + #[doc = ""] + #[doc = "- `origin`: Must be Root."] + #[doc = "- `maybe_xcm_version`: The default XCM encoding version, or `None` to disable."] + pub fn force_default_xcm_version( + &self, + maybe_xcm_version: ::core::option::Option<::core::primitive::u32>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "force_default_xcm_version", + ForceDefaultXcmVersion { maybe_xcm_version }, + [ + 38u8, 36u8, 59u8, 231u8, 18u8, 79u8, 76u8, 9u8, 200u8, 125u8, 214u8, + 166u8, 37u8, 99u8, 111u8, 161u8, 135u8, 2u8, 133u8, 157u8, 165u8, 18u8, + 152u8, 81u8, 209u8, 255u8, 137u8, 237u8, 28u8, 126u8, 224u8, 141u8, + ], + ) + } + #[doc = "Ask a location to notify us regarding their XCM version and any changes to it."] + #[doc = ""] + #[doc = "- `origin`: Must be Root."] + #[doc = "- `location`: The location to which we should subscribe for XCM version notifications."] + pub fn force_subscribe_version_notify( + &self, + location: runtime_types::xcm::VersionedMultiLocation, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "force_subscribe_version_notify", + ForceSubscribeVersionNotify { location: ::std::boxed::Box::new(location) }, + [ + 236u8, 37u8, 153u8, 26u8, 174u8, 187u8, 154u8, 38u8, 179u8, 223u8, + 130u8, 32u8, 128u8, 30u8, 148u8, 229u8, 7u8, 185u8, 174u8, 9u8, 96u8, + 215u8, 189u8, 178u8, 148u8, 141u8, 249u8, 118u8, 7u8, 238u8, 1u8, 49u8, + ], + ) + } + #[doc = "Require that a particular destination should no longer notify us regarding any XCM"] + #[doc = "version changes."] + #[doc = ""] + #[doc = "- `origin`: Must be Root."] + #[doc = "- `location`: The location to which we are currently subscribed for XCM version"] + #[doc = " notifications which we no longer desire."] + pub fn force_unsubscribe_version_notify( + &self, + location: runtime_types::xcm::VersionedMultiLocation, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "force_unsubscribe_version_notify", + ForceUnsubscribeVersionNotify { + location: ::std::boxed::Box::new(location), + }, + [ + 154u8, 169u8, 145u8, 211u8, 185u8, 71u8, 9u8, 63u8, 3u8, 158u8, 187u8, + 173u8, 115u8, 166u8, 100u8, 66u8, 12u8, 40u8, 198u8, 40u8, 213u8, + 104u8, 95u8, 183u8, 215u8, 53u8, 94u8, 158u8, 106u8, 56u8, 149u8, 52u8, + ], + ) + } + #[doc = "Transfer some assets from the local chain to the sovereign account of a destination"] + #[doc = "chain and forward a notification XCM."] + #[doc = ""] + #[doc = "Fee payment on the destination side is made from the asset in the `assets` vector of"] + #[doc = "index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight"] + #[doc = "is needed than `weight_limit`, then the operation will fail and the assets send may be"] + #[doc = "at risk."] + #[doc = ""] + #[doc = "- `origin`: Must be capable of withdrawing the `assets` and executing XCM."] + #[doc = "- `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send"] + #[doc = " from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain."] + #[doc = "- `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be"] + #[doc = " an `AccountId32` value."] + #[doc = "- `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the"] + #[doc = " `dest` side."] + #[doc = "- `fee_asset_item`: The index into `assets` of the item which should be used to pay"] + #[doc = " fees."] + #[doc = "- `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase."] + pub fn limited_reserve_transfer_assets( + &self, + dest: runtime_types::xcm::VersionedMultiLocation, + beneficiary: runtime_types::xcm::VersionedMultiLocation, + assets: runtime_types::xcm::VersionedMultiAssets, + fee_asset_item: ::core::primitive::u32, + weight_limit: runtime_types::xcm::v3::WeightLimit, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "limited_reserve_transfer_assets", + LimitedReserveTransferAssets { + dest: ::std::boxed::Box::new(dest), + beneficiary: ::std::boxed::Box::new(beneficiary), + assets: ::std::boxed::Box::new(assets), + fee_asset_item, + weight_limit, + }, + [ + 131u8, 191u8, 89u8, 27u8, 236u8, 142u8, 130u8, 129u8, 245u8, 95u8, + 159u8, 96u8, 252u8, 80u8, 28u8, 40u8, 128u8, 55u8, 41u8, 123u8, 22u8, + 18u8, 0u8, 236u8, 77u8, 68u8, 135u8, 181u8, 40u8, 47u8, 92u8, 240u8, + ], + ) + } + #[doc = "Teleport some assets from the local chain to some destination chain."] + #[doc = ""] + #[doc = "Fee payment on the destination side is made from the asset in the `assets` vector of"] + #[doc = "index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight"] + #[doc = "is needed than `weight_limit`, then the operation will fail and the assets send may be"] + #[doc = "at risk."] + #[doc = ""] + #[doc = "- `origin`: Must be capable of withdrawing the `assets` and executing XCM."] + #[doc = "- `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send"] + #[doc = " from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain."] + #[doc = "- `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be"] + #[doc = " an `AccountId32` value."] + #[doc = "- `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the"] + #[doc = " `dest` side. May not be empty."] + #[doc = "- `fee_asset_item`: The index into `assets` of the item which should be used to pay"] + #[doc = " fees."] + #[doc = "- `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase."] + pub fn limited_teleport_assets( + &self, + dest: runtime_types::xcm::VersionedMultiLocation, + beneficiary: runtime_types::xcm::VersionedMultiLocation, + assets: runtime_types::xcm::VersionedMultiAssets, + fee_asset_item: ::core::primitive::u32, + weight_limit: runtime_types::xcm::v3::WeightLimit, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "PolkadotXcm", + "limited_teleport_assets", + LimitedTeleportAssets { + dest: ::std::boxed::Box::new(dest), + beneficiary: ::std::boxed::Box::new(beneficiary), + assets: ::std::boxed::Box::new(assets), + fee_asset_item, + weight_limit, + }, + [ + 234u8, 19u8, 104u8, 174u8, 98u8, 159u8, 205u8, 110u8, 240u8, 78u8, + 186u8, 138u8, 236u8, 116u8, 104u8, 215u8, 57u8, 178u8, 166u8, 208u8, + 197u8, 113u8, 101u8, 56u8, 23u8, 56u8, 84u8, 14u8, 173u8, 70u8, 211u8, + 201u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::pallet_xcm::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Execution of an XCM message was attempted."] + #[doc = ""] + #[doc = "\\[ outcome \\]"] + pub struct Attempted(pub runtime_types::xcm::v3::traits::Outcome); + impl ::subxt::events::StaticEvent for Attempted { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "Attempted"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A XCM message was sent."] + #[doc = ""] + #[doc = "\\[ origin, destination, message \\]"] + pub struct Sent( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub runtime_types::xcm::v3::Xcm, + ); + impl ::subxt::events::StaticEvent for Sent { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "Sent"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Query response received which does not match a registered query. This may be because a"] + #[doc = "matching query was never registered, it may be because it is a duplicate response, or"] + #[doc = "because the query timed out."] + #[doc = ""] + #[doc = "\\[ origin location, id \\]"] + pub struct UnexpectedResponse( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::primitive::u64, + ); + impl ::subxt::events::StaticEvent for UnexpectedResponse { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "UnexpectedResponse"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Query response has been received and is ready for taking with `take_response`. There is"] + #[doc = "no registered notification call."] + #[doc = ""] + #[doc = "\\[ id, response \\]"] + pub struct ResponseReady( + pub ::core::primitive::u64, + pub runtime_types::xcm::v3::Response, + ); + impl ::subxt::events::StaticEvent for ResponseReady { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "ResponseReady"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Query response has been received and query is removed. The registered notification has"] + #[doc = "been dispatched and executed successfully."] + #[doc = ""] + #[doc = "\\[ id, pallet index, call index \\]"] + pub struct Notified( + pub ::core::primitive::u64, + pub ::core::primitive::u8, + pub ::core::primitive::u8, + ); + impl ::subxt::events::StaticEvent for Notified { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "Notified"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Query response has been received and query is removed. The registered notification could"] + #[doc = "not be dispatched because the dispatch weight is greater than the maximum weight"] + #[doc = "originally budgeted by this runtime for the query result."] + #[doc = ""] + #[doc = "\\[ id, pallet index, call index, actual weight, max budgeted weight \\]"] + pub struct NotifyOverweight( + pub ::core::primitive::u64, + pub ::core::primitive::u8, + pub ::core::primitive::u8, + pub ::sp_weights::Weight, + pub ::sp_weights::Weight, + ); + impl ::subxt::events::StaticEvent for NotifyOverweight { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "NotifyOverweight"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Query response has been received and query is removed. There was a general error with"] + #[doc = "dispatching the notification call."] + #[doc = ""] + #[doc = "\\[ id, pallet index, call index \\]"] + pub struct NotifyDispatchError( + pub ::core::primitive::u64, + pub ::core::primitive::u8, + pub ::core::primitive::u8, + ); + impl ::subxt::events::StaticEvent for NotifyDispatchError { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "NotifyDispatchError"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Query response has been received and query is removed. The dispatch was unable to be"] + #[doc = "decoded into a `Call`; this might be due to dispatch function having a signature which"] + #[doc = "is not `(origin, QueryId, Response)`."] + #[doc = ""] + #[doc = "\\[ id, pallet index, call index \\]"] + pub struct NotifyDecodeFailed( + pub ::core::primitive::u64, + pub ::core::primitive::u8, + pub ::core::primitive::u8, + ); + impl ::subxt::events::StaticEvent for NotifyDecodeFailed { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "NotifyDecodeFailed"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Expected query response has been received but the origin location of the response does"] + #[doc = "not match that expected. The query remains registered for a later, valid, response to"] + #[doc = "be received and acted upon."] + #[doc = ""] + #[doc = "\\[ origin location, id, expected location \\]"] + pub struct InvalidResponder( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::primitive::u64, + pub ::core::option::Option, + ); + impl ::subxt::events::StaticEvent for InvalidResponder { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "InvalidResponder"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Expected query response has been received but the expected origin location placed in"] + #[doc = "storage by this runtime previously cannot be decoded. The query remains registered."] + #[doc = ""] + #[doc = "This is unexpected (since a location placed in storage in a previously executing"] + #[doc = "runtime should be readable prior to query timeout) and dangerous since the possibly"] + #[doc = "valid response will be dropped. Manual governance intervention is probably going to be"] + #[doc = "needed."] + #[doc = ""] + #[doc = "\\[ origin location, id \\]"] + pub struct InvalidResponderVersion( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::primitive::u64, + ); + impl ::subxt::events::StaticEvent for InvalidResponderVersion { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "InvalidResponderVersion"; + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Received query response has been read and removed."] + #[doc = ""] + #[doc = "\\[ id \\]"] + pub struct ResponseTaken(pub ::core::primitive::u64); + impl ::subxt::events::StaticEvent for ResponseTaken { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "ResponseTaken"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some assets have been placed in an asset trap."] + #[doc = ""] + #[doc = "\\[ hash, origin, assets \\]"] + pub struct AssetsTrapped( + pub ::subxt::utils::H256, + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub runtime_types::xcm::VersionedMultiAssets, + ); + impl ::subxt::events::StaticEvent for AssetsTrapped { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "AssetsTrapped"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "An XCM version change notification message has been attempted to be sent."] + #[doc = ""] + #[doc = "The cost of sending it (borne by the chain) is included."] + #[doc = ""] + #[doc = "\\[ destination, result, cost \\]"] + pub struct VersionChangeNotified( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::primitive::u32, + pub runtime_types::xcm::v3::multiasset::MultiAssets, + ); + impl ::subxt::events::StaticEvent for VersionChangeNotified { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "VersionChangeNotified"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "The supported version of a location has been changed. This might be through an"] + #[doc = "automatic notification or a manual intervention."] + #[doc = ""] + #[doc = "\\[ location, XCM version \\]"] + pub struct SupportedVersionChanged( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::primitive::u32, + ); + impl ::subxt::events::StaticEvent for SupportedVersionChanged { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "SupportedVersionChanged"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A given location which had a version change subscription was dropped owing to an error"] + #[doc = "sending the notification to it."] + #[doc = ""] + #[doc = "\\[ location, query ID, error \\]"] + pub struct NotifyTargetSendFail( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::primitive::u64, + pub runtime_types::xcm::v3::traits::Error, + ); + impl ::subxt::events::StaticEvent for NotifyTargetSendFail { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "NotifyTargetSendFail"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A given location which had a version change subscription was dropped owing to an error"] + #[doc = "migrating the location to our new XCM format."] + #[doc = ""] + #[doc = "\\[ location, query ID \\]"] + pub struct NotifyTargetMigrationFail( + pub runtime_types::xcm::VersionedMultiLocation, + pub ::core::primitive::u64, + ); + impl ::subxt::events::StaticEvent for NotifyTargetMigrationFail { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "NotifyTargetMigrationFail"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Expected query response has been received but the expected querier location placed in"] + #[doc = "storage by this runtime previously cannot be decoded. The query remains registered."] + #[doc = ""] + #[doc = "This is unexpected (since a location placed in storage in a previously executing"] + #[doc = "runtime should be readable prior to query timeout) and dangerous since the possibly"] + #[doc = "valid response will be dropped. Manual governance intervention is probably going to be"] + #[doc = "needed."] + #[doc = ""] + #[doc = "\\[ origin location, id \\]"] + pub struct InvalidQuerierVersion( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::primitive::u64, + ); + impl ::subxt::events::StaticEvent for InvalidQuerierVersion { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "InvalidQuerierVersion"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Expected query response has been received but the querier location of the response does"] + #[doc = "not match the expected. The query remains registered for a later, valid, response to"] + #[doc = "be received and acted upon."] + #[doc = ""] + #[doc = "\\[ origin location, id, expected querier, maybe actual querier \\]"] + pub struct InvalidQuerier( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::primitive::u64, + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub ::core::option::Option, + ); + impl ::subxt::events::StaticEvent for InvalidQuerier { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "InvalidQuerier"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "A remote has requested XCM version change notification from us and we have honored it."] + #[doc = "A version information message is sent to them and its cost is included."] + #[doc = ""] + #[doc = "\\[ destination location, cost \\]"] + pub struct VersionNotifyStarted( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub runtime_types::xcm::v3::multiasset::MultiAssets, + ); + impl ::subxt::events::StaticEvent for VersionNotifyStarted { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "VersionNotifyStarted"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "We have requested that a remote chain sends us XCM version change notifications."] + #[doc = ""] + #[doc = "\\[ destination location, cost \\]"] + pub struct VersionNotifyRequested( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub runtime_types::xcm::v3::multiasset::MultiAssets, + ); + impl ::subxt::events::StaticEvent for VersionNotifyRequested { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "VersionNotifyRequested"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "We have requested that a remote chain stops sending us XCM version change notifications."] + #[doc = ""] + #[doc = "\\[ destination location, cost \\]"] + pub struct VersionNotifyUnrequested( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub runtime_types::xcm::v3::multiasset::MultiAssets, + ); + impl ::subxt::events::StaticEvent for VersionNotifyUnrequested { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "VersionNotifyUnrequested"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Fees were paid from a location for an operation (often for using `SendXcm`)."] + #[doc = ""] + #[doc = "\\[ paying location, fees \\]"] + pub struct FeesPaid( + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub runtime_types::xcm::v3::multiasset::MultiAssets, + ); + impl ::subxt::events::StaticEvent for FeesPaid { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "FeesPaid"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Some assets have been claimed from an asset trap"] + #[doc = ""] + #[doc = "\\[ hash, origin, assets \\]"] + pub struct AssetsClaimed( + pub ::subxt::utils::H256, + pub runtime_types::xcm::v3::multilocation::MultiLocation, + pub runtime_types::xcm::VersionedMultiAssets, + ); + impl ::subxt::events::StaticEvent for AssetsClaimed { + const PALLET: &'static str = "PolkadotXcm"; + const EVENT: &'static str = "AssetsClaimed"; + } + } + } + pub mod cumulus_xcm { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + pub struct TransactionApi; + impl TransactionApi {} + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::cumulus_pallet_xcm::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward message is invalid XCM."] + #[doc = "\\[ id \\]"] + pub struct InvalidFormat(pub [::core::primitive::u8; 32usize]); + impl ::subxt::events::StaticEvent for InvalidFormat { + const PALLET: &'static str = "CumulusXcm"; + const EVENT: &'static str = "InvalidFormat"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward message is unsupported version of XCM."] + #[doc = "\\[ id \\]"] + pub struct UnsupportedVersion(pub [::core::primitive::u8; 32usize]); + impl ::subxt::events::StaticEvent for UnsupportedVersion { + const PALLET: &'static str = "CumulusXcm"; + const EVENT: &'static str = "UnsupportedVersion"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward message executed with the given outcome."] + #[doc = "\\[ id, outcome \\]"] + pub struct ExecutedDownward( + pub [::core::primitive::u8; 32usize], + pub runtime_types::xcm::v3::traits::Outcome, + ); + impl ::subxt::events::StaticEvent for ExecutedDownward { + const PALLET: &'static str = "CumulusXcm"; + const EVENT: &'static str = "ExecutedDownward"; + } + } + } + pub mod dmp_queue { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ServiceOverweight { + pub index: ::core::primitive::u64, + pub weight_limit: ::sp_weights::Weight, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Service a single overweight message."] + pub fn service_overweight( + &self, + index: ::core::primitive::u64, + weight_limit: ::sp_weights::Weight, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "DmpQueue", + "service_overweight", + ServiceOverweight { index, weight_limit }, + [ + 121u8, 236u8, 235u8, 23u8, 210u8, 238u8, 238u8, 122u8, 15u8, 86u8, + 34u8, 119u8, 105u8, 100u8, 214u8, 236u8, 117u8, 39u8, 254u8, 235u8, + 189u8, 15u8, 72u8, 74u8, 225u8, 134u8, 148u8, 126u8, 31u8, 203u8, + 144u8, 106u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::cumulus_pallet_dmp_queue::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward message is invalid XCM."] + pub struct InvalidFormat { + pub message_id: [::core::primitive::u8; 32usize], + } + impl ::subxt::events::StaticEvent for InvalidFormat { + const PALLET: &'static str = "DmpQueue"; + const EVENT: &'static str = "InvalidFormat"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward message is unsupported version of XCM."] + pub struct UnsupportedVersion { + pub message_id: [::core::primitive::u8; 32usize], + } + impl ::subxt::events::StaticEvent for UnsupportedVersion { + const PALLET: &'static str = "DmpQueue"; + const EVENT: &'static str = "UnsupportedVersion"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward message executed with the given outcome."] + pub struct ExecutedDownward { + pub message_id: [::core::primitive::u8; 32usize], + pub outcome: runtime_types::xcm::v3::traits::Outcome, + } + impl ::subxt::events::StaticEvent for ExecutedDownward { + const PALLET: &'static str = "DmpQueue"; + const EVENT: &'static str = "ExecutedDownward"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "The weight limit for handling downward messages was reached."] + pub struct WeightExhausted { + pub message_id: [::core::primitive::u8; 32usize], + pub remaining_weight: ::sp_weights::Weight, + pub required_weight: ::sp_weights::Weight, + } + impl ::subxt::events::StaticEvent for WeightExhausted { + const PALLET: &'static str = "DmpQueue"; + const EVENT: &'static str = "WeightExhausted"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward message is overweight and was placed in the overweight queue."] + pub struct OverweightEnqueued { + pub message_id: [::core::primitive::u8; 32usize], + pub overweight_index: ::core::primitive::u64, + pub required_weight: ::sp_weights::Weight, + } + impl ::subxt::events::StaticEvent for OverweightEnqueued { + const PALLET: &'static str = "DmpQueue"; + const EVENT: &'static str = "OverweightEnqueued"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Downward message from the overweight queue was executed."] + pub struct OverweightServiced { + pub overweight_index: ::core::primitive::u64, + pub weight_used: ::sp_weights::Weight, + } + impl ::subxt::events::StaticEvent for OverweightServiced { + const PALLET: &'static str = "DmpQueue"; + const EVENT: &'static str = "OverweightServiced"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "The maximum number of downward messages was."] + pub struct MaxMessagesExhausted { + pub message_id: [::core::primitive::u8; 32usize], + } + impl ::subxt::events::StaticEvent for MaxMessagesExhausted { + const PALLET: &'static str = "DmpQueue"; + const EVENT: &'static str = "MaxMessagesExhausted"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " The configuration."] + pub fn configuration( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::cumulus_pallet_dmp_queue::ConfigData, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "DmpQueue", + "Configuration", + vec![], + [ + 133u8, 113u8, 115u8, 164u8, 128u8, 145u8, 234u8, 106u8, 150u8, 54u8, + 247u8, 135u8, 181u8, 197u8, 178u8, 30u8, 204u8, 46u8, 6u8, 137u8, 82u8, + 1u8, 75u8, 171u8, 7u8, 157u8, 3u8, 19u8, 92u8, 10u8, 234u8, 66u8, + ], + ) + } + #[doc = " The page index."] + pub fn page_index( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::cumulus_pallet_dmp_queue::PageIndexData, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "DmpQueue", + "PageIndex", + vec![], + [ + 94u8, 132u8, 34u8, 67u8, 10u8, 22u8, 235u8, 96u8, 168u8, 26u8, 57u8, + 200u8, 130u8, 218u8, 37u8, 71u8, 28u8, 119u8, 78u8, 107u8, 209u8, + 120u8, 190u8, 2u8, 101u8, 215u8, 122u8, 187u8, 94u8, 38u8, 255u8, + 234u8, + ], + ) + } + #[doc = " The queue pages."] + pub fn pages( + &self, + _0: impl ::std::borrow::Borrow<::core::primitive::u32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec<( + ::core::primitive::u32, + ::std::vec::Vec<::core::primitive::u8>, + )>, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "DmpQueue", + "Pages", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 228u8, 86u8, 33u8, 107u8, 248u8, 4u8, 223u8, 175u8, 222u8, 25u8, 204u8, + 42u8, 235u8, 21u8, 215u8, 91u8, 167u8, 14u8, 133u8, 151u8, 190u8, 57u8, + 138u8, 208u8, 79u8, 244u8, 132u8, 14u8, 48u8, 247u8, 171u8, 108u8, + ], + ) + } + #[doc = " The queue pages."] + pub fn pages_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + ::std::vec::Vec<( + ::core::primitive::u32, + ::std::vec::Vec<::core::primitive::u8>, + )>, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "DmpQueue", + "Pages", + Vec::new(), + [ + 228u8, 86u8, 33u8, 107u8, 248u8, 4u8, 223u8, 175u8, 222u8, 25u8, 204u8, + 42u8, 235u8, 21u8, 215u8, 91u8, 167u8, 14u8, 133u8, 151u8, 190u8, 57u8, + 138u8, 208u8, 79u8, 244u8, 132u8, 14u8, 48u8, 247u8, 171u8, 108u8, + ], + ) + } + #[doc = " The overweight messages."] + pub fn overweight( + &self, + _0: impl ::std::borrow::Borrow<::core::primitive::u64>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<( + ::core::primitive::u32, + ::std::vec::Vec<::core::primitive::u8>, + )>, + ::subxt::storage::address::Yes, + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "DmpQueue", + "Overweight", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 222u8, 85u8, 143u8, 49u8, 42u8, 248u8, 138u8, 163u8, 46u8, 199u8, + 188u8, 61u8, 137u8, 135u8, 127u8, 146u8, 210u8, 254u8, 121u8, 42u8, + 112u8, 114u8, 22u8, 228u8, 207u8, 207u8, 245u8, 175u8, 152u8, 140u8, + 225u8, 237u8, + ], + ) + } + #[doc = " The overweight messages."] + pub fn overweight_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<( + ::core::primitive::u32, + ::std::vec::Vec<::core::primitive::u8>, + )>, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "DmpQueue", + "Overweight", + Vec::new(), + [ + 222u8, 85u8, 143u8, 49u8, 42u8, 248u8, 138u8, 163u8, 46u8, 199u8, + 188u8, 61u8, 137u8, 135u8, 127u8, 146u8, 210u8, 254u8, 121u8, 42u8, + 112u8, 114u8, 22u8, 228u8, 207u8, 207u8, 245u8, 175u8, 152u8, 140u8, + 225u8, 237u8, + ], + ) + } + #[doc = "Counter for the related counted storage map"] + pub fn counter_for_overweight( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "DmpQueue", + "CounterForOverweight", + vec![], + [ + 148u8, 226u8, 248u8, 107u8, 165u8, 97u8, 218u8, 160u8, 127u8, 48u8, + 185u8, 251u8, 35u8, 137u8, 119u8, 251u8, 151u8, 167u8, 189u8, 66u8, + 80u8, 74u8, 134u8, 129u8, 222u8, 180u8, 51u8, 182u8, 50u8, 110u8, 10u8, + 43u8, + ], + ) + } + } + } + } + pub mod bridge_relayers { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ClaimRewards { + pub rewards_account_params: runtime_types::bp_relayers::RewardsAccountParams, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Claim accumulated rewards."] + pub fn claim_rewards( + &self, + rewards_account_params: runtime_types::bp_relayers::RewardsAccountParams, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeRelayers", + "claim_rewards", + ClaimRewards { rewards_account_params }, + [ + 141u8, 52u8, 193u8, 42u8, 145u8, 26u8, 147u8, 35u8, 227u8, 221u8, + 221u8, 188u8, 104u8, 186u8, 123u8, 46u8, 190u8, 236u8, 120u8, 19u8, + 230u8, 219u8, 238u8, 227u8, 75u8, 35u8, 36u8, 177u8, 227u8, 130u8, + 103u8, 128u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::pallet_bridge_relayers::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Reward has been paid to the relayer."] + pub struct RewardPaid { + pub relayer: ::sp_core::crypto::AccountId32, + pub rewards_account_params: runtime_types::bp_relayers::RewardsAccountParams, + pub reward: ::core::primitive::u128, + } + impl ::subxt::events::StaticEvent for RewardPaid { + const PALLET: &'static str = "BridgeRelayers"; + const EVENT: &'static str = "RewardPaid"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " Map of the relayer => accumulated reward."] + pub fn relayer_rewards( + &self, + _0: impl ::std::borrow::Borrow<::sp_core::crypto::AccountId32>, + _1: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u128>, + ::subxt::storage::address::Yes, + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeRelayers", + "RelayerRewards", + vec![ + ::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + ), + ::subxt::storage::address::StorageMapKey::new( + _1.borrow(), + ::subxt::storage::address::StorageHasher::Identity, + ), + ], + [ + 116u8, 81u8, 48u8, 55u8, 199u8, 26u8, 100u8, 7u8, 177u8, 230u8, 132u8, + 248u8, 221u8, 90u8, 33u8, 155u8, 198u8, 216u8, 43u8, 149u8, 92u8, + 100u8, 199u8, 183u8, 150u8, 214u8, 199u8, 222u8, 224u8, 228u8, 238u8, + 108u8, + ], + ) + } + #[doc = " Map of the relayer => accumulated reward."] + pub fn relayer_rewards_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u128>, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeRelayers", + "RelayerRewards", + Vec::new(), + [ + 116u8, 81u8, 48u8, 55u8, 199u8, 26u8, 100u8, 7u8, 177u8, 230u8, 132u8, + 248u8, 221u8, 90u8, 33u8, 155u8, 198u8, 216u8, 43u8, 149u8, 92u8, + 100u8, 199u8, 183u8, 150u8, 214u8, 199u8, 222u8, 224u8, 228u8, 238u8, + 108u8, + ], + ) + } + } + } + } + pub mod bridge_millau_grandpa { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SubmitFinalityProof { + pub finality_target: ::std::boxed::Box< + ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + >, + pub justification: ::bp_header_chain::justification::GrandpaJustification< + ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + >, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Initialize { + pub init_data: ::bp_header_chain::InitializationData< + ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + >, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetOwner { + pub new_owner: ::core::option::Option<::sp_core::crypto::AccountId32>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetOperatingMode { + pub operating_mode: runtime_types::bp_runtime::BasicOperatingMode, + } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Verify a target header is finalized according to the given finality proof."] + #[doc = ""] + #[doc = "It will use the underlying storage pallet to fetch information about the current"] + #[doc = "authorities and best finalized header in order to verify that the header is finalized."] + #[doc = ""] + #[doc = "If successful in verification, it will write the target header to the underlying storage"] + #[doc = "pallet."] + pub fn submit_finality_proof( + &self, + finality_target: ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + justification: ::bp_header_chain::justification::GrandpaJustification< + ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + >, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeMillauGrandpa", + "submit_finality_proof", + SubmitFinalityProof { + finality_target: ::std::boxed::Box::new(finality_target), + justification, + }, + [ + 3u8, 161u8, 243u8, 208u8, 245u8, 135u8, 86u8, 233u8, 103u8, 140u8, + 81u8, 3u8, 119u8, 185u8, 68u8, 167u8, 208u8, 155u8, 169u8, 201u8, + 209u8, 248u8, 162u8, 45u8, 155u8, 225u8, 173u8, 62u8, 156u8, 171u8, + 19u8, 190u8, + ], + ) + } + #[doc = "Bootstrap the bridge pallet with an initial header and authority set from which to sync."] + #[doc = ""] + #[doc = "The initial configuration provided does not need to be the genesis header of the bridged"] + #[doc = "chain, it can be any arbitrary header. You can also provide the next scheduled set"] + #[doc = "change if it is already know."] + #[doc = ""] + #[doc = "This function is only allowed to be called from a trusted origin and writes to storage"] + #[doc = "with practically no checks in terms of the validity of the data. It is important that"] + #[doc = "you ensure that valid data is being passed in."] + pub fn initialize( + &self, + init_data: ::bp_header_chain::InitializationData< + ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + >, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeMillauGrandpa", + "initialize", + Initialize { init_data }, + [ + 244u8, 188u8, 202u8, 145u8, 218u8, 91u8, 74u8, 80u8, 41u8, 185u8, + 239u8, 178u8, 231u8, 128u8, 198u8, 90u8, 135u8, 219u8, 200u8, 23u8, + 194u8, 47u8, 61u8, 222u8, 194u8, 84u8, 142u8, 37u8, 64u8, 37u8, 69u8, + 198u8, + ], + ) + } + #[doc = "Change `PalletOwner`."] + #[doc = ""] + #[doc = "May only be called either by root, or by `PalletOwner`."] + pub fn set_owner( + &self, + new_owner: ::core::option::Option<::sp_core::crypto::AccountId32>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeMillauGrandpa", + "set_owner", + SetOwner { new_owner }, + [ + 100u8, 221u8, 84u8, 142u8, 158u8, 5u8, 47u8, 212u8, 9u8, 35u8, 82u8, + 135u8, 108u8, 238u8, 231u8, 197u8, 77u8, 219u8, 176u8, 222u8, 88u8, + 167u8, 152u8, 34u8, 177u8, 244u8, 160u8, 195u8, 211u8, 3u8, 66u8, + 253u8, + ], + ) + } + #[doc = "Halt or resume all pallet operations."] + #[doc = ""] + #[doc = "May only be called either by root, or by `PalletOwner`."] + pub fn set_operating_mode( + &self, + operating_mode: runtime_types::bp_runtime::BasicOperatingMode, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeMillauGrandpa", + "set_operating_mode", + SetOperatingMode { operating_mode }, + [ + 128u8, 25u8, 81u8, 145u8, 111u8, 185u8, 226u8, 152u8, 18u8, 51u8, 89u8, + 236u8, 200u8, 157u8, 157u8, 186u8, 207u8, 208u8, 152u8, 168u8, 12u8, + 39u8, 249u8, 48u8, 195u8, 160u8, 54u8, 73u8, 30u8, 230u8, 25u8, 46u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::pallet_bridge_grandpa::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Best finalized chain header has been updated to the header with given number and hash."] + pub struct UpdatedBestFinalizedHeader { + pub number: ::core::primitive::u64, + pub hash: ::bp_millau::MillauHash, + } + impl ::subxt::events::StaticEvent for UpdatedBestFinalizedHeader { + const PALLET: &'static str = "BridgeMillauGrandpa"; + const EVENT: &'static str = "UpdatedBestFinalizedHeader"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " The current number of requests which have written to storage."] + #[doc = ""] + #[doc = " If the `RequestCount` hits `MaxRequests`, no more calls will be allowed to the pallet until"] + #[doc = " the request capacity is increased."] + #[doc = ""] + #[doc = " The `RequestCount` is decreased by one at the beginning of every block. This is to ensure"] + #[doc = " that the pallet can always make progress."] + pub fn request_count( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "RequestCount", + vec![], + [ + 100u8, 156u8, 98u8, 176u8, 229u8, 85u8, 81u8, 159u8, 120u8, 156u8, + 33u8, 179u8, 224u8, 237u8, 52u8, 198u8, 81u8, 81u8, 10u8, 180u8, 53u8, + 141u8, 96u8, 4u8, 39u8, 217u8, 58u8, 9u8, 57u8, 79u8, 47u8, 201u8, + ], + ) + } + #[doc = " Hash of the header used to bootstrap the pallet."] + pub fn initial_hash( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::bp_millau::MillauHash>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "InitialHash", + vec![], + [ + 167u8, 131u8, 64u8, 215u8, 102u8, 70u8, 21u8, 34u8, 254u8, 233u8, 2u8, + 49u8, 253u8, 67u8, 235u8, 10u8, 21u8, 223u8, 220u8, 198u8, 180u8, + 137u8, 88u8, 251u8, 230u8, 108u8, 9u8, 104u8, 101u8, 105u8, 38u8, + 138u8, + ], + ) + } + #[doc = " Hash of the best finalized header."] + pub fn best_finalized( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_runtime::HeaderId< + ::bp_millau::MillauHash, + ::core::primitive::u64, + >, + >, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "BestFinalized", + vec![], + [ + 61u8, 173u8, 97u8, 223u8, 180u8, 235u8, 85u8, 126u8, 217u8, 228u8, + 87u8, 174u8, 116u8, 156u8, 162u8, 252u8, 100u8, 200u8, 138u8, 14u8, + 102u8, 177u8, 66u8, 164u8, 216u8, 114u8, 18u8, 223u8, 94u8, 78u8, + 107u8, 58u8, + ], + ) + } + #[doc = " A ring buffer of imported hashes. Ordered by the insertion time."] + pub fn imported_hashes( + &self, + _0: impl ::std::borrow::Borrow<::core::primitive::u32>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::bp_millau::MillauHash>, + ::subxt::storage::address::Yes, + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "ImportedHashes", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Identity, + )], + [ + 249u8, 185u8, 202u8, 36u8, 40u8, 197u8, 111u8, 168u8, 136u8, 138u8, + 84u8, 135u8, 69u8, 34u8, 181u8, 46u8, 158u8, 16u8, 150u8, 190u8, 81u8, + 53u8, 239u8, 199u8, 83u8, 93u8, 197u8, 205u8, 129u8, 173u8, 141u8, + 43u8, + ], + ) + } + #[doc = " A ring buffer of imported hashes. Ordered by the insertion time."] + pub fn imported_hashes_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::bp_millau::MillauHash>, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "ImportedHashes", + Vec::new(), + [ + 249u8, 185u8, 202u8, 36u8, 40u8, 197u8, 111u8, 168u8, 136u8, 138u8, + 84u8, 135u8, 69u8, 34u8, 181u8, 46u8, 158u8, 16u8, 150u8, 190u8, 81u8, + 53u8, 239u8, 199u8, 83u8, 93u8, 197u8, 205u8, 129u8, 173u8, 141u8, + 43u8, + ], + ) + } + #[doc = " Current ring buffer position."] + pub fn imported_hashes_pointer( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "ImportedHashesPointer", + vec![], + [ + 159u8, 83u8, 35u8, 45u8, 27u8, 249u8, 155u8, 131u8, 181u8, 196u8, + 224u8, 26u8, 92u8, 132u8, 127u8, 237u8, 13u8, 142u8, 196u8, 147u8, + 221u8, 216u8, 11u8, 78u8, 190u8, 241u8, 201u8, 96u8, 74u8, 185u8, + 208u8, 42u8, + ], + ) + } + #[doc = " Relevant fields of imported headers."] + pub fn imported_headers( + &self, + _0: impl ::std::borrow::Borrow<::bp_millau::MillauHash>, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_header_chain::StoredHeaderData< + ::core::primitive::u64, + ::bp_millau::MillauHash, + >, + >, + ::subxt::storage::address::Yes, + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "ImportedHeaders", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Identity, + )], + [ + 109u8, 41u8, 102u8, 223u8, 133u8, 169u8, 46u8, 221u8, 235u8, 67u8, + 28u8, 192u8, 2u8, 242u8, 215u8, 166u8, 227u8, 182u8, 136u8, 217u8, + 61u8, 10u8, 246u8, 70u8, 17u8, 246u8, 223u8, 113u8, 9u8, 136u8, 181u8, + 242u8, + ], + ) + } + #[doc = " Relevant fields of imported headers."] + pub fn imported_headers_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_header_chain::StoredHeaderData< + ::core::primitive::u64, + ::bp_millau::MillauHash, + >, + >, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "ImportedHeaders", + Vec::new(), + [ + 109u8, 41u8, 102u8, 223u8, 133u8, 169u8, 46u8, 221u8, 235u8, 67u8, + 28u8, 192u8, 2u8, 242u8, 215u8, 166u8, 227u8, 182u8, 136u8, 217u8, + 61u8, 10u8, 246u8, 70u8, 17u8, 246u8, 223u8, 113u8, 9u8, 136u8, 181u8, + 242u8, + ], + ) + } + #[doc = " The current GRANDPA Authority set."] + pub fn current_authority_set( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::pallet_bridge_grandpa::storage_types::StoredAuthoritySet, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "CurrentAuthoritySet", + vec![], + [ + 249u8, 40u8, 229u8, 120u8, 141u8, 219u8, 206u8, 5u8, 54u8, 121u8, + 207u8, 77u8, 8u8, 80u8, 105u8, 107u8, 151u8, 111u8, 82u8, 119u8, 8u8, + 31u8, 104u8, 82u8, 92u8, 156u8, 37u8, 160u8, 235u8, 64u8, 62u8, 94u8, + ], + ) + } + #[doc = " Optional pallet owner."] + #[doc = ""] + #[doc = " Pallet owner has a right to halt all pallet operations and then resume it. If it is"] + #[doc = " `None`, then there are no direct ways to halt/resume pallet operations, but other"] + #[doc = " runtime methods may still be used to do that (i.e. democracy::referendum to update halt"] + #[doc = " flag directly or call the `halt_operations`)."] + pub fn pallet_owner( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::sp_core::crypto::AccountId32>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "PalletOwner", + vec![], + [ + 89u8, 42u8, 74u8, 119u8, 21u8, 164u8, 30u8, 115u8, 207u8, 126u8, 98u8, + 16u8, 162u8, 214u8, 67u8, 172u8, 178u8, 223u8, 139u8, 121u8, 174u8, + 89u8, 215u8, 75u8, 200u8, 161u8, 61u8, 195u8, 65u8, 222u8, 246u8, + 233u8, + ], + ) + } + #[doc = " The current operating mode of the pallet."] + #[doc = ""] + #[doc = " Depending on the mode either all, or no transactions will be allowed."] + pub fn pallet_operating_mode( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_runtime::BasicOperatingMode, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauGrandpa", + "PalletOperatingMode", + vec![], + [ + 218u8, 66u8, 212u8, 71u8, 38u8, 152u8, 55u8, 129u8, 125u8, 231u8, 91u8, + 216u8, 157u8, 141u8, 173u8, 146u8, 30u8, 40u8, 132u8, 107u8, 97u8, + 39u8, 36u8, 81u8, 231u8, 222u8, 113u8, 136u8, 233u8, 212u8, 225u8, + 75u8, + ], + ) + } + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " The upper bound on the number of requests allowed by the pallet."] + #[doc = ""] + #[doc = " A request refers to an action which writes a header to storage."] + #[doc = ""] + #[doc = " Once this bound is reached the pallet will not allow any dispatchables to be called"] + #[doc = " until the request count has decreased."] + pub fn max_requests( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + > { + ::subxt::constants::StaticConstantAddress::new( + "BridgeMillauGrandpa", + "MaxRequests", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + #[doc = " Maximal number of finalized headers to keep in the storage."] + #[doc = ""] + #[doc = " The setting is there to prevent growing the on-chain state indefinitely. Note"] + #[doc = " the setting does not relate to block numbers - we will simply keep as much items"] + #[doc = " in the storage, so it doesn't guarantee any fixed timeframe for finality headers."] + #[doc = ""] + #[doc = " Incautious change of this constant may lead to orphan entries in the runtime storage."] + pub fn headers_to_keep( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + > { + ::subxt::constants::StaticConstantAddress::new( + "BridgeMillauGrandpa", + "HeadersToKeep", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + } + } + } + pub mod bridge_millau_messages { + use super::{root_mod, runtime_types}; + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub mod calls { + use super::{root_mod, runtime_types}; + type DispatchError = runtime_types::sp_runtime::DispatchError; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetOwner { + pub new_owner: ::core::option::Option<::sp_core::crypto::AccountId32>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SetOperatingMode { + pub operating_mode: runtime_types::bp_messages::MessagesOperatingMode, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ReceiveMessagesProof { + pub relayer_id_at_bridged_chain: ::sp_core::crypto::AccountId32, + pub proof: ::bridge_runtime_common::messages::target::FromBridgedChainMessagesProof< + ::bp_millau::MillauHash, + >, + pub messages_count: ::core::primitive::u32, + pub dispatch_weight: ::sp_weights::Weight, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ReceiveMessagesDeliveryProof { pub proof : :: bridge_runtime_common :: messages :: source :: FromBridgedChainMessagesDeliveryProof < :: bp_millau :: MillauHash > , pub relayers_state : :: bp_messages :: UnrewardedRelayersState , } + pub struct TransactionApi; + impl TransactionApi { + #[doc = "Change `PalletOwner`."] + #[doc = ""] + #[doc = "May only be called either by root, or by `PalletOwner`."] + pub fn set_owner( + &self, + new_owner: ::core::option::Option<::sp_core::crypto::AccountId32>, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeMillauMessages", + "set_owner", + SetOwner { new_owner }, + [ + 100u8, 221u8, 84u8, 142u8, 158u8, 5u8, 47u8, 212u8, 9u8, 35u8, 82u8, + 135u8, 108u8, 238u8, 231u8, 197u8, 77u8, 219u8, 176u8, 222u8, 88u8, + 167u8, 152u8, 34u8, 177u8, 244u8, 160u8, 195u8, 211u8, 3u8, 66u8, + 253u8, + ], + ) + } + #[doc = "Halt or resume all/some pallet operations."] + #[doc = ""] + #[doc = "May only be called either by root, or by `PalletOwner`."] + pub fn set_operating_mode( + &self, + operating_mode: runtime_types::bp_messages::MessagesOperatingMode, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeMillauMessages", + "set_operating_mode", + SetOperatingMode { operating_mode }, + [ + 236u8, 230u8, 127u8, 17u8, 145u8, 186u8, 102u8, 200u8, 227u8, 208u8, + 230u8, 121u8, 102u8, 199u8, 123u8, 118u8, 199u8, 160u8, 131u8, 116u8, + 102u8, 167u8, 119u8, 144u8, 70u8, 114u8, 0u8, 223u8, 54u8, 197u8, 39u8, + 58u8, + ], + ) + } + #[doc = "Receive messages proof from bridged chain."] + #[doc = ""] + #[doc = "The weight of the call assumes that the transaction always brings outbound lane"] + #[doc = "state update. Because of that, the submitter (relayer) has no benefit of not including"] + #[doc = "this data in the transaction, so reward confirmations lags should be minimal."] + pub fn receive_messages_proof( + &self, + relayer_id_at_bridged_chain: ::sp_core::crypto::AccountId32, + proof: ::bridge_runtime_common::messages::target::FromBridgedChainMessagesProof< + ::bp_millau::MillauHash, + >, + messages_count: ::core::primitive::u32, + dispatch_weight: ::sp_weights::Weight, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeMillauMessages", + "receive_messages_proof", + ReceiveMessagesProof { + relayer_id_at_bridged_chain, + proof, + messages_count, + dispatch_weight, + }, + [ + 14u8, 23u8, 191u8, 242u8, 252u8, 163u8, 87u8, 149u8, 211u8, 25u8, + 112u8, 192u8, 206u8, 49u8, 135u8, 124u8, 79u8, 92u8, 204u8, 39u8, 80u8, + 139u8, 155u8, 124u8, 134u8, 1u8, 66u8, 68u8, 213u8, 85u8, 42u8, 250u8, + ], + ) + } + #[doc = "Receive messages delivery proof from bridged chain."] + pub fn receive_messages_delivery_proof( + &self, + proof : :: bridge_runtime_common :: messages :: source :: FromBridgedChainMessagesDeliveryProof < :: bp_millau :: MillauHash >, + relayers_state: ::bp_messages::UnrewardedRelayersState, + ) -> ::subxt::tx::StaticTxPayload { + ::subxt::tx::StaticTxPayload::new( + "BridgeMillauMessages", + "receive_messages_delivery_proof", + ReceiveMessagesDeliveryProof { proof, relayers_state }, + [ + 216u8, 113u8, 64u8, 20u8, 16u8, 64u8, 144u8, 143u8, 105u8, 30u8, 192u8, + 89u8, 74u8, 34u8, 56u8, 151u8, 20u8, 234u8, 14u8, 211u8, 64u8, 103u8, + 218u8, 164u8, 69u8, 107u8, 6u8, 119u8, 13u8, 90u8, 150u8, 24u8, + ], + ) + } + } + } + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub type Event = runtime_types::pallet_bridge_messages::pallet::Event; + pub mod events { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Message has been accepted and is waiting to be delivered."] + pub struct MessageAccepted { + pub lane_id: runtime_types::bp_messages::LaneId, + pub nonce: ::core::primitive::u64, + } + impl ::subxt::events::StaticEvent for MessageAccepted { + const PALLET: &'static str = "BridgeMillauMessages"; + const EVENT: &'static str = "MessageAccepted"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Messages have been received from the bridged chain."] + pub struct MessagesReceived (pub :: std :: vec :: Vec < runtime_types :: bp_messages :: ReceivedMessages < runtime_types :: bridge_runtime_common :: messages_xcm_extension :: XcmBlobMessageDispatchResult > > ,) ; + impl ::subxt::events::StaticEvent for MessagesReceived { + const PALLET: &'static str = "BridgeMillauMessages"; + const EVENT: &'static str = "MessagesReceived"; + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + #[doc = "Messages in the inclusive range have been delivered to the bridged chain."] + pub struct MessagesDelivered { + pub lane_id: runtime_types::bp_messages::LaneId, + pub messages: runtime_types::bp_messages::DeliveredMessages, + } + impl ::subxt::events::StaticEvent for MessagesDelivered { + const PALLET: &'static str = "BridgeMillauMessages"; + const EVENT: &'static str = "MessagesDelivered"; + } + } + pub mod storage { + use super::runtime_types; + pub struct StorageApi; + impl StorageApi { + #[doc = " Optional pallet owner."] + #[doc = ""] + #[doc = " Pallet owner has a right to halt all pallet operations and then resume it. If it is"] + #[doc = " `None`, then there are no direct ways to halt/resume pallet operations, but other"] + #[doc = " runtime methods may still be used to do that (i.e. democracy::referendum to update halt"] + #[doc = " flag directly or call the `halt_operations`)."] + pub fn pallet_owner( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType<::sp_core::crypto::AccountId32>, + ::subxt::storage::address::Yes, + (), + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauMessages", + "PalletOwner", + vec![], + [ + 89u8, 42u8, 74u8, 119u8, 21u8, 164u8, 30u8, 115u8, 207u8, 126u8, 98u8, + 16u8, 162u8, 214u8, 67u8, 172u8, 178u8, 223u8, 139u8, 121u8, 174u8, + 89u8, 215u8, 75u8, 200u8, 161u8, 61u8, 195u8, 65u8, 222u8, 246u8, + 233u8, + ], + ) + } + #[doc = " The current operating mode of the pallet."] + #[doc = ""] + #[doc = " Depending on the mode either all, some, or no transactions will be allowed."] + pub fn pallet_operating_mode( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_messages::MessagesOperatingMode, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + (), + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauMessages", + "PalletOperatingMode", + vec![], + [ + 215u8, 195u8, 85u8, 231u8, 158u8, 22u8, 160u8, 132u8, 69u8, 206u8, + 238u8, 14u8, 56u8, 100u8, 134u8, 41u8, 58u8, 120u8, 225u8, 164u8, + 173u8, 87u8, 22u8, 123u8, 102u8, 167u8, 68u8, 70u8, 184u8, 131u8, + 232u8, 65u8, + ], + ) + } + #[doc = " Map of lane id => inbound lane data."] + pub fn inbound_lanes( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_messages::InboundLaneData<::sp_core::crypto::AccountId32>, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauMessages", + "InboundLanes", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 38u8, 58u8, 110u8, 130u8, 112u8, 76u8, 231u8, 76u8, 56u8, 241u8, 183u8, + 153u8, 112u8, 41u8, 248u8, 208u8, 217u8, 57u8, 102u8, 30u8, 107u8, + 98u8, 59u8, 78u8, 56u8, 119u8, 186u8, 183u8, 213u8, 72u8, 199u8, 90u8, + ], + ) + } + #[doc = " Map of lane id => inbound lane data."] + pub fn inbound_lanes_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_messages::InboundLaneData<::sp_core::crypto::AccountId32>, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauMessages", + "InboundLanes", + Vec::new(), + [ + 38u8, 58u8, 110u8, 130u8, 112u8, 76u8, 231u8, 76u8, 56u8, 241u8, 183u8, + 153u8, 112u8, 41u8, 248u8, 208u8, 217u8, 57u8, 102u8, 30u8, 107u8, + 98u8, 59u8, 78u8, 56u8, 119u8, 186u8, 183u8, 213u8, 72u8, 199u8, 90u8, + ], + ) + } + #[doc = " Map of lane id => outbound lane data."] + pub fn outbound_lanes( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_messages::OutboundLaneData, + >, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauMessages", + "OutboundLanes", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 67u8, 155u8, 173u8, 244u8, 80u8, 38u8, 26u8, 71u8, 51u8, 150u8, 86u8, + 146u8, 132u8, 122u8, 70u8, 122u8, 172u8, 246u8, 106u8, 232u8, 149u8, + 227u8, 240u8, 146u8, 51u8, 184u8, 30u8, 182u8, 200u8, 43u8, 190u8, + 38u8, + ], + ) + } + #[doc = " Map of lane id => outbound lane data."] + pub fn outbound_lanes_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bp_messages::OutboundLaneData, + >, + (), + ::subxt::storage::address::Yes, + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauMessages", + "OutboundLanes", + Vec::new(), + [ + 67u8, 155u8, 173u8, 244u8, 80u8, 38u8, 26u8, 71u8, 51u8, 150u8, 86u8, + 146u8, 132u8, 122u8, 70u8, 122u8, 172u8, 246u8, 106u8, 232u8, 149u8, + 227u8, 240u8, 146u8, 51u8, 184u8, 30u8, 182u8, 200u8, 43u8, 190u8, + 38u8, + ], + ) + } + #[doc = " All queued outbound messages."] + pub fn outbound_messages( + &self, + _0: impl ::std::borrow::Borrow, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >, + >, + ::subxt::storage::address::Yes, + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauMessages", + "OutboundMessages", + vec![::subxt::storage::address::StorageMapKey::new( + _0.borrow(), + ::subxt::storage::address::StorageHasher::Blake2_128Concat, + )], + [ + 44u8, 35u8, 2u8, 25u8, 91u8, 101u8, 152u8, 23u8, 48u8, 250u8, 178u8, + 15u8, 194u8, 118u8, 146u8, 1u8, 112u8, 83u8, 243u8, 166u8, 124u8, + 153u8, 48u8, 193u8, 43u8, 31u8, 33u8, 72u8, 228u8, 113u8, 86u8, 217u8, + ], + ) + } + #[doc = " All queued outbound messages."] + pub fn outbound_messages_root( + &self, + ) -> ::subxt::storage::address::StaticStorageAddress< + ::subxt::metadata::DecodeStaticType< + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >, + >, + (), + (), + ::subxt::storage::address::Yes, + > { + ::subxt::storage::address::StaticStorageAddress::new( + "BridgeMillauMessages", + "OutboundMessages", + Vec::new(), + [ + 44u8, 35u8, 2u8, 25u8, 91u8, 101u8, 152u8, 23u8, 48u8, 250u8, 178u8, + 15u8, 194u8, 118u8, 146u8, 1u8, 112u8, 83u8, 243u8, 166u8, 124u8, + 153u8, 48u8, 193u8, 43u8, 31u8, 33u8, 72u8, 228u8, 113u8, 86u8, 217u8, + ], + ) + } + } + } + pub mod constants { + use super::runtime_types; + pub struct ConstantsApi; + impl ConstantsApi { + #[doc = " Gets the chain id value from the instance."] + pub fn bridged_chain_id( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<[::core::primitive::u8; 4usize]>, + > { + ::subxt::constants::StaticConstantAddress::new( + "BridgeMillauMessages", + "BridgedChainId", + [ + 101u8, 157u8, 37u8, 163u8, 190u8, 134u8, 129u8, 212u8, 240u8, 135u8, + 174u8, 76u8, 220u8, 179u8, 252u8, 69u8, 65u8, 253u8, 69u8, 214u8, 61u8, + 249u8, 4u8, 38u8, 181u8, 237u8, 25u8, 131u8, 242u8, 20u8, 17u8, 152u8, + ], + ) + } + #[doc = " Maximal encoded size of the outbound payload."] + pub fn maximal_outbound_payload_size( + &self, + ) -> ::subxt::constants::StaticConstantAddress< + ::subxt::metadata::DecodeStaticType<::core::primitive::u32>, + > { + ::subxt::constants::StaticConstantAddress::new( + "BridgeMillauMessages", + "MaximalOutboundPayloadSize", + [ + 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, + 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, + 178u8, 197u8, 113u8, 31u8, 79u8, 200u8, 90u8, 203u8, 100u8, 41u8, + 145u8, + ], + ) + } + } + } + } + pub mod runtime_types { + use super::runtime_types; + pub mod bounded_collections { + use super::runtime_types; + pub mod bounded_vec { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct BoundedVec<_0>(pub ::std::vec::Vec<_0>); + } + pub mod weak_bounded_vec { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct WeakBoundedVec<_0>(pub ::std::vec::Vec<_0>); + } + } + pub mod bp_header_chain { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct StoredHeaderData<_0, _1> { + pub number: _0, + pub state_root: _1, + } + } + pub mod bp_messages { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct DeliveredMessages { + pub begin: ::core::primitive::u64, + pub end: ::core::primitive::u64, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct InboundLaneData<_0> { + pub relayers: ::std::vec::Vec>, + pub last_confirmed_nonce: ::core::primitive::u64, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct LaneId(pub [::core::primitive::u8; 4usize]); + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct MessageKey { + pub lane_id: runtime_types::bp_messages::LaneId, + pub nonce: ::core::primitive::u64, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum MessagesOperatingMode { + #[codec(index = 0)] + Basic(runtime_types::bp_runtime::BasicOperatingMode), + #[codec(index = 1)] + RejectingOutboundMessages, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct OutboundLaneData { + pub oldest_unpruned_nonce: ::core::primitive::u64, + pub latest_received_nonce: ::core::primitive::u64, + pub latest_generated_nonce: ::core::primitive::u64, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum ReceivalResult<_0> { + #[codec(index = 0)] + Dispatched(runtime_types::bp_runtime::messages::MessageDispatchResult<_0>), + #[codec(index = 1)] + InvalidNonce, + #[codec(index = 2)] + TooManyUnrewardedRelayers, + #[codec(index = 3)] + TooManyUnconfirmedMessages, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ReceivedMessages<_0> { + pub lane: runtime_types::bp_messages::LaneId, + pub receive_results: ::std::vec::Vec<( + ::core::primitive::u64, + runtime_types::bp_messages::ReceivalResult<_0>, + )>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct UnrewardedRelayer<_0> { + pub relayer: _0, + pub messages: runtime_types::bp_messages::DeliveredMessages, + } + } + pub mod bp_relayers { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum RewardsAccountOwner { + #[codec(index = 0)] + ThisChain, + #[codec(index = 1)] + BridgedChain, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct RewardsAccountParams { + pub lane_id: runtime_types::bp_messages::LaneId, + pub bridged_chain_id: [::core::primitive::u8; 4usize], + pub owner: runtime_types::bp_relayers::RewardsAccountOwner, + } + } + pub mod bp_runtime { + use super::runtime_types; + pub mod messages { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct MessageDispatchResult<_0> { + pub unspent_weight: ::sp_weights::Weight, + pub dispatch_level_result: _0, + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum BasicOperatingMode { + #[codec(index = 0)] + Normal, + #[codec(index = 1)] + Halted, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct HeaderId<_0, _1>(pub _1, pub _0); + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum OwnedBridgeModuleError { + #[codec(index = 0)] + Halted, + } + } + pub mod bridge_runtime_common { + use super::runtime_types; + pub mod messages_xcm_extension { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum XcmBlobMessageDispatchResult { + #[codec(index = 0)] + InvalidPayload, + #[codec(index = 1)] + Dispatched, + #[codec(index = 2)] + NotDispatched, + } + } + } + pub mod cumulus_pallet_dmp_queue { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + #[doc = "Service a single overweight message."] + service_overweight { + index: ::core::primitive::u64, + weight_limit: ::sp_weights::Weight, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error { + #[codec(index = 0)] + #[doc = "The message index given is unknown."] + Unknown, + #[codec(index = 1)] + #[doc = "The amount of weight given is possibly not enough for executing the message."] + OverLimit, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "Downward message is invalid XCM."] + InvalidFormat { message_id: [::core::primitive::u8; 32usize] }, + #[codec(index = 1)] + #[doc = "Downward message is unsupported version of XCM."] + UnsupportedVersion { message_id: [::core::primitive::u8; 32usize] }, + #[codec(index = 2)] + #[doc = "Downward message executed with the given outcome."] + ExecutedDownward { + message_id: [::core::primitive::u8; 32usize], + outcome: runtime_types::xcm::v3::traits::Outcome, + }, + #[codec(index = 3)] + #[doc = "The weight limit for handling downward messages was reached."] + WeightExhausted { + message_id: [::core::primitive::u8; 32usize], + remaining_weight: ::sp_weights::Weight, + required_weight: ::sp_weights::Weight, + }, + #[codec(index = 4)] + #[doc = "Downward message is overweight and was placed in the overweight queue."] + OverweightEnqueued { + message_id: [::core::primitive::u8; 32usize], + overweight_index: ::core::primitive::u64, + required_weight: ::sp_weights::Weight, + }, + #[codec(index = 5)] + #[doc = "Downward message from the overweight queue was executed."] + OverweightServiced { + overweight_index: ::core::primitive::u64, + weight_used: ::sp_weights::Weight, + }, + #[codec(index = 6)] + #[doc = "The maximum number of downward messages was."] + MaxMessagesExhausted { message_id: [::core::primitive::u8; 32usize] }, + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ConfigData { + pub max_individual: ::sp_weights::Weight, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct PageIndexData { + pub begin_used: ::core::primitive::u32, + pub end_used: ::core::primitive::u32, + pub overweight_count: ::core::primitive::u64, + } + } + pub mod cumulus_pallet_parachain_system { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + # [codec (index = 0)] # [doc = "Set the current validation data."] # [doc = ""] # [doc = "This should be invoked exactly once per block. It will panic at the finalization"] # [doc = "phase if the call was not invoked."] # [doc = ""] # [doc = "The dispatch origin for this call must be `Inherent`"] # [doc = ""] # [doc = "As a side effect, this function upgrades the current validation function"] # [doc = "if the appropriate time has come."] set_validation_data { data : runtime_types :: cumulus_primitives_parachain_inherent :: ParachainInherentData , } , # [codec (index = 1)] sudo_send_upward_message { message : :: std :: vec :: Vec < :: core :: primitive :: u8 > , } , # [codec (index = 2)] # [doc = "Authorize an upgrade to a given `code_hash` for the runtime. The runtime can be supplied"] # [doc = "later."] # [doc = ""] # [doc = "The `check_version` parameter sets a boolean flag for whether or not the runtime's spec"] # [doc = "version and name should be verified on upgrade. Since the authorization only has a hash,"] # [doc = "it cannot actually perform the verification."] # [doc = ""] # [doc = "This call requires Root origin."] authorize_upgrade { code_hash : :: subxt :: utils :: H256 , check_version : :: core :: primitive :: bool , } , # [codec (index = 3)] # [doc = "Provide the preimage (runtime binary) `code` for an upgrade that has been authorized."] # [doc = ""] # [doc = "If the authorization required a version check, this call will ensure the spec name"] # [doc = "remains unchanged and that the spec version has increased."] # [doc = ""] # [doc = "Note that this function will not apply the new `code`, but only attempt to schedule the"] # [doc = "upgrade with the Relay Chain."] # [doc = ""] # [doc = "All origins are allowed."] enact_authorized_upgrade { code : :: std :: vec :: Vec < :: core :: primitive :: u8 > , } , } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error { + #[codec(index = 0)] + #[doc = "Attempt to upgrade validation function while existing upgrade pending."] + OverlappingUpgrades, + #[codec(index = 1)] + #[doc = "Polkadot currently prohibits this parachain from upgrading its validation function."] + ProhibitedByPolkadot, + #[codec(index = 2)] + #[doc = "The supplied validation function has compiled into a blob larger than Polkadot is"] + #[doc = "willing to run."] + TooBig, + #[codec(index = 3)] + #[doc = "The inherent which supplies the validation data did not run this block."] + ValidationDataNotAvailable, + #[codec(index = 4)] + #[doc = "The inherent which supplies the host configuration did not run this block."] + HostConfigurationNotAvailable, + #[codec(index = 5)] + #[doc = "No validation function upgrade is currently scheduled."] + NotScheduled, + #[codec(index = 6)] + #[doc = "No code upgrade has been authorized."] + NothingAuthorized, + #[codec(index = 7)] + #[doc = "The given code upgrade has not been authorized."] + Unauthorized, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "The validation function has been scheduled to apply."] + ValidationFunctionStored, + #[codec(index = 1)] + #[doc = "The validation function was applied as of the contained relay chain block number."] + ValidationFunctionApplied { relay_chain_block_num: ::core::primitive::u32 }, + #[codec(index = 2)] + #[doc = "The relay-chain aborted the upgrade process."] + ValidationFunctionDiscarded, + #[codec(index = 3)] + #[doc = "An upgrade has been authorized."] + UpgradeAuthorized { code_hash: ::subxt::utils::H256 }, + #[codec(index = 4)] + #[doc = "Some downward messages have been received and will be processed."] + DownwardMessagesReceived { count: ::core::primitive::u32 }, + #[codec(index = 5)] + #[doc = "Downward messages were processed using the given weight."] + DownwardMessagesProcessed { + weight_used: ::sp_weights::Weight, + dmq_head: ::subxt::utils::H256, + }, + #[codec(index = 6)] + #[doc = "An upward message was sent to the relay chain."] + UpwardMessageSent { + message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + }, + } + } + pub mod relay_state_snapshot { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct MessagingStateSnapshot { + pub dmq_mqc_head: ::subxt::utils::H256, + pub relay_dispatch_queue_size: (::core::primitive::u32, ::core::primitive::u32), + pub ingress_channels: ::std::vec::Vec<( + runtime_types::polkadot_parachain::primitives::Id, + runtime_types::polkadot_primitives::v4::AbridgedHrmpChannel, + )>, + pub egress_channels: ::std::vec::Vec<( + runtime_types::polkadot_parachain::primitives::Id, + runtime_types::polkadot_primitives::v4::AbridgedHrmpChannel, + )>, + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct CodeUpgradeAuthorization { + pub code_hash: ::subxt::utils::H256, + pub check_version: ::core::primitive::bool, + } + } + pub mod cumulus_pallet_xcm { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call {} + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error {} + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "Downward message is invalid XCM."] + #[doc = "\\[ id \\]"] + InvalidFormat([::core::primitive::u8; 32usize]), + #[codec(index = 1)] + #[doc = "Downward message is unsupported version of XCM."] + #[doc = "\\[ id \\]"] + UnsupportedVersion([::core::primitive::u8; 32usize]), + #[codec(index = 2)] + #[doc = "Downward message executed with the given outcome."] + #[doc = "\\[ id, outcome \\]"] + ExecutedDownward( + [::core::primitive::u8; 32usize], + runtime_types::xcm::v3::traits::Outcome, + ), + } + } + } + pub mod cumulus_pallet_xcmp_queue { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + #[doc = "Services a single overweight XCM."] + #[doc = ""] + #[doc = "- `origin`: Must pass `ExecuteOverweightOrigin`."] + #[doc = "- `index`: The index of the overweight XCM to service"] + #[doc = "- `weight_limit`: The amount of weight that XCM execution may take."] + #[doc = ""] + #[doc = "Errors:"] + #[doc = "- `BadOverweightIndex`: XCM under `index` is not found in the `Overweight` storage map."] + #[doc = "- `BadXcm`: XCM under `index` cannot be properly decoded into a valid XCM format."] + #[doc = "- `WeightOverLimit`: XCM execution may use greater `weight_limit`."] + #[doc = ""] + #[doc = "Events:"] + #[doc = "- `OverweightServiced`: On success."] + service_overweight { + index: ::core::primitive::u64, + weight_limit: ::sp_weights::Weight, + }, + #[codec(index = 1)] + #[doc = "Suspends all XCM executions for the XCMP queue, regardless of the sender's origin."] + #[doc = ""] + #[doc = "- `origin`: Must pass `ControllerOrigin`."] + suspend_xcm_execution, + #[codec(index = 2)] + #[doc = "Resumes all XCM executions for the XCMP queue."] + #[doc = ""] + #[doc = "Note that this function doesn't change the status of the in/out bound channels."] + #[doc = ""] + #[doc = "- `origin`: Must pass `ControllerOrigin`."] + resume_xcm_execution, + #[codec(index = 3)] + #[doc = "Overwrites the number of pages of messages which must be in the queue for the other side to be told to"] + #[doc = "suspend their sending."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.suspend_value`"] + update_suspend_threshold { new: ::core::primitive::u32 }, + #[codec(index = 4)] + #[doc = "Overwrites the number of pages of messages which must be in the queue after which we drop any further"] + #[doc = "messages from the channel."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.drop_threshold`"] + update_drop_threshold { new: ::core::primitive::u32 }, + #[codec(index = 5)] + #[doc = "Overwrites the number of pages of messages which the queue must be reduced to before it signals that"] + #[doc = "message sending may recommence after it has been suspended."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.resume_threshold`"] + update_resume_threshold { new: ::core::primitive::u32 }, + #[codec(index = 6)] + #[doc = "Overwrites the amount of remaining weight under which we stop processing messages."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.threshold_weight`"] + update_threshold_weight { new: ::sp_weights::Weight }, + #[codec(index = 7)] + #[doc = "Overwrites the speed to which the available weight approaches the maximum weight."] + #[doc = "A lower number results in a faster progression. A value of 1 makes the entire weight available initially."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.weight_restrict_decay`."] + update_weight_restrict_decay { new: ::sp_weights::Weight }, + #[codec(index = 8)] + #[doc = "Overwrite the maximum amount of weight any individual message may consume."] + #[doc = "Messages above this weight go into the overweight queue and may only be serviced explicitly."] + #[doc = ""] + #[doc = "- `origin`: Must pass `Root`."] + #[doc = "- `new`: Desired value for `QueueConfigData.xcmp_max_individual_weight`."] + update_xcmp_max_individual_weight { new: ::sp_weights::Weight }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error { + #[codec(index = 0)] + #[doc = "Failed to send XCM message."] + FailedToSend, + #[codec(index = 1)] + #[doc = "Bad XCM origin."] + BadXcmOrigin, + #[codec(index = 2)] + #[doc = "Bad XCM data."] + BadXcm, + #[codec(index = 3)] + #[doc = "Bad overweight index."] + BadOverweightIndex, + #[codec(index = 4)] + #[doc = "Provided weight is possibly not enough to execute the message."] + WeightOverLimit, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "Some XCM was executed ok."] + Success { + message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + weight: ::sp_weights::Weight, + }, + #[codec(index = 1)] + #[doc = "Some XCM failed."] + Fail { + message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + error: runtime_types::xcm::v3::traits::Error, + weight: ::sp_weights::Weight, + }, + #[codec(index = 2)] + #[doc = "Bad XCM version used."] + BadVersion { + message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + }, + #[codec(index = 3)] + #[doc = "Bad XCM format used."] + BadFormat { + message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + }, + #[codec(index = 4)] + #[doc = "An HRMP message was sent to a sibling parachain."] + XcmpMessageSent { + message_hash: ::core::option::Option<[::core::primitive::u8; 32usize]>, + }, + #[codec(index = 5)] + #[doc = "An XCM exceeded the individual message weight budget."] + OverweightEnqueued { + sender: runtime_types::polkadot_parachain::primitives::Id, + sent_at: ::core::primitive::u32, + index: ::core::primitive::u64, + required: ::sp_weights::Weight, + }, + #[codec(index = 6)] + #[doc = "An XCM from the overweight queue was executed with the given actual weight used."] + OverweightServiced { index: ::core::primitive::u64, used: ::sp_weights::Weight }, + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct InboundChannelDetails { + pub sender: runtime_types::polkadot_parachain::primitives::Id, + pub state: runtime_types::cumulus_pallet_xcmp_queue::InboundState, + pub message_metadata: ::std::vec::Vec<( + ::core::primitive::u32, + runtime_types::polkadot_parachain::primitives::XcmpMessageFormat, + )>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum InboundState { + #[codec(index = 0)] + Ok, + #[codec(index = 1)] + Suspended, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct OutboundChannelDetails { + pub recipient: runtime_types::polkadot_parachain::primitives::Id, + pub state: runtime_types::cumulus_pallet_xcmp_queue::OutboundState, + pub signals_exist: ::core::primitive::bool, + pub first_index: ::core::primitive::u16, + pub last_index: ::core::primitive::u16, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum OutboundState { + #[codec(index = 0)] + Ok, + #[codec(index = 1)] + Suspended, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct QueueConfigData { + pub suspend_threshold: ::core::primitive::u32, + pub drop_threshold: ::core::primitive::u32, + pub resume_threshold: ::core::primitive::u32, + pub threshold_weight: ::sp_weights::Weight, + pub weight_restrict_decay: ::sp_weights::Weight, + pub xcmp_max_individual_weight: ::sp_weights::Weight, + } + } + pub mod cumulus_primitives_parachain_inherent { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct MessageQueueChain(pub ::subxt::utils::H256); + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ParachainInherentData { + pub validation_data: + runtime_types::polkadot_primitives::v4::PersistedValidationData< + ::subxt::utils::H256, + ::core::primitive::u32, + >, + pub relay_chain_state: runtime_types::sp_trie::storage_proof::StorageProof, + pub downward_messages: ::std::vec::Vec< + runtime_types::polkadot_core_primitives::InboundDownwardMessage< + ::core::primitive::u32, + >, + >, + pub horizontal_messages: ::subxt::utils::KeyedVec< + runtime_types::polkadot_parachain::primitives::Id, + ::std::vec::Vec< + runtime_types::polkadot_core_primitives::InboundHrmpMessage< + ::core::primitive::u32, + >, + >, + >, + } + } + pub mod finality_grandpa { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Commit<_0, _1, _2, _3> { + pub target_hash: _0, + pub target_number: _1, + pub precommits: ::std::vec::Vec< + runtime_types::finality_grandpa::SignedPrecommit<_0, _1, _2, _3>, + >, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Precommit<_0, _1> { + pub target_hash: _0, + pub target_number: _1, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct SignedPrecommit<_0, _1, _2, _3> { + pub precommit: runtime_types::finality_grandpa::Precommit<_0, _1>, + pub signature: _2, + pub id: _3, + } + } + pub mod frame_support { + use super::runtime_types; + pub mod dispatch { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum DispatchClass { + #[codec(index = 0)] + Normal, + #[codec(index = 1)] + Operational, + #[codec(index = 2)] + Mandatory, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct DispatchInfo { + pub weight: ::sp_weights::Weight, + pub class: runtime_types::frame_support::dispatch::DispatchClass, + pub pays_fee: runtime_types::frame_support::dispatch::Pays, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Pays { + #[codec(index = 0)] + Yes, + #[codec(index = 1)] + No, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct PerDispatchClass<_0> { + pub normal: _0, + pub operational: _0, + pub mandatory: _0, + } + } + pub mod traits { + use super::runtime_types; + pub mod tokens { + use super::runtime_types; + pub mod misc { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum BalanceStatus { + #[codec(index = 0)] + Free, + #[codec(index = 1)] + Reserved, + } + } + } + } + } + pub mod frame_system { + use super::runtime_types; + pub mod extensions { + use super::runtime_types; + pub mod check_genesis { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct CheckGenesis; + } + pub mod check_mortality { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct CheckMortality(pub ::sp_runtime::generic::Era); + } + pub mod check_non_zero_sender { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct CheckNonZeroSender; + } + pub mod check_nonce { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct CheckNonce(#[codec(compact)] pub ::core::primitive::u32); + } + pub mod check_spec_version { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct CheckSpecVersion; + } + pub mod check_tx_version { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct CheckTxVersion; + } + pub mod check_weight { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct CheckWeight; + } + } + pub mod limits { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct BlockLength { + pub max: runtime_types::frame_support::dispatch::PerDispatchClass< + ::core::primitive::u32, + >, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct BlockWeights { + pub base_block: ::sp_weights::Weight, + pub max_block: ::sp_weights::Weight, + pub per_class: runtime_types::frame_support::dispatch::PerDispatchClass< + runtime_types::frame_system::limits::WeightsPerClass, + >, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct WeightsPerClass { + pub base_extrinsic: ::sp_weights::Weight, + pub max_extrinsic: ::core::option::Option<::sp_weights::Weight>, + pub max_total: ::core::option::Option<::sp_weights::Weight>, + pub reserved: ::core::option::Option<::sp_weights::Weight>, + } + } + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + #[doc = "Make some on-chain remark."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- `O(1)`"] + remark { remark: ::std::vec::Vec<::core::primitive::u8> }, + #[codec(index = 1)] + #[doc = "Set the number of pages in the WebAssembly environment's heap."] + set_heap_pages { pages: ::core::primitive::u64 }, + #[codec(index = 2)] + #[doc = "Set the new runtime code."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- `O(C + S)` where `C` length of `code` and `S` complexity of `can_set_code`"] + set_code { code: ::std::vec::Vec<::core::primitive::u8> }, + #[codec(index = 3)] + #[doc = "Set the new runtime code without doing any checks of the given `code`."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- `O(C)` where `C` length of `code`"] + set_code_without_checks { code: ::std::vec::Vec<::core::primitive::u8> }, + #[codec(index = 4)] + #[doc = "Set some items of storage."] + set_storage { + items: ::std::vec::Vec<( + ::std::vec::Vec<::core::primitive::u8>, + ::std::vec::Vec<::core::primitive::u8>, + )>, + }, + #[codec(index = 5)] + #[doc = "Kill some items from storage."] + kill_storage { keys: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>> }, + #[codec(index = 6)] + #[doc = "Kill all storage items with a key that starts with the given prefix."] + #[doc = ""] + #[doc = "**NOTE:** We rely on the Root origin to provide us the number of subkeys under"] + #[doc = "the prefix we are removing to accurately calculate the weight of this function."] + kill_prefix { + prefix: ::std::vec::Vec<::core::primitive::u8>, + subkeys: ::core::primitive::u32, + }, + #[codec(index = 7)] + #[doc = "Make some on-chain remark and emit event."] + remark_with_event { remark: ::std::vec::Vec<::core::primitive::u8> }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Error for the System pallet"] + pub enum Error { + #[codec(index = 0)] + #[doc = "The name of specification does not match between the current runtime"] + #[doc = "and the new runtime."] + InvalidSpecName, + #[codec(index = 1)] + #[doc = "The specification version is not allowed to decrease between the current runtime"] + #[doc = "and the new runtime."] + SpecVersionNeedsToIncrease, + #[codec(index = 2)] + #[doc = "Failed to extract the runtime version from the new runtime."] + #[doc = ""] + #[doc = "Either calling `Core_version` or decoding `RuntimeVersion` failed."] + FailedToExtractRuntimeVersion, + #[codec(index = 3)] + #[doc = "Suicide called when the account has non-default composite data."] + NonDefaultComposite, + #[codec(index = 4)] + #[doc = "There is a non-zero reference count preventing the account from being purged."] + NonZeroRefCount, + #[codec(index = 5)] + #[doc = "The origin filter prevent the call to be dispatched."] + CallFiltered, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Event for the System pallet."] + pub enum Event { + #[codec(index = 0)] + #[doc = "An extrinsic completed successfully."] + ExtrinsicSuccess { + dispatch_info: runtime_types::frame_support::dispatch::DispatchInfo, + }, + #[codec(index = 1)] + #[doc = "An extrinsic failed."] + ExtrinsicFailed { + dispatch_error: runtime_types::sp_runtime::DispatchError, + dispatch_info: runtime_types::frame_support::dispatch::DispatchInfo, + }, + #[codec(index = 2)] + #[doc = "`:code` was updated."] + CodeUpdated, + #[codec(index = 3)] + #[doc = "A new account was created."] + NewAccount { account: ::sp_core::crypto::AccountId32 }, + #[codec(index = 4)] + #[doc = "An account was reaped."] + KilledAccount { account: ::sp_core::crypto::AccountId32 }, + #[codec(index = 5)] + #[doc = "On on-chain remark happened."] + Remarked { sender: ::sp_core::crypto::AccountId32, hash: ::subxt::utils::H256 }, + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct AccountInfo<_0, _1> { + pub nonce: _0, + pub consumers: _0, + pub providers: _0, + pub sufficients: _0, + pub data: _1, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct EventRecord<_0, _1> { + pub phase: runtime_types::frame_system::Phase, + pub event: _0, + pub topics: ::std::vec::Vec<_1>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct LastRuntimeUpgradeInfo { + #[codec(compact)] + pub spec_version: ::core::primitive::u32, + pub spec_name: ::std::string::String, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum Phase { + #[codec(index = 0)] + ApplyExtrinsic(::core::primitive::u32), + #[codec(index = 1)] + Finalization, + #[codec(index = 2)] + Initialization, + } + } + pub mod pallet_balances { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + #[doc = "Transfer some liquid free balance to another account."] + #[doc = ""] + #[doc = "`transfer_allow_death` will set the `FreeBalance` of the sender and receiver."] + #[doc = "If the sender's account is below the existential deposit as a result"] + #[doc = "of the transfer, the account will be reaped."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be `Signed` by the transactor."] + transfer_allow_death { + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + value: ::core::primitive::u128, + }, + #[codec(index = 1)] + #[doc = "Set the regular balance of a given account; it also takes a reserved balance but this"] + #[doc = "must be the same as the account's current reserved balance."] + #[doc = ""] + #[doc = "The dispatch origin for this call is `root`."] + #[doc = ""] + #[doc = "WARNING: This call is DEPRECATED! Use `force_set_balance` instead."] + set_balance_deprecated { + who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + new_free: ::core::primitive::u128, + #[codec(compact)] + old_reserved: ::core::primitive::u128, + }, + #[codec(index = 2)] + #[doc = "Exactly as `transfer_allow_death`, except the origin must be root and the source account"] + #[doc = "may be specified."] + force_transfer { + source: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + value: ::core::primitive::u128, + }, + #[codec(index = 3)] + #[doc = "Same as the [`transfer_allow_death`] call, but with a check that the transfer will not"] + #[doc = "kill the origin account."] + #[doc = ""] + #[doc = "99% of the time you want [`transfer_allow_death`] instead."] + #[doc = ""] + #[doc = "[`transfer_allow_death`]: struct.Pallet.html#method.transfer"] + transfer_keep_alive { + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + value: ::core::primitive::u128, + }, + #[codec(index = 4)] + #[doc = "Transfer the entire transferable balance from the caller account."] + #[doc = ""] + #[doc = "NOTE: This function only attempts to transfer _transferable_ balances. This means that"] + #[doc = "any locked, reserved, or existential deposits (when `keep_alive` is `true`), will not be"] + #[doc = "transferred by this function. To ensure that this function results in a killed account,"] + #[doc = "you might need to prepare the account by removing any reference counters, storage"] + #[doc = "deposits, etc..."] + #[doc = ""] + #[doc = "The dispatch origin of this call must be Signed."] + #[doc = ""] + #[doc = "- `dest`: The recipient of the transfer."] + #[doc = "- `keep_alive`: A boolean to determine if the `transfer_all` operation should send all"] + #[doc = " of the funds the account has, causing the sender account to be killed (false), or"] + #[doc = " transfer everything except at least the existential deposit, which will guarantee to"] + #[doc = " keep the sender account alive (true)."] + transfer_all { + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + keep_alive: ::core::primitive::bool, + }, + #[codec(index = 5)] + #[doc = "Unreserve some balance from a user by force."] + #[doc = ""] + #[doc = "Can only be called by ROOT."] + force_unreserve { + who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + amount: ::core::primitive::u128, + }, + #[codec(index = 6)] + #[doc = "Upgrade a specified account."] + #[doc = ""] + #[doc = "- `origin`: Must be `Signed`."] + #[doc = "- `who`: The account to be upgraded."] + #[doc = ""] + #[doc = "This will waive the transaction fee if at least all but 10% of the accounts needed to"] + #[doc = "be upgraded. (We let some not have to be upgraded just in order to allow for the"] + #[doc = "possibililty of churn)."] + upgrade_accounts { who: ::std::vec::Vec<::sp_core::crypto::AccountId32> }, + #[codec(index = 7)] + #[doc = "Alias for `transfer_allow_death`, provided only for name-wise compatibility."] + #[doc = ""] + #[doc = "WARNING: DEPRECATED! Will be released in approximately 3 months."] + transfer { + dest: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + value: ::core::primitive::u128, + }, + #[codec(index = 8)] + #[doc = "Set the regular balance of a given account."] + #[doc = ""] + #[doc = "The dispatch origin for this call is `root`."] + force_set_balance { + who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + #[codec(compact)] + new_free: ::core::primitive::u128, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error { + #[codec(index = 0)] + #[doc = "Vesting balance too high to send value."] + VestingBalance, + #[codec(index = 1)] + #[doc = "Account liquidity restrictions prevent withdrawal."] + LiquidityRestrictions, + #[codec(index = 2)] + #[doc = "Balance too low to send value."] + InsufficientBalance, + #[codec(index = 3)] + #[doc = "Value too low to create account due to existential deposit."] + ExistentialDeposit, + #[codec(index = 4)] + #[doc = "Transfer/payment would kill account."] + Expendability, + #[codec(index = 5)] + #[doc = "A vesting schedule already exists for this account."] + ExistingVestingSchedule, + #[codec(index = 6)] + #[doc = "Beneficiary account must pre-exist."] + DeadAccount, + #[codec(index = 7)] + #[doc = "Number of named reserves exceed `MaxReserves`."] + TooManyReserves, + #[codec(index = 8)] + #[doc = "Number of holds exceed `MaxHolds`."] + TooManyHolds, + #[codec(index = 9)] + #[doc = "Number of freezes exceed `MaxFreezes`."] + TooManyFreezes, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "An account was created with some free balance."] + Endowed { + account: ::sp_core::crypto::AccountId32, + free_balance: ::core::primitive::u128, + }, + #[codec(index = 1)] + #[doc = "An account was removed whose balance was non-zero but below ExistentialDeposit,"] + #[doc = "resulting in an outright loss."] + DustLost { + account: ::sp_core::crypto::AccountId32, + amount: ::core::primitive::u128, + }, + #[codec(index = 2)] + #[doc = "Transfer succeeded."] + Transfer { + from: ::sp_core::crypto::AccountId32, + to: ::sp_core::crypto::AccountId32, + amount: ::core::primitive::u128, + }, + #[codec(index = 3)] + #[doc = "A balance was set by root."] + BalanceSet { + who: ::sp_core::crypto::AccountId32, + free: ::core::primitive::u128, + }, + #[codec(index = 4)] + #[doc = "Some balance was reserved (moved from free to reserved)."] + Reserved { + who: ::sp_core::crypto::AccountId32, + amount: ::core::primitive::u128, + }, + #[codec(index = 5)] + #[doc = "Some balance was unreserved (moved from reserved to free)."] + Unreserved { + who: ::sp_core::crypto::AccountId32, + amount: ::core::primitive::u128, + }, + #[codec(index = 6)] + #[doc = "Some balance was moved from the reserve of the first account to the second account."] + #[doc = "Final argument indicates the destination balance type."] + ReserveRepatriated { + from: ::sp_core::crypto::AccountId32, + to: ::sp_core::crypto::AccountId32, + amount: ::core::primitive::u128, + destination_status: + runtime_types::frame_support::traits::tokens::misc::BalanceStatus, + }, + #[codec(index = 7)] + #[doc = "Some amount was deposited (e.g. for transaction fees)."] + Deposit { who: ::sp_core::crypto::AccountId32, amount: ::core::primitive::u128 }, + #[codec(index = 8)] + #[doc = "Some amount was withdrawn from the account (e.g. for transaction fees)."] + Withdraw { + who: ::sp_core::crypto::AccountId32, + amount: ::core::primitive::u128, + }, + #[codec(index = 9)] + #[doc = "Some amount was removed from the account (e.g. for misbehavior)."] + Slashed { who: ::sp_core::crypto::AccountId32, amount: ::core::primitive::u128 }, + #[codec(index = 10)] + #[doc = "Some amount was minted into an account."] + Minted { who: ::sp_core::crypto::AccountId32, amount: ::core::primitive::u128 }, + #[codec(index = 11)] + #[doc = "Some amount was burned from an account."] + Burned { who: ::sp_core::crypto::AccountId32, amount: ::core::primitive::u128 }, + #[codec(index = 12)] + #[doc = "Some amount was suspended from an account (it can be restored later)."] + Suspended { + who: ::sp_core::crypto::AccountId32, + amount: ::core::primitive::u128, + }, + #[codec(index = 13)] + #[doc = "Some amount was restored into an account."] + Restored { + who: ::sp_core::crypto::AccountId32, + amount: ::core::primitive::u128, + }, + #[codec(index = 14)] + #[doc = "An account was upgraded."] + Upgraded { who: ::sp_core::crypto::AccountId32 }, + #[codec(index = 15)] + #[doc = "Total issuance was increased by `amount`, creating a credit to be balanced."] + Issued { amount: ::core::primitive::u128 }, + #[codec(index = 16)] + #[doc = "Total issuance was decreased by `amount`, creating a debt to be balanced."] + Rescinded { amount: ::core::primitive::u128 }, + } + } + pub mod types { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct AccountData<_0> { + pub free: _0, + pub reserved: _0, + pub frozen: _0, + pub flags: runtime_types::pallet_balances::types::ExtraFlags, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct BalanceLock<_0> { + pub id: [::core::primitive::u8; 8usize], + pub amount: _0, + pub reasons: runtime_types::pallet_balances::types::Reasons, + } + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct ExtraFlags(pub ::core::primitive::u128); + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct IdAmount<_0, _1> { + pub id: _0, + pub amount: _1, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Reasons { + #[codec(index = 0)] + Fee, + #[codec(index = 1)] + Misc, + #[codec(index = 2)] + All, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct ReserveData<_0, _1> { + pub id: _0, + pub amount: _1, + } + } + } + pub mod pallet_bridge_grandpa { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + #[doc = "Verify a target header is finalized according to the given finality proof."] + #[doc = ""] + #[doc = "It will use the underlying storage pallet to fetch information about the current"] + #[doc = "authorities and best finalized header in order to verify that the header is finalized."] + #[doc = ""] + #[doc = "If successful in verification, it will write the target header to the underlying storage"] + #[doc = "pallet."] + submit_finality_proof { + finality_target: ::std::boxed::Box< + ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + >, + justification: ::bp_header_chain::justification::GrandpaJustification< + ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + >, + }, + #[codec(index = 1)] + #[doc = "Bootstrap the bridge pallet with an initial header and authority set from which to sync."] + #[doc = ""] + #[doc = "The initial configuration provided does not need to be the genesis header of the bridged"] + #[doc = "chain, it can be any arbitrary header. You can also provide the next scheduled set"] + #[doc = "change if it is already know."] + #[doc = ""] + #[doc = "This function is only allowed to be called from a trusted origin and writes to storage"] + #[doc = "with practically no checks in terms of the validity of the data. It is important that"] + #[doc = "you ensure that valid data is being passed in."] + initialize { + init_data: ::bp_header_chain::InitializationData< + ::sp_runtime::generic::Header< + ::core::primitive::u64, + ::bp_millau::BlakeTwoAndKeccak256, + >, + >, + }, + #[codec(index = 2)] + #[doc = "Change `PalletOwner`."] + #[doc = ""] + #[doc = "May only be called either by root, or by `PalletOwner`."] + set_owner { new_owner: ::core::option::Option<::sp_core::crypto::AccountId32> }, + #[codec(index = 3)] + #[doc = "Halt or resume all pallet operations."] + #[doc = ""] + #[doc = "May only be called either by root, or by `PalletOwner`."] + set_operating_mode { + operating_mode: runtime_types::bp_runtime::BasicOperatingMode, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error { + #[codec(index = 0)] + #[doc = "The given justification is invalid for the given header."] + InvalidJustification, + #[codec(index = 1)] + #[doc = "The authority set from the underlying header chain is invalid."] + InvalidAuthoritySet, + #[codec(index = 2)] + #[doc = "There are too many requests for the current window to handle."] + TooManyRequests, + #[codec(index = 3)] + #[doc = "The header being imported is older than the best finalized header known to the pallet."] + OldHeader, + #[codec(index = 4)] + #[doc = "The scheduled authority set change found in the header is unsupported by the pallet."] + #[doc = ""] + #[doc = "This is the case for non-standard (e.g forced) authority set changes."] + UnsupportedScheduledChange, + #[codec(index = 5)] + #[doc = "The pallet is not yet initialized."] + NotInitialized, + #[codec(index = 6)] + #[doc = "The pallet has already been initialized."] + AlreadyInitialized, + #[codec(index = 7)] + #[doc = "Too many authorities in the set."] + TooManyAuthoritiesInSet, + #[codec(index = 8)] + #[doc = "Error generated by the `OwnedBridgeModule` trait."] + BridgeModule(runtime_types::bp_runtime::OwnedBridgeModuleError), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "Best finalized chain header has been updated to the header with given number and hash."] + UpdatedBestFinalizedHeader { + number: ::core::primitive::u64, + hash: ::bp_millau::MillauHash, + }, + } + } + pub mod storage_types { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct StoredAuthoritySet { + pub authorities: runtime_types::bounded_collections::bounded_vec::BoundedVec<( + runtime_types::sp_consensus_grandpa::app::Public, + ::core::primitive::u64, + )>, + pub set_id: ::core::primitive::u64, + } + } + } + pub mod pallet_bridge_messages { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + # [codec (index = 0)] # [doc = "Change `PalletOwner`."] # [doc = ""] # [doc = "May only be called either by root, or by `PalletOwner`."] set_owner { new_owner : :: core :: option :: Option < :: sp_core :: crypto :: AccountId32 > , } , # [codec (index = 1)] # [doc = "Halt or resume all/some pallet operations."] # [doc = ""] # [doc = "May only be called either by root, or by `PalletOwner`."] set_operating_mode { operating_mode : runtime_types :: bp_messages :: MessagesOperatingMode , } , # [codec (index = 2)] # [doc = "Receive messages proof from bridged chain."] # [doc = ""] # [doc = "The weight of the call assumes that the transaction always brings outbound lane"] # [doc = "state update. Because of that, the submitter (relayer) has no benefit of not including"] # [doc = "this data in the transaction, so reward confirmations lags should be minimal."] receive_messages_proof { relayer_id_at_bridged_chain : :: sp_core :: crypto :: AccountId32 , proof : :: bridge_runtime_common :: messages :: target :: FromBridgedChainMessagesProof < :: bp_millau :: MillauHash > , messages_count : :: core :: primitive :: u32 , dispatch_weight : :: sp_weights :: Weight , } , # [codec (index = 3)] # [doc = "Receive messages delivery proof from bridged chain."] receive_messages_delivery_proof { proof : :: bridge_runtime_common :: messages :: source :: FromBridgedChainMessagesDeliveryProof < :: bp_millau :: MillauHash > , relayers_state : :: bp_messages :: UnrewardedRelayersState , } , } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error { + #[codec(index = 0)] + #[doc = "Pallet is not in Normal operating mode."] + NotOperatingNormally, + #[codec(index = 1)] + #[doc = "The outbound lane is inactive."] + InactiveOutboundLane, + #[codec(index = 2)] + #[doc = "The message is too large to be sent over the bridge."] + MessageIsTooLarge, + #[codec(index = 3)] + #[doc = "Message has been treated as invalid by chain verifier."] + MessageRejectedByChainVerifier, + #[codec(index = 4)] + #[doc = "Message has been treated as invalid by lane verifier."] + MessageRejectedByLaneVerifier, + #[codec(index = 5)] + #[doc = "Submitter has failed to pay fee for delivering and dispatching messages."] + FailedToWithdrawMessageFee, + #[codec(index = 6)] + #[doc = "The transaction brings too many messages."] + TooManyMessagesInTheProof, + #[codec(index = 7)] + #[doc = "Invalid messages has been submitted."] + InvalidMessagesProof, + #[codec(index = 8)] + #[doc = "Invalid messages delivery proof has been submitted."] + InvalidMessagesDeliveryProof, + #[codec(index = 9)] + #[doc = "The bridged chain has invalid `UnrewardedRelayers` in its storage (fatal for the lane)."] + InvalidUnrewardedRelayers, + #[codec(index = 10)] + #[doc = "The relayer has declared invalid unrewarded relayers state in the"] + #[doc = "`receive_messages_delivery_proof` call."] + InvalidUnrewardedRelayersState, + #[codec(index = 11)] + #[doc = "The cumulative dispatch weight, passed by relayer is not enough to cover dispatch"] + #[doc = "of all bundled messages."] + InsufficientDispatchWeight, + #[codec(index = 12)] + #[doc = "The message someone is trying to work with (i.e. increase fee) is not yet sent."] + MessageIsNotYetSent, + #[codec(index = 13)] + #[doc = "The number of actually confirmed messages is going to be larger than the number of"] + #[doc = "messages in the proof. This may mean that this or bridged chain storage is corrupted."] + TryingToConfirmMoreMessagesThanExpected, + #[codec(index = 14)] + #[doc = "Error generated by the `OwnedBridgeModule` trait."] + BridgeModule(runtime_types::bp_runtime::OwnedBridgeModuleError), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + # [codec (index = 0)] # [doc = "Message has been accepted and is waiting to be delivered."] MessageAccepted { lane_id : runtime_types :: bp_messages :: LaneId , nonce : :: core :: primitive :: u64 , } , # [codec (index = 1)] # [doc = "Messages have been received from the bridged chain."] MessagesReceived (:: std :: vec :: Vec < runtime_types :: bp_messages :: ReceivedMessages < runtime_types :: bridge_runtime_common :: messages_xcm_extension :: XcmBlobMessageDispatchResult > > ,) , # [codec (index = 2)] # [doc = "Messages in the inclusive range have been delivered to the bridged chain."] MessagesDelivered { lane_id : runtime_types :: bp_messages :: LaneId , messages : runtime_types :: bp_messages :: DeliveredMessages , } , } + } + } + pub mod pallet_bridge_relayers { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + #[doc = "Claim accumulated rewards."] + claim_rewards { + rewards_account_params: runtime_types::bp_relayers::RewardsAccountParams, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error { + #[codec(index = 0)] + #[doc = "No reward can be claimed by given relayer."] + NoRewardForRelayer, + #[codec(index = 1)] + #[doc = "Reward payment procedure has failed."] + FailedToPayReward, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "Reward has been paid to the relayer."] + RewardPaid { + relayer: ::sp_core::crypto::AccountId32, + rewards_account_params: runtime_types::bp_relayers::RewardsAccountParams, + reward: ::core::primitive::u128, + }, + } + } + } + pub mod pallet_sudo { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + sudo { + call: + ::std::boxed::Box, + }, + #[codec(index = 1)] + #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] + #[doc = "This function does not check the weight of the call, and instead allows the"] + #[doc = "Sudo user to specify the weight of the call."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + sudo_unchecked_weight { + call: + ::std::boxed::Box, + weight: ::sp_weights::Weight, + }, + #[codec(index = 2)] + #[doc = "Authenticates the current sudo key and sets the given AccountId (`new`) as the new sudo"] + #[doc = "key."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + set_key { + new: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + }, + #[codec(index = 3)] + #[doc = "Authenticates the sudo key and dispatches a function call with `Signed` origin from"] + #[doc = "a given account."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be _Signed_."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- O(1)."] + sudo_as { + who: ::subxt::utils::MultiAddress<::sp_core::crypto::AccountId32, ()>, + call: + ::std::boxed::Box, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Error for the Sudo pallet"] + pub enum Error { + #[codec(index = 0)] + #[doc = "Sender must be the Sudo account"] + RequireSudo, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "A sudo just took place. \\[result\\]"] + Sudid { + sudo_result: + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, + }, + #[codec(index = 1)] + #[doc = "The \\[sudoer\\] just switched identity; the old key is supplied if one existed."] + KeyChanged { + old_sudoer: ::core::option::Option<::sp_core::crypto::AccountId32>, + }, + #[codec(index = 2)] + #[doc = "A sudo just took place. \\[result\\]"] + SudoAsDone { + sudo_result: + ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, + }, + } + } + } + pub mod pallet_timestamp { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + #[doc = "Set the current time."] + #[doc = ""] + #[doc = "This call should be invoked exactly once per block. It will panic at the finalization"] + #[doc = "phase, if this call hasn't been invoked by that time."] + #[doc = ""] + #[doc = "The timestamp should be greater than the previous one by the amount specified by"] + #[doc = "`MinimumPeriod`."] + #[doc = ""] + #[doc = "The dispatch origin for this call must be `Inherent`."] + #[doc = ""] + #[doc = "## Complexity"] + #[doc = "- `O(1)` (Note that implementations of `OnTimestampSet` must also be `O(1)`)"] + #[doc = "- 1 storage read and 1 storage mutation (codec `O(1)`). (because of `DidUpdate::take` in"] + #[doc = " `on_finalize`)"] + #[doc = "- 1 event handler `on_timestamp_set`. Must be `O(1)`."] + set { + #[codec(compact)] + now: ::core::primitive::u64, + }, + } + } + } + pub mod pallet_transaction_payment { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "A transaction fee `actual_fee`, of which `tip` was added to the minimum inclusion fee,"] + #[doc = "has been paid by `who`."] + TransactionFeePaid { + who: ::sp_core::crypto::AccountId32, + actual_fee: ::core::primitive::u128, + tip: ::core::primitive::u128, + }, + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ChargeTransactionPayment(#[codec(compact)] pub ::core::primitive::u128); + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum Releases { + #[codec(index = 0)] + V1Ancient, + #[codec(index = 1)] + V2, + } + } + pub mod pallet_xcm { + use super::runtime_types; + pub mod pallet { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "Contains one variant per dispatchable that can be called by an extrinsic."] + pub enum Call { + #[codec(index = 0)] + send { + dest: ::std::boxed::Box, + message: ::std::boxed::Box, + }, + #[codec(index = 1)] + #[doc = "Teleport some assets from the local chain to some destination chain."] + #[doc = ""] + #[doc = "Fee payment on the destination side is made from the asset in the `assets` vector of"] + #[doc = "index `fee_asset_item`. The weight limit for fees is not provided and thus is unlimited,"] + #[doc = "with all fees taken as needed from the asset."] + #[doc = ""] + #[doc = "- `origin`: Must be capable of withdrawing the `assets` and executing XCM."] + #[doc = "- `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send"] + #[doc = " from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain."] + #[doc = "- `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be"] + #[doc = " an `AccountId32` value."] + #[doc = "- `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the"] + #[doc = " `dest` side. May not be empty."] + #[doc = "- `fee_asset_item`: The index into `assets` of the item which should be used to pay"] + #[doc = " fees."] + teleport_assets { + dest: ::std::boxed::Box, + beneficiary: ::std::boxed::Box, + assets: ::std::boxed::Box, + fee_asset_item: ::core::primitive::u32, + }, + #[codec(index = 2)] + #[doc = "Transfer some assets from the local chain to the sovereign account of a destination"] + #[doc = "chain and forward a notification XCM."] + #[doc = ""] + #[doc = "Fee payment on the destination side is made from the asset in the `assets` vector of"] + #[doc = "index `fee_asset_item`. The weight limit for fees is not provided and thus is unlimited,"] + #[doc = "with all fees taken as needed from the asset."] + #[doc = ""] + #[doc = "- `origin`: Must be capable of withdrawing the `assets` and executing XCM."] + #[doc = "- `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send"] + #[doc = " from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain."] + #[doc = "- `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be"] + #[doc = " an `AccountId32` value."] + #[doc = "- `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the"] + #[doc = " `dest` side."] + #[doc = "- `fee_asset_item`: The index into `assets` of the item which should be used to pay"] + #[doc = " fees."] + reserve_transfer_assets { + dest: ::std::boxed::Box, + beneficiary: ::std::boxed::Box, + assets: ::std::boxed::Box, + fee_asset_item: ::core::primitive::u32, + }, + #[codec(index = 3)] + #[doc = "Execute an XCM message from a local, signed, origin."] + #[doc = ""] + #[doc = "An event is deposited indicating whether `msg` could be executed completely or only"] + #[doc = "partially."] + #[doc = ""] + #[doc = "No more than `max_weight` will be used in its attempted execution. If this is less than the"] + #[doc = "maximum amount of weight that the message could take to be executed, then no execution"] + #[doc = "attempt will be made."] + #[doc = ""] + #[doc = "NOTE: A successful return to this does *not* imply that the `msg` was executed successfully"] + #[doc = "to completion; only that *some* of it was executed."] + execute { + message: ::std::boxed::Box, + max_weight: ::sp_weights::Weight, + }, + #[codec(index = 4)] + #[doc = "Extoll that a particular destination can be communicated with through a particular"] + #[doc = "version of XCM."] + #[doc = ""] + #[doc = "- `origin`: Must be Root."] + #[doc = "- `location`: The destination that is being described."] + #[doc = "- `xcm_version`: The latest version of XCM that `location` supports."] + force_xcm_version { + location: + ::std::boxed::Box, + xcm_version: ::core::primitive::u32, + }, + #[codec(index = 5)] + #[doc = "Set a safe XCM version (the version that XCM should be encoded with if the most recent"] + #[doc = "version a destination can accept is unknown)."] + #[doc = ""] + #[doc = "- `origin`: Must be Root."] + #[doc = "- `maybe_xcm_version`: The default XCM encoding version, or `None` to disable."] + force_default_xcm_version { + maybe_xcm_version: ::core::option::Option<::core::primitive::u32>, + }, + #[codec(index = 6)] + #[doc = "Ask a location to notify us regarding their XCM version and any changes to it."] + #[doc = ""] + #[doc = "- `origin`: Must be Root."] + #[doc = "- `location`: The location to which we should subscribe for XCM version notifications."] + force_subscribe_version_notify { + location: ::std::boxed::Box, + }, + #[codec(index = 7)] + #[doc = "Require that a particular destination should no longer notify us regarding any XCM"] + #[doc = "version changes."] + #[doc = ""] + #[doc = "- `origin`: Must be Root."] + #[doc = "- `location`: The location to which we are currently subscribed for XCM version"] + #[doc = " notifications which we no longer desire."] + force_unsubscribe_version_notify { + location: ::std::boxed::Box, + }, + #[codec(index = 8)] + #[doc = "Transfer some assets from the local chain to the sovereign account of a destination"] + #[doc = "chain and forward a notification XCM."] + #[doc = ""] + #[doc = "Fee payment on the destination side is made from the asset in the `assets` vector of"] + #[doc = "index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight"] + #[doc = "is needed than `weight_limit`, then the operation will fail and the assets send may be"] + #[doc = "at risk."] + #[doc = ""] + #[doc = "- `origin`: Must be capable of withdrawing the `assets` and executing XCM."] + #[doc = "- `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send"] + #[doc = " from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain."] + #[doc = "- `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be"] + #[doc = " an `AccountId32` value."] + #[doc = "- `assets`: The assets to be withdrawn. This should include the assets used to pay the fee on the"] + #[doc = " `dest` side."] + #[doc = "- `fee_asset_item`: The index into `assets` of the item which should be used to pay"] + #[doc = " fees."] + #[doc = "- `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase."] + limited_reserve_transfer_assets { + dest: ::std::boxed::Box, + beneficiary: ::std::boxed::Box, + assets: ::std::boxed::Box, + fee_asset_item: ::core::primitive::u32, + weight_limit: runtime_types::xcm::v3::WeightLimit, + }, + #[codec(index = 9)] + #[doc = "Teleport some assets from the local chain to some destination chain."] + #[doc = ""] + #[doc = "Fee payment on the destination side is made from the asset in the `assets` vector of"] + #[doc = "index `fee_asset_item`, up to enough to pay for `weight_limit` of weight. If more weight"] + #[doc = "is needed than `weight_limit`, then the operation will fail and the assets send may be"] + #[doc = "at risk."] + #[doc = ""] + #[doc = "- `origin`: Must be capable of withdrawing the `assets` and executing XCM."] + #[doc = "- `dest`: Destination context for the assets. Will typically be `X2(Parent, Parachain(..))` to send"] + #[doc = " from parachain to parachain, or `X1(Parachain(..))` to send from relay to parachain."] + #[doc = "- `beneficiary`: A beneficiary location for the assets in the context of `dest`. Will generally be"] + #[doc = " an `AccountId32` value."] + #[doc = "- `assets`: The assets to be withdrawn. The first item should be the currency used to to pay the fee on the"] + #[doc = " `dest` side. May not be empty."] + #[doc = "- `fee_asset_item`: The index into `assets` of the item which should be used to pay"] + #[doc = " fees."] + #[doc = "- `weight_limit`: The remote-side weight limit, if any, for the XCM fee purchase."] + limited_teleport_assets { + dest: ::std::boxed::Box, + beneficiary: ::std::boxed::Box, + assets: ::std::boxed::Box, + fee_asset_item: ::core::primitive::u32, + weight_limit: runtime_types::xcm::v3::WeightLimit, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tCustom [dispatch errors](https://docs.substrate.io/main-docs/build/events-errors/)\n\t\t\tof this pallet.\n\t\t\t"] + pub enum Error { + #[codec(index = 0)] + #[doc = "The desired destination was unreachable, generally because there is a no way of routing"] + #[doc = "to it."] + Unreachable, + #[codec(index = 1)] + #[doc = "There was some other issue (i.e. not to do with routing) in sending the message. Perhaps"] + #[doc = "a lack of space for buffering the message."] + SendFailure, + #[codec(index = 2)] + #[doc = "The message execution fails the filter."] + Filtered, + #[codec(index = 3)] + #[doc = "The message's weight could not be determined."] + UnweighableMessage, + #[codec(index = 4)] + #[doc = "The destination `MultiLocation` provided cannot be inverted."] + DestinationNotInvertible, + #[codec(index = 5)] + #[doc = "The assets to be sent are empty."] + Empty, + #[codec(index = 6)] + #[doc = "Could not re-anchor the assets to declare the fees for the destination chain."] + CannotReanchor, + #[codec(index = 7)] + #[doc = "Too many assets have been attempted for transfer."] + TooManyAssets, + #[codec(index = 8)] + #[doc = "Origin is invalid for sending."] + InvalidOrigin, + #[codec(index = 9)] + #[doc = "The version of the `Versioned` value used is not able to be interpreted."] + BadVersion, + #[codec(index = 10)] + #[doc = "The given location could not be used (e.g. because it cannot be expressed in the"] + #[doc = "desired version of XCM)."] + BadLocation, + #[codec(index = 11)] + #[doc = "The referenced subscription could not be found."] + NoSubscription, + #[codec(index = 12)] + #[doc = "The location is invalid since it already has a subscription from us."] + AlreadySubscribed, + #[codec(index = 13)] + #[doc = "Invalid asset for the operation."] + InvalidAsset, + #[codec(index = 14)] + #[doc = "The owner does not own (all) of the asset that they wish to do the operation on."] + LowBalance, + #[codec(index = 15)] + #[doc = "The asset owner has too many locks on the asset."] + TooManyLocks, + #[codec(index = 16)] + #[doc = "The given account is not an identifiable sovereign account for any location."] + AccountNotSovereign, + #[codec(index = 17)] + #[doc = "The operation required fees to be paid which the initiator could not meet."] + FeesNotMet, + #[codec(index = 18)] + #[doc = "A remote lock with the corresponding data could not be found."] + LockNotFound, + #[codec(index = 19)] + #[doc = "The unlock operation cannot succeed because there are still users of the lock."] + InUse, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + #[doc = "\n\t\t\tThe [event](https://docs.substrate.io/main-docs/build/events-errors/) emitted\n\t\t\tby this pallet.\n\t\t\t"] + pub enum Event { + #[codec(index = 0)] + #[doc = "Execution of an XCM message was attempted."] + #[doc = ""] + #[doc = "\\[ outcome \\]"] + Attempted(runtime_types::xcm::v3::traits::Outcome), + #[codec(index = 1)] + #[doc = "A XCM message was sent."] + #[doc = ""] + #[doc = "\\[ origin, destination, message \\]"] + Sent( + runtime_types::xcm::v3::multilocation::MultiLocation, + runtime_types::xcm::v3::multilocation::MultiLocation, + runtime_types::xcm::v3::Xcm, + ), + #[codec(index = 2)] + #[doc = "Query response received which does not match a registered query. This may be because a"] + #[doc = "matching query was never registered, it may be because it is a duplicate response, or"] + #[doc = "because the query timed out."] + #[doc = ""] + #[doc = "\\[ origin location, id \\]"] + UnexpectedResponse( + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::primitive::u64, + ), + #[codec(index = 3)] + #[doc = "Query response has been received and is ready for taking with `take_response`. There is"] + #[doc = "no registered notification call."] + #[doc = ""] + #[doc = "\\[ id, response \\]"] + ResponseReady(::core::primitive::u64, runtime_types::xcm::v3::Response), + #[codec(index = 4)] + #[doc = "Query response has been received and query is removed. The registered notification has"] + #[doc = "been dispatched and executed successfully."] + #[doc = ""] + #[doc = "\\[ id, pallet index, call index \\]"] + Notified(::core::primitive::u64, ::core::primitive::u8, ::core::primitive::u8), + #[codec(index = 5)] + #[doc = "Query response has been received and query is removed. The registered notification could"] + #[doc = "not be dispatched because the dispatch weight is greater than the maximum weight"] + #[doc = "originally budgeted by this runtime for the query result."] + #[doc = ""] + #[doc = "\\[ id, pallet index, call index, actual weight, max budgeted weight \\]"] + NotifyOverweight( + ::core::primitive::u64, + ::core::primitive::u8, + ::core::primitive::u8, + ::sp_weights::Weight, + ::sp_weights::Weight, + ), + #[codec(index = 6)] + #[doc = "Query response has been received and query is removed. There was a general error with"] + #[doc = "dispatching the notification call."] + #[doc = ""] + #[doc = "\\[ id, pallet index, call index \\]"] + NotifyDispatchError( + ::core::primitive::u64, + ::core::primitive::u8, + ::core::primitive::u8, + ), + #[codec(index = 7)] + #[doc = "Query response has been received and query is removed. The dispatch was unable to be"] + #[doc = "decoded into a `Call`; this might be due to dispatch function having a signature which"] + #[doc = "is not `(origin, QueryId, Response)`."] + #[doc = ""] + #[doc = "\\[ id, pallet index, call index \\]"] + NotifyDecodeFailed( + ::core::primitive::u64, + ::core::primitive::u8, + ::core::primitive::u8, + ), + #[codec(index = 8)] + #[doc = "Expected query response has been received but the origin location of the response does"] + #[doc = "not match that expected. The query remains registered for a later, valid, response to"] + #[doc = "be received and acted upon."] + #[doc = ""] + #[doc = "\\[ origin location, id, expected location \\]"] + InvalidResponder( + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::primitive::u64, + ::core::option::Option< + runtime_types::xcm::v3::multilocation::MultiLocation, + >, + ), + #[codec(index = 9)] + #[doc = "Expected query response has been received but the expected origin location placed in"] + #[doc = "storage by this runtime previously cannot be decoded. The query remains registered."] + #[doc = ""] + #[doc = "This is unexpected (since a location placed in storage in a previously executing"] + #[doc = "runtime should be readable prior to query timeout) and dangerous since the possibly"] + #[doc = "valid response will be dropped. Manual governance intervention is probably going to be"] + #[doc = "needed."] + #[doc = ""] + #[doc = "\\[ origin location, id \\]"] + InvalidResponderVersion( + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::primitive::u64, + ), + #[codec(index = 10)] + #[doc = "Received query response has been read and removed."] + #[doc = ""] + #[doc = "\\[ id \\]"] + ResponseTaken(::core::primitive::u64), + #[codec(index = 11)] + #[doc = "Some assets have been placed in an asset trap."] + #[doc = ""] + #[doc = "\\[ hash, origin, assets \\]"] + AssetsTrapped( + ::subxt::utils::H256, + runtime_types::xcm::v3::multilocation::MultiLocation, + runtime_types::xcm::VersionedMultiAssets, + ), + #[codec(index = 12)] + #[doc = "An XCM version change notification message has been attempted to be sent."] + #[doc = ""] + #[doc = "The cost of sending it (borne by the chain) is included."] + #[doc = ""] + #[doc = "\\[ destination, result, cost \\]"] + VersionChangeNotified( + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::primitive::u32, + runtime_types::xcm::v3::multiasset::MultiAssets, + ), + #[codec(index = 13)] + #[doc = "The supported version of a location has been changed. This might be through an"] + #[doc = "automatic notification or a manual intervention."] + #[doc = ""] + #[doc = "\\[ location, XCM version \\]"] + SupportedVersionChanged( + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::primitive::u32, + ), + #[codec(index = 14)] + #[doc = "A given location which had a version change subscription was dropped owing to an error"] + #[doc = "sending the notification to it."] + #[doc = ""] + #[doc = "\\[ location, query ID, error \\]"] + NotifyTargetSendFail( + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::primitive::u64, + runtime_types::xcm::v3::traits::Error, + ), + #[codec(index = 15)] + #[doc = "A given location which had a version change subscription was dropped owing to an error"] + #[doc = "migrating the location to our new XCM format."] + #[doc = ""] + #[doc = "\\[ location, query ID \\]"] + NotifyTargetMigrationFail( + runtime_types::xcm::VersionedMultiLocation, + ::core::primitive::u64, + ), + #[codec(index = 16)] + #[doc = "Expected query response has been received but the expected querier location placed in"] + #[doc = "storage by this runtime previously cannot be decoded. The query remains registered."] + #[doc = ""] + #[doc = "This is unexpected (since a location placed in storage in a previously executing"] + #[doc = "runtime should be readable prior to query timeout) and dangerous since the possibly"] + #[doc = "valid response will be dropped. Manual governance intervention is probably going to be"] + #[doc = "needed."] + #[doc = ""] + #[doc = "\\[ origin location, id \\]"] + InvalidQuerierVersion( + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::primitive::u64, + ), + #[codec(index = 17)] + #[doc = "Expected query response has been received but the querier location of the response does"] + #[doc = "not match the expected. The query remains registered for a later, valid, response to"] + #[doc = "be received and acted upon."] + #[doc = ""] + #[doc = "\\[ origin location, id, expected querier, maybe actual querier \\]"] + InvalidQuerier( + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::primitive::u64, + runtime_types::xcm::v3::multilocation::MultiLocation, + ::core::option::Option< + runtime_types::xcm::v3::multilocation::MultiLocation, + >, + ), + #[codec(index = 18)] + #[doc = "A remote has requested XCM version change notification from us and we have honored it."] + #[doc = "A version information message is sent to them and its cost is included."] + #[doc = ""] + #[doc = "\\[ destination location, cost \\]"] + VersionNotifyStarted( + runtime_types::xcm::v3::multilocation::MultiLocation, + runtime_types::xcm::v3::multiasset::MultiAssets, + ), + #[codec(index = 19)] + #[doc = "We have requested that a remote chain sends us XCM version change notifications."] + #[doc = ""] + #[doc = "\\[ destination location, cost \\]"] + VersionNotifyRequested( + runtime_types::xcm::v3::multilocation::MultiLocation, + runtime_types::xcm::v3::multiasset::MultiAssets, + ), + #[codec(index = 20)] + #[doc = "We have requested that a remote chain stops sending us XCM version change notifications."] + #[doc = ""] + #[doc = "\\[ destination location, cost \\]"] + VersionNotifyUnrequested( + runtime_types::xcm::v3::multilocation::MultiLocation, + runtime_types::xcm::v3::multiasset::MultiAssets, + ), + #[codec(index = 21)] + #[doc = "Fees were paid from a location for an operation (often for using `SendXcm`)."] + #[doc = ""] + #[doc = "\\[ paying location, fees \\]"] + FeesPaid( + runtime_types::xcm::v3::multilocation::MultiLocation, + runtime_types::xcm::v3::multiasset::MultiAssets, + ), + #[codec(index = 22)] + #[doc = "Some assets have been claimed from an asset trap"] + #[doc = ""] + #[doc = "\\[ hash, origin, assets \\]"] + AssetsClaimed( + ::subxt::utils::H256, + runtime_types::xcm::v3::multilocation::MultiLocation, + runtime_types::xcm::VersionedMultiAssets, + ), + } + } + } + pub mod polkadot_core_primitives { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct InboundDownwardMessage<_0> { + pub sent_at: _0, + pub msg: ::std::vec::Vec<::core::primitive::u8>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct InboundHrmpMessage<_0> { + pub sent_at: _0, + pub data: ::std::vec::Vec<::core::primitive::u8>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct OutboundHrmpMessage<_0> { + pub recipient: _0, + pub data: ::std::vec::Vec<::core::primitive::u8>, + } + } + pub mod polkadot_parachain { + use super::runtime_types; + pub mod primitives { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct HeadData(pub ::std::vec::Vec<::core::primitive::u8>); + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Id(pub ::core::primitive::u32); + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum XcmpMessageFormat { + #[codec(index = 0)] + ConcatenatedVersionedXcm, + #[codec(index = 1)] + ConcatenatedEncodedBlob, + #[codec(index = 2)] + Signals, + } + } + } + pub mod polkadot_primitives { + use super::runtime_types; + pub mod v4 { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct AbridgedHostConfiguration { + pub max_code_size: ::core::primitive::u32, + pub max_head_data_size: ::core::primitive::u32, + pub max_upward_queue_count: ::core::primitive::u32, + pub max_upward_queue_size: ::core::primitive::u32, + pub max_upward_message_size: ::core::primitive::u32, + pub max_upward_message_num_per_candidate: ::core::primitive::u32, + pub hrmp_max_message_num_per_candidate: ::core::primitive::u32, + pub validation_upgrade_cooldown: ::core::primitive::u32, + pub validation_upgrade_delay: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct AbridgedHrmpChannel { + pub max_capacity: ::core::primitive::u32, + pub max_total_size: ::core::primitive::u32, + pub max_message_size: ::core::primitive::u32, + pub msg_count: ::core::primitive::u32, + pub total_size: ::core::primitive::u32, + pub mqc_head: ::core::option::Option<::subxt::utils::H256>, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct PersistedValidationData<_0, _1> { + pub parent_head: runtime_types::polkadot_parachain::primitives::HeadData, + pub relay_parent_number: _1, + pub relay_parent_storage_root: _0, + pub max_pov_size: _1, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum UpgradeRestriction { + #[codec(index = 0)] + Present, + } + } + } + pub mod rialto_parachain_runtime { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct BridgeRejectObsoleteHeadersAndMessages; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct DummyBridgeRefundMillauMessages; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct Runtime; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum RuntimeCall { + #[codec(index = 0)] + System(runtime_types::frame_system::pallet::Call), + #[codec(index = 1)] + Timestamp(runtime_types::pallet_timestamp::pallet::Call), + #[codec(index = 2)] + Sudo(runtime_types::pallet_sudo::pallet::Call), + #[codec(index = 20)] + ParachainSystem(runtime_types::cumulus_pallet_parachain_system::pallet::Call), + #[codec(index = 30)] + Balances(runtime_types::pallet_balances::pallet::Call), + #[codec(index = 50)] + XcmpQueue(runtime_types::cumulus_pallet_xcmp_queue::pallet::Call), + #[codec(index = 51)] + PolkadotXcm(runtime_types::pallet_xcm::pallet::Call), + #[codec(index = 52)] + CumulusXcm(runtime_types::cumulus_pallet_xcm::pallet::Call), + #[codec(index = 53)] + DmpQueue(runtime_types::cumulus_pallet_dmp_queue::pallet::Call), + #[codec(index = 54)] + BridgeRelayers(runtime_types::pallet_bridge_relayers::pallet::Call), + #[codec(index = 55)] + BridgeMillauGrandpa(runtime_types::pallet_bridge_grandpa::pallet::Call), + #[codec(index = 56)] + BridgeMillauMessages(runtime_types::pallet_bridge_messages::pallet::Call), + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum RuntimeEvent { + #[codec(index = 0)] + System(runtime_types::frame_system::pallet::Event), + #[codec(index = 2)] + Sudo(runtime_types::pallet_sudo::pallet::Event), + #[codec(index = 3)] + TransactionPayment(runtime_types::pallet_transaction_payment::pallet::Event), + #[codec(index = 20)] + ParachainSystem(runtime_types::cumulus_pallet_parachain_system::pallet::Event), + #[codec(index = 30)] + Balances(runtime_types::pallet_balances::pallet::Event), + #[codec(index = 50)] + XcmpQueue(runtime_types::cumulus_pallet_xcmp_queue::pallet::Event), + #[codec(index = 51)] + PolkadotXcm(runtime_types::pallet_xcm::pallet::Event), + #[codec(index = 52)] + CumulusXcm(runtime_types::cumulus_pallet_xcm::pallet::Event), + #[codec(index = 53)] + DmpQueue(runtime_types::cumulus_pallet_dmp_queue::pallet::Event), + #[codec(index = 54)] + BridgeRelayers(runtime_types::pallet_bridge_relayers::pallet::Event), + #[codec(index = 55)] + BridgeMillauGrandpa(runtime_types::pallet_bridge_grandpa::pallet::Event), + #[codec(index = 56)] + BridgeMillauMessages(runtime_types::pallet_bridge_messages::pallet::Event), + } + } + pub mod sp_arithmetic { + use super::runtime_types; + pub mod fixed_point { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: CompactAs, + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct FixedU128(pub ::core::primitive::u128); + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum ArithmeticError { + #[codec(index = 0)] + Underflow, + #[codec(index = 1)] + Overflow, + #[codec(index = 2)] + DivisionByZero, + } + } + pub mod sp_consensus_grandpa { + use super::runtime_types; + pub mod app { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Public(pub runtime_types::sp_core::ed25519::Public); + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Signature(pub runtime_types::sp_core::ed25519::Signature); + } + } + pub mod sp_core { + use super::runtime_types; + pub mod ecdsa { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Signature(pub [::core::primitive::u8; 65usize]); + } + pub mod ed25519 { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Public(pub [::core::primitive::u8; 32usize]); + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Signature(pub [::core::primitive::u8; 64usize]); + } + pub mod sr25519 { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Signature(pub [::core::primitive::u8; 64usize]); + } + } + pub mod sp_runtime { + use super::runtime_types; + pub mod generic { + use super::runtime_types; + pub mod digest { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum DigestItem { + #[codec(index = 6)] + PreRuntime( + [::core::primitive::u8; 4usize], + ::std::vec::Vec<::core::primitive::u8>, + ), + #[codec(index = 4)] + Consensus( + [::core::primitive::u8; 4usize], + ::std::vec::Vec<::core::primitive::u8>, + ), + #[codec(index = 5)] + Seal( + [::core::primitive::u8; 4usize], + ::std::vec::Vec<::core::primitive::u8>, + ), + #[codec(index = 0)] + Other(::std::vec::Vec<::core::primitive::u8>), + #[codec(index = 8)] + RuntimeEnvironmentUpdated, + } + } + pub mod unchecked_extrinsic { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct UncheckedExtrinsic<_0, _1, _2, _3>( + pub ::std::vec::Vec<::core::primitive::u8>, + #[codec(skip)] pub ::core::marker::PhantomData<(_1, _0, _2, _3)>, + ); + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum DispatchError { + #[codec(index = 0)] + Other, + #[codec(index = 1)] + CannotLookup, + #[codec(index = 2)] + BadOrigin, + #[codec(index = 3)] + Module(runtime_types::sp_runtime::ModuleError), + #[codec(index = 4)] + ConsumerRemaining, + #[codec(index = 5)] + NoProviders, + #[codec(index = 6)] + TooManyConsumers, + #[codec(index = 7)] + Token(runtime_types::sp_runtime::TokenError), + #[codec(index = 8)] + Arithmetic(runtime_types::sp_arithmetic::ArithmeticError), + #[codec(index = 9)] + Transactional(runtime_types::sp_runtime::TransactionalError), + #[codec(index = 10)] + Exhausted, + #[codec(index = 11)] + Corruption, + #[codec(index = 12)] + Unavailable, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct ModuleError { + pub index: ::core::primitive::u8, + pub error: [::core::primitive::u8; 4usize], + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum MultiSignature { + #[codec(index = 0)] + Ed25519(runtime_types::sp_core::ed25519::Signature), + #[codec(index = 1)] + Sr25519(runtime_types::sp_core::sr25519::Signature), + #[codec(index = 2)] + Ecdsa(runtime_types::sp_core::ecdsa::Signature), + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum TokenError { + #[codec(index = 0)] + FundsUnavailable, + #[codec(index = 1)] + OnlyProvider, + #[codec(index = 2)] + BelowMinimum, + #[codec(index = 3)] + CannotCreate, + #[codec(index = 4)] + UnknownAsset, + #[codec(index = 5)] + Frozen, + #[codec(index = 6)] + Unsupported, + #[codec(index = 7)] + CannotCreateHold, + #[codec(index = 8)] + NotExpendable, + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum TransactionalError { + #[codec(index = 0)] + LimitReached, + #[codec(index = 1)] + NoLayer, + } + } + pub mod sp_trie { + use super::runtime_types; + pub mod storage_proof { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct StorageProof { + pub trie_nodes: ::std::vec::Vec<::std::vec::Vec<::core::primitive::u8>>, + } + } + } + pub mod sp_version { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct RuntimeVersion { + pub spec_name: ::std::string::String, + pub impl_name: ::std::string::String, + pub authoring_version: ::core::primitive::u32, + pub spec_version: ::core::primitive::u32, + pub impl_version: ::core::primitive::u32, + pub apis: + ::std::vec::Vec<([::core::primitive::u8; 8usize], ::core::primitive::u32)>, + pub transaction_version: ::core::primitive::u32, + pub state_version: ::core::primitive::u8, + } + } + pub mod sp_weights { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub struct RuntimeDbWeight { + pub read: ::core::primitive::u64, + pub write: ::core::primitive::u64, + } + } + pub mod xcm { + use super::runtime_types; + pub mod double_encoded { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct DoubleEncoded { + pub encoded: ::std::vec::Vec<::core::primitive::u8>, + } + } + pub mod v2 { + use super::runtime_types; + pub mod junction { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Junction { + #[codec(index = 0)] + Parachain(#[codec(compact)] ::core::primitive::u32), + #[codec(index = 1)] + AccountId32 { + network: runtime_types::xcm::v2::NetworkId, + id: [::core::primitive::u8; 32usize], + }, + #[codec(index = 2)] + AccountIndex64 { + network: runtime_types::xcm::v2::NetworkId, + #[codec(compact)] + index: ::core::primitive::u64, + }, + #[codec(index = 3)] + AccountKey20 { + network: runtime_types::xcm::v2::NetworkId, + key: [::core::primitive::u8; 20usize], + }, + #[codec(index = 4)] + PalletInstance(::core::primitive::u8), + #[codec(index = 5)] + GeneralIndex(#[codec(compact)] ::core::primitive::u128), + #[codec(index = 6)] + GeneralKey( + runtime_types::bounded_collections::weak_bounded_vec::WeakBoundedVec< + ::core::primitive::u8, + >, + ), + #[codec(index = 7)] + OnlyChild, + #[codec(index = 8)] + Plurality { + id: runtime_types::xcm::v2::BodyId, + part: runtime_types::xcm::v2::BodyPart, + }, + } + } + pub mod multiasset { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum AssetId { + #[codec(index = 0)] + Concrete(runtime_types::xcm::v2::multilocation::MultiLocation), + #[codec(index = 1)] + Abstract(::std::vec::Vec<::core::primitive::u8>), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum AssetInstance { + #[codec(index = 0)] + Undefined, + #[codec(index = 1)] + Index(#[codec(compact)] ::core::primitive::u128), + #[codec(index = 2)] + Array4([::core::primitive::u8; 4usize]), + #[codec(index = 3)] + Array8([::core::primitive::u8; 8usize]), + #[codec(index = 4)] + Array16([::core::primitive::u8; 16usize]), + #[codec(index = 5)] + Array32([::core::primitive::u8; 32usize]), + #[codec(index = 6)] + Blob(::std::vec::Vec<::core::primitive::u8>), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Fungibility { + #[codec(index = 0)] + Fungible(#[codec(compact)] ::core::primitive::u128), + #[codec(index = 1)] + NonFungible(runtime_types::xcm::v2::multiasset::AssetInstance), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct MultiAsset { + pub id: runtime_types::xcm::v2::multiasset::AssetId, + pub fun: runtime_types::xcm::v2::multiasset::Fungibility, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum MultiAssetFilter { + #[codec(index = 0)] + Definite(runtime_types::xcm::v2::multiasset::MultiAssets), + #[codec(index = 1)] + Wild(runtime_types::xcm::v2::multiasset::WildMultiAsset), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct MultiAssets( + pub ::std::vec::Vec, + ); + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum WildFungibility { + #[codec(index = 0)] + Fungible, + #[codec(index = 1)] + NonFungible, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum WildMultiAsset { + #[codec(index = 0)] + All, + #[codec(index = 1)] + AllOf { + id: runtime_types::xcm::v2::multiasset::AssetId, + fun: runtime_types::xcm::v2::multiasset::WildFungibility, + }, + } + } + pub mod multilocation { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Junctions { + #[codec(index = 0)] + Here, + #[codec(index = 1)] + X1(runtime_types::xcm::v2::junction::Junction), + #[codec(index = 2)] + X2( + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + ), + #[codec(index = 3)] + X3( + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + ), + #[codec(index = 4)] + X4( + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + ), + #[codec(index = 5)] + X5( + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + ), + #[codec(index = 6)] + X6( + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + ), + #[codec(index = 7)] + X7( + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + ), + #[codec(index = 8)] + X8( + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + runtime_types::xcm::v2::junction::Junction, + ), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct MultiLocation { + pub parents: ::core::primitive::u8, + pub interior: runtime_types::xcm::v2::multilocation::Junctions, + } + } + pub mod traits { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Error { + #[codec(index = 0)] + Overflow, + #[codec(index = 1)] + Unimplemented, + #[codec(index = 2)] + UntrustedReserveLocation, + #[codec(index = 3)] + UntrustedTeleportLocation, + #[codec(index = 4)] + MultiLocationFull, + #[codec(index = 5)] + MultiLocationNotInvertible, + #[codec(index = 6)] + BadOrigin, + #[codec(index = 7)] + InvalidLocation, + #[codec(index = 8)] + AssetNotFound, + #[codec(index = 9)] + FailedToTransactAsset, + #[codec(index = 10)] + NotWithdrawable, + #[codec(index = 11)] + LocationCannotHold, + #[codec(index = 12)] + ExceedsMaxMessageSize, + #[codec(index = 13)] + DestinationUnsupported, + #[codec(index = 14)] + Transport, + #[codec(index = 15)] + Unroutable, + #[codec(index = 16)] + UnknownClaim, + #[codec(index = 17)] + FailedToDecode, + #[codec(index = 18)] + MaxWeightInvalid, + #[codec(index = 19)] + NotHoldingFees, + #[codec(index = 20)] + TooExpensive, + #[codec(index = 21)] + Trap(::core::primitive::u64), + #[codec(index = 22)] + UnhandledXcmVersion, + #[codec(index = 23)] + WeightLimitReached(::core::primitive::u64), + #[codec(index = 24)] + Barrier, + #[codec(index = 25)] + WeightNotComputable, + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum BodyId { + #[codec(index = 0)] + Unit, + #[codec(index = 1)] + Named( + runtime_types::bounded_collections::weak_bounded_vec::WeakBoundedVec< + ::core::primitive::u8, + >, + ), + #[codec(index = 2)] + Index(#[codec(compact)] ::core::primitive::u32), + #[codec(index = 3)] + Executive, + #[codec(index = 4)] + Technical, + #[codec(index = 5)] + Legislative, + #[codec(index = 6)] + Judicial, + #[codec(index = 7)] + Defense, + #[codec(index = 8)] + Administration, + #[codec(index = 9)] + Treasury, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum BodyPart { + #[codec(index = 0)] + Voice, + #[codec(index = 1)] + Members { + #[codec(compact)] + count: ::core::primitive::u32, + }, + #[codec(index = 2)] + Fraction { + #[codec(compact)] + nom: ::core::primitive::u32, + #[codec(compact)] + denom: ::core::primitive::u32, + }, + #[codec(index = 3)] + AtLeastProportion { + #[codec(compact)] + nom: ::core::primitive::u32, + #[codec(compact)] + denom: ::core::primitive::u32, + }, + #[codec(index = 4)] + MoreThanProportion { + #[codec(compact)] + nom: ::core::primitive::u32, + #[codec(compact)] + denom: ::core::primitive::u32, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Instruction { + #[codec(index = 0)] + WithdrawAsset(runtime_types::xcm::v2::multiasset::MultiAssets), + #[codec(index = 1)] + ReserveAssetDeposited(runtime_types::xcm::v2::multiasset::MultiAssets), + #[codec(index = 2)] + ReceiveTeleportedAsset(runtime_types::xcm::v2::multiasset::MultiAssets), + #[codec(index = 3)] + QueryResponse { + #[codec(compact)] + query_id: ::core::primitive::u64, + response: runtime_types::xcm::v2::Response, + #[codec(compact)] + max_weight: ::core::primitive::u64, + }, + #[codec(index = 4)] + TransferAsset { + assets: runtime_types::xcm::v2::multiasset::MultiAssets, + beneficiary: runtime_types::xcm::v2::multilocation::MultiLocation, + }, + #[codec(index = 5)] + TransferReserveAsset { + assets: runtime_types::xcm::v2::multiasset::MultiAssets, + dest: runtime_types::xcm::v2::multilocation::MultiLocation, + xcm: runtime_types::xcm::v2::Xcm, + }, + #[codec(index = 6)] + Transact { + origin_type: runtime_types::xcm::v2::OriginKind, + #[codec(compact)] + require_weight_at_most: ::core::primitive::u64, + call: runtime_types::xcm::double_encoded::DoubleEncoded, + }, + #[codec(index = 7)] + HrmpNewChannelOpenRequest { + #[codec(compact)] + sender: ::core::primitive::u32, + #[codec(compact)] + max_message_size: ::core::primitive::u32, + #[codec(compact)] + max_capacity: ::core::primitive::u32, + }, + #[codec(index = 8)] + HrmpChannelAccepted { + #[codec(compact)] + recipient: ::core::primitive::u32, + }, + #[codec(index = 9)] + HrmpChannelClosing { + #[codec(compact)] + initiator: ::core::primitive::u32, + #[codec(compact)] + sender: ::core::primitive::u32, + #[codec(compact)] + recipient: ::core::primitive::u32, + }, + #[codec(index = 10)] + ClearOrigin, + #[codec(index = 11)] + DescendOrigin(runtime_types::xcm::v2::multilocation::Junctions), + #[codec(index = 12)] + ReportError { + #[codec(compact)] + query_id: ::core::primitive::u64, + dest: runtime_types::xcm::v2::multilocation::MultiLocation, + #[codec(compact)] + max_response_weight: ::core::primitive::u64, + }, + #[codec(index = 13)] + DepositAsset { + assets: runtime_types::xcm::v2::multiasset::MultiAssetFilter, + #[codec(compact)] + max_assets: ::core::primitive::u32, + beneficiary: runtime_types::xcm::v2::multilocation::MultiLocation, + }, + #[codec(index = 14)] + DepositReserveAsset { + assets: runtime_types::xcm::v2::multiasset::MultiAssetFilter, + #[codec(compact)] + max_assets: ::core::primitive::u32, + dest: runtime_types::xcm::v2::multilocation::MultiLocation, + xcm: runtime_types::xcm::v2::Xcm, + }, + #[codec(index = 15)] + ExchangeAsset { + give: runtime_types::xcm::v2::multiasset::MultiAssetFilter, + receive: runtime_types::xcm::v2::multiasset::MultiAssets, + }, + #[codec(index = 16)] + InitiateReserveWithdraw { + assets: runtime_types::xcm::v2::multiasset::MultiAssetFilter, + reserve: runtime_types::xcm::v2::multilocation::MultiLocation, + xcm: runtime_types::xcm::v2::Xcm, + }, + #[codec(index = 17)] + InitiateTeleport { + assets: runtime_types::xcm::v2::multiasset::MultiAssetFilter, + dest: runtime_types::xcm::v2::multilocation::MultiLocation, + xcm: runtime_types::xcm::v2::Xcm, + }, + #[codec(index = 18)] + QueryHolding { + #[codec(compact)] + query_id: ::core::primitive::u64, + dest: runtime_types::xcm::v2::multilocation::MultiLocation, + assets: runtime_types::xcm::v2::multiasset::MultiAssetFilter, + #[codec(compact)] + max_response_weight: ::core::primitive::u64, + }, + #[codec(index = 19)] + BuyExecution { + fees: runtime_types::xcm::v2::multiasset::MultiAsset, + weight_limit: runtime_types::xcm::v2::WeightLimit, + }, + #[codec(index = 20)] + RefundSurplus, + #[codec(index = 21)] + SetErrorHandler(runtime_types::xcm::v2::Xcm), + #[codec(index = 22)] + SetAppendix(runtime_types::xcm::v2::Xcm), + #[codec(index = 23)] + ClearError, + #[codec(index = 24)] + ClaimAsset { + assets: runtime_types::xcm::v2::multiasset::MultiAssets, + ticket: runtime_types::xcm::v2::multilocation::MultiLocation, + }, + #[codec(index = 25)] + Trap(#[codec(compact)] ::core::primitive::u64), + #[codec(index = 26)] + SubscribeVersion { + #[codec(compact)] + query_id: ::core::primitive::u64, + #[codec(compact)] + max_response_weight: ::core::primitive::u64, + }, + #[codec(index = 27)] + UnsubscribeVersion, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum NetworkId { + #[codec(index = 0)] + Any, + #[codec(index = 1)] + Named( + runtime_types::bounded_collections::weak_bounded_vec::WeakBoundedVec< + ::core::primitive::u8, + >, + ), + #[codec(index = 2)] + Polkadot, + #[codec(index = 3)] + Kusama, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum OriginKind { + #[codec(index = 0)] + Native, + #[codec(index = 1)] + SovereignAccount, + #[codec(index = 2)] + Superuser, + #[codec(index = 3)] + Xcm, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Response { + #[codec(index = 0)] + Null, + #[codec(index = 1)] + Assets(runtime_types::xcm::v2::multiasset::MultiAssets), + #[codec(index = 2)] + ExecutionResult( + ::core::option::Option<( + ::core::primitive::u32, + runtime_types::xcm::v2::traits::Error, + )>, + ), + #[codec(index = 3)] + Version(::core::primitive::u32), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum WeightLimit { + #[codec(index = 0)] + Unlimited, + #[codec(index = 1)] + Limited(#[codec(compact)] ::core::primitive::u64), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Xcm(pub ::std::vec::Vec); + } + pub mod v3 { + use super::runtime_types; + pub mod junction { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum BodyId { + #[codec(index = 0)] + Unit, + #[codec(index = 1)] + Moniker([::core::primitive::u8; 4usize]), + #[codec(index = 2)] + Index(#[codec(compact)] ::core::primitive::u32), + #[codec(index = 3)] + Executive, + #[codec(index = 4)] + Technical, + #[codec(index = 5)] + Legislative, + #[codec(index = 6)] + Judicial, + #[codec(index = 7)] + Defense, + #[codec(index = 8)] + Administration, + #[codec(index = 9)] + Treasury, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum BodyPart { + #[codec(index = 0)] + Voice, + #[codec(index = 1)] + Members { + #[codec(compact)] + count: ::core::primitive::u32, + }, + #[codec(index = 2)] + Fraction { + #[codec(compact)] + nom: ::core::primitive::u32, + #[codec(compact)] + denom: ::core::primitive::u32, + }, + #[codec(index = 3)] + AtLeastProportion { + #[codec(compact)] + nom: ::core::primitive::u32, + #[codec(compact)] + denom: ::core::primitive::u32, + }, + #[codec(index = 4)] + MoreThanProportion { + #[codec(compact)] + nom: ::core::primitive::u32, + #[codec(compact)] + denom: ::core::primitive::u32, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Junction { + #[codec(index = 0)] + Parachain(#[codec(compact)] ::core::primitive::u32), + #[codec(index = 1)] + AccountId32 { + network: + ::core::option::Option, + id: [::core::primitive::u8; 32usize], + }, + #[codec(index = 2)] + AccountIndex64 { + network: + ::core::option::Option, + #[codec(compact)] + index: ::core::primitive::u64, + }, + #[codec(index = 3)] + AccountKey20 { + network: + ::core::option::Option, + key: [::core::primitive::u8; 20usize], + }, + #[codec(index = 4)] + PalletInstance(::core::primitive::u8), + #[codec(index = 5)] + GeneralIndex(#[codec(compact)] ::core::primitive::u128), + #[codec(index = 6)] + GeneralKey { + length: ::core::primitive::u8, + data: [::core::primitive::u8; 32usize], + }, + #[codec(index = 7)] + OnlyChild, + #[codec(index = 8)] + Plurality { + id: runtime_types::xcm::v3::junction::BodyId, + part: runtime_types::xcm::v3::junction::BodyPart, + }, + #[codec(index = 9)] + GlobalConsensus(runtime_types::xcm::v3::junction::NetworkId), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum NetworkId { + #[codec(index = 0)] + ByGenesis([::core::primitive::u8; 32usize]), + #[codec(index = 1)] + ByFork { + block_number: ::core::primitive::u64, + block_hash: [::core::primitive::u8; 32usize], + }, + #[codec(index = 2)] + Polkadot, + #[codec(index = 3)] + Kusama, + #[codec(index = 4)] + Westend, + #[codec(index = 5)] + Rococo, + #[codec(index = 6)] + Wococo, + #[codec(index = 7)] + Ethereum { + #[codec(compact)] + chain_id: ::core::primitive::u64, + }, + #[codec(index = 8)] + BitcoinCore, + #[codec(index = 9)] + BitcoinCash, + } + } + pub mod junctions { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Junctions { + #[codec(index = 0)] + Here, + #[codec(index = 1)] + X1(runtime_types::xcm::v3::junction::Junction), + #[codec(index = 2)] + X2( + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + ), + #[codec(index = 3)] + X3( + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + ), + #[codec(index = 4)] + X4( + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + ), + #[codec(index = 5)] + X5( + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + ), + #[codec(index = 6)] + X6( + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + ), + #[codec(index = 7)] + X7( + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + ), + #[codec(index = 8)] + X8( + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + runtime_types::xcm::v3::junction::Junction, + ), + } + } + pub mod multiasset { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum AssetId { + #[codec(index = 0)] + Concrete(runtime_types::xcm::v3::multilocation::MultiLocation), + #[codec(index = 1)] + Abstract([::core::primitive::u8; 32usize]), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum AssetInstance { + #[codec(index = 0)] + Undefined, + #[codec(index = 1)] + Index(#[codec(compact)] ::core::primitive::u128), + #[codec(index = 2)] + Array4([::core::primitive::u8; 4usize]), + #[codec(index = 3)] + Array8([::core::primitive::u8; 8usize]), + #[codec(index = 4)] + Array16([::core::primitive::u8; 16usize]), + #[codec(index = 5)] + Array32([::core::primitive::u8; 32usize]), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Fungibility { + #[codec(index = 0)] + Fungible(#[codec(compact)] ::core::primitive::u128), + #[codec(index = 1)] + NonFungible(runtime_types::xcm::v3::multiasset::AssetInstance), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct MultiAsset { + pub id: runtime_types::xcm::v3::multiasset::AssetId, + pub fun: runtime_types::xcm::v3::multiasset::Fungibility, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum MultiAssetFilter { + #[codec(index = 0)] + Definite(runtime_types::xcm::v3::multiasset::MultiAssets), + #[codec(index = 1)] + Wild(runtime_types::xcm::v3::multiasset::WildMultiAsset), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct MultiAssets( + pub ::std::vec::Vec, + ); + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum WildFungibility { + #[codec(index = 0)] + Fungible, + #[codec(index = 1)] + NonFungible, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum WildMultiAsset { + #[codec(index = 0)] + All, + #[codec(index = 1)] + AllOf { + id: runtime_types::xcm::v3::multiasset::AssetId, + fun: runtime_types::xcm::v3::multiasset::WildFungibility, + }, + #[codec(index = 2)] + AllCounted(#[codec(compact)] ::core::primitive::u32), + #[codec(index = 3)] + AllOfCounted { + id: runtime_types::xcm::v3::multiasset::AssetId, + fun: runtime_types::xcm::v3::multiasset::WildFungibility, + #[codec(compact)] + count: ::core::primitive::u32, + }, + } + } + pub mod multilocation { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct MultiLocation { + pub parents: ::core::primitive::u8, + pub interior: runtime_types::xcm::v3::junctions::Junctions, + } + } + pub mod traits { + use super::runtime_types; + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Error { + #[codec(index = 0)] + Overflow, + #[codec(index = 1)] + Unimplemented, + #[codec(index = 2)] + UntrustedReserveLocation, + #[codec(index = 3)] + UntrustedTeleportLocation, + #[codec(index = 4)] + LocationFull, + #[codec(index = 5)] + LocationNotInvertible, + #[codec(index = 6)] + BadOrigin, + #[codec(index = 7)] + InvalidLocation, + #[codec(index = 8)] + AssetNotFound, + #[codec(index = 9)] + FailedToTransactAsset, + #[codec(index = 10)] + NotWithdrawable, + #[codec(index = 11)] + LocationCannotHold, + #[codec(index = 12)] + ExceedsMaxMessageSize, + #[codec(index = 13)] + DestinationUnsupported, + #[codec(index = 14)] + Transport, + #[codec(index = 15)] + Unroutable, + #[codec(index = 16)] + UnknownClaim, + #[codec(index = 17)] + FailedToDecode, + #[codec(index = 18)] + MaxWeightInvalid, + #[codec(index = 19)] + NotHoldingFees, + #[codec(index = 20)] + TooExpensive, + #[codec(index = 21)] + Trap(::core::primitive::u64), + #[codec(index = 22)] + ExpectationFalse, + #[codec(index = 23)] + PalletNotFound, + #[codec(index = 24)] + NameMismatch, + #[codec(index = 25)] + VersionIncompatible, + #[codec(index = 26)] + HoldingWouldOverflow, + #[codec(index = 27)] + ExportError, + #[codec(index = 28)] + ReanchorFailed, + #[codec(index = 29)] + NoDeal, + #[codec(index = 30)] + FeesNotMet, + #[codec(index = 31)] + LockError, + #[codec(index = 32)] + NoPermission, + #[codec(index = 33)] + Unanchored, + #[codec(index = 34)] + NotDepositable, + #[codec(index = 35)] + UnhandledXcmVersion, + #[codec(index = 36)] + WeightLimitReached(::sp_weights::Weight), + #[codec(index = 37)] + Barrier, + #[codec(index = 38)] + WeightNotComputable, + #[codec(index = 39)] + ExceedsStackLimit, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Outcome { + #[codec(index = 0)] + Complete(::sp_weights::Weight), + #[codec(index = 1)] + Incomplete(::sp_weights::Weight, runtime_types::xcm::v3::traits::Error), + #[codec(index = 2)] + Error(runtime_types::xcm::v3::traits::Error), + } + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Instruction { + #[codec(index = 0)] + WithdrawAsset(runtime_types::xcm::v3::multiasset::MultiAssets), + #[codec(index = 1)] + ReserveAssetDeposited(runtime_types::xcm::v3::multiasset::MultiAssets), + #[codec(index = 2)] + ReceiveTeleportedAsset(runtime_types::xcm::v3::multiasset::MultiAssets), + #[codec(index = 3)] + QueryResponse { + #[codec(compact)] + query_id: ::core::primitive::u64, + response: runtime_types::xcm::v3::Response, + max_weight: ::sp_weights::Weight, + querier: ::core::option::Option< + runtime_types::xcm::v3::multilocation::MultiLocation, + >, + }, + #[codec(index = 4)] + TransferAsset { + assets: runtime_types::xcm::v3::multiasset::MultiAssets, + beneficiary: runtime_types::xcm::v3::multilocation::MultiLocation, + }, + #[codec(index = 5)] + TransferReserveAsset { + assets: runtime_types::xcm::v3::multiasset::MultiAssets, + dest: runtime_types::xcm::v3::multilocation::MultiLocation, + xcm: runtime_types::xcm::v3::Xcm, + }, + #[codec(index = 6)] + Transact { + origin_kind: runtime_types::xcm::v2::OriginKind, + require_weight_at_most: ::sp_weights::Weight, + call: runtime_types::xcm::double_encoded::DoubleEncoded, + }, + #[codec(index = 7)] + HrmpNewChannelOpenRequest { + #[codec(compact)] + sender: ::core::primitive::u32, + #[codec(compact)] + max_message_size: ::core::primitive::u32, + #[codec(compact)] + max_capacity: ::core::primitive::u32, + }, + #[codec(index = 8)] + HrmpChannelAccepted { + #[codec(compact)] + recipient: ::core::primitive::u32, + }, + #[codec(index = 9)] + HrmpChannelClosing { + #[codec(compact)] + initiator: ::core::primitive::u32, + #[codec(compact)] + sender: ::core::primitive::u32, + #[codec(compact)] + recipient: ::core::primitive::u32, + }, + #[codec(index = 10)] + ClearOrigin, + #[codec(index = 11)] + DescendOrigin(runtime_types::xcm::v3::junctions::Junctions), + #[codec(index = 12)] + ReportError(runtime_types::xcm::v3::QueryResponseInfo), + #[codec(index = 13)] + DepositAsset { + assets: runtime_types::xcm::v3::multiasset::MultiAssetFilter, + beneficiary: runtime_types::xcm::v3::multilocation::MultiLocation, + }, + #[codec(index = 14)] + DepositReserveAsset { + assets: runtime_types::xcm::v3::multiasset::MultiAssetFilter, + dest: runtime_types::xcm::v3::multilocation::MultiLocation, + xcm: runtime_types::xcm::v3::Xcm, + }, + #[codec(index = 15)] + ExchangeAsset { + give: runtime_types::xcm::v3::multiasset::MultiAssetFilter, + want: runtime_types::xcm::v3::multiasset::MultiAssets, + maximal: ::core::primitive::bool, + }, + #[codec(index = 16)] + InitiateReserveWithdraw { + assets: runtime_types::xcm::v3::multiasset::MultiAssetFilter, + reserve: runtime_types::xcm::v3::multilocation::MultiLocation, + xcm: runtime_types::xcm::v3::Xcm, + }, + #[codec(index = 17)] + InitiateTeleport { + assets: runtime_types::xcm::v3::multiasset::MultiAssetFilter, + dest: runtime_types::xcm::v3::multilocation::MultiLocation, + xcm: runtime_types::xcm::v3::Xcm, + }, + #[codec(index = 18)] + ReportHolding { + response_info: runtime_types::xcm::v3::QueryResponseInfo, + assets: runtime_types::xcm::v3::multiasset::MultiAssetFilter, + }, + #[codec(index = 19)] + BuyExecution { + fees: runtime_types::xcm::v3::multiasset::MultiAsset, + weight_limit: runtime_types::xcm::v3::WeightLimit, + }, + #[codec(index = 20)] + RefundSurplus, + #[codec(index = 21)] + SetErrorHandler(runtime_types::xcm::v3::Xcm), + #[codec(index = 22)] + SetAppendix(runtime_types::xcm::v3::Xcm), + #[codec(index = 23)] + ClearError, + #[codec(index = 24)] + ClaimAsset { + assets: runtime_types::xcm::v3::multiasset::MultiAssets, + ticket: runtime_types::xcm::v3::multilocation::MultiLocation, + }, + #[codec(index = 25)] + Trap(#[codec(compact)] ::core::primitive::u64), + #[codec(index = 26)] + SubscribeVersion { + #[codec(compact)] + query_id: ::core::primitive::u64, + max_response_weight: ::sp_weights::Weight, + }, + #[codec(index = 27)] + UnsubscribeVersion, + #[codec(index = 28)] + BurnAsset(runtime_types::xcm::v3::multiasset::MultiAssets), + #[codec(index = 29)] + ExpectAsset(runtime_types::xcm::v3::multiasset::MultiAssets), + #[codec(index = 30)] + ExpectOrigin( + ::core::option::Option< + runtime_types::xcm::v3::multilocation::MultiLocation, + >, + ), + #[codec(index = 31)] + ExpectError( + ::core::option::Option<( + ::core::primitive::u32, + runtime_types::xcm::v3::traits::Error, + )>, + ), + #[codec(index = 32)] + ExpectTransactStatus(runtime_types::xcm::v3::MaybeErrorCode), + #[codec(index = 33)] + QueryPallet { + module_name: ::std::vec::Vec<::core::primitive::u8>, + response_info: runtime_types::xcm::v3::QueryResponseInfo, + }, + #[codec(index = 34)] + ExpectPallet { + #[codec(compact)] + index: ::core::primitive::u32, + name: ::std::vec::Vec<::core::primitive::u8>, + module_name: ::std::vec::Vec<::core::primitive::u8>, + #[codec(compact)] + crate_major: ::core::primitive::u32, + #[codec(compact)] + min_crate_minor: ::core::primitive::u32, + }, + #[codec(index = 35)] + ReportTransactStatus(runtime_types::xcm::v3::QueryResponseInfo), + #[codec(index = 36)] + ClearTransactStatus, + #[codec(index = 37)] + UniversalOrigin(runtime_types::xcm::v3::junction::Junction), + #[codec(index = 38)] + ExportMessage { + network: runtime_types::xcm::v3::junction::NetworkId, + destination: runtime_types::xcm::v3::junctions::Junctions, + xcm: runtime_types::xcm::v3::Xcm, + }, + #[codec(index = 39)] + LockAsset { + asset: runtime_types::xcm::v3::multiasset::MultiAsset, + unlocker: runtime_types::xcm::v3::multilocation::MultiLocation, + }, + #[codec(index = 40)] + UnlockAsset { + asset: runtime_types::xcm::v3::multiasset::MultiAsset, + target: runtime_types::xcm::v3::multilocation::MultiLocation, + }, + #[codec(index = 41)] + NoteUnlockable { + asset: runtime_types::xcm::v3::multiasset::MultiAsset, + owner: runtime_types::xcm::v3::multilocation::MultiLocation, + }, + #[codec(index = 42)] + RequestUnlock { + asset: runtime_types::xcm::v3::multiasset::MultiAsset, + locker: runtime_types::xcm::v3::multilocation::MultiLocation, + }, + #[codec(index = 43)] + SetFeesMode { jit_withdraw: ::core::primitive::bool }, + #[codec(index = 44)] + SetTopic([::core::primitive::u8; 32usize]), + #[codec(index = 45)] + ClearTopic, + #[codec(index = 46)] + AliasOrigin(runtime_types::xcm::v3::multilocation::MultiLocation), + #[codec(index = 47)] + UnpaidExecution { + weight_limit: runtime_types::xcm::v3::WeightLimit, + check_origin: ::core::option::Option< + runtime_types::xcm::v3::multilocation::MultiLocation, + >, + }, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum MaybeErrorCode { + #[codec(index = 0)] + Success, + #[codec(index = 1)] + Error( + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >, + ), + #[codec(index = 2)] + TruncatedError( + runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >, + ), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct PalletInfo { + #[codec(compact)] + pub index: ::core::primitive::u32, + pub name: runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >, + pub module_name: runtime_types::bounded_collections::bounded_vec::BoundedVec< + ::core::primitive::u8, + >, + #[codec(compact)] + pub major: ::core::primitive::u32, + #[codec(compact)] + pub minor: ::core::primitive::u32, + #[codec(compact)] + pub patch: ::core::primitive::u32, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct QueryResponseInfo { + pub destination: runtime_types::xcm::v3::multilocation::MultiLocation, + #[codec(compact)] + pub query_id: ::core::primitive::u64, + pub max_weight: ::sp_weights::Weight, + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum Response { + #[codec(index = 0)] + Null, + #[codec(index = 1)] + Assets(runtime_types::xcm::v3::multiasset::MultiAssets), + #[codec(index = 2)] + ExecutionResult( + ::core::option::Option<( + ::core::primitive::u32, + runtime_types::xcm::v3::traits::Error, + )>, + ), + #[codec(index = 3)] + Version(::core::primitive::u32), + #[codec(index = 4)] + PalletsInfo( + runtime_types::bounded_collections::bounded_vec::BoundedVec< + runtime_types::xcm::v3::PalletInfo, + >, + ), + #[codec(index = 5)] + DispatchResult(runtime_types::xcm::v3::MaybeErrorCode), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub enum WeightLimit { + #[codec(index = 0)] + Unlimited, + #[codec(index = 1)] + Limited(::sp_weights::Weight), + } + #[derive( + :: subxt :: ext :: codec :: Decode, + :: subxt :: ext :: codec :: Encode, + Clone, + Debug, + )] + pub struct Xcm(pub ::std::vec::Vec); + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum VersionedMultiAssets { + #[codec(index = 1)] + V2(runtime_types::xcm::v2::multiasset::MultiAssets), + #[codec(index = 3)] + V3(runtime_types::xcm::v3::multiasset::MultiAssets), + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum VersionedMultiLocation { + #[codec(index = 1)] + V2(runtime_types::xcm::v2::multilocation::MultiLocation), + #[codec(index = 3)] + V3(runtime_types::xcm::v3::multilocation::MultiLocation), + } + #[derive( + :: subxt :: ext :: codec :: Decode, :: subxt :: ext :: codec :: Encode, Clone, Debug, + )] + pub enum VersionedXcm { + #[codec(index = 2)] + V2(runtime_types::xcm::v2::Xcm), + #[codec(index = 3)] + V3(runtime_types::xcm::v3::Xcm), + } + } + } + #[doc = r" The default error type returned when there is a runtime issue,"] + #[doc = r" exposed here for ease of use."] + pub type DispatchError = runtime_types::sp_runtime::DispatchError; + pub fn constants() -> ConstantsApi { + ConstantsApi + } + pub fn storage() -> StorageApi { + StorageApi + } + pub fn tx() -> TransactionApi { + TransactionApi + } + pub struct ConstantsApi; + impl ConstantsApi { + pub fn system(&self) -> system::constants::ConstantsApi { + system::constants::ConstantsApi + } + pub fn timestamp(&self) -> timestamp::constants::ConstantsApi { + timestamp::constants::ConstantsApi + } + pub fn transaction_payment(&self) -> transaction_payment::constants::ConstantsApi { + transaction_payment::constants::ConstantsApi + } + pub fn balances(&self) -> balances::constants::ConstantsApi { + balances::constants::ConstantsApi + } + pub fn bridge_millau_grandpa(&self) -> bridge_millau_grandpa::constants::ConstantsApi { + bridge_millau_grandpa::constants::ConstantsApi + } + pub fn bridge_millau_messages(&self) -> bridge_millau_messages::constants::ConstantsApi { + bridge_millau_messages::constants::ConstantsApi + } + } + pub struct StorageApi; + impl StorageApi { + pub fn system(&self) -> system::storage::StorageApi { + system::storage::StorageApi + } + pub fn timestamp(&self) -> timestamp::storage::StorageApi { + timestamp::storage::StorageApi + } + pub fn sudo(&self) -> sudo::storage::StorageApi { + sudo::storage::StorageApi + } + pub fn transaction_payment(&self) -> transaction_payment::storage::StorageApi { + transaction_payment::storage::StorageApi + } + pub fn parachain_system(&self) -> parachain_system::storage::StorageApi { + parachain_system::storage::StorageApi + } + pub fn parachain_info(&self) -> parachain_info::storage::StorageApi { + parachain_info::storage::StorageApi + } + pub fn balances(&self) -> balances::storage::StorageApi { + balances::storage::StorageApi + } + pub fn xcmp_queue(&self) -> xcmp_queue::storage::StorageApi { + xcmp_queue::storage::StorageApi + } + pub fn dmp_queue(&self) -> dmp_queue::storage::StorageApi { + dmp_queue::storage::StorageApi + } + pub fn bridge_relayers(&self) -> bridge_relayers::storage::StorageApi { + bridge_relayers::storage::StorageApi + } + pub fn bridge_millau_grandpa(&self) -> bridge_millau_grandpa::storage::StorageApi { + bridge_millau_grandpa::storage::StorageApi + } + pub fn bridge_millau_messages(&self) -> bridge_millau_messages::storage::StorageApi { + bridge_millau_messages::storage::StorageApi + } + } + pub struct TransactionApi; + impl TransactionApi { + pub fn system(&self) -> system::calls::TransactionApi { + system::calls::TransactionApi + } + pub fn timestamp(&self) -> timestamp::calls::TransactionApi { + timestamp::calls::TransactionApi + } + pub fn sudo(&self) -> sudo::calls::TransactionApi { + sudo::calls::TransactionApi + } + pub fn parachain_system(&self) -> parachain_system::calls::TransactionApi { + parachain_system::calls::TransactionApi + } + pub fn balances(&self) -> balances::calls::TransactionApi { + balances::calls::TransactionApi + } + pub fn xcmp_queue(&self) -> xcmp_queue::calls::TransactionApi { + xcmp_queue::calls::TransactionApi + } + pub fn polkadot_xcm(&self) -> polkadot_xcm::calls::TransactionApi { + polkadot_xcm::calls::TransactionApi + } + pub fn cumulus_xcm(&self) -> cumulus_xcm::calls::TransactionApi { + cumulus_xcm::calls::TransactionApi + } + pub fn dmp_queue(&self) -> dmp_queue::calls::TransactionApi { + dmp_queue::calls::TransactionApi + } + pub fn bridge_relayers(&self) -> bridge_relayers::calls::TransactionApi { + bridge_relayers::calls::TransactionApi + } + pub fn bridge_millau_grandpa(&self) -> bridge_millau_grandpa::calls::TransactionApi { + bridge_millau_grandpa::calls::TransactionApi + } + pub fn bridge_millau_messages(&self) -> bridge_millau_messages::calls::TransactionApi { + bridge_millau_messages::calls::TransactionApi + } + } + #[doc = r" check whether the Client you are using is aligned with the statically generated codegen."] + pub fn validate_codegen>( + client: &C, + ) -> Result<(), ::subxt::error::MetadataError> { + let runtime_metadata_hash = client.metadata().metadata_hash(&PALLETS); + if runtime_metadata_hash != + [ + 244u8, 26u8, 245u8, 96u8, 241u8, 56u8, 22u8, 163u8, 219u8, 209u8, 103u8, 161u8, + 138u8, 242u8, 33u8, 114u8, 162u8, 107u8, 1u8, 216u8, 115u8, 116u8, 164u8, 126u8, + 81u8, 51u8, 88u8, 36u8, 180u8, 113u8, 18u8, 58u8, + ] { + Err(::subxt::error::MetadataError::IncompatibleMetadata) + } else { + Ok(()) + } + } +} diff --git a/relays/client-rialto-parachain/src/lib.rs b/relays/client-rialto-parachain/src/lib.rs new file mode 100644 index 00000000000..ddb54fbefc0 --- /dev/null +++ b/relays/client-rialto-parachain/src/lib.rs @@ -0,0 +1,138 @@ +// Copyright 2019-2021 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 . + +//! Types used to connect to the Rialto-Substrate chain. + +pub mod codegen_runtime; + +use bp_bridge_hub_cumulus::BridgeHubSignedExtension; +use bp_messages::MessageNonce; +use bp_runtime::ChainId; +use codec::Encode; +use relay_substrate_client::{ + Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions, Error as SubstrateError, + SignParam, UnderlyingChainProvider, UnsignedTransaction, +}; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount, MultiAddress}; +use std::time::Duration; + +pub use codegen_runtime::api::runtime_types; + +pub type RuntimeCall = runtime_types::rialto_parachain_runtime::RuntimeCall; +pub type SudoCall = runtime_types::pallet_sudo::pallet::Call; +pub type BridgeGrandpaCall = runtime_types::pallet_bridge_grandpa::pallet::Call; +pub type BridgeMessagesCall = runtime_types::pallet_bridge_messages::pallet::Call; + +/// The address format for describing accounts. +pub type Address = MultiAddress; + +/// Rialto parachain definition +#[derive(Debug, Clone, Copy)] +pub struct RialtoParachain; + +impl UnderlyingChainProvider for RialtoParachain { + type Chain = bp_rialto_parachain::RialtoParachain; +} + +impl Chain for RialtoParachain { + const ID: ChainId = bp_runtime::RIALTO_PARACHAIN_CHAIN_ID; + const NAME: &'static str = "RialtoParachain"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_rialto_parachain::BEST_FINALIZED_RIALTO_PARACHAIN_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); + + type SignedBlock = bp_polkadot_core::SignedBlock; + type Call = runtime_types::rialto_parachain_runtime::RuntimeCall; +} + +impl ChainWithBalances for RialtoParachain { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + let key = codegen_runtime::api::storage().system().account(account_id); + StorageKey(key.to_bytes()) + } +} + +impl ChainWithMessages for RialtoParachain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_rialto_parachain::WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME; + // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): change the name + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = Some("BridgeRelayers"); + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rialto_parachain::TO_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rialto_parachain::FROM_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_rialto_parachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_rialto_parachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; +} + +impl ChainWithTransactions for RialtoParachain { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = + bp_polkadot_core::UncheckedExtrinsic; + + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { + let raw_payload = SignedPayload::new( + unsigned.call, + bp_rialto_parachain::SignedExtension::from_params( + param.spec_version, + param.transaction_version, + unsigned.era, + param.genesis_hash, + unsigned.nonce, + unsigned.tip, + ), + )?; + + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); + let (call, extra, _) = raw_payload.deconstruct(); + + Ok(Self::SignedTransaction::new_signed( + call, + signer.into_account().into(), + signature.into(), + extra, + )) + } + + fn is_signed(tx: &Self::SignedTransaction) -> bool { + tx.signature.is_some() + } + + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { + tx.signature + .as_ref() + .map(|(address, _, _)| *address == Address::Id(signer.public().into())) + .unwrap_or(false) + } + + fn parse_transaction(tx: Self::SignedTransaction) -> Option> { + let extra = &tx.signature.as_ref()?.2; + Some(UnsignedTransaction::new(tx.function, extra.nonce()).tip(extra.tip())) + } +} + +/// RialtoParachain signing params. +pub type SigningParams = sp_core::sr25519::Pair; + +/// RialtoParachain header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; diff --git a/relays/client-rialto/Cargo.toml b/relays/client-rialto/Cargo.toml new file mode 100644 index 00000000000..c1ae0dfabe7 --- /dev/null +++ b/relays/client-rialto/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "relay-rialto-client" +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" } +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-messages = { path = "../../primitives/messages" } +bp-rialto = { path = "../../primitives/chain-rialto" } +bp-runtime = { path = "../../primitives/runtime" } +rialto-runtime = { path = "../../bin/rialto/runtime" } + +# Substrate Dependencies + +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-rialto/src/lib.rs b/relays/client-rialto/src/lib.rs new file mode 100644 index 00000000000..f8f696068fe --- /dev/null +++ b/relays/client-rialto/src/lib.rs @@ -0,0 +1,184 @@ +// Copyright 2019-2021 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 . + +//! Types used to connect to the Rialto-Substrate chain. + +use bp_messages::MessageNonce; +use bp_runtime::ChainId; +use codec::{Compact, Decode, Encode}; +use relay_substrate_client::{ + BalanceOf, Chain, ChainWithBalances, ChainWithMessages, ChainWithTransactions, + Error as SubstrateError, IndexOf, RelayChain, SignParam, UnderlyingChainProvider, + UnsignedTransaction, +}; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount}; +use std::time::Duration; + +/// Rialto header id. +pub type HeaderId = relay_utils::HeaderId; + +/// Rialto chain definition +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Rialto; + +impl UnderlyingChainProvider for Rialto { + type Chain = bp_rialto::Rialto; +} + +impl Chain for Rialto { + const ID: ChainId = bp_runtime::RIALTO_CHAIN_ID; + const NAME: &'static str = "Rialto"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); + + type SignedBlock = rialto_runtime::SignedBlock; + type Call = rialto_runtime::RuntimeCall; +} + +impl RelayChain for Rialto { + const PARAS_PALLET_NAME: &'static str = bp_rialto::PARAS_PALLET_NAME; + const PARACHAINS_FINALITY_PALLET_NAME: &'static str = + bp_rialto::WITH_RIALTO_BRIDGE_PARAS_PALLET_NAME; +} + +impl ChainWithMessages for Rialto { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME; + // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): change the name + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str> = Some("BridgeRelayers"); + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD; + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rialto::FROM_RIALTO_MESSAGE_DETAILS_METHOD; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; +} + +impl ChainWithBalances for Rialto { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + use frame_support::storage::generator::StorageMap; + StorageKey(frame_system::Account::::storage_map_final_key( + account_id, + )) + } +} + +impl ChainWithTransactions for Rialto { + type AccountKeyPair = sp_core::sr25519::Pair; + type SignedTransaction = rialto_runtime::UncheckedExtrinsic; + + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result { + let raw_payload = SignedPayload::from_raw( + unsigned.call.clone(), + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::::from(unsigned.era.frame_era()), + frame_system::CheckNonce::::from(unsigned.nonce), + frame_system::CheckWeight::::new(), + pallet_transaction_payment::ChargeTransactionPayment::::from(unsigned.tip), + ), + ( + (), + param.spec_version, + param.transaction_version, + param.genesis_hash, + unsigned.era.signed_payload(param.genesis_hash), + (), + (), + (), + ), + ); + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); + let (call, extra, _) = raw_payload.deconstruct(); + + Ok(rialto_runtime::UncheckedExtrinsic::new_signed( + call.into_decoded()?, + signer.into_account().into(), + signature.into(), + extra, + )) + } + + fn is_signed(tx: &Self::SignedTransaction) -> bool { + tx.signature.is_some() + } + + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool { + tx.signature + .as_ref() + .map(|(address, _, _)| *address == rialto_runtime::Address::Id(signer.public().into())) + .unwrap_or(false) + } + + fn parse_transaction(tx: Self::SignedTransaction) -> Option> { + let extra = &tx.signature.as_ref()?.2; + Some( + UnsignedTransaction::new( + tx.function.into(), + Compact::>::decode(&mut &extra.5.encode()[..]).ok()?.into(), + ) + .tip(Compact::>::decode(&mut &extra.7.encode()[..]).ok()?.into()), + ) + } +} + +/// Rialto signing params. +pub type SigningParams = sp_core::sr25519::Pair; + +/// Rialto header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; + +#[cfg(test)] +mod tests { + use super::*; + use relay_substrate_client::TransactionEra; + + #[test] + fn parse_transaction_works() { + let unsigned = UnsignedTransaction { + call: rialto_runtime::RuntimeCall::System(rialto_runtime::SystemCall::remark { + remark: b"Hello world!".to_vec(), + }) + .into(), + nonce: 777, + tip: 888, + era: TransactionEra::immortal(), + }; + let signed_transaction = Rialto::sign_transaction( + SignParam { + spec_version: 42, + transaction_version: 50000, + genesis_hash: [42u8; 32].into(), + signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(), + }, + unsigned.clone(), + ) + .unwrap(); + let parsed_transaction = Rialto::parse_transaction(signed_transaction).unwrap(); + assert_eq!(parsed_transaction, unsigned); + } +} diff --git a/relays/client-rococo/Cargo.toml b/relays/client-rococo/Cargo.toml new file mode 100644 index 00000000000..2a5b556dce2 --- /dev/null +++ b/relays/client-rococo/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "relay-rococo-client" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-rococo = { path = "../../primitives/chain-rococo" } +bp-runtime = { path = "../../primitives/runtime" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-rococo/src/lib.rs b/relays/client-rococo/src/lib.rs new file mode 100644 index 00000000000..ede1bf1ded4 --- /dev/null +++ b/relays/client-rococo/src/lib.rs @@ -0,0 +1,58 @@ +// Copyright 2019-2021 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 . + +//! Types used to connect to the Rococo-Substrate chain. + +use bp_runtime::ChainId; +use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider}; +use sp_core::storage::StorageKey; +use std::time::Duration; + +/// Rococo header id. +pub type HeaderId = relay_utils::HeaderId; + +/// Rococo header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; + +/// Rococo chain definition +#[derive(Debug, Clone, Copy)] +pub struct Rococo; + +impl UnderlyingChainProvider for Rococo { + type Chain = bp_rococo::Rococo; +} + +impl Chain for Rococo { + const ID: ChainId = bp_runtime::ROCOCO_CHAIN_ID; + const NAME: &'static str = "Rococo"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); + + type SignedBlock = bp_rococo::SignedBlock; + type Call = (); +} + +impl ChainWithBalances for Rococo { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + bp_rococo::AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +impl RelayChain for Rococo { + const PARAS_PALLET_NAME: &'static str = bp_rococo::PARAS_PALLET_NAME; + const PARACHAINS_FINALITY_PALLET_NAME: &'static str = "BridgeRococoParachain"; +} diff --git a/relays/client-substrate/Cargo.toml b/relays/client-substrate/Cargo.toml new file mode 100644 index 00000000000..2a79832bf9d --- /dev/null +++ b/relays/client-substrate/Cargo.toml @@ -0,0 +1,55 @@ +[package] +name = "relay-substrate-client" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +async-std = { version = "1.6.5", features = ["attributes"] } +async-trait = "0.1" +codec = { package = "parity-scale-codec", version = "3.1.5" } +futures = "0.3.28" +jsonrpsee = { version = "0.16", features = ["macros", "ws-client"] } +log = "0.4.17" +num-traits = "0.2" +rand = "0.8" +scale-info = { version = "2.5.0", features = ["derive"] } +tokio = { version = "1.27", features = ["rt-multi-thread"] } +thiserror = "1.0.40" + +# Bridge dependencies + +bp-header-chain = { path = "../../primitives/header-chain" } +bp-messages = { path = "../../primitives/messages" } +bp-polkadot-core = { path = "../../primitives/polkadot-core" } +bp-runtime = { path = "../../primitives/runtime" } +pallet-bridge-messages = { path = "../../modules/messages" } +finality-relay = { path = "../finality" } +relay-utils = { path = "../utils" } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-utility = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" } + +# Polkadot Dependencies + +xcm = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false } + +[features] +default = [] +test-helpers = [] diff --git a/relays/client-substrate/src/calls.rs b/relays/client-substrate/src/calls.rs new file mode 100644 index 00000000000..4e0ae9d99d2 --- /dev/null +++ b/relays/client-substrate/src/calls.rs @@ -0,0 +1,59 @@ +// Copyright 2019-2023 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 . + +//! Basic runtime calls. + +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_std::{boxed::Box, vec::Vec}; + +use xcm::{VersionedMultiLocation, VersionedXcm}; + +/// A minimized version of `frame-system::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum SystemCall { + /// `frame-system::Call::remark` + #[codec(index = 1)] + remark(Vec), +} + +/// A minimized version of `pallet-utility::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum UtilityCall { + /// `pallet-utility::Call::batch_all` + #[codec(index = 2)] + batch_all(Vec), +} + +/// A minimized version of `pallet-sudo::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum SudoCall { + /// `pallet-sudo::Call::sudo` + #[codec(index = 0)] + sudo(Box), +} + +/// A minimized version of `pallet-xcm::Call`, that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum XcmCall { + /// `pallet-xcm::Call::send` + #[codec(index = 0)] + send(Box, Box>), +} diff --git a/relays/client-substrate/src/chain.rs b/relays/client-substrate/src/chain.rs new file mode 100644 index 00000000000..8c7dc00aa67 --- /dev/null +++ b/relays/client-substrate/src/chain.rs @@ -0,0 +1,294 @@ +// Copyright 2019-2021 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 . + +use crate::calls::UtilityCall; + +use bp_messages::MessageNonce; +use bp_runtime::{ + Chain as ChainBase, ChainId, EncodedOrDecodedCall, HashOf, Parachain as ParachainBase, + TransactionEra, TransactionEraOf, UnderlyingChainProvider, +}; +use codec::{Codec, Encode}; +use jsonrpsee::core::{DeserializeOwned, Serialize}; +use num_traits::Zero; +use sc_transaction_pool_api::TransactionStatus; +use sp_core::{storage::StorageKey, Pair}; +use sp_runtime::{ + generic::SignedBlock, + traits::{Block as BlockT, Member}, + ConsensusEngineId, EncodedJustification, +}; +use std::{fmt::Debug, time::Duration}; + +/// Substrate-based chain from minimal relay-client point of view. +pub trait Chain: ChainBase + Clone { + /// Chain id. + const ID: ChainId; + /// Chain name. + const NAME: &'static str; + /// Name of the runtime API method that is returning best known finalized header number + /// and hash (as tuple). + /// + /// Keep in mind that this method is normally provided by the other chain, which is + /// bridged with this chain. + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str; + + /// Average block interval. + /// + /// How often blocks are produced on that chain. It's suggested to set this value + /// to match the block time of the chain. + const AVERAGE_BLOCK_INTERVAL: Duration; + + /// Block type. + type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification; + /// The aggregated `Call` type. + type Call: Clone + Codec + Debug + Send; +} + +/// Substrate-based relay chain that supports parachains. +/// +/// We assume that the parachains are supported using `runtime_parachains::paras` pallet. +pub trait RelayChain: Chain { + /// Name of the `runtime_parachains::paras` pallet in the runtime of this chain. + const PARAS_PALLET_NAME: &'static str; + /// Name of the bridge parachains pallet (used in `construct_runtime` macro call) that is + /// deployed at the **bridged** chain. + /// + /// We assume that all chains that are bridging with this `RelayChain` are using + /// the same name. + const PARACHAINS_FINALITY_PALLET_NAME: &'static str; +} + +/// Substrate-based chain that is using direct GRANDPA finality from minimal relay-client point of +/// view. +/// +/// Keep in mind that parachains are relying on relay chain GRANDPA, so they should not implement +/// this trait. +pub trait ChainWithGrandpa: Chain { + /// Name of the bridge GRANDPA pallet (used in `construct_runtime` macro call) that is deployed + /// at some other chain to bridge with this `ChainWithGrandpa`. + /// + /// We assume that all chains that are bridging with this `ChainWithGrandpa` are using + /// the same name. + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str; +} + +impl ChainWithGrandpa for T +where + T: Chain + UnderlyingChainProvider, + T::Chain: bp_header_chain::ChainWithGrandpa, +{ + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = + ::WITH_CHAIN_GRANDPA_PALLET_NAME; +} + +/// Substrate-based parachain from minimal relay-client point of view. +pub trait Parachain: Chain + ParachainBase {} + +impl Parachain for T where T: UnderlyingChainProvider + Chain + ParachainBase {} + +/// Substrate-based chain with messaging support from minimal relay-client point of view. +pub trait ChainWithMessages: Chain { + /// Name of the bridge messages pallet (used in `construct_runtime` macro call) that is deployed + /// at some other chain to bridge with this `ChainWithMessages`. + /// + /// We assume that all chains that are bridging with this `ChainWithMessages` are using + /// the same name. + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str; + + // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): check all the names + // after the issue is fixed - all names must be changed + + /// Name of the bridge relayers pallet (used in `construct_runtime` macro call) that is deployed + /// at some other chain to bridge with this `ChainWithMessages`. + /// + /// We assume that all chains that are bridging with this `ChainWithMessages` are using + /// the same name. + const WITH_CHAIN_RELAYERS_PALLET_NAME: Option<&'static str>; + + /// Name of the `ToOutboundLaneApi::message_details` runtime API method. + /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str; + + /// Name of the `FromInboundLaneApi::message_details` runtime API method. + /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. + const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str; + + /// Maximal number of unrewarded relayers in a single confirmation transaction at this + /// `ChainWithMessages`. + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce; + /// Maximal number of unconfirmed messages in a single confirmation transaction at this + /// `ChainWithMessages`. + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce; +} + +/// Call type used by the chain. +pub type CallOf = ::Call; +/// Transaction status of the chain. +pub type TransactionStatusOf = TransactionStatus, HashOf>; + +/// Substrate-based chain with `AccountData` generic argument of `frame_system::AccountInfo` set to +/// the `pallet_balances::AccountData`. +pub trait ChainWithBalances: Chain { + /// Return runtime storage key for getting `frame_system::AccountInfo` of given account. + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey; +} + +/// SCALE-encoded extrinsic. +pub type EncodedExtrinsic = Vec; + +/// Block with justification. +pub trait BlockWithJustification
{ + /// Return block header. + fn header(&self) -> Header; + /// Return encoded block extrinsics. + fn extrinsics(&self) -> Vec; + /// Return block justification, if known. + fn justification(&self, engine_id: ConsensusEngineId) -> Option<&EncodedJustification>; +} + +/// Transaction before it is signed. +#[derive(Clone, Debug, PartialEq)] +pub struct UnsignedTransaction { + /// Runtime call of this transaction. + pub call: EncodedOrDecodedCall, + /// Transaction nonce. + pub nonce: C::Index, + /// Tip included into transaction. + pub tip: C::Balance, + /// Transaction era used by the chain. + pub era: TransactionEraOf, +} + +impl UnsignedTransaction { + /// Create new unsigned transaction with given call, nonce, era and zero tip. + pub fn new(call: EncodedOrDecodedCall, nonce: C::Index) -> Self { + Self { call, nonce, era: TransactionEra::Immortal, tip: Zero::zero() } + } + + /// Set transaction tip. + #[must_use] + pub fn tip(mut self, tip: C::Balance) -> Self { + self.tip = tip; + self + } + + /// Set transaction era. + #[must_use] + pub fn era(mut self, era: TransactionEraOf) -> Self { + self.era = era; + self + } +} + +/// Account key pair used by transactions signing scheme. +pub type AccountKeyPairOf = ::AccountKeyPair; + +/// Substrate-based chain transactions signing scheme. +pub trait ChainWithTransactions: Chain { + /// Type of key pairs used to sign transactions. + type AccountKeyPair: Pair; + /// Signed transaction. + type SignedTransaction: Clone + Debug + Codec + Send + 'static; + + /// Create transaction for given runtime call, signed by given account. + fn sign_transaction( + param: SignParam, + unsigned: UnsignedTransaction, + ) -> Result + where + Self: Sized; + + /// Returns true if transaction is signed. + fn is_signed(tx: &Self::SignedTransaction) -> bool; + + /// Returns true if transaction is signed by given signer. + fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool; + + /// Parse signed transaction into its unsigned part. + /// + /// Returns `None` if signed transaction has unsupported format. + fn parse_transaction(tx: Self::SignedTransaction) -> Option>; +} + +/// Sign transaction parameters +pub struct SignParam { + /// Version of the runtime specification. + pub spec_version: u32, + /// Transaction version + pub transaction_version: u32, + /// Hash of the genesis block. + pub genesis_hash: HashOf, + /// Signer account + pub signer: AccountKeyPairOf, +} + +impl BlockWithJustification for SignedBlock { + fn header(&self) -> Block::Header { + self.block.header().clone() + } + + fn extrinsics(&self) -> Vec { + self.block.extrinsics().iter().map(Encode::encode).collect() + } + + fn justification(&self, engine_id: ConsensusEngineId) -> Option<&EncodedJustification> { + self.justifications.as_ref().and_then(|j| j.get(engine_id)) + } +} + +/// Trait that provides functionality defined inside `pallet-utility` +pub trait UtilityPallet { + /// Create batch call from given calls vector. + fn build_batch_call(calls: Vec) -> C::Call; +} + +/// Structure that implements `UtilityPalletProvider` based on a full runtime. +pub struct FullRuntimeUtilityPallet { + _phantom: std::marker::PhantomData, +} + +impl UtilityPallet for FullRuntimeUtilityPallet +where + C: Chain, + R: pallet_utility::Config, + ::RuntimeCall: From>, +{ + fn build_batch_call(calls: Vec) -> C::Call { + pallet_utility::Call::batch_all { calls }.into() + } +} + +/// Structure that implements `UtilityPalletProvider` based on a call conversion. +pub struct MockedRuntimeUtilityPallet { + _phantom: std::marker::PhantomData, +} + +impl UtilityPallet for MockedRuntimeUtilityPallet +where + C: Chain, + C::Call: From>, +{ + fn build_batch_call(calls: Vec) -> C::Call { + UtilityCall::batch_all(calls).into() + } +} + +/// Substrate-based chain that uses `pallet-utility`. +pub trait ChainWithUtilityPallet: Chain { + /// The utility pallet provider. + type UtilityPallet: UtilityPallet; +} diff --git a/relays/client-substrate/src/client.rs b/relays/client-substrate/src/client.rs new file mode 100644 index 00000000000..27af7d7d77f --- /dev/null +++ b/relays/client-substrate/src/client.rs @@ -0,0 +1,813 @@ +// Copyright 2019-2021 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 . + +//! Substrate node client. + +use crate::{ + chain::{Chain, ChainWithBalances, ChainWithTransactions}, + rpc::{ + SubstrateAuthorClient, SubstrateChainClient, SubstrateFinalityClient, + SubstrateFrameSystemClient, SubstrateStateClient, SubstrateSystemClient, + }, + transaction_stall_timeout, AccountKeyPairOf, ConnectionParams, Error, HashOf, HeaderIdOf, + Result, SignParam, TransactionTracker, UnsignedTransaction, +}; + +use async_std::sync::{Arc, Mutex, RwLock}; +use async_trait::async_trait; +use bp_runtime::{HeaderIdProvider, StorageDoubleMapKeyProvider, StorageMapKeyProvider}; +use codec::{Decode, Encode}; +use frame_support::weights::Weight; +use frame_system::AccountInfo; +use futures::{SinkExt, StreamExt}; +use jsonrpsee::{ + core::DeserializeOwned, + ws_client::{WsClient as RpcClient, WsClientBuilder as RpcClientBuilder}, +}; +use num_traits::{Saturating, Zero}; +use pallet_balances::AccountData; +use pallet_transaction_payment::RuntimeDispatchInfo; +use relay_utils::{relay_loop::RECONNECT_DELAY, STALL_TIMEOUT}; +use sp_core::{ + storage::{StorageData, StorageKey}, + Bytes, Hasher, Pair, +}; +use sp_runtime::{ + traits::Header as HeaderT, + transaction_validity::{TransactionSource, TransactionValidity}, +}; +use sp_trie::StorageProof; +use sp_version::RuntimeVersion; +use std::future::Future; + +const SUB_API_GRANDPA_AUTHORITIES: &str = "GrandpaApi_grandpa_authorities"; +const SUB_API_TXPOOL_VALIDATE_TRANSACTION: &str = "TaggedTransactionQueue_validate_transaction"; +const SUB_API_TX_PAYMENT_QUERY_INFO: &str = "TransactionPaymentApi_query_info"; +const MAX_SUBSCRIPTION_CAPACITY: usize = 4096; + +/// The difference between best block number and number of its ancestor, that is enough +/// for us to consider that ancestor an "ancient" block with dropped state. +/// +/// The relay does not assume that it is connected to the archive node, so it always tries +/// to use the best available chain state. But sometimes it still may use state of some +/// old block. If the state of that block is already dropped, relay will see errors when +/// e.g. it tries to prove something. +/// +/// By default Substrate-based nodes are storing state for last 256 blocks. We'll use +/// half of this value. +pub const ANCIENT_BLOCK_THRESHOLD: u32 = 128; + +/// Returns `true` if we think that the state is already discarded for given block. +pub fn is_ancient_block + PartialOrd + Saturating>(block: N, best: N) -> bool { + best.saturating_sub(block) >= N::from(ANCIENT_BLOCK_THRESHOLD) +} + +/// Opaque justifications subscription type. +pub struct Subscription(pub(crate) Mutex>>); + +/// Opaque GRANDPA authorities set. +pub type OpaqueGrandpaAuthoritiesSet = Vec; + +/// A simple runtime version. It only includes the `spec_version` and `transaction_version`. +#[derive(Copy, Clone, Debug)] +pub struct SimpleRuntimeVersion { + /// Version of the runtime specification. + pub spec_version: u32, + /// All existing dispatches are fully compatible when this number doesn't change. + pub transaction_version: u32, +} + +impl SimpleRuntimeVersion { + /// Create a new instance of `SimpleRuntimeVersion` from a `RuntimeVersion`. + pub const fn from_runtime_version(runtime_version: &RuntimeVersion) -> Self { + Self { + spec_version: runtime_version.spec_version, + transaction_version: runtime_version.transaction_version, + } + } +} + +/// Chain runtime version in client +#[derive(Clone, Debug)] +pub enum ChainRuntimeVersion { + /// Auto query from chain. + Auto, + /// Custom runtime version, defined by user. + Custom(SimpleRuntimeVersion), +} + +/// Substrate client type. +/// +/// Cloning `Client` is a cheap operation that only clones internal references. Different +/// clones of the same client are guaranteed to use the same references. +pub struct Client { + // Lock order: `submit_signed_extrinsic_lock`, `data` + /// Client connection params. + params: Arc, + /// Saved chain runtime version. + chain_runtime_version: ChainRuntimeVersion, + /// If several tasks are submitting their transactions simultaneously using + /// `submit_signed_extrinsic` method, they may get the same transaction nonce. So one of + /// transactions will be rejected from the pool. This lock is here to prevent situations like + /// that. + submit_signed_extrinsic_lock: Arc>, + /// Genesis block hash. + genesis_hash: HashOf, + /// Shared dynamic data. + data: Arc>, +} + +/// Client data, shared by all `Client` clones. +struct ClientData { + /// Tokio runtime handle. + tokio: Arc, + /// Substrate RPC client. + client: Arc, +} + +#[async_trait] +impl relay_utils::relay_loop::Client for Client { + type Error = Error; + + async fn reconnect(&mut self) -> Result<()> { + let mut data = self.data.write().await; + let (tokio, client) = Self::build_client(&self.params).await?; + data.tokio = tokio; + data.client = client; + Ok(()) + } +} + +impl Clone for Client { + fn clone(&self) -> Self { + Client { + params: self.params.clone(), + chain_runtime_version: self.chain_runtime_version.clone(), + submit_signed_extrinsic_lock: self.submit_signed_extrinsic_lock.clone(), + genesis_hash: self.genesis_hash, + data: self.data.clone(), + } + } +} + +impl std::fmt::Debug for Client { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct("Client").field("genesis_hash", &self.genesis_hash).finish() + } +} + +impl Client { + /// Returns client that is able to call RPCs on Substrate node over websocket connection. + /// + /// This function will keep connecting to given Substrate node until connection is established + /// and is functional. If attempt fail, it will wait for `RECONNECT_DELAY` and retry again. + pub async fn new(params: ConnectionParams) -> Self { + let params = Arc::new(params); + loop { + match Self::try_connect(params.clone()).await { + Ok(client) => return client, + Err(error) => log::error!( + target: "bridge", + "Failed to connect to {} node: {:?}. Going to retry in {}s", + C::NAME, + error, + RECONNECT_DELAY.as_secs(), + ), + } + + async_std::task::sleep(RECONNECT_DELAY).await; + } + } + + /// Try to connect to Substrate node over websocket. Returns Substrate RPC client if connection + /// has been established or error otherwise. + pub async fn try_connect(params: Arc) -> Result { + let (tokio, client) = Self::build_client(¶ms).await?; + + let number: C::BlockNumber = Zero::zero(); + let genesis_hash_client = client.clone(); + let genesis_hash = tokio + .spawn(async move { + SubstrateChainClient::::block_hash(&*genesis_hash_client, Some(number)).await + }) + .await??; + + let chain_runtime_version = params.chain_runtime_version.clone(); + Ok(Self { + params, + chain_runtime_version, + submit_signed_extrinsic_lock: Arc::new(Mutex::new(())), + genesis_hash, + data: Arc::new(RwLock::new(ClientData { tokio, client })), + }) + } + + /// Build client to use in connection. + async fn build_client( + params: &ConnectionParams, + ) -> Result<(Arc, Arc)> { + let tokio = tokio::runtime::Runtime::new()?; + let uri = format!( + "{}://{}:{}", + if params.secure { "wss" } else { "ws" }, + params.host, + params.port, + ); + log::info!(target: "bridge", "Connecting to {} node at {}", C::NAME, uri); + + let client = tokio + .spawn(async move { + RpcClientBuilder::default() + .max_notifs_per_subscription(MAX_SUBSCRIPTION_CAPACITY) + .build(&uri) + .await + }) + .await??; + + Ok((Arc::new(tokio), Arc::new(client))) + } +} + +impl Client { + /// Return simple runtime version, only include `spec_version` and `transaction_version`. + pub async fn simple_runtime_version(&self) -> Result { + Ok(match &self.chain_runtime_version { + ChainRuntimeVersion::Auto => { + let runtime_version = self.runtime_version().await?; + SimpleRuntimeVersion::from_runtime_version(&runtime_version) + }, + ChainRuntimeVersion::Custom(version) => *version, + }) + } + + /// Returns true if client is connected to at least one peer and is in synced state. + pub async fn ensure_synced(&self) -> Result<()> { + self.jsonrpsee_execute(|client| async move { + let health = SubstrateSystemClient::::health(&*client).await?; + let is_synced = !health.is_syncing && (!health.should_have_peers || health.peers > 0); + if is_synced { + Ok(()) + } else { + Err(Error::ClientNotSynced(health)) + } + }) + .await + } + + /// Return hash of the genesis block. + pub fn genesis_hash(&self) -> &C::Hash { + &self.genesis_hash + } + + /// Return hash of the best finalized block. + pub async fn best_finalized_header_hash(&self) -> Result { + self.jsonrpsee_execute(|client| async move { + Ok(SubstrateChainClient::::finalized_head(&*client).await?) + }) + .await + .map_err(|e| Error::FailedToReadBestFinalizedHeaderHash { + chain: C::NAME.into(), + error: e.boxed(), + }) + } + + /// Return number of the best finalized block. + pub async fn best_finalized_header_number(&self) -> Result { + Ok(*self.best_finalized_header().await?.number()) + } + + /// Return header of the best finalized block. + pub async fn best_finalized_header(&self) -> Result { + self.header_by_hash(self.best_finalized_header_hash().await?).await + } + + /// Returns the best Substrate header. + pub async fn best_header(&self) -> Result + where + C::Header: DeserializeOwned, + { + self.jsonrpsee_execute(|client| async move { + Ok(SubstrateChainClient::::header(&*client, None).await?) + }) + .await + .map_err(|e| Error::FailedToReadBestHeader { chain: C::NAME.into(), error: e.boxed() }) + } + + /// Get a Substrate block from its hash. + pub async fn get_block(&self, block_hash: Option) -> Result { + self.jsonrpsee_execute(move |client| async move { + Ok(SubstrateChainClient::::block(&*client, block_hash).await?) + }) + .await + } + + /// Get a Substrate header by its hash. + pub async fn header_by_hash(&self, block_hash: C::Hash) -> Result + where + C::Header: DeserializeOwned, + { + self.jsonrpsee_execute(move |client| async move { + Ok(SubstrateChainClient::::header(&*client, Some(block_hash)).await?) + }) + .await + .map_err(|e| Error::FailedToReadHeaderByHash { + chain: C::NAME.into(), + hash: format!("{block_hash}"), + error: e.boxed(), + }) + } + + /// Get a Substrate block hash by its number. + pub async fn block_hash_by_number(&self, number: C::BlockNumber) -> Result { + self.jsonrpsee_execute(move |client| async move { + Ok(SubstrateChainClient::::block_hash(&*client, Some(number)).await?) + }) + .await + } + + /// Get a Substrate header by its number. + pub async fn header_by_number(&self, block_number: C::BlockNumber) -> Result + where + C::Header: DeserializeOwned, + { + let block_hash = Self::block_hash_by_number(self, block_number).await?; + let header_by_hash = Self::header_by_hash(self, block_hash).await?; + Ok(header_by_hash) + } + + /// Return runtime version. + pub async fn runtime_version(&self) -> Result { + self.jsonrpsee_execute(move |client| async move { + Ok(SubstrateStateClient::::runtime_version(&*client).await?) + }) + .await + } + + /// Read value from runtime storage. + pub async fn storage_value( + &self, + storage_key: StorageKey, + block_hash: Option, + ) -> Result> { + self.raw_storage_value(storage_key, block_hash) + .await? + .map(|encoded_value| { + T::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed) + }) + .transpose() + } + + /// Read `MapStorage` value from runtime storage. + pub async fn storage_map_value( + &self, + pallet_prefix: &str, + key: &T::Key, + block_hash: Option, + ) -> Result> { + let storage_key = T::final_key(pallet_prefix, key); + + self.raw_storage_value(storage_key, block_hash) + .await? + .map(|encoded_value| { + T::Value::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed) + }) + .transpose() + } + + /// Read `DoubleMapStorage` value from runtime storage. + pub async fn storage_double_map_value( + &self, + pallet_prefix: &str, + key1: &T::Key1, + key2: &T::Key2, + block_hash: Option, + ) -> Result> { + let storage_key = T::final_key(pallet_prefix, key1, key2); + + self.raw_storage_value(storage_key, block_hash) + .await? + .map(|encoded_value| { + T::Value::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed) + }) + .transpose() + } + + /// Read raw value from runtime storage. + pub async fn raw_storage_value( + &self, + storage_key: StorageKey, + block_hash: Option, + ) -> Result> { + let cloned_storage_key = storage_key.clone(); + self.jsonrpsee_execute(move |client| async move { + Ok(SubstrateStateClient::::storage(&*client, storage_key.clone(), block_hash) + .await?) + }) + .await + .map_err(|e| Error::FailedToReadRuntimeStorageValue { + chain: C::NAME.into(), + key: cloned_storage_key, + error: e.boxed(), + }) + } + + /// Return native tokens balance of the account. + pub async fn free_native_balance(&self, account: C::AccountId) -> Result + where + C: ChainWithBalances, + { + self.jsonrpsee_execute(move |client| async move { + let storage_key = C::account_info_storage_key(&account); + let encoded_account_data = + SubstrateStateClient::::storage(&*client, storage_key, None) + .await? + .ok_or(Error::AccountDoesNotExist)?; + let decoded_account_data = AccountInfo::>::decode( + &mut &encoded_account_data.0[..], + ) + .map_err(Error::ResponseParseFailed)?; + Ok(decoded_account_data.data.free) + }) + .await + } + + /// Get the nonce of the given Substrate account. + /// + /// Note: It's the caller's responsibility to make sure `account` is a valid SS58 address. + pub async fn next_account_index(&self, account: C::AccountId) -> Result { + self.jsonrpsee_execute(move |client| async move { + Ok(SubstrateFrameSystemClient::::account_next_index(&*client, account).await?) + }) + .await + } + + /// Submit unsigned extrinsic for inclusion in a block. + /// + /// Note: The given transaction needs to be SCALE encoded beforehand. + pub async fn submit_unsigned_extrinsic(&self, transaction: Bytes) -> Result { + self.jsonrpsee_execute(move |client| async move { + let tx_hash = SubstrateAuthorClient::::submit_extrinsic(&*client, transaction) + .await + .map_err(|e| { + log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); + e + })?; + log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); + Ok(tx_hash) + }) + .await + } + + async fn build_sign_params(&self, signer: AccountKeyPairOf) -> Result> + where + C: ChainWithTransactions, + { + let runtime_version = self.simple_runtime_version().await?; + Ok(SignParam:: { + spec_version: runtime_version.spec_version, + transaction_version: runtime_version.transaction_version, + genesis_hash: self.genesis_hash, + signer, + }) + } + + /// Submit an extrinsic signed by given account. + /// + /// All calls of this method are synchronized, so there can't be more than one active + /// `submit_signed_extrinsic()` call. This guarantees that no nonces collision may happen + /// if all client instances are clones of the same initial `Client`. + /// + /// Note: The given transaction needs to be SCALE encoded beforehand. + pub async fn submit_signed_extrinsic( + &self, + signer: &AccountKeyPairOf, + prepare_extrinsic: impl FnOnce(HeaderIdOf, C::Index) -> Result> + + Send + + 'static, + ) -> Result + where + C: ChainWithTransactions, + C::AccountId: From<::Public>, + { + let _guard = self.submit_signed_extrinsic_lock.lock().await; + let transaction_nonce = self.next_account_index(signer.public().into()).await?; + let best_header = self.best_header().await?; + let signing_data = self.build_sign_params(signer.clone()).await?; + + // By using parent of best block here, we are protecing again best-block reorganizations. + // E.g. transaction may have been submitted when the best block was `A[num=100]`. Then it + // has been changed to `B[num=100]`. Hash of `A` has been included into transaction + // signature payload. So when signature will be checked, the check will fail and transaction + // will be dropped from the pool. + let best_header_id = best_header.parent_id().unwrap_or_else(|| best_header.id()); + + self.jsonrpsee_execute(move |client| async move { + let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?; + let signed_extrinsic = C::sign_transaction(signing_data, extrinsic)?.encode(); + let tx_hash = + SubstrateAuthorClient::::submit_extrinsic(&*client, Bytes(signed_extrinsic)) + .await + .map_err(|e| { + log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); + e + })?; + log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); + Ok(tx_hash) + }) + .await + } + + /// Does exactly the same as `submit_signed_extrinsic`, but keeps watching for extrinsic status + /// after submission. + pub async fn submit_and_watch_signed_extrinsic( + &self, + signer: &AccountKeyPairOf, + prepare_extrinsic: impl FnOnce(HeaderIdOf, C::Index) -> Result> + + Send + + 'static, + ) -> Result> + where + C: ChainWithTransactions, + C::AccountId: From<::Public>, + { + let self_clone = self.clone(); + let signing_data = self.build_sign_params(signer.clone()).await?; + let _guard = self.submit_signed_extrinsic_lock.lock().await; + let transaction_nonce = self.next_account_index(signer.public().into()).await?; + let best_header = self.best_header().await?; + let best_header_id = best_header.id(); + let (sender, receiver) = futures::channel::mpsc::channel(MAX_SUBSCRIPTION_CAPACITY); + let (tracker, subscription) = self + .jsonrpsee_execute(move |client| async move { + let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?; + let stall_timeout = transaction_stall_timeout( + extrinsic.era.mortality_period(), + C::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); + let signed_extrinsic = C::sign_transaction(signing_data, extrinsic)?.encode(); + let tx_hash = C::Hasher::hash(&signed_extrinsic); + let subscription = SubstrateAuthorClient::::submit_and_watch_extrinsic( + &*client, + Bytes(signed_extrinsic), + ) + .await + .map_err(|e| { + log::error!(target: "bridge", "Failed to send transaction to {} node: {:?}", C::NAME, e); + e + })?; + log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash); + let tracker = TransactionTracker::new( + self_clone, + stall_timeout, + tx_hash, + Subscription(Mutex::new(receiver)), + ); + Ok((tracker, subscription)) + }) + .await?; + self.data.read().await.tokio.spawn(Subscription::background_worker( + C::NAME.into(), + "extrinsic".into(), + subscription, + sender, + )); + Ok(tracker) + } + + /// Returns pending extrinsics from transaction pool. + pub async fn pending_extrinsics(&self) -> Result> { + self.jsonrpsee_execute(move |client| async move { + Ok(SubstrateAuthorClient::::pending_extrinsics(&*client).await?) + }) + .await + } + + /// Validate transaction at given block state. + pub async fn validate_transaction( + &self, + at_block: C::Hash, + transaction: SignedTransaction, + ) -> Result { + self.jsonrpsee_execute(move |client| async move { + let call = SUB_API_TXPOOL_VALIDATE_TRANSACTION.to_string(); + let data = Bytes((TransactionSource::External, transaction, at_block).encode()); + + let encoded_response = + SubstrateStateClient::::call(&*client, call, data, Some(at_block)).await?; + let validity = TransactionValidity::decode(&mut &encoded_response.0[..]) + .map_err(Error::ResponseParseFailed)?; + + Ok(validity) + }) + .await + } + + /// Returns weight of the given transaction. + pub async fn extimate_extrinsic_weight( + &self, + transaction: SignedTransaction, + ) -> Result { + self.jsonrpsee_execute(move |client| async move { + let transaction_len = transaction.encoded_size() as u32; + + let call = SUB_API_TX_PAYMENT_QUERY_INFO.to_string(); + let data = Bytes((transaction, transaction_len).encode()); + + let encoded_response = + SubstrateStateClient::::call(&*client, call, data, None).await?; + let dispatch_info = + RuntimeDispatchInfo::::decode(&mut &encoded_response.0[..]) + .map_err(Error::ResponseParseFailed)?; + + Ok(dispatch_info.weight) + }) + .await + } + + /// Get the GRANDPA authority set at given block. + pub async fn grandpa_authorities_set( + &self, + block: C::Hash, + ) -> Result { + self.jsonrpsee_execute(move |client| async move { + let call = SUB_API_GRANDPA_AUTHORITIES.to_string(); + let data = Bytes(Vec::new()); + + let encoded_response = + SubstrateStateClient::::call(&*client, call, data, Some(block)).await?; + let authority_list = encoded_response.0; + + Ok(authority_list) + }) + .await + } + + /// Execute runtime call at given block, provided the input and output types. + /// It also performs the input encode and output decode. + pub async fn typed_state_call( + &self, + method_name: String, + input: Input, + at_block: Option, + ) -> Result { + let encoded_output = self + .state_call(method_name.clone(), Bytes(input.encode()), at_block) + .await + .map_err(|e| Error::ErrorExecutingRuntimeCall { + chain: C::NAME.into(), + method: method_name, + error: e.boxed(), + })?; + Output::decode(&mut &encoded_output.0[..]).map_err(Error::ResponseParseFailed) + } + + /// Execute runtime call at given block. + pub async fn state_call( + &self, + method: String, + data: Bytes, + at_block: Option, + ) -> Result { + self.jsonrpsee_execute(move |client| async move { + SubstrateStateClient::::call(&*client, method, data, at_block) + .await + .map_err(Into::into) + }) + .await + } + + /// Returns storage proof of given storage keys. + pub async fn prove_storage( + &self, + keys: Vec, + at_block: C::Hash, + ) -> Result { + self.jsonrpsee_execute(move |client| async move { + SubstrateStateClient::::prove_storage(&*client, keys, Some(at_block)) + .await + .map(|proof| { + StorageProof::new(proof.proof.into_iter().map(|b| b.0).collect::>()) + }) + .map_err(Into::into) + }) + .await + } + + /// Return `tokenDecimals` property from the set of chain properties. + pub async fn token_decimals(&self) -> Result> { + self.jsonrpsee_execute(move |client| async move { + let system_properties = SubstrateSystemClient::::properties(&*client).await?; + Ok(system_properties.get("tokenDecimals").and_then(|v| v.as_u64())) + }) + .await + } + + /// Return new finality justifications stream. + pub async fn subscribe_finality_justifications>( + &self, + ) -> Result> { + let subscription = self + .jsonrpsee_execute(move |client| async move { + Ok(FC::subscribe_justifications(&client).await?) + }) + .await?; + let (sender, receiver) = futures::channel::mpsc::channel(MAX_SUBSCRIPTION_CAPACITY); + self.data.read().await.tokio.spawn(Subscription::background_worker( + C::NAME.into(), + "justification".into(), + subscription, + sender, + )); + Ok(Subscription(Mutex::new(receiver))) + } + + /// Execute jsonrpsee future in tokio context. + async fn jsonrpsee_execute(&self, make_jsonrpsee_future: MF) -> Result + where + MF: FnOnce(Arc) -> F + Send + 'static, + F: Future> + Send + 'static, + T: Send + 'static, + { + let data = self.data.read().await; + let client = data.client.clone(); + data.tokio.spawn(make_jsonrpsee_future(client)).await? + } + + /// Returns `true` if version guard can be started. + /// + /// There's no reason to run version guard when version mode is set to `Auto`. It can + /// lead to relay shutdown when chain is upgraded, even though we have explicitly + /// said that we don't want to shutdown. + pub fn can_start_version_guard(&self) -> bool { + !matches!(self.chain_runtime_version, ChainRuntimeVersion::Auto) + } +} + +impl Subscription { + /// Consumes subscription and returns future statuses stream. + pub fn into_stream(self) -> impl futures::Stream { + futures::stream::unfold(self, |this| async { + let item = this.0.lock().await.next().await.unwrap_or(None); + item.map(|i| (i, this)) + }) + } + + /// Return next item from the subscription. + pub async fn next(&self) -> Result> { + let mut receiver = self.0.lock().await; + let item = receiver.next().await; + Ok(item.unwrap_or(None)) + } + + /// Background worker that is executed in tokio context as `jsonrpsee` requires. + async fn background_worker( + chain_name: String, + item_type: String, + mut subscription: jsonrpsee::core::client::Subscription, + mut sender: futures::channel::mpsc::Sender>, + ) { + loop { + match subscription.next().await { + Some(Ok(item)) => + if sender.send(Some(item)).await.is_err() { + break + }, + Some(Err(e)) => { + log::trace!( + target: "bridge", + "{} {} subscription stream has returned '{:?}'. Stream needs to be restarted.", + chain_name, + item_type, + e, + ); + let _ = sender.send(None).await; + break + }, + None => { + log::trace!( + target: "bridge", + "{} {} subscription stream has returned None. Stream needs to be restarted.", + chain_name, + item_type, + ); + let _ = sender.send(None).await; + break + }, + } + } + } +} diff --git a/relays/client-substrate/src/error.rs b/relays/client-substrate/src/error.rs new file mode 100644 index 00000000000..54247c5dc17 --- /dev/null +++ b/relays/client-substrate/src/error.rs @@ -0,0 +1,155 @@ +// Copyright 2019-2021 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 . + +//! Substrate node RPC errors. + +use bp_polkadot_core::parachains::ParaId; +use jsonrpsee::core::Error as RpcError; +use relay_utils::MaybeConnectionError; +use sc_rpc_api::system::Health; +use sp_core::storage::StorageKey; +use sp_runtime::transaction_validity::TransactionValidityError; +use thiserror::Error; + +/// Result type used by Substrate client. +pub type Result = std::result::Result; + +/// Errors that can occur only when interacting with +/// a Substrate node through RPC. +#[derive(Error, Debug)] +pub enum Error { + /// IO error. + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + /// An error that can occur when making a request to + /// an JSON-RPC server. + #[error("RPC error: {0}")] + RpcError(#[from] RpcError), + /// The response from the server could not be SCALE decoded. + #[error("Response parse failed: {0}")] + ResponseParseFailed(#[from] codec::Error), + /// Account does not exist on the chain. + #[error("Account does not exist on the chain.")] + AccountDoesNotExist, + /// Runtime storage is missing some mandatory value. + #[error("Mandatory storage value is missing from the runtime storage.")] + MissingMandatoryStorageValue, + /// Required parachain head is not present at the relay chain. + #[error("Parachain {0:?} head {1} is missing from the relay chain storage.")] + MissingRequiredParachainHead(ParaId, u64), + /// Failed to find finality proof for the given header. + #[error("Failed to find finality proof for header {0}.")] + FinalityProofNotFound(u64), + /// The client we're connected to is not synced, so we can't rely on its state. + #[error("Substrate client is not synced {0}.")] + ClientNotSynced(Health), + /// Failed to read best finalized header hash from given chain. + #[error("Failed to read best finalized header hash of {chain}: {error:?}.")] + FailedToReadBestFinalizedHeaderHash { + /// Name of the chain where the error has happened. + chain: String, + /// Underlying error. + error: Box, + }, + /// Failed to read best finalized header from given chain. + #[error("Failed to read best header of {chain}: {error:?}.")] + FailedToReadBestHeader { + /// Name of the chain where the error has happened. + chain: String, + /// Underlying error. + error: Box, + }, + /// Failed to read header by hash from given chain. + #[error("Failed to read header {hash} of {chain}: {error:?}.")] + FailedToReadHeaderByHash { + /// Name of the chain where the error has happened. + chain: String, + /// Hash of the header we've tried to read. + hash: String, + /// Underlying error. + error: Box, + }, + /// Failed to execute runtime call at given chain. + #[error("Failed to execute runtime call {method} at {chain}: {error:?}.")] + ErrorExecutingRuntimeCall { + /// Name of the chain where the error has happened. + chain: String, + /// Runtime method name. + method: String, + /// Underlying error. + error: Box, + }, + /// Failed to read sotrage value at given chain. + #[error("Failed to read storage value {key:?} at {chain}: {error:?}.")] + FailedToReadRuntimeStorageValue { + /// Name of the chain where the error has happened. + chain: String, + /// Runtime storage key + key: StorageKey, + /// Underlying error. + error: Box, + }, + /// The bridge pallet is halted and all transactions will be rejected. + #[error("Bridge pallet is halted.")] + BridgePalletIsHalted, + /// The bridge pallet is not yet initialized and all transactions will be rejected. + #[error("Bridge pallet is not initialized.")] + BridgePalletIsNotInitialized, + /// There's no best head of the parachain at the `pallet-bridge-parachains` at the target side. + #[error("No head of the ParaId({0}) at the bridge parachains pallet at {1}.")] + NoParachainHeadAtTarget(u32, String), + /// An error has happened when we have tried to parse storage proof. + #[error("Error when parsing storage proof: {0:?}.")] + StorageProofError(bp_runtime::StorageProofError), + /// The Substrate transaction is invalid. + #[error("Substrate transaction is invalid: {0:?}")] + TransactionInvalid(#[from] TransactionValidityError), + /// Custom logic error. + #[error("{0}")] + Custom(String), +} + +impl From for Error { + fn from(error: tokio::task::JoinError) -> Self { + Error::Custom(format!("Failed to wait tokio task: {error}")) + } +} + +impl Error { + /// Box the error. + pub fn boxed(self) -> Box { + Box::new(self) + } +} + +impl MaybeConnectionError for Error { + fn is_connection_error(&self) -> bool { + match *self { + Error::RpcError(RpcError::Transport(_)) + // right now if connection to the ws server is dropped (after it is already established), + // we're getting this error + | Error::RpcError(RpcError::Internal(_)) + | Error::RpcError(RpcError::RestartNeeded(_)) + | Error::ClientNotSynced(_) => true, + Error::FailedToReadBestFinalizedHeaderHash { ref error, .. } => error.is_connection_error(), + Error::FailedToReadBestHeader { ref error, .. } => error.is_connection_error(), + Error::FailedToReadHeaderByHash { ref error, .. } => error.is_connection_error(), + Error::ErrorExecutingRuntimeCall { ref error, .. } => error.is_connection_error(), + Error::FailedToReadRuntimeStorageValue { ref error, .. } => error.is_connection_error(), + _ => false, + } + } +} diff --git a/relays/client-substrate/src/guard.rs b/relays/client-substrate/src/guard.rs new file mode 100644 index 00000000000..1afbf0d3d17 --- /dev/null +++ b/relays/client-substrate/src/guard.rs @@ -0,0 +1,373 @@ +// Copyright 2019-2021 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 . + +//! Pallet provides a set of guard functions that are running in background threads +//! and are aborting process if some condition fails. + +use crate::{error::Error, Chain, ChainWithBalances, Client}; + +use async_trait::async_trait; +use num_traits::CheckedSub; +use sp_version::RuntimeVersion; +use std::{ + collections::VecDeque, + fmt::Display, + time::{Duration, Instant}, +}; + +/// Guards environment. +#[async_trait] +pub trait Environment: Send + Sync + 'static { + /// Error type. + type Error: Display + Send + Sync + 'static; + + /// Return current runtime version. + async fn runtime_version(&mut self) -> Result; + /// Return free native balance of the account on the chain. + async fn free_native_balance( + &mut self, + account: C::AccountId, + ) -> Result; + + /// Return current time. + fn now(&self) -> Instant { + Instant::now() + } + + /// Sleep given amount of time. + async fn sleep(&mut self, duration: Duration) { + async_std::task::sleep(duration).await + } + + /// Abort current process. Called when guard condition check fails. + async fn abort(&mut self) { + std::process::abort(); + } +} + +/// Abort when runtime spec version is different from specified. +pub fn abort_on_spec_version_change( + mut env: impl Environment, + expected_spec_version: u32, +) { + async_std::task::spawn(async move { + log::info!( + target: "bridge-guard", + "Starting spec_version guard for {}. Expected spec_version: {}", + C::NAME, + expected_spec_version, + ); + + loop { + let actual_spec_version = env.runtime_version().await; + match actual_spec_version { + Ok(version) if version.spec_version == expected_spec_version => (), + Ok(version) => { + log::error!( + target: "bridge-guard", + "{} runtime spec version has changed from {} to {}. Aborting relay", + C::NAME, + expected_spec_version, + version.spec_version, + ); + + env.abort().await; + }, + Err(error) => log::warn!( + target: "bridge-guard", + "Failed to read {} runtime version: {}. Relay may need to be stopped manually", + C::NAME, + error, + ), + } + + env.sleep(conditions_check_delay::()).await; + } + }); +} + +/// Abort if, during 24 hours, free balance of given account is decreased at least by given value. +/// Other components may increase (or decrease) balance of account and it WILL affect logic of the +/// guard. +pub fn abort_when_account_balance_decreased( + mut env: impl Environment, + account_id: C::AccountId, + maximal_decrease: C::Balance, +) { + const DAY: Duration = Duration::from_secs(60 * 60 * 24); + + async_std::task::spawn(async move { + log::info!( + target: "bridge-guard", + "Starting balance guard for {}/{:?}. Maximal decrease: {:?}", + C::NAME, + account_id, + maximal_decrease, + ); + + let mut balances = VecDeque::new(); + + loop { + let current_time = env.now(); + + // remember balances that are beyound 24h border + if let Some(time_border) = current_time.checked_sub(DAY) { + while balances.front().map(|(time, _)| *time < time_border).unwrap_or(false) { + balances.pop_front(); + } + } + + // read balance of the account + let current_balance = env.free_native_balance(account_id.clone()).await; + + // remember balance and check difference + match current_balance { + Ok(current_balance) => { + // remember balance + balances.push_back((current_time, current_balance)); + + // check if difference between current and oldest balance is too large + let (oldest_time, oldest_balance) = + balances.front().expect("pushed to queue couple of lines above; qed"); + let balances_difference = oldest_balance.checked_sub(¤t_balance); + if balances_difference > Some(maximal_decrease) { + log::error!( + target: "bridge-guard", + "Balance of {} account {:?} has decreased from {:?} to {:?} in {} minutes. Aborting relay", + C::NAME, + account_id, + oldest_balance, + current_balance, + current_time.duration_since(*oldest_time).as_secs() / 60, + ); + + env.abort().await; + } + }, + Err(error) => { + log::warn!( + target: "bridge-guard", + "Failed to read {} account {:?} balance: {}. Relay may need to be stopped manually", + C::NAME, + account_id, + error, + ); + }, + }; + + env.sleep(conditions_check_delay::()).await; + } + }); +} + +/// Delay between conditions check. +fn conditions_check_delay() -> Duration { + C::AVERAGE_BLOCK_INTERVAL * (10 + rand::random::() % 10) +} + +#[async_trait] +impl Environment for Client { + type Error = Error; + + async fn runtime_version(&mut self) -> Result { + Client::::runtime_version(self).await + } + + async fn free_native_balance( + &mut self, + account: C::AccountId, + ) -> Result { + Client::::free_native_balance(self, account).await + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_chain::TestChain; + use futures::{ + channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, + future::FutureExt, + stream::StreamExt, + SinkExt, + }; + + struct TestEnvironment { + runtime_version_rx: UnboundedReceiver, + free_native_balance_rx: UnboundedReceiver, + slept_tx: UnboundedSender<()>, + aborted_tx: UnboundedSender<()>, + } + + #[async_trait] + impl Environment for TestEnvironment { + type Error = Error; + + async fn runtime_version(&mut self) -> Result { + Ok(self.runtime_version_rx.next().await.unwrap_or_default()) + } + + async fn free_native_balance(&mut self, _account: u32) -> Result { + Ok(self.free_native_balance_rx.next().await.unwrap_or_default()) + } + + async fn sleep(&mut self, _duration: Duration) { + let _ = self.slept_tx.send(()).await; + } + + async fn abort(&mut self) { + let _ = self.aborted_tx.send(()).await; + // simulate process abort :) + async_std::task::sleep(Duration::from_secs(60)).await; + } + } + + #[test] + fn aborts_when_spec_version_is_changed() { + async_std::task::block_on(async { + let ( + (mut runtime_version_tx, runtime_version_rx), + (_free_native_balance_tx, free_native_balance_rx), + (slept_tx, mut slept_rx), + (aborted_tx, mut aborted_rx), + ) = (unbounded(), unbounded(), unbounded(), unbounded()); + abort_on_spec_version_change( + TestEnvironment { + runtime_version_rx, + free_native_balance_rx, + slept_tx, + aborted_tx, + }, + 0, + ); + + // client responds with wrong version + runtime_version_tx + .send(RuntimeVersion { spec_version: 42, ..Default::default() }) + .await + .unwrap(); + + // then the `abort` function is called + aborted_rx.next().await; + // and we do not reach the `sleep` function call + assert!(slept_rx.next().now_or_never().is_none()); + }); + } + + #[test] + fn does_not_aborts_when_spec_version_is_unchanged() { + async_std::task::block_on(async { + let ( + (mut runtime_version_tx, runtime_version_rx), + (_free_native_balance_tx, free_native_balance_rx), + (slept_tx, mut slept_rx), + (aborted_tx, mut aborted_rx), + ) = (unbounded(), unbounded(), unbounded(), unbounded()); + abort_on_spec_version_change( + TestEnvironment { + runtime_version_rx, + free_native_balance_rx, + slept_tx, + aborted_tx, + }, + 42, + ); + + // client responds with the same version + runtime_version_tx + .send(RuntimeVersion { spec_version: 42, ..Default::default() }) + .await + .unwrap(); + + // then the `sleep` function is called + slept_rx.next().await; + // and the `abort` function is not called + assert!(aborted_rx.next().now_or_never().is_none()); + }); + } + + #[test] + fn aborts_when_balance_is_too_low() { + async_std::task::block_on(async { + let ( + (_runtime_version_tx, runtime_version_rx), + (mut free_native_balance_tx, free_native_balance_rx), + (slept_tx, mut slept_rx), + (aborted_tx, mut aborted_rx), + ) = (unbounded(), unbounded(), unbounded(), unbounded()); + abort_when_account_balance_decreased( + TestEnvironment { + runtime_version_rx, + free_native_balance_rx, + slept_tx, + aborted_tx, + }, + 0, + 100, + ); + + // client responds with initial balance + free_native_balance_tx.send(1000).await.unwrap(); + + // then the guard sleeps + slept_rx.next().await; + + // and then client responds with updated balance, which is too low + free_native_balance_tx.send(899).await.unwrap(); + + // then the `abort` function is called + aborted_rx.next().await; + // and we do not reach next `sleep` function call + assert!(slept_rx.next().now_or_never().is_none()); + }); + } + + #[test] + fn does_not_aborts_when_balance_is_enough() { + async_std::task::block_on(async { + let ( + (_runtime_version_tx, runtime_version_rx), + (mut free_native_balance_tx, free_native_balance_rx), + (slept_tx, mut slept_rx), + (aborted_tx, mut aborted_rx), + ) = (unbounded(), unbounded(), unbounded(), unbounded()); + abort_when_account_balance_decreased( + TestEnvironment { + runtime_version_rx, + free_native_balance_rx, + slept_tx, + aborted_tx, + }, + 0, + 100, + ); + + // client responds with initial balance + free_native_balance_tx.send(1000).await.unwrap(); + + // then the guard sleeps + slept_rx.next().await; + + // and then client responds with updated balance, which is enough + free_native_balance_tx.send(950).await.unwrap(); + + // then the `sleep` function is called + slept_rx.next().await; + // and `abort` is not called + assert!(aborted_rx.next().now_or_never().is_none()); + }); + } +} diff --git a/relays/client-substrate/src/lib.rs b/relays/client-substrate/src/lib.rs new file mode 100644 index 00000000000..c8d8b6f8129 --- /dev/null +++ b/relays/client-substrate/src/lib.rs @@ -0,0 +1,94 @@ +// Copyright 2019-2021 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 . + +//! Tools to interact with Substrate node using RPC methods. + +#![warn(missing_docs)] + +mod chain; +mod client; +mod error; +mod rpc; +mod sync_header; +mod transaction_tracker; + +pub mod calls; +pub mod guard; +pub mod metrics; +pub mod test_chain; + +use std::time::Duration; + +pub use crate::{ + chain::{ + AccountKeyPairOf, BlockWithJustification, CallOf, Chain, ChainWithBalances, + ChainWithGrandpa, ChainWithMessages, ChainWithTransactions, ChainWithUtilityPallet, + FullRuntimeUtilityPallet, MockedRuntimeUtilityPallet, Parachain, RelayChain, SignParam, + TransactionStatusOf, UnsignedTransaction, UtilityPallet, + }, + client::{ + is_ancient_block, ChainRuntimeVersion, Client, OpaqueGrandpaAuthoritiesSet, + SimpleRuntimeVersion, Subscription, ANCIENT_BLOCK_THRESHOLD, + }, + error::{Error, Result}, + rpc::{SubstrateBeefyFinalityClient, SubstrateFinalityClient, SubstrateGrandpaFinalityClient}, + sync_header::SyncHeader, + transaction_tracker::TransactionTracker, +}; +pub use bp_runtime::{ + AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain as ChainBase, HashOf, HeaderIdOf, + HeaderOf, IndexOf, Parachain as ParachainBase, SignatureOf, TransactionEra, TransactionEraOf, + UnderlyingChainProvider, +}; + +/// Substrate-over-websocket connection params. +#[derive(Debug, Clone)] +pub struct ConnectionParams { + /// Websocket server host name. + pub host: String, + /// Websocket server TCP port. + pub port: u16, + /// Use secure websocket connection. + pub secure: bool, + /// Defined chain runtime version + pub chain_runtime_version: ChainRuntimeVersion, +} + +impl Default for ConnectionParams { + fn default() -> Self { + ConnectionParams { + host: "localhost".into(), + port: 9944, + secure: false, + chain_runtime_version: ChainRuntimeVersion::Auto, + } + } +} + +/// Returns stall timeout for relay loop. +/// +/// Relay considers himself stalled if he has submitted transaction to the node, but it has not +/// been mined for this period. +pub fn transaction_stall_timeout( + mortality_period: Option, + average_block_interval: Duration, + default_stall_timeout: Duration, +) -> Duration { + // 1 extra block for transaction to reach the pool && 1 for relayer to awake after it is mined + mortality_period + .map(|mortality_period| average_block_interval.saturating_mul(mortality_period + 1 + 1)) + .unwrap_or(default_stall_timeout) +} diff --git a/relays/client-substrate/src/metrics/float_storage_value.rs b/relays/client-substrate/src/metrics/float_storage_value.rs new file mode 100644 index 00000000000..7bb92693b38 --- /dev/null +++ b/relays/client-substrate/src/metrics/float_storage_value.rs @@ -0,0 +1,133 @@ +// Copyright 2019-2021 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 . + +use crate::{chain::Chain, client::Client, Error as SubstrateError}; + +use async_std::sync::{Arc, RwLock}; +use async_trait::async_trait; +use codec::Decode; +use num_traits::One; +use relay_utils::metrics::{ + metric_name, register, F64SharedRef, Gauge, Metric, PrometheusError, Registry, + StandaloneMetric, F64, +}; +use sp_core::storage::{StorageData, StorageKey}; +use sp_runtime::{traits::UniqueSaturatedInto, FixedPointNumber, FixedU128}; +use std::{marker::PhantomData, time::Duration}; + +/// Storage value update interval (in blocks). +const UPDATE_INTERVAL_IN_BLOCKS: u32 = 5; + +/// Fied-point storage value and the way it is decoded from the raw storage value. +pub trait FloatStorageValue: 'static + Clone + Send + Sync { + /// Type of the value. + type Value: FixedPointNumber; + /// Try to decode value from the raw storage value. + fn decode( + &self, + maybe_raw_value: Option, + ) -> Result, SubstrateError>; +} + +/// Implementation of `FloatStorageValue` that expects encoded `FixedU128` value and returns `1` if +/// value is missing from the storage. +#[derive(Clone, Debug, Default)] +pub struct FixedU128OrOne; + +impl FloatStorageValue for FixedU128OrOne { + type Value = FixedU128; + + fn decode( + &self, + maybe_raw_value: Option, + ) -> Result, SubstrateError> { + maybe_raw_value + .map(|raw_value| { + FixedU128::decode(&mut &raw_value.0[..]) + .map_err(SubstrateError::ResponseParseFailed) + .map(Some) + }) + .unwrap_or_else(|| Ok(Some(FixedU128::one()))) + } +} + +/// Metric that represents fixed-point runtime storage value as float gauge. +#[derive(Clone, Debug)] +pub struct FloatStorageValueMetric { + value_converter: V, + client: Client, + storage_key: StorageKey, + metric: Gauge, + shared_value_ref: F64SharedRef, + _phantom: PhantomData, +} + +impl FloatStorageValueMetric { + /// Create new metric. + pub fn new( + value_converter: V, + client: Client, + storage_key: StorageKey, + name: String, + help: String, + ) -> Result { + let shared_value_ref = Arc::new(RwLock::new(None)); + Ok(FloatStorageValueMetric { + value_converter, + client, + storage_key, + metric: Gauge::new(metric_name(None, &name), help)?, + shared_value_ref, + _phantom: Default::default(), + }) + } + + /// Get shared reference to metric value. + pub fn shared_value_ref(&self) -> F64SharedRef { + self.shared_value_ref.clone() + } +} + +impl Metric for FloatStorageValueMetric { + fn register(&self, registry: &Registry) -> Result<(), PrometheusError> { + register(self.metric.clone(), registry).map(drop) + } +} + +#[async_trait] +impl StandaloneMetric for FloatStorageValueMetric { + fn update_interval(&self) -> Duration { + C::AVERAGE_BLOCK_INTERVAL * UPDATE_INTERVAL_IN_BLOCKS + } + + async fn update(&self) { + let value = self + .client + .raw_storage_value(self.storage_key.clone(), None) + .await + .and_then(|maybe_storage_value| { + self.value_converter.decode(maybe_storage_value).map(|maybe_fixed_point_value| { + maybe_fixed_point_value.map(|fixed_point_value| { + fixed_point_value.into_inner().unique_saturated_into() as f64 / + V::Value::DIV.unique_saturated_into() as f64 + }) + }) + }) + .map_err(|e| e.to_string()); + relay_utils::metrics::set_gauge_value(&self.metric, value.clone()); + *self.shared_value_ref.write().await = value.ok().and_then(|x| x); + } +} diff --git a/relays/client-substrate/src/metrics/mod.rs b/relays/client-substrate/src/metrics/mod.rs new file mode 100644 index 00000000000..fe200e2d3dc --- /dev/null +++ b/relays/client-substrate/src/metrics/mod.rs @@ -0,0 +1,21 @@ +// Copyright 2019-2020 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 . + +//! Contains several Substrate-specific metrics that may be exposed by relay. + +pub use float_storage_value::{FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric}; + +mod float_storage_value; diff --git a/relays/client-substrate/src/rpc.rs b/relays/client-substrate/src/rpc.rs new file mode 100644 index 00000000000..083b1dea761 --- /dev/null +++ b/relays/client-substrate/src/rpc.rs @@ -0,0 +1,170 @@ +// Copyright 2019-2021 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 . + +//! The most generic Substrate node RPC interface. + +use async_trait::async_trait; + +use crate::{Chain, ChainWithGrandpa, TransactionStatusOf}; + +use jsonrpsee::{ + core::{client::Subscription, RpcResult}, + proc_macros::rpc, + ws_client::WsClient, +}; +use pallet_transaction_payment_rpc_runtime_api::FeeDetails; +use sc_rpc_api::{state::ReadProof, system::Health}; +use sp_core::{ + storage::{StorageData, StorageKey}, + Bytes, +}; +use sp_rpc::number::NumberOrHex; +use sp_version::RuntimeVersion; + +/// RPC methods of Substrate `system` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "system")] +pub(crate) trait SubstrateSystem { + /// Return node health. + #[method(name = "health")] + async fn health(&self) -> RpcResult; + /// Return system properties. + #[method(name = "properties")] + async fn properties(&self) -> RpcResult; +} + +/// RPC methods of Substrate `chain` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "chain")] +pub(crate) trait SubstrateChain { + /// Get block hash by its number. + #[method(name = "getBlockHash")] + async fn block_hash(&self, block_number: Option) -> RpcResult; + /// Return block header by its hash. + #[method(name = "getHeader")] + async fn header(&self, block_hash: Option) -> RpcResult; + /// Return best finalized block hash. + #[method(name = "getFinalizedHead")] + async fn finalized_head(&self) -> RpcResult; + /// Return signed block (with justifications) by its hash. + #[method(name = "getBlock")] + async fn block(&self, block_hash: Option) -> RpcResult; +} + +/// RPC methods of Substrate `author` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "author")] +pub(crate) trait SubstrateAuthor { + /// Submit extrinsic to the transaction pool. + #[method(name = "submitExtrinsic")] + async fn submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult; + /// Return vector of pending extrinsics from the transaction pool. + #[method(name = "pendingExtrinsics")] + async fn pending_extrinsics(&self) -> RpcResult>; + /// Submit and watch for extrinsic state. + #[subscription(name = "submitAndWatchExtrinsic", unsubscribe = "unwatchExtrinsic", item = TransactionStatusOf)] + fn submit_and_watch_extrinsic(&self, extrinsic: Bytes); +} + +/// RPC methods of Substrate `state` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "state")] +pub(crate) trait SubstrateState { + /// Get current runtime version. + #[method(name = "getRuntimeVersion")] + async fn runtime_version(&self) -> RpcResult; + /// Call given runtime method. + #[method(name = "call")] + async fn call( + &self, + method: String, + data: Bytes, + at_block: Option, + ) -> RpcResult; + /// Get value of the runtime storage. + #[method(name = "getStorage")] + async fn storage( + &self, + key: StorageKey, + at_block: Option, + ) -> RpcResult>; + /// Get proof of the runtime storage value. + #[method(name = "getReadProof")] + async fn prove_storage( + &self, + keys: Vec, + hash: Option, + ) -> RpcResult>; +} + +/// RPC methods that we are using for a certain finality gadget. +#[async_trait] +pub trait SubstrateFinalityClient { + /// Subscribe to finality justifications. + async fn subscribe_justifications(client: &WsClient) -> RpcResult>; +} + +/// RPC methods of Substrate `grandpa` namespace, that we are using. +#[rpc(client, client_bounds(C: ChainWithGrandpa), namespace = "grandpa")] +pub(crate) trait SubstrateGrandpa { + /// Subscribe to GRANDPA justifications. + #[subscription(name = "subscribeJustifications", unsubscribe = "unsubscribeJustifications", item = Bytes)] + fn subscribe_justifications(&self); +} + +/// RPC finality methods of Substrate `grandpa` namespace, that we are using. +pub struct SubstrateGrandpaFinalityClient; +#[async_trait] +impl SubstrateFinalityClient for SubstrateGrandpaFinalityClient { + async fn subscribe_justifications(client: &WsClient) -> RpcResult> { + SubstrateGrandpaClient::::subscribe_justifications(client).await + } +} + +// TODO: Use `ChainWithBeefy` instead of `Chain` after #1606 is merged +/// RPC methods of Substrate `beefy` namespace, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "beefy")] +pub(crate) trait SubstrateBeefy { + /// Subscribe to BEEFY justifications. + #[subscription(name = "subscribeJustifications", unsubscribe = "unsubscribeJustifications", item = Bytes)] + fn subscribe_justifications(&self); +} + +/// RPC finality methods of Substrate `beefy` namespace, that we are using. +pub struct SubstrateBeefyFinalityClient; +// TODO: Use `ChainWithBeefy` instead of `Chain` after #1606 is merged +#[async_trait] +impl SubstrateFinalityClient for SubstrateBeefyFinalityClient { + async fn subscribe_justifications(client: &WsClient) -> RpcResult> { + SubstrateBeefyClient::::subscribe_justifications(client).await + } +} + +/// RPC methods of Substrate `system` frame pallet, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "system")] +pub(crate) trait SubstrateFrameSystem { + /// Return index of next account transaction. + #[method(name = "accountNextIndex")] + async fn account_next_index(&self, account_id: C::AccountId) -> RpcResult; +} + +/// RPC methods of Substrate `pallet_transaction_payment` frame pallet, that we are using. +#[rpc(client, client_bounds(C: Chain), namespace = "payment")] +pub(crate) trait SubstrateTransactionPayment { + /// Query transaction fee details. + #[method(name = "queryFeeDetails")] + async fn fee_details( + &self, + extrinsic: Bytes, + at_block: Option, + ) -> RpcResult>; +} diff --git a/relays/client-substrate/src/sync_header.rs b/relays/client-substrate/src/sync_header.rs new file mode 100644 index 00000000000..fdfd1f22ce9 --- /dev/null +++ b/relays/client-substrate/src/sync_header.rs @@ -0,0 +1,61 @@ +// Copyright 2019-2021 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 . + +use bp_header_chain::ConsensusLogReader; +use finality_relay::SourceHeader as FinalitySourceHeader; +use sp_runtime::traits::Header as HeaderT; + +/// Generic wrapper for `sp_runtime::traits::Header` based headers, that +/// implements `finality_relay::SourceHeader` and may be used in headers sync directly. +#[derive(Clone, Debug, PartialEq)] +pub struct SyncHeader
(Header); + +impl
SyncHeader
{ + /// Extracts wrapped header from self. + pub fn into_inner(self) -> Header { + self.0 + } +} + +impl
std::ops::Deref for SyncHeader
{ + type Target = Header; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl
From
for SyncHeader
{ + fn from(header: Header) -> Self { + Self(header) + } +} + +impl FinalitySourceHeader + for SyncHeader
+{ + fn hash(&self) -> Header::Hash { + self.0.hash() + } + + fn number(&self) -> Header::Number { + *self.0.number() + } + + fn is_mandatory(&self) -> bool { + R::schedules_authorities_change(self.digest()) + } +} diff --git a/relays/client-substrate/src/test_chain.rs b/relays/client-substrate/src/test_chain.rs new file mode 100644 index 00000000000..64c7590ee52 --- /dev/null +++ b/relays/client-substrate/src/test_chain.rs @@ -0,0 +1,117 @@ +// Copyright 2019-2021 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 . + +//! Pallet provides a set of guard functions that are running in background threads +//! and are aborting process if some condition fails. + +//! Test chain implementation to use in tests. + +#![cfg(any(feature = "test-helpers", test))] + +use crate::{Chain, ChainWithBalances}; +use bp_runtime::ChainId; +use frame_support::weights::Weight; +use std::time::Duration; + +/// Chain that may be used in tests. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TestChain; + +impl bp_runtime::Chain for TestChain { + type BlockNumber = u32; + type Hash = sp_core::H256; + type Hasher = sp_runtime::traits::BlakeTwo256; + type Header = sp_runtime::generic::Header; + + type AccountId = u32; + type Balance = u32; + type Index = u32; + type Signature = sp_runtime::testing::TestSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +impl Chain for TestChain { + const ID: ChainId = *b"test"; + const NAME: &'static str = "Test"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestMethod"; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0); + + type SignedBlock = sp_runtime::generic::SignedBlock< + sp_runtime::generic::Block, + >; + type Call = (); +} + +impl ChainWithBalances for TestChain { + fn account_info_storage_key(_account_id: &u32) -> sp_core::storage::StorageKey { + unreachable!() + } +} + +/// Primitives-level parachain that may be used in tests. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TestParachainBase; + +impl bp_runtime::Chain for TestParachainBase { + type BlockNumber = u32; + type Hash = sp_core::H256; + type Hasher = sp_runtime::traits::BlakeTwo256; + type Header = sp_runtime::generic::Header; + + type AccountId = u32; + type Balance = u32; + type Index = u32; + type Signature = sp_runtime::testing::TestSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + + fn max_extrinsic_weight() -> Weight { + unreachable!() + } +} + +impl bp_runtime::Parachain for TestParachainBase { + const PARACHAIN_ID: u32 = 1000; +} + +/// Parachain that may be used in tests. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TestParachain; + +impl bp_runtime::UnderlyingChainProvider for TestParachain { + type Chain = TestParachainBase; +} + +impl Chain for TestParachain { + const ID: ChainId = *b"test"; + const NAME: &'static str = "TestParachain"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestParachainMethod"; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0); + + type SignedBlock = sp_runtime::generic::SignedBlock< + sp_runtime::generic::Block, + >; + type Call = (); +} diff --git a/relays/client-substrate/src/transaction_tracker.rs b/relays/client-substrate/src/transaction_tracker.rs new file mode 100644 index 00000000000..211f7faab0e --- /dev/null +++ b/relays/client-substrate/src/transaction_tracker.rs @@ -0,0 +1,447 @@ +// Copyright 2019-2021 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 . + +//! Helper for tracking transaction invalidation events. + +use crate::{Chain, Client, Error, HashOf, HeaderIdOf, Subscription, TransactionStatusOf}; + +use async_trait::async_trait; +use futures::{future::Either, Future, FutureExt, Stream, StreamExt}; +use relay_utils::{HeaderId, TrackedTransactionStatus}; +use sp_runtime::traits::Header as _; +use std::time::Duration; + +/// Transaction tracker environment. +#[async_trait] +pub trait Environment: Send + Sync { + /// Returns header id by its hash. + async fn header_id_by_hash(&self, hash: HashOf) -> Result, Error>; +} + +#[async_trait] +impl Environment for Client { + async fn header_id_by_hash(&self, hash: HashOf) -> Result, Error> { + self.header_by_hash(hash).await.map(|h| HeaderId(*h.number(), hash)) + } +} + +/// Substrate transaction tracker implementation. +/// +/// Substrate node provides RPC API to submit and watch for transaction events. This way +/// we may know when transaction is included into block, finalized or rejected. There are +/// some edge cases, when we can't fully trust this mechanism - e.g. transaction may broadcasted +/// and then dropped out of node transaction pool (some other cases are also possible - node +/// restarts, connection lost, ...). Then we can't know for sure - what is currently happening +/// with our transaction. Is the transaction really lost? Is it still alive on the chain network? +/// +/// We have several options to handle such cases: +/// +/// 1) hope that the transaction is still alive and wait for its mining until it is spoiled; +/// +/// 2) assume that the transaction is lost and resubmit another transaction instantly; +/// +/// 3) wait for some time (if transaction is mortal - then until block where it dies; if it is +/// immortal - then for some time that we assume is long enough to mine it) and assume that +/// it is lost. +/// +/// This struct implements third option as it seems to be the most optimal. +pub struct TransactionTracker { + environment: E, + transaction_hash: HashOf, + stall_timeout: Duration, + subscription: Subscription>, +} + +impl> TransactionTracker { + /// Create transaction tracker. + pub fn new( + environment: E, + stall_timeout: Duration, + transaction_hash: HashOf, + subscription: Subscription>, + ) -> Self { + Self { environment, stall_timeout, transaction_hash, subscription } + } + + /// Wait for final transaction status and return it along with last known internal invalidation + /// status. + async fn do_wait( + self, + wait_for_stall_timeout: impl Future, + wait_for_stall_timeout_rest: impl Future, + ) -> (TrackedTransactionStatus>, Option>>) { + // sometimes we want to wait for the rest of the stall timeout even if + // `wait_for_invalidation` has been "select"ed first => it is shared + let wait_for_invalidation = watch_transaction_status::<_, C, _>( + self.environment, + self.transaction_hash, + self.subscription.into_stream(), + ); + futures::pin_mut!(wait_for_stall_timeout, wait_for_invalidation); + + match futures::future::select(wait_for_stall_timeout, wait_for_invalidation).await { + Either::Left((_, _)) => { + log::trace!( + target: "bridge", + "{} transaction {:?} is considered lost after timeout (no status response from the node)", + C::NAME, + self.transaction_hash, + ); + + (TrackedTransactionStatus::Lost, None) + }, + Either::Right((invalidation_status, _)) => match invalidation_status { + InvalidationStatus::Finalized(at_block) => + (TrackedTransactionStatus::Finalized(at_block), Some(invalidation_status)), + InvalidationStatus::Invalid => + (TrackedTransactionStatus::Lost, Some(invalidation_status)), + InvalidationStatus::Lost => { + // wait for the rest of stall timeout - this way we'll be sure that the + // transaction is actually dead if it has been crafted properly + wait_for_stall_timeout_rest.await; + // if someone is still watching for our transaction, then we're reporting + // an error here (which is treated as "transaction lost") + log::trace!( + target: "bridge", + "{} transaction {:?} is considered lost after timeout", + C::NAME, + self.transaction_hash, + ); + + (TrackedTransactionStatus::Lost, Some(invalidation_status)) + }, + }, + } + } +} + +#[async_trait] +impl> relay_utils::TransactionTracker for TransactionTracker { + type HeaderId = HeaderIdOf; + + async fn wait(self) -> TrackedTransactionStatus> { + let wait_for_stall_timeout = async_std::task::sleep(self.stall_timeout).shared(); + let wait_for_stall_timeout_rest = wait_for_stall_timeout.clone(); + self.do_wait(wait_for_stall_timeout, wait_for_stall_timeout_rest).await.0 + } +} + +/// Transaction invalidation status. +/// +/// Note that in places where the `TransactionTracker` is used, the finalization event will be +/// ignored - relay loops are detecting the mining/finalization using their own +/// techniques. That's why we're using `InvalidationStatus` here. +#[derive(Debug, PartialEq)] +enum InvalidationStatus { + /// Transaction has been included into block and finalized at given block. + Finalized(BlockId), + /// Transaction has been invalidated. + Invalid, + /// We have lost track of transaction status. + Lost, +} + +/// Watch for transaction status until transaction is finalized or we lose track of its status. +async fn watch_transaction_status< + E: Environment, + C: Chain, + S: Stream>, +>( + environment: E, + transaction_hash: HashOf, + subscription: S, +) -> InvalidationStatus> { + futures::pin_mut!(subscription); + + loop { + match subscription.next().await { + Some(TransactionStatusOf::::Finalized((block_hash, _))) => { + // the only "successful" outcome of this method is when the block with transaction + // has been finalized + log::trace!( + target: "bridge", + "{} transaction {:?} has been finalized at block: {:?}", + C::NAME, + transaction_hash, + block_hash, + ); + + let header_id = match environment.header_id_by_hash(block_hash).await { + Ok(header_id) => header_id, + Err(e) => { + log::error!( + target: "bridge", + "Failed to read header {:?} when watching for {} transaction {:?}: {:?}", + block_hash, + C::NAME, + transaction_hash, + e, + ); + // that's the best option we have here + return InvalidationStatus::Lost + }, + }; + return InvalidationStatus::Finalized(header_id) + }, + Some(TransactionStatusOf::::Invalid) => { + // if node says that the transaction is invalid, there are still chances that + // it is not actually invalid - e.g. if the block where transaction has been + // revalidated is retracted and transaction (at some other node pool) becomes + // valid again on other fork. But let's assume that the chances of this event + // are almost zero - there's a lot of things that must happen for this to be the + // case. + log::trace!( + target: "bridge", + "{} transaction {:?} has been invalidated", + C::NAME, + transaction_hash, + ); + return InvalidationStatus::Invalid + }, + Some(TransactionStatusOf::::Future) | + Some(TransactionStatusOf::::Ready) | + Some(TransactionStatusOf::::Broadcast(_)) => { + // nothing important (for us) has happened + }, + Some(TransactionStatusOf::::InBlock(block_hash)) => { + // TODO: read matching system event (ExtrinsicSuccess or ExtrinsicFailed), log it + // here and use it later (on finality) for reporting invalid transaction + // https://github.com/paritytech/parity-bridges-common/issues/1464 + log::trace!( + target: "bridge", + "{} transaction {:?} has been included in block: {:?}", + C::NAME, + transaction_hash, + block_hash, + ); + }, + Some(TransactionStatusOf::::Retracted(block_hash)) => { + log::trace!( + target: "bridge", + "{} transaction {:?} at block {:?} has been retracted", + C::NAME, + transaction_hash, + block_hash, + ); + }, + Some(TransactionStatusOf::::FinalityTimeout(block_hash)) => { + // finality is lagging? let's wait a bit more and report a stall + log::trace!( + target: "bridge", + "{} transaction {:?} block {:?} has not been finalized for too long", + C::NAME, + transaction_hash, + block_hash, + ); + return InvalidationStatus::Lost + }, + Some(TransactionStatusOf::::Usurped(new_transaction_hash)) => { + // this may be result of our transaction resubmitter work or some manual + // intervention. In both cases - let's start stall timeout, because the meaning + // of transaction may have changed + log::trace!( + target: "bridge", + "{} transaction {:?} has been usurped by new transaction: {:?}", + C::NAME, + transaction_hash, + new_transaction_hash, + ); + return InvalidationStatus::Lost + }, + Some(TransactionStatusOf::::Dropped) => { + // the transaction has been removed from the pool because of its limits. Let's wait + // a bit and report a stall + log::trace!( + target: "bridge", + "{} transaction {:?} has been dropped from the pool", + C::NAME, + transaction_hash, + ); + return InvalidationStatus::Lost + }, + None => { + // the status of transaction is unknown to us (the subscription has been closed?). + // Let's wait a bit and report a stall + return InvalidationStatus::Lost + }, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::test_chain::TestChain; + use futures::{FutureExt, SinkExt}; + use sc_transaction_pool_api::TransactionStatus; + + struct TestEnvironment(Result, Error>); + + #[async_trait] + impl Environment for TestEnvironment { + async fn header_id_by_hash( + &self, + _hash: HashOf, + ) -> Result, Error> { + self.0.as_ref().map_err(|_| Error::BridgePalletIsNotInitialized).cloned() + } + } + + async fn on_transaction_status( + status: TransactionStatus, HashOf>, + ) -> Option<( + TrackedTransactionStatus>, + InvalidationStatus>, + )> { + let (mut sender, receiver) = futures::channel::mpsc::channel(1); + let tx_tracker = TransactionTracker::::new( + TestEnvironment(Ok(HeaderId(0, Default::default()))), + Duration::from_secs(0), + Default::default(), + Subscription(async_std::sync::Mutex::new(receiver)), + ); + + let wait_for_stall_timeout = futures::future::pending(); + let wait_for_stall_timeout_rest = futures::future::ready(()); + sender.send(Some(status)).await.unwrap(); + tx_tracker + .do_wait(wait_for_stall_timeout, wait_for_stall_timeout_rest) + .now_or_never() + .map(|(ts, is)| (ts, is.unwrap())) + } + + #[async_std::test] + async fn returns_finalized_on_finalized() { + assert_eq!( + on_transaction_status(TransactionStatus::Finalized(Default::default())).await, + Some(( + TrackedTransactionStatus::Finalized(Default::default()), + InvalidationStatus::Finalized(Default::default()) + )), + ); + } + + #[async_std::test] + async fn returns_lost_on_finalized_and_environment_error() { + assert_eq!( + watch_transaction_status::<_, TestChain, _>( + TestEnvironment(Err(Error::BridgePalletIsNotInitialized)), + Default::default(), + futures::stream::iter([TransactionStatus::Finalized(Default::default())]) + ) + .now_or_never(), + Some(InvalidationStatus::Lost), + ); + } + + #[async_std::test] + async fn returns_invalid_on_invalid() { + assert_eq!( + on_transaction_status(TransactionStatus::Invalid).await, + Some((TrackedTransactionStatus::Lost, InvalidationStatus::Invalid)), + ); + } + + #[async_std::test] + async fn waits_on_future() { + assert_eq!(on_transaction_status(TransactionStatus::Future).await, None,); + } + + #[async_std::test] + async fn waits_on_ready() { + assert_eq!(on_transaction_status(TransactionStatus::Ready).await, None,); + } + + #[async_std::test] + async fn waits_on_broadcast() { + assert_eq!( + on_transaction_status(TransactionStatus::Broadcast(Default::default())).await, + None, + ); + } + + #[async_std::test] + async fn waits_on_in_block() { + assert_eq!( + on_transaction_status(TransactionStatus::InBlock(Default::default())).await, + None, + ); + } + + #[async_std::test] + async fn waits_on_retracted() { + assert_eq!( + on_transaction_status(TransactionStatus::Retracted(Default::default())).await, + None, + ); + } + + #[async_std::test] + async fn lost_on_finality_timeout() { + assert_eq!( + on_transaction_status(TransactionStatus::FinalityTimeout(Default::default())).await, + Some((TrackedTransactionStatus::Lost, InvalidationStatus::Lost)), + ); + } + + #[async_std::test] + async fn lost_on_usurped() { + assert_eq!( + on_transaction_status(TransactionStatus::Usurped(Default::default())).await, + Some((TrackedTransactionStatus::Lost, InvalidationStatus::Lost)), + ); + } + + #[async_std::test] + async fn lost_on_dropped() { + assert_eq!( + on_transaction_status(TransactionStatus::Dropped).await, + Some((TrackedTransactionStatus::Lost, InvalidationStatus::Lost)), + ); + } + + #[async_std::test] + async fn lost_on_subscription_error() { + assert_eq!( + watch_transaction_status::<_, TestChain, _>( + TestEnvironment(Ok(HeaderId(0, Default::default()))), + Default::default(), + futures::stream::iter([]) + ) + .now_or_never(), + Some(InvalidationStatus::Lost), + ); + } + + #[async_std::test] + async fn lost_on_timeout_when_waiting_for_invalidation_status() { + let (_sender, receiver) = futures::channel::mpsc::channel(1); + let tx_tracker = TransactionTracker::::new( + TestEnvironment(Ok(HeaderId(0, Default::default()))), + Duration::from_secs(0), + Default::default(), + Subscription(async_std::sync::Mutex::new(receiver)), + ); + + let wait_for_stall_timeout = futures::future::ready(()).shared(); + let wait_for_stall_timeout_rest = wait_for_stall_timeout.clone(); + let wait_result = tx_tracker + .do_wait(wait_for_stall_timeout, wait_for_stall_timeout_rest) + .now_or_never(); + + assert_eq!(wait_result, Some((TrackedTransactionStatus::Lost, None))); + } +} diff --git a/relays/client-westend/Cargo.toml b/relays/client-westend/Cargo.toml new file mode 100644 index 00000000000..351013bd864 --- /dev/null +++ b/relays/client-westend/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "relay-westend-client" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-runtime = { path = "../../primitives/runtime" } +bp-westend = { path = "../../primitives/chain-westend" } + +# Substrate Dependencies + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-westend/src/lib.rs b/relays/client-westend/src/lib.rs new file mode 100644 index 00000000000..6013bfad128 --- /dev/null +++ b/relays/client-westend/src/lib.rs @@ -0,0 +1,80 @@ +// Copyright 2019-2021 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 . + +//! Types used to connect to the Westend chain. + +use bp_runtime::ChainId; +use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider}; +use sp_core::storage::StorageKey; +use std::time::Duration; + +/// Westend header id. +pub type HeaderId = relay_utils::HeaderId; + +/// Westend header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; + +/// Westend chain definition +#[derive(Debug, Clone, Copy)] +pub struct Westend; + +impl UnderlyingChainProvider for Westend { + type Chain = bp_westend::Westend; +} + +impl Chain for Westend { + const ID: ChainId = bp_runtime::WESTEND_CHAIN_ID; + const NAME: &'static str = "Westend"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); + + type SignedBlock = bp_westend::SignedBlock; + type Call = (); +} + +impl RelayChain for Westend { + const PARAS_PALLET_NAME: &'static str = bp_westend::PARAS_PALLET_NAME; + const PARACHAINS_FINALITY_PALLET_NAME: &'static str = + bp_westend::WITH_WESTEND_BRIDGE_PARAS_PALLET_NAME; +} + +impl ChainWithBalances for Westend { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + bp_westend::AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +/// Westmint parachain definition +#[derive(Debug, Clone, Copy)] +pub struct Westmint; + +impl UnderlyingChainProvider for Westmint { + type Chain = bp_westend::Westmint; +} + +// Westmint seems to use the same configuration as all Polkadot-like chains, so we'll use Westend +// primitives here. +impl Chain for Westmint { + const ID: ChainId = bp_runtime::WESTMINT_CHAIN_ID; + const NAME: &'static str = "Westmint"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_westend::BEST_FINALIZED_WESTMINT_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); + + type SignedBlock = bp_westend::SignedBlock; + type Call = (); +} diff --git a/relays/client-wococo/Cargo.toml b/relays/client-wococo/Cargo.toml new file mode 100644 index 00000000000..78a5afe17ca --- /dev/null +++ b/relays/client-wococo/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "relay-wococo-client" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +relay-substrate-client = { path = "../client-substrate" } +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-runtime = { path = "../../primitives/runtime" } +bp-wococo = { path = "../../primitives/chain-wococo" } + +# Substrate Dependencies +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-wococo/src/lib.rs b/relays/client-wococo/src/lib.rs new file mode 100644 index 00000000000..2f0d6b22f92 --- /dev/null +++ b/relays/client-wococo/src/lib.rs @@ -0,0 +1,58 @@ +// Copyright 2019-2021 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 . + +//! Types used to connect to the Wococo-Substrate chain. + +use bp_runtime::ChainId; +use relay_substrate_client::{Chain, ChainWithBalances, RelayChain, UnderlyingChainProvider}; +use sp_core::storage::StorageKey; +use std::time::Duration; + +/// Wococo header id. +pub type HeaderId = relay_utils::HeaderId; + +/// Wococo header type used in headers sync. +pub type SyncHeader = relay_substrate_client::SyncHeader; + +/// Wococo chain definition +#[derive(Debug, Clone, Copy)] +pub struct Wococo; + +impl UnderlyingChainProvider for Wococo { + type Chain = bp_wococo::Wococo; +} + +impl Chain for Wococo { + const ID: ChainId = bp_runtime::WOCOCO_CHAIN_ID; + const NAME: &'static str = "Wococo"; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; + const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); + + type SignedBlock = bp_wococo::SignedBlock; + type Call = (); +} + +impl ChainWithBalances for Wococo { + fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { + bp_wococo::AccountInfoStorageMapKeyProvider::final_key(account_id) + } +} + +impl RelayChain for Wococo { + const PARAS_PALLET_NAME: &'static str = bp_wococo::PARAS_PALLET_NAME; + const PARACHAINS_FINALITY_PALLET_NAME: &'static str = "BridgeWococoParachain"; +} diff --git a/relays/finality/Cargo.toml b/relays/finality/Cargo.toml new file mode 100644 index 00000000000..ab75533b023 --- /dev/null +++ b/relays/finality/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "finality-relay" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +description = "Finality proofs relay" + +[dependencies] +async-std = "1.6.5" +async-trait = "0.1" +backoff = "0.4" +bp-header-chain = { path = "../../primitives/header-chain" } +futures = "0.3.28" +log = "0.4.17" +num-traits = "0.2" +relay-utils = { path = "../utils" } + +[dev-dependencies] +parking_lot = "0.12.1" diff --git a/relays/finality/README.md b/relays/finality/README.md new file mode 100644 index 00000000000..444056e7563 --- /dev/null +++ b/relays/finality/README.md @@ -0,0 +1,58 @@ +# GRANDPA Finality Relay + +The finality relay is able to work with different finality engines. In the modern Substrate world they are GRANDPA +and BEEFY. Let's talk about GRANDPA here, because BEEFY relay and bridge BEEFY pallet are in development. + +In general, the relay works as follows: it connects to the source and target chain. The source chain must have the +[GRANDPA gadget](https://github.com/paritytech/finality-grandpa) running (so it can't be a parachain). The target +chain must have the [bridge GRANDPA pallet](../../modules/grandpa/) deployed at its runtime. The relay subscribes +to the GRANDPA finality notifications at the source chain and when the new justification is received, it is submitted +to the pallet at the target chain. + +Apart from that, the relay is watching for every source header that is missing at target. If it finds the missing +mandatory header (header that is changing the current GRANDPA validators set), it submits the justification for +this header. The case when the source node can't return the mandatory justification is considered a fatal error, +because the pallet can't proceed without it. + +More: [GRANDPA Finality Relay Sequence Diagram](../../docs/grandpa-finality-relay.html). + +## How to Use the Finality Relay + +The most important trait is the [`FinalitySyncPipeline`](./src/lib.rs), which defines the basic primitives of the +source chain (like block hash and number) and the type of finality proof (GRANDPA justification or MMR proof). Once +that is defined, there are two other traits - [`SourceClient`](./src/finality_loop.rs) and +[`TargetClient`](./src/finality_loop.rs). + +The `SourceClient` represents the Substrate node client that connects to the source chain. The client needs to +be able to return the best finalized header number, finalized header and its finality proof and the stream of +finality proofs. + +The `TargetClient` implementation must be able to craft finality delivery transaction and submit it to the target +node. The transaction is then tracked by the relay until it is mined and finalized. + +The main entrypoint for the crate is the [`run` function](./src/finality_loop.rs), which takes source and target +clients and [`FinalitySyncParams`](./src/finality_loop.rs) parameters. The most important parameter is the +`only_mandatory_headers` - it is set to `true`, the relay will only submit mandatory headers. Since transactions +with mandatory headers are fee-free, the cost of running such relay is zero (in terms of fees). + +## Finality Relay Metrics + +Finality relay provides several metrics. Metrics names depend on names of source and target chains. The list below +shows metrics names for Rialto (source chain) to Millau (target chain) finality relay. For other chains, simply +change chain names. So the metrics are: + +- `Rialto_to_Millau_Sync_best_source_block_number` - returns best finalized source chain (Rialto) block number, known + to the relay. If relay is running in [on-demand mode](../bin-substrate/src/cli/relay_headers_and_messages/), the + number may not match (it may be far behind) the actual best finalized number; + +- `Rialto_to_Millau_Sync_best_source_at_target_block_number` - returns best finalized source chain (Rialto) block + number that is known to the bridge GRANDPA pallet at the target chain. + +- `Rialto_to_Millau_Sync_is_source_and_source_at_target_using_different_forks` - if this metrics is set to `1`, then + the best source chain header, known to the target chain doesn't match the same-number-header at the source chain. + It means that the GRANDPA validators set has crafted the duplicate justification and it has been submitted to the + target chain. Normally (if majority of validators are honest and if you're running finality relay without large + breaks) this shall not happen and the metric will have `0` value. + +If relay operates properly, you should see that the `Rialto_to_Millau_Sync_best_source_at_target_block_number` +tries to reach the `Rialto_to_Millau_Sync_best_source_block_number`. And the latter one always increases. diff --git a/relays/finality/src/finality_loop.rs b/relays/finality/src/finality_loop.rs new file mode 100644 index 00000000000..1ee1a8d9db6 --- /dev/null +++ b/relays/finality/src/finality_loop.rs @@ -0,0 +1,761 @@ +// Copyright 2019-2021 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 . + +//! The loop basically reads all missing headers and their finality proofs from the source client. +//! The proof for the best possible header is then submitted to the target node. The only exception +//! is the mandatory headers, which we always submit to the target node. For such headers, we +//! assume that the persistent proof either exists, or will eventually become available. + +use crate::{ + sync_loop_metrics::SyncLoopMetrics, FinalityProof, FinalitySyncPipeline, SourceHeader, +}; + +use async_trait::async_trait; +use backoff::backoff::Backoff; +use futures::{select, Future, FutureExt, Stream, StreamExt}; +use num_traits::{One, Saturating}; +use relay_utils::{ + metrics::MetricsParams, relay_loop::Client as RelayClient, retry_backoff, FailedClient, + HeaderId, MaybeConnectionError, TrackedTransactionStatus, TransactionTracker, +}; +use std::{ + fmt::Debug, + pin::Pin, + time::{Duration, Instant}, +}; + +/// Finality proof synchronization loop parameters. +#[derive(Debug, Clone)] +pub struct FinalitySyncParams { + /// Interval at which we check updates on both clients. Normally should be larger than + /// `min(source_block_time, target_block_time)`. + /// + /// This parameter may be used to limit transactions rate. Increase the value && you'll get + /// infrequent updates => sparse headers => potential slow down of bridge applications, but + /// pallet storage won't be super large. Decrease the value to near `source_block_time` and + /// you'll get transaction for (almost) every block of the source chain => all source headers + /// will be known to the target chain => bridge applications will run faster, but pallet + /// storage may explode (but if pruning is there, then it's fine). + pub tick: Duration, + /// Number of finality proofs to keep in internal buffer between loop iterations. + /// + /// While in "major syncing" state, we still read finality proofs from the stream. They're + /// stored in the internal buffer between loop iterations. When we're close to the tip of the + /// chain, we may meet finality delays if headers are not finalized frequently. So instead of + /// waiting for next finality proof to appear in the stream, we may use existing proof from + /// that buffer. + pub recent_finality_proofs_limit: usize, + /// Timeout before we treat our transactions as lost and restart the whole sync process. + pub stall_timeout: Duration, + /// If true, only mandatory headers are relayed. + pub only_mandatory_headers: bool, +} + +/// Source client used in finality synchronization loop. +#[async_trait] +pub trait SourceClient: RelayClient { + /// Stream of new finality proofs. The stream is allowed to miss proofs for some + /// headers, even if those headers are mandatory. + type FinalityProofsStream: Stream + Send; + + /// Get best finalized block number. + async fn best_finalized_block_number(&self) -> Result; + + /// Get canonical header and its finality proof by number. + async fn header_and_finality_proof( + &self, + number: P::Number, + ) -> Result<(P::Header, Option), Self::Error>; + + /// Subscribe to new finality proofs. + async fn finality_proofs(&self) -> Result; +} + +/// Target client used in finality synchronization loop. +#[async_trait] +pub trait TargetClient: RelayClient { + /// Transaction tracker to track submitted transactions. + type TransactionTracker: TransactionTracker; + + /// Get best finalized source block number. + async fn best_finalized_source_block_id( + &self, + ) -> Result, Self::Error>; + + /// Submit header finality proof. + async fn submit_finality_proof( + &self, + header: P::Header, + proof: P::FinalityProof, + ) -> Result; +} + +/// Return prefix that will be used by default to expose Prometheus metrics of the finality proofs +/// sync loop. +pub fn metrics_prefix() -> String { + format!("{}_to_{}_Sync", P::SOURCE_NAME, P::TARGET_NAME) +} + +/// Run finality proofs synchronization loop. +pub async fn run( + source_client: impl SourceClient

, + target_client: impl TargetClient

, + sync_params: FinalitySyncParams, + metrics_params: MetricsParams, + exit_signal: impl Future + 'static + Send, +) -> Result<(), relay_utils::Error> { + let exit_signal = exit_signal.shared(); + relay_utils::relay_loop(source_client, target_client) + .with_metrics(metrics_params) + .loop_metric(SyncLoopMetrics::new( + Some(&metrics_prefix::

()), + "source", + "source_at_target", + )?)? + .expose() + .await? + .run(metrics_prefix::

(), move |source_client, target_client, metrics| { + run_until_connection_lost( + source_client, + target_client, + sync_params.clone(), + metrics, + exit_signal.clone(), + ) + }) + .await +} + +/// Unjustified headers container. Ordered by header number. +pub(crate) type UnjustifiedHeaders = Vec; +/// Finality proofs container. Ordered by target header number. +pub(crate) type FinalityProofs

= + Vec<(

::Number,

::FinalityProof)>; +/// Reference to finality proofs container. +pub(crate) type FinalityProofsRef<'a, P> = + &'a [(

::Number,

::FinalityProof)]; + +/// Error that may happen inside finality synchronization loop. +#[derive(Debug)] +pub(crate) enum Error { + /// Source client request has failed with given error. + Source(SourceError), + /// Target client request has failed with given error. + Target(TargetError), + /// Finality proof for mandatory header is missing from the source node. + MissingMandatoryFinalityProof(P::Number), +} + +impl Error +where + P: FinalitySyncPipeline, + SourceError: MaybeConnectionError, + TargetError: MaybeConnectionError, +{ + fn fail_if_connection_error(&self) -> Result<(), FailedClient> { + match *self { + Error::Source(ref error) if error.is_connection_error() => Err(FailedClient::Source), + Error::Target(ref error) if error.is_connection_error() => Err(FailedClient::Target), + _ => Ok(()), + } + } +} + +/// Information about transaction that we have submitted. +#[derive(Debug, Clone)] +pub(crate) struct Transaction { + /// Submitted transaction tracker. + pub tracker: Tracker, + /// The number of the header we have submitted. + pub submitted_header_number: Number, +} + +impl Transaction { + pub async fn submit< + C: TargetClient, + P: FinalitySyncPipeline, + >( + target_client: &C, + header: P::Header, + justification: P::FinalityProof, + ) -> Result { + let submitted_header_number = header.number(); + log::debug!( + target: "bridge", + "Going to submit finality proof of {} header #{:?} to {}", + P::SOURCE_NAME, + submitted_header_number, + P::TARGET_NAME, + ); + + let tracker = target_client.submit_finality_proof(header, justification).await?; + Ok(Transaction { tracker, submitted_header_number }) + } + + pub async fn track, P: FinalitySyncPipeline>( + self, + target_client: &C, + ) -> Result<(), String> { + match self.tracker.wait().await { + TrackedTransactionStatus::Finalized(_) => { + // The transaction has been finalized, but it may have been finalized in the + // "failed" state. So let's check if the block number was actually updated. + // If it wasn't then we are stalled. + // + // Please also note that we're returning an error if we fail to read required data + // from the target client - that's the best we can do here to avoid actual stall. + target_client + .best_finalized_source_block_id() + .await + .map_err(|e| format!("failed to read best block from target node: {e:?}")) + .and_then(|best_id_at_target| { + if self.submitted_header_number > best_id_at_target.0 { + return Err(format!( + "best block at target after tx is {:?} and we've submitted {:?}", + best_id_at_target.0, self.submitted_header_number, + )) + } + Ok(()) + }) + }, + TrackedTransactionStatus::Lost => Err("transaction failed".to_string()), + } + } +} + +/// Finality proofs stream that may be restarted. +pub(crate) struct RestartableFinalityProofsStream { + /// Flag that the stream needs to be restarted. + pub(crate) needs_restart: bool, + /// The stream itself. + stream: Pin>, +} + +impl RestartableFinalityProofsStream { + pub async fn create_raw_stream< + C: SourceClient, + P: FinalitySyncPipeline, + >( + source_client: &C, + ) -> Result { + source_client.finality_proofs().await.map_err(|error| { + log::error!( + target: "bridge", + "Failed to subscribe to {} justifications: {:?}. Going to reconnect", + P::SOURCE_NAME, + error, + ); + + FailedClient::Source + }) + } + + pub async fn restart_if_scheduled< + C: SourceClient, + P: FinalitySyncPipeline, + >( + &mut self, + source_client: &C, + ) -> Result<(), FailedClient> { + if self.needs_restart { + log::warn!(target: "bridge", "{} finality proofs stream is being restarted", P::SOURCE_NAME); + + self.needs_restart = false; + self.stream = Box::pin(Self::create_raw_stream(source_client).await?); + } + Ok(()) + } + + pub fn next(&mut self) -> Option { + match self.stream.next().now_or_never() { + Some(Some(finality_proof)) => Some(finality_proof), + Some(None) => { + self.needs_restart = true; + None + }, + None => None, + } + } +} + +impl From for RestartableFinalityProofsStream { + fn from(stream: S) -> Self { + RestartableFinalityProofsStream { needs_restart: false, stream: Box::pin(stream) } + } +} + +/// Finality synchronization loop state. +pub(crate) struct FinalityLoopState<'a, P: FinalitySyncPipeline, FinalityProofsStream> { + /// Synchronization loop progress. + pub(crate) progress: &'a mut (Instant, Option), + /// Finality proofs stream. + pub(crate) finality_proofs_stream: + &'a mut RestartableFinalityProofsStream, + /// Recent finality proofs that we have read from the stream. + pub(crate) recent_finality_proofs: &'a mut FinalityProofs

, + /// Number of the last header, submitted to the target node. + pub(crate) submitted_header_number: Option, +} + +/// Run finality relay loop until connection to one of nodes is lost. +pub(crate) async fn run_until_connection_lost( + source_client: impl SourceClient

, + target_client: impl TargetClient

, + sync_params: FinalitySyncParams, + metrics_sync: Option, + exit_signal: impl Future, +) -> Result<(), FailedClient> { + let last_transaction_tracker = futures::future::Fuse::terminated(); + let exit_signal = exit_signal.fuse(); + futures::pin_mut!(last_transaction_tracker, exit_signal); + + let mut finality_proofs_stream = + RestartableFinalityProofsStream::create_raw_stream(&source_client).await?.into(); + let mut recent_finality_proofs = Vec::new(); + + let mut progress = (Instant::now(), None); + let mut retry_backoff = retry_backoff(); + let mut last_submitted_header_number = None; + + loop { + // run loop iteration + let iteration_result = run_loop_iteration( + &source_client, + &target_client, + FinalityLoopState { + progress: &mut progress, + finality_proofs_stream: &mut finality_proofs_stream, + recent_finality_proofs: &mut recent_finality_proofs, + submitted_header_number: last_submitted_header_number, + }, + &sync_params, + &metrics_sync, + ) + .await; + + // deal with errors + let next_tick = match iteration_result { + Ok(Some(updated_transaction)) => { + last_submitted_header_number = Some(updated_transaction.submitted_header_number); + last_transaction_tracker.set(updated_transaction.track(&target_client).fuse()); + retry_backoff.reset(); + sync_params.tick + }, + Ok(None) => { + retry_backoff.reset(); + sync_params.tick + }, + Err(error) => { + log::error!(target: "bridge", "Finality sync loop iteration has failed with error: {:?}", error); + error.fail_if_connection_error()?; + retry_backoff.next_backoff().unwrap_or(relay_utils::relay_loop::RECONNECT_DELAY) + }, + }; + finality_proofs_stream.restart_if_scheduled(&source_client).await?; + + // wait till exit signal, or new source block + select! { + transaction_result = last_transaction_tracker => { + transaction_result.map_err(|e| { + log::error!( + target: "bridge", + "Finality synchronization from {} to {} has stalled with error: {}. Going to restart", + P::SOURCE_NAME, + P::TARGET_NAME, + e, + ); + + // Restart the loop if we're stalled. + FailedClient::Both + })? + }, + _ = async_std::task::sleep(next_tick).fuse() => {}, + _ = exit_signal => return Ok(()), + } + } +} + +pub(crate) async fn run_loop_iteration( + source_client: &SC, + target_client: &TC, + state: FinalityLoopState<'_, P, SC::FinalityProofsStream>, + sync_params: &FinalitySyncParams, + metrics_sync: &Option, +) -> Result>, Error> +where + P: FinalitySyncPipeline, + SC: SourceClient

, + TC: TargetClient

, +{ + // read best source headers ids from source and target nodes + let best_number_at_source = + source_client.best_finalized_block_number().await.map_err(Error::Source)?; + let best_id_at_target = + target_client.best_finalized_source_block_id().await.map_err(Error::Target)?; + let best_number_at_target = best_id_at_target.0; + + let different_hash_at_source = ensure_same_fork::(&best_id_at_target, source_client) + .await + .map_err(Error::Source)?; + let using_same_fork = different_hash_at_source.is_none(); + if let Some(ref different_hash_at_source) = different_hash_at_source { + log::error!( + target: "bridge", + "Source node ({}) and pallet at target node ({}) have different headers at the same height {:?}: \ + at-source {:?} vs at-target {:?}", + P::SOURCE_NAME, + P::TARGET_NAME, + best_number_at_target, + different_hash_at_source, + best_id_at_target.1, + ); + } + + if let Some(ref metrics_sync) = *metrics_sync { + metrics_sync.update_best_block_at_source(best_number_at_source); + metrics_sync.update_best_block_at_target(best_number_at_target); + metrics_sync.update_using_same_fork(using_same_fork); + } + *state.progress = + print_sync_progress::

(*state.progress, best_number_at_source, best_number_at_target); + + // if we have already submitted header, then we just need to wait for it + // if we're waiting too much, then we believe our transaction has been lost and restart sync + if let Some(submitted_header_number) = state.submitted_header_number { + if best_number_at_target >= submitted_header_number { + // transaction has been mined && we can continue + } else { + return Ok(None) + } + } + + // submit new header if we have something new + match select_header_to_submit( + source_client, + target_client, + state.finality_proofs_stream, + state.recent_finality_proofs, + best_number_at_source, + best_number_at_target, + sync_params, + ) + .await? + { + Some((header, justification)) => { + let transaction = Transaction::submit(target_client, header, justification) + .await + .map_err(Error::Target)?; + Ok(Some(transaction)) + }, + None => Ok(None), + } +} + +pub(crate) async fn select_header_to_submit( + source_client: &SC, + target_client: &TC, + finality_proofs_stream: &mut RestartableFinalityProofsStream, + recent_finality_proofs: &mut FinalityProofs

, + best_number_at_source: P::Number, + best_number_at_target: P::Number, + sync_params: &FinalitySyncParams, +) -> Result, Error> +where + P: FinalitySyncPipeline, + SC: SourceClient

, + TC: TargetClient

, +{ + // to see that the loop is progressing + log::trace!( + target: "bridge", + "Considering range of headers ({:?}; {:?}]", + best_number_at_target, + best_number_at_source, + ); + + // read missing headers. if we see that the header schedules GRANDPA change, we need to + // submit this header + let selected_finality_proof = read_missing_headers::( + source_client, + target_client, + best_number_at_source, + best_number_at_target, + ) + .await?; + let (mut unjustified_headers, mut selected_finality_proof) = match selected_finality_proof { + SelectedFinalityProof::Mandatory(header, finality_proof) => + return Ok(Some((header, finality_proof))), + _ if sync_params.only_mandatory_headers => { + // we are not reading finality proofs from the stream, so eventually it'll break + // but we don't care about transient proofs at all, so it is acceptable + return Ok(None) + }, + SelectedFinalityProof::Regular(unjustified_headers, header, finality_proof) => + (unjustified_headers, Some((header, finality_proof))), + SelectedFinalityProof::None(unjustified_headers) => (unjustified_headers, None), + }; + + // all headers that are missing from the target client are non-mandatory + // => even if we have already selected some header and its persistent finality proof, + // we may try to select better header by reading non-persistent proofs from the stream + read_finality_proofs_from_stream::(finality_proofs_stream, recent_finality_proofs); + selected_finality_proof = select_better_recent_finality_proof::

( + recent_finality_proofs, + &mut unjustified_headers, + selected_finality_proof, + ); + + // remove obsolete 'recent' finality proofs + keep its size under certain limit + let oldest_finality_proof_to_keep = selected_finality_proof + .as_ref() + .map(|(header, _)| header.number()) + .unwrap_or(best_number_at_target); + prune_recent_finality_proofs::

( + oldest_finality_proof_to_keep, + recent_finality_proofs, + sync_params.recent_finality_proofs_limit, + ); + + Ok(selected_finality_proof) +} + +/// Ensures that both clients are on the same fork. +/// +/// Returns `Some(_)` with header has at the source client if headers are different. +async fn ensure_same_fork>( + best_id_at_target: &HeaderId, + source_client: &SC, +) -> Result, SC::Error> { + let header_at_source = source_client.header_and_finality_proof(best_id_at_target.0).await?.0; + let header_hash_at_source = header_at_source.hash(); + Ok(if best_id_at_target.1 == header_hash_at_source { + None + } else { + Some(header_hash_at_source) + }) +} + +/// Finality proof that has been selected by the `read_missing_headers` function. +pub(crate) enum SelectedFinalityProof { + /// Mandatory header and its proof has been selected. We shall submit proof for this header. + Mandatory(Header, FinalityProof), + /// Regular header and its proof has been selected. We may submit this proof, or proof for + /// some better header. + Regular(UnjustifiedHeaders

, Header, FinalityProof), + /// We haven't found any missing header with persistent proof at the target client. + None(UnjustifiedHeaders
), +} + +/// Read missing headers and their persistent finality proofs from the target client. +/// +/// If we have found some header with known proof, it is returned. +/// Otherwise, `SelectedFinalityProof::None` is returned. +/// +/// Unless we have found mandatory header, all missing headers are collected and returned. +pub(crate) async fn read_missing_headers< + P: FinalitySyncPipeline, + SC: SourceClient

, + TC: TargetClient

, +>( + source_client: &SC, + _target_client: &TC, + best_number_at_source: P::Number, + best_number_at_target: P::Number, +) -> Result, Error> { + let mut unjustified_headers = Vec::new(); + let mut selected_finality_proof = None; + let mut header_number = best_number_at_target + One::one(); + while header_number <= best_number_at_source { + let (header, finality_proof) = source_client + .header_and_finality_proof(header_number) + .await + .map_err(Error::Source)?; + let is_mandatory = header.is_mandatory(); + + match (is_mandatory, finality_proof) { + (true, Some(finality_proof)) => { + log::trace!(target: "bridge", "Header {:?} is mandatory", header_number); + return Ok(SelectedFinalityProof::Mandatory(header, finality_proof)) + }, + (true, None) => return Err(Error::MissingMandatoryFinalityProof(header.number())), + (false, Some(finality_proof)) => { + log::trace!(target: "bridge", "Header {:?} has persistent finality proof", header_number); + unjustified_headers.clear(); + selected_finality_proof = Some((header, finality_proof)); + }, + (false, None) => { + unjustified_headers.push(header); + }, + } + + header_number = header_number + One::one(); + } + + log::trace!( + target: "bridge", + "Read {} {} headers. Selected finality proof for header: {:?}", + best_number_at_source.saturating_sub(best_number_at_target), + P::SOURCE_NAME, + selected_finality_proof.as_ref().map(|(header, _)| header), + ); + + Ok(match selected_finality_proof { + Some((header, proof)) => SelectedFinalityProof::Regular(unjustified_headers, header, proof), + None => SelectedFinalityProof::None(unjustified_headers), + }) +} + +/// Read finality proofs from the stream. +pub(crate) fn read_finality_proofs_from_stream< + P: FinalitySyncPipeline, + FPS: Stream, +>( + finality_proofs_stream: &mut RestartableFinalityProofsStream, + recent_finality_proofs: &mut FinalityProofs

, +) { + let mut proofs_count = 0; + let mut first_header_number = None; + let mut last_header_number = None; + while let Some(finality_proof) = finality_proofs_stream.next() { + let target_header_number = finality_proof.target_header_number(); + if first_header_number.is_none() { + first_header_number = Some(target_header_number); + } + last_header_number = Some(target_header_number); + proofs_count += 1; + + recent_finality_proofs.push((target_header_number, finality_proof)); + } + + if proofs_count != 0 { + log::trace!( + target: "bridge", + "Read {} finality proofs from {} finality stream for headers in range [{:?}; {:?}]", + proofs_count, + P::SOURCE_NAME, + first_header_number, + last_header_number, + ); + } +} + +/// Try to select better header and its proof, given finality proofs that we +/// have recently read from the stream. +pub(crate) fn select_better_recent_finality_proof( + recent_finality_proofs: FinalityProofsRef

, + unjustified_headers: &mut UnjustifiedHeaders, + selected_finality_proof: Option<(P::Header, P::FinalityProof)>, +) -> Option<(P::Header, P::FinalityProof)> { + if unjustified_headers.is_empty() || recent_finality_proofs.is_empty() { + log::trace!( + target: "bridge", + "Can not improve selected {} finality proof {:?}. No unjustified headers and recent proofs", + P::SOURCE_NAME, + selected_finality_proof.as_ref().map(|(h, _)| h.number()), + ); + return selected_finality_proof + } + + const NOT_EMPTY_PROOF: &str = "we have checked that the vec is not empty; qed"; + + // we need proofs for headers in range unjustified_range_begin..=unjustified_range_end + let unjustified_range_begin = unjustified_headers.first().expect(NOT_EMPTY_PROOF).number(); + let unjustified_range_end = unjustified_headers.last().expect(NOT_EMPTY_PROOF).number(); + + // we have proofs for headers in range buffered_range_begin..=buffered_range_end + let buffered_range_begin = recent_finality_proofs.first().expect(NOT_EMPTY_PROOF).0; + let buffered_range_end = recent_finality_proofs.last().expect(NOT_EMPTY_PROOF).0; + + // we have two ranges => find intersection + let intersection_begin = std::cmp::max(unjustified_range_begin, buffered_range_begin); + let intersection_end = std::cmp::min(unjustified_range_end, buffered_range_end); + let intersection = intersection_begin..=intersection_end; + + // find last proof from intersection + let selected_finality_proof_index = recent_finality_proofs + .binary_search_by_key(intersection.end(), |(number, _)| *number) + .unwrap_or_else(|index| index.saturating_sub(1)); + let (selected_header_number, finality_proof) = + &recent_finality_proofs[selected_finality_proof_index]; + let has_selected_finality_proof = intersection.contains(selected_header_number); + log::trace!( + target: "bridge", + "Trying to improve selected {} finality proof {:?}. Headers range: [{:?}; {:?}]. Proofs range: [{:?}; {:?}].\ + Trying to improve to: {:?}. Result: {}", + P::SOURCE_NAME, + selected_finality_proof.as_ref().map(|(h, _)| h.number()), + unjustified_range_begin, + unjustified_range_end, + buffered_range_begin, + buffered_range_end, + selected_header_number, + if has_selected_finality_proof { "improved" } else { "not improved" }, + ); + if !has_selected_finality_proof { + return selected_finality_proof + } + + // now remove all obsolete headers and extract selected header + let selected_header_position = unjustified_headers + .binary_search_by_key(selected_header_number, |header| header.number()) + .expect("unjustified_headers contain all headers from intersection; qed"); + let selected_header = unjustified_headers.swap_remove(selected_header_position); + Some((selected_header, finality_proof.clone())) +} + +pub(crate) fn prune_recent_finality_proofs( + justified_header_number: P::Number, + recent_finality_proofs: &mut FinalityProofs

, + recent_finality_proofs_limit: usize, +) { + let justified_header_idx = recent_finality_proofs + .binary_search_by_key(&justified_header_number, |(header_number, _)| *header_number) + .map(|idx| idx + 1) + .unwrap_or_else(|idx| idx); + let proofs_limit_idx = + recent_finality_proofs.len().saturating_sub(recent_finality_proofs_limit); + + *recent_finality_proofs = + recent_finality_proofs.split_off(std::cmp::max(justified_header_idx, proofs_limit_idx)); +} + +fn print_sync_progress( + progress_context: (Instant, Option), + best_number_at_source: P::Number, + best_number_at_target: P::Number, +) -> (Instant, Option) { + let (prev_time, prev_best_number_at_target) = progress_context; + let now = Instant::now(); + + let need_update = now - prev_time > Duration::from_secs(10) || + prev_best_number_at_target + .map(|prev_best_number_at_target| { + best_number_at_target.saturating_sub(prev_best_number_at_target) > 10.into() + }) + .unwrap_or(true); + + if !need_update { + return (prev_time, prev_best_number_at_target) + } + + log::info!( + target: "bridge", + "Synced {:?} of {:?} headers", + best_number_at_target, + best_number_at_source, + ); + (now, Some(best_number_at_target)) +} diff --git a/relays/finality/src/finality_loop_tests.rs b/relays/finality/src/finality_loop_tests.rs new file mode 100644 index 00000000000..1853c095f70 --- /dev/null +++ b/relays/finality/src/finality_loop_tests.rs @@ -0,0 +1,598 @@ +// Copyright 2019-2021 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 . + +//! Tests for finality synchronization loop. + +#![cfg(test)] + +use crate::{ + finality_loop::{ + prune_recent_finality_proofs, read_finality_proofs_from_stream, run_loop_iteration, + run_until_connection_lost, select_better_recent_finality_proof, select_header_to_submit, + FinalityLoopState, FinalityProofs, FinalitySyncParams, RestartableFinalityProofsStream, + SourceClient, TargetClient, + }, + sync_loop_metrics::SyncLoopMetrics, + FinalityProof, FinalitySyncPipeline, SourceHeader, +}; + +use async_trait::async_trait; +use bp_header_chain::GrandpaConsensusLogReader; +use futures::{FutureExt, Stream, StreamExt}; +use parking_lot::Mutex; +use relay_utils::{ + relay_loop::Client as RelayClient, FailedClient, HeaderId, MaybeConnectionError, + TrackedTransactionStatus, TransactionTracker, +}; +use std::{ + collections::HashMap, + pin::Pin, + sync::Arc, + time::{Duration, Instant}, +}; + +type IsMandatory = bool; +type TestNumber = u64; +type TestHash = u64; + +#[derive(Clone, Debug)] +struct TestTransactionTracker(TrackedTransactionStatus>); + +impl Default for TestTransactionTracker { + fn default() -> TestTransactionTracker { + TestTransactionTracker(TrackedTransactionStatus::Finalized(Default::default())) + } +} + +#[async_trait] +impl TransactionTracker for TestTransactionTracker { + type HeaderId = HeaderId; + + async fn wait(self) -> TrackedTransactionStatus> { + self.0 + } +} + +#[derive(Debug, Clone)] +enum TestError { + NonConnection, +} + +impl MaybeConnectionError for TestError { + fn is_connection_error(&self) -> bool { + false + } +} + +#[derive(Debug, Clone)] +struct TestFinalitySyncPipeline; + +impl FinalitySyncPipeline for TestFinalitySyncPipeline { + const SOURCE_NAME: &'static str = "TestSource"; + const TARGET_NAME: &'static str = "TestTarget"; + + type Hash = TestHash; + type Number = TestNumber; + type ConsensusLogReader = GrandpaConsensusLogReader; + type Header = TestSourceHeader; + type FinalityProof = TestFinalityProof; +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct TestSourceHeader(IsMandatory, TestNumber, TestHash); + +impl SourceHeader> + for TestSourceHeader +{ + fn hash(&self) -> TestHash { + self.2 + } + + fn number(&self) -> TestNumber { + self.1 + } + + fn is_mandatory(&self) -> bool { + self.0 + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +struct TestFinalityProof(TestNumber); + +impl FinalityProof for TestFinalityProof { + fn target_header_number(&self) -> TestNumber { + self.0 + } +} + +#[derive(Debug, Clone, Default)] +struct ClientsData { + source_best_block_number: TestNumber, + source_headers: HashMap)>, + source_proofs: Vec, + + target_best_block_id: HeaderId, + target_headers: Vec<(TestSourceHeader, TestFinalityProof)>, + target_transaction_tracker: TestTransactionTracker, +} + +#[derive(Clone)] +struct TestSourceClient { + on_method_call: Arc, + data: Arc>, +} + +#[async_trait] +impl RelayClient for TestSourceClient { + type Error = TestError; + + async fn reconnect(&mut self) -> Result<(), TestError> { + unreachable!() + } +} + +#[async_trait] +impl SourceClient for TestSourceClient { + type FinalityProofsStream = Pin + 'static + Send>>; + + async fn best_finalized_block_number(&self) -> Result { + let mut data = self.data.lock(); + (self.on_method_call)(&mut data); + Ok(data.source_best_block_number) + } + + async fn header_and_finality_proof( + &self, + number: TestNumber, + ) -> Result<(TestSourceHeader, Option), TestError> { + let mut data = self.data.lock(); + (self.on_method_call)(&mut data); + data.source_headers.get(&number).cloned().ok_or(TestError::NonConnection) + } + + async fn finality_proofs(&self) -> Result { + let mut data = self.data.lock(); + (self.on_method_call)(&mut data); + Ok(futures::stream::iter(data.source_proofs.clone()).boxed()) + } +} + +#[derive(Clone)] +struct TestTargetClient { + on_method_call: Arc, + data: Arc>, +} + +#[async_trait] +impl RelayClient for TestTargetClient { + type Error = TestError; + + async fn reconnect(&mut self) -> Result<(), TestError> { + unreachable!() + } +} + +#[async_trait] +impl TargetClient for TestTargetClient { + type TransactionTracker = TestTransactionTracker; + + async fn best_finalized_source_block_id( + &self, + ) -> Result, TestError> { + let mut data = self.data.lock(); + (self.on_method_call)(&mut data); + Ok(data.target_best_block_id) + } + + async fn submit_finality_proof( + &self, + header: TestSourceHeader, + proof: TestFinalityProof, + ) -> Result { + let mut data = self.data.lock(); + (self.on_method_call)(&mut data); + data.target_best_block_id = HeaderId(header.number(), header.hash()); + data.target_headers.push((header, proof)); + (self.on_method_call)(&mut data); + Ok(data.target_transaction_tracker.clone()) + } +} + +fn prepare_test_clients( + exit_sender: futures::channel::mpsc::UnboundedSender<()>, + state_function: impl Fn(&mut ClientsData) -> bool + Send + Sync + 'static, + source_headers: HashMap)>, +) -> (TestSourceClient, TestTargetClient) { + let internal_state_function: Arc = + Arc::new(move |data| { + if state_function(data) { + exit_sender.unbounded_send(()).unwrap(); + } + }); + let clients_data = Arc::new(Mutex::new(ClientsData { + source_best_block_number: 10, + source_headers, + source_proofs: vec![TestFinalityProof(12), TestFinalityProof(14)], + + target_best_block_id: HeaderId(5, 5), + target_headers: vec![], + target_transaction_tracker: TestTransactionTracker(TrackedTransactionStatus::Finalized( + Default::default(), + )), + })); + ( + TestSourceClient { + on_method_call: internal_state_function.clone(), + data: clients_data.clone(), + }, + TestTargetClient { on_method_call: internal_state_function, data: clients_data }, + ) +} + +fn test_sync_params() -> FinalitySyncParams { + FinalitySyncParams { + tick: Duration::from_secs(0), + recent_finality_proofs_limit: 1024, + stall_timeout: Duration::from_secs(1), + only_mandatory_headers: false, + } +} + +fn run_sync_loop( + state_function: impl Fn(&mut ClientsData) -> bool + Send + Sync + 'static, +) -> (ClientsData, Result<(), FailedClient>) { + let (exit_sender, exit_receiver) = futures::channel::mpsc::unbounded(); + let (source_client, target_client) = prepare_test_clients( + exit_sender, + state_function, + vec![ + (5, (TestSourceHeader(false, 5, 5), None)), + (6, (TestSourceHeader(false, 6, 6), None)), + (7, (TestSourceHeader(false, 7, 7), Some(TestFinalityProof(7)))), + (8, (TestSourceHeader(true, 8, 8), Some(TestFinalityProof(8)))), + (9, (TestSourceHeader(false, 9, 9), Some(TestFinalityProof(9)))), + (10, (TestSourceHeader(false, 10, 10), None)), + ] + .into_iter() + .collect(), + ); + let sync_params = test_sync_params(); + + let clients_data = source_client.data.clone(); + let result = async_std::task::block_on(run_until_connection_lost( + source_client, + target_client, + sync_params, + None, + exit_receiver.into_future().map(|(_, _)| ()), + )); + + let clients_data = clients_data.lock().clone(); + (clients_data, result) +} + +#[test] +fn finality_sync_loop_works() { + let (client_data, result) = run_sync_loop(|data| { + // header#7 has persistent finality proof, but it isn't mandatory => it isn't submitted, + // because header#8 has persistent finality proof && it is mandatory => it is submitted + // header#9 has persistent finality proof, but it isn't mandatory => it is submitted, + // because there are no more persistent finality proofs + // + // once this ^^^ is done, we generate more blocks && read proof for blocks 12 and 14 from + // the stream + if data.target_best_block_id.0 == 9 { + data.source_best_block_number = 14; + data.source_headers.insert(11, (TestSourceHeader(false, 11, 11), None)); + data.source_headers + .insert(12, (TestSourceHeader(false, 12, 12), Some(TestFinalityProof(12)))); + data.source_headers.insert(13, (TestSourceHeader(false, 13, 13), None)); + data.source_headers + .insert(14, (TestSourceHeader(false, 14, 14), Some(TestFinalityProof(14)))); + } + // once this ^^^ is done, we generate more blocks && read persistent proof for block 16 + if data.target_best_block_id.0 == 14 { + data.source_best_block_number = 17; + data.source_headers.insert(15, (TestSourceHeader(false, 15, 15), None)); + data.source_headers + .insert(16, (TestSourceHeader(false, 16, 16), Some(TestFinalityProof(16)))); + data.source_headers.insert(17, (TestSourceHeader(false, 17, 17), None)); + } + + data.target_best_block_id.0 == 16 + }); + + assert_eq!(result, Ok(())); + assert_eq!( + client_data.target_headers, + vec![ + // before adding 11..14: finality proof for mandatory header#8 + (TestSourceHeader(true, 8, 8), TestFinalityProof(8)), + // before adding 11..14: persistent finality proof for non-mandatory header#9 + (TestSourceHeader(false, 9, 9), TestFinalityProof(9)), + // after adding 11..14: ephemeral finality proof for non-mandatory header#14 + (TestSourceHeader(false, 14, 14), TestFinalityProof(14)), + // after adding 15..17: persistent finality proof for non-mandatory header#16 + (TestSourceHeader(false, 16, 16), TestFinalityProof(16)), + ], + ); +} + +fn run_only_mandatory_headers_mode_test( + only_mandatory_headers: bool, + has_mandatory_headers: bool, +) -> Option<(TestSourceHeader, TestFinalityProof)> { + let (exit_sender, _) = futures::channel::mpsc::unbounded(); + let (source_client, target_client) = prepare_test_clients( + exit_sender, + |_| false, + vec![ + (6, (TestSourceHeader(false, 6, 6), Some(TestFinalityProof(6)))), + (7, (TestSourceHeader(false, 7, 7), Some(TestFinalityProof(7)))), + (8, (TestSourceHeader(has_mandatory_headers, 8, 8), Some(TestFinalityProof(8)))), + (9, (TestSourceHeader(false, 9, 9), Some(TestFinalityProof(9)))), + (10, (TestSourceHeader(false, 10, 10), Some(TestFinalityProof(10)))), + ] + .into_iter() + .collect(), + ); + async_std::task::block_on(select_header_to_submit( + &source_client, + &target_client, + &mut RestartableFinalityProofsStream::from(futures::stream::empty().boxed()), + &mut vec![], + 10, + 5, + &FinalitySyncParams { + tick: Duration::from_secs(0), + recent_finality_proofs_limit: 0, + stall_timeout: Duration::from_secs(0), + only_mandatory_headers, + }, + )) + .unwrap() +} + +#[test] +fn select_header_to_submit_skips_non_mandatory_headers_when_only_mandatory_headers_are_required() { + assert_eq!(run_only_mandatory_headers_mode_test(true, false), None); + assert_eq!( + run_only_mandatory_headers_mode_test(false, false), + Some((TestSourceHeader(false, 10, 10), TestFinalityProof(10))), + ); +} + +#[test] +fn select_header_to_submit_selects_mandatory_headers_when_only_mandatory_headers_are_required() { + assert_eq!( + run_only_mandatory_headers_mode_test(true, true), + Some((TestSourceHeader(true, 8, 8), TestFinalityProof(8))), + ); + assert_eq!( + run_only_mandatory_headers_mode_test(false, true), + Some((TestSourceHeader(true, 8, 8), TestFinalityProof(8))), + ); +} + +#[test] +fn select_better_recent_finality_proof_works() { + // if there are no unjustified headers, nothing is changed + assert_eq!( + select_better_recent_finality_proof::( + &[(5, TestFinalityProof(5))], + &mut vec![], + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ), + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ); + + // if there are no recent finality proofs, nothing is changed + assert_eq!( + select_better_recent_finality_proof::( + &[], + &mut vec![TestSourceHeader(false, 5, 5)], + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ), + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ); + + // if there's no intersection between recent finality proofs and unjustified headers, nothing is + // changed + let mut unjustified_headers = + vec![TestSourceHeader(false, 9, 9), TestSourceHeader(false, 10, 10)]; + assert_eq!( + select_better_recent_finality_proof::( + &[(1, TestFinalityProof(1)), (4, TestFinalityProof(4))], + &mut unjustified_headers, + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ), + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ); + + // if there's intersection between recent finality proofs and unjustified headers, but there are + // no proofs in this intersection, nothing is changed + let mut unjustified_headers = vec![ + TestSourceHeader(false, 8, 8), + TestSourceHeader(false, 9, 9), + TestSourceHeader(false, 10, 10), + ]; + assert_eq!( + select_better_recent_finality_proof::( + &[(7, TestFinalityProof(7)), (11, TestFinalityProof(11))], + &mut unjustified_headers, + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ), + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ); + assert_eq!( + unjustified_headers, + vec![ + TestSourceHeader(false, 8, 8), + TestSourceHeader(false, 9, 9), + TestSourceHeader(false, 10, 10) + ] + ); + + // if there's intersection between recent finality proofs and unjustified headers and there's + // a proof in this intersection: + // - this better (last from intersection) proof is selected; + // - 'obsolete' unjustified headers are pruned. + let mut unjustified_headers = vec![ + TestSourceHeader(false, 8, 8), + TestSourceHeader(false, 9, 9), + TestSourceHeader(false, 10, 10), + ]; + assert_eq!( + select_better_recent_finality_proof::( + &[(7, TestFinalityProof(7)), (9, TestFinalityProof(9))], + &mut unjustified_headers, + Some((TestSourceHeader(false, 2, 2), TestFinalityProof(2))), + ), + Some((TestSourceHeader(false, 9, 9), TestFinalityProof(9))), + ); +} + +#[test] +fn read_finality_proofs_from_stream_works() { + // when stream is currently empty, nothing is changed + let mut recent_finality_proofs = vec![(1, TestFinalityProof(1))]; + let mut stream = futures::stream::pending().into(); + read_finality_proofs_from_stream::( + &mut stream, + &mut recent_finality_proofs, + ); + assert_eq!(recent_finality_proofs, vec![(1, TestFinalityProof(1))]); + assert!(!stream.needs_restart); + + // when stream has entry with target, it is added to the recent proofs container + let mut stream = futures::stream::iter(vec![TestFinalityProof(4)]) + .chain(futures::stream::pending()) + .into(); + read_finality_proofs_from_stream::( + &mut stream, + &mut recent_finality_proofs, + ); + assert_eq!(recent_finality_proofs, vec![(1, TestFinalityProof(1)), (4, TestFinalityProof(4))]); + assert!(!stream.needs_restart); + + // when stream has ended, we'll need to restart it + let mut stream = futures::stream::empty().into(); + read_finality_proofs_from_stream::( + &mut stream, + &mut recent_finality_proofs, + ); + assert_eq!(recent_finality_proofs, vec![(1, TestFinalityProof(1)), (4, TestFinalityProof(4))]); + assert!(stream.needs_restart); +} + +#[test] +fn prune_recent_finality_proofs_works() { + let original_recent_finality_proofs: FinalityProofs = vec![ + (10, TestFinalityProof(10)), + (13, TestFinalityProof(13)), + (15, TestFinalityProof(15)), + (17, TestFinalityProof(17)), + (19, TestFinalityProof(19)), + ] + .into_iter() + .collect(); + + // when there's proof for justified header in the vec + let mut recent_finality_proofs = original_recent_finality_proofs.clone(); + prune_recent_finality_proofs::(10, &mut recent_finality_proofs, 1024); + assert_eq!(&original_recent_finality_proofs[1..], recent_finality_proofs,); + + // when there are no proof for justified header in the vec + let mut recent_finality_proofs = original_recent_finality_proofs.clone(); + prune_recent_finality_proofs::(11, &mut recent_finality_proofs, 1024); + assert_eq!(&original_recent_finality_proofs[1..], recent_finality_proofs,); + + // when there are too many entries after initial prune && they also need to be pruned + let mut recent_finality_proofs = original_recent_finality_proofs.clone(); + prune_recent_finality_proofs::(10, &mut recent_finality_proofs, 2); + assert_eq!(&original_recent_finality_proofs[3..], recent_finality_proofs,); + + // when last entry is pruned + let mut recent_finality_proofs = original_recent_finality_proofs.clone(); + prune_recent_finality_proofs::(19, &mut recent_finality_proofs, 2); + assert_eq!(&original_recent_finality_proofs[5..], recent_finality_proofs,); + + // when post-last entry is pruned + let mut recent_finality_proofs = original_recent_finality_proofs.clone(); + prune_recent_finality_proofs::(20, &mut recent_finality_proofs, 2); + assert_eq!(&original_recent_finality_proofs[5..], recent_finality_proofs,); +} + +#[test] +fn different_forks_at_source_and_at_target_are_detected() { + let (exit_sender, _exit_receiver) = futures::channel::mpsc::unbounded(); + let (source_client, target_client) = prepare_test_clients( + exit_sender, + |_| false, + vec![ + (5, (TestSourceHeader(false, 5, 42), None)), + (6, (TestSourceHeader(false, 6, 6), None)), + (7, (TestSourceHeader(false, 7, 7), None)), + (8, (TestSourceHeader(false, 8, 8), None)), + (9, (TestSourceHeader(false, 9, 9), None)), + (10, (TestSourceHeader(false, 10, 10), None)), + ] + .into_iter() + .collect(), + ); + + let mut progress = (Instant::now(), None); + let mut finality_proofs_stream = futures::stream::iter(vec![]).boxed().into(); + let mut recent_finality_proofs = Vec::new(); + let metrics_sync = SyncLoopMetrics::new(None, "source", "target").unwrap(); + async_std::task::block_on(run_loop_iteration::( + &source_client, + &target_client, + FinalityLoopState { + progress: &mut progress, + finality_proofs_stream: &mut finality_proofs_stream, + recent_finality_proofs: &mut recent_finality_proofs, + submitted_header_number: None, + }, + &test_sync_params(), + &Some(metrics_sync.clone()), + )) + .unwrap(); + + assert!(!metrics_sync.is_using_same_fork()); +} + +#[test] +fn stalls_when_transaction_tracker_returns_error() { + let (_, result) = run_sync_loop(|data| { + data.target_transaction_tracker = TestTransactionTracker(TrackedTransactionStatus::Lost); + data.target_best_block_id = HeaderId(5, 5); + data.target_best_block_id.0 == 16 + }); + + assert_eq!(result, Err(FailedClient::Both)); +} + +#[test] +fn stalls_when_transaction_tracker_returns_finalized_but_transaction_fails() { + let (_, result) = run_sync_loop(|data| { + data.target_best_block_id = HeaderId(5, 5); + data.target_best_block_id.0 == 16 + }); + + assert_eq!(result, Err(FailedClient::Both)); +} diff --git a/relays/finality/src/lib.rs b/relays/finality/src/lib.rs new file mode 100644 index 00000000000..dca47c6a572 --- /dev/null +++ b/relays/finality/src/lib.rs @@ -0,0 +1,61 @@ +// Copyright 2019-2021 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 . + +//! This crate has single entrypoint to run synchronization loop that is built around finality +//! proofs, as opposed to headers synchronization loop, which is built around headers. The headers +//! are still submitted to the target node, but are treated as auxiliary data as we are not trying +//! to submit all source headers to the target node. + +pub use crate::{ + finality_loop::{metrics_prefix, run, FinalitySyncParams, SourceClient, TargetClient}, + sync_loop_metrics::SyncLoopMetrics, +}; + +use bp_header_chain::{ConsensusLogReader, FinalityProof}; +use std::fmt::Debug; + +mod finality_loop; +mod finality_loop_tests; +mod sync_loop_metrics; + +/// Finality proofs synchronization pipeline. +pub trait FinalitySyncPipeline: 'static + Clone + Debug + Send + Sync { + /// Name of the finality proofs source. + const SOURCE_NAME: &'static str; + /// Name of the finality proofs target. + const TARGET_NAME: &'static str; + + /// Headers we're syncing are identified by this hash. + type Hash: Eq + Clone + Copy + Send + Sync + Debug; + /// Headers we're syncing are identified by this number. + type Number: relay_utils::BlockNumberBase; + /// A reader that can extract the consensus log from the header digest and interpret it. + type ConsensusLogReader: ConsensusLogReader; + /// Type of header that we're syncing. + type Header: SourceHeader; + /// Finality proof type. + type FinalityProof: FinalityProof; +} + +/// Header that we're receiving from source node. +pub trait SourceHeader: Clone + Debug + PartialEq + Send + Sync { + /// Returns hash of header. + fn hash(&self) -> Hash; + /// Returns number of header. + fn number(&self) -> Number; + /// Returns true if this header needs to be submitted to target node. + fn is_mandatory(&self) -> bool; +} diff --git a/relays/finality/src/sync_loop_metrics.rs b/relays/finality/src/sync_loop_metrics.rs new file mode 100644 index 00000000000..4da1df811f6 --- /dev/null +++ b/relays/finality/src/sync_loop_metrics.rs @@ -0,0 +1,95 @@ +// Copyright 2019-2021 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 . + +//! Metrics for headers synchronization relay loop. + +use relay_utils::{ + metrics::{metric_name, register, IntGauge, Metric, PrometheusError, Registry}, + UniqueSaturatedInto, +}; + +/// Headers sync metrics. +#[derive(Clone)] +pub struct SyncLoopMetrics { + /// Best syncing header at the source. + best_source_block_number: IntGauge, + /// Best syncing header at the target. + best_target_block_number: IntGauge, + /// Flag that has `0` value when best source headers at the source node and at-target-chain + /// are matching and `1` otherwise. + using_different_forks: IntGauge, +} + +impl SyncLoopMetrics { + /// Create and register headers loop metrics. + pub fn new( + prefix: Option<&str>, + at_source_chain_label: &str, + at_target_chain_label: &str, + ) -> Result { + Ok(SyncLoopMetrics { + best_source_block_number: IntGauge::new( + metric_name(prefix, &format!("best_{at_source_chain_label}_block_number")), + format!("Best block number at the {at_source_chain_label}"), + )?, + best_target_block_number: IntGauge::new( + metric_name(prefix, &format!("best_{at_target_chain_label}_block_number")), + format!("Best block number at the {at_target_chain_label}"), + )?, + using_different_forks: IntGauge::new( + metric_name(prefix, &format!("is_{at_source_chain_label}_and_{at_target_chain_label}_using_different_forks")), + "Whether the best finalized source block at target node is different (value 1) from the \ + corresponding block at the source node", + )?, + }) + } + + /// Returns current value of the using-same-fork flag. + #[cfg(test)] + pub(crate) fn is_using_same_fork(&self) -> bool { + self.using_different_forks.get() == 0 + } + + /// Update best block number at source. + pub fn update_best_block_at_source>( + &self, + source_best_number: Number, + ) { + self.best_source_block_number.set(source_best_number.unique_saturated_into()); + } + + /// Update best block number at target. + pub fn update_best_block_at_target>( + &self, + target_best_number: Number, + ) { + self.best_target_block_number.set(target_best_number.unique_saturated_into()); + } + + /// Update using-same-fork flag. + pub fn update_using_same_fork(&self, using_same_fork: bool) { + self.using_different_forks.set((!using_same_fork).into()) + } +} + +impl Metric for SyncLoopMetrics { + fn register(&self, registry: &Registry) -> Result<(), PrometheusError> { + register(self.best_source_block_number.clone(), registry)?; + register(self.best_target_block_number.clone(), registry)?; + register(self.using_different_forks.clone(), registry)?; + Ok(()) + } +} diff --git a/relays/lib-substrate-relay/Cargo.toml b/relays/lib-substrate-relay/Cargo.toml new file mode 100644 index 00000000000..d07aa936b57 --- /dev/null +++ b/relays/lib-substrate-relay/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "substrate-relay-helper" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +anyhow = "1.0" +thiserror = "1.0.40" +async-std = "1.9.0" +async-trait = "0.1" +codec = { package = "parity-scale-codec", version = "3.1.5" } +futures = "0.3.28" +hex = "0.4" +num-traits = "0.2" +log = "0.4.17" + +# Bridge dependencies + +bp-header-chain = { path = "../../primitives/header-chain" } +bp-parachains = { path = "../../primitives/parachains" } +bp-polkadot-core = { path = "../../primitives/polkadot-core" } +bp-relayers = { path = "../../primitives/relayers" } +bridge-runtime-common = { path = "../../bin/runtime-common" } + +finality-grandpa = { version = "0.16.2" } +finality-relay = { path = "../finality" } +parachains-relay = { path = "../parachains" } +relay-utils = { path = "../utils" } +messages-relay = { path = "../messages" } +relay-substrate-client = { path = "../client-substrate" } + +pallet-bridge-grandpa = { path = "../../modules/grandpa" } +pallet-bridge-messages = { path = "../../modules/messages" } +pallet-bridge-parachains = { path = "../../modules/parachains" } + +bp-runtime = { path = "../../primitives/runtime" } +bp-messages = { path = "../../primitives/messages" } + +# Substrate Dependencies + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } + +[dev-dependencies] +bp-rialto = { path = "../../primitives/chain-rialto" } +bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" } +bp-rococo = { path = "../../primitives/chain-rococo" } +bp-wococo = { path = "../../primitives/chain-wococo" } +pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } +relay-rialto-client = { path = "../client-rialto" } +relay-rococo-client = { path = "../client-rococo" } +relay-wococo-client = { path = "../client-wococo" } +rialto-runtime = { path = "../../bin/rialto/runtime" } diff --git a/relays/lib-substrate-relay/src/error.rs b/relays/lib-substrate-relay/src/error.rs new file mode 100644 index 00000000000..2ebd9130f39 --- /dev/null +++ b/relays/lib-substrate-relay/src/error.rs @@ -0,0 +1,63 @@ +// Copyright 2019-2021 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 . + +//! Relay errors. + +use relay_substrate_client as client; +use sp_consensus_grandpa::AuthorityList; +use sp_runtime::traits::MaybeDisplay; +use std::fmt::Debug; +use thiserror::Error; + +/// Relay errors. +#[derive(Error, Debug)] +pub enum Error { + /// Failed to submit signed extrinsic from to the target chain. + #[error("Failed to submit {0} transaction: {1:?}")] + SubmitTransaction(&'static str, client::Error), + /// Failed subscribe to justification stream of the source chain. + #[error("Failed to subscribe to {0} justifications: {1:?}")] + Subscribe(&'static str, client::Error), + /// Failed subscribe to read justification from the source chain (client error). + #[error("Failed to read {0} justification from the stream: {1}")] + ReadJustification(&'static str, client::Error), + /// Failed subscribe to read justification from the source chain (stream ended). + #[error("Failed to read {0} justification from the stream: stream has ended unexpectedly")] + ReadJustificationStreamEnded(&'static str), + /// Failed subscribe to decode justification from the source chain. + #[error("Failed to decode {0} justification: {1:?}")] + DecodeJustification(&'static str, codec::Error), + /// GRANDPA authorities read from the source chain are invalid. + #[error("Read invalid {0} authorities set: {1:?}")] + ReadInvalidAuthorities(&'static str, AuthorityList), + /// Failed to guess initial GRANDPA authorities at the given header of the source chain. + #[error("Failed to guess initial {0} GRANDPA authorities set id: checked all possible ids in range [0; {1}]")] + GuessInitialAuthorities(&'static str, HeaderNumber), + /// Failed to retrieve GRANDPA authorities at the given header from the source chain. + #[error("Failed to retrive {0} GRANDPA authorities set at header {1}: {2:?}")] + RetrieveAuthorities(&'static str, Hash, client::Error), + /// Failed to decode GRANDPA authorities at the given header of the source chain. + #[error("Failed to decode {0} GRANDPA authorities set at header {1}: {2:?}")] + DecodeAuthorities(&'static str, Hash, codec::Error), + /// Failed to retrieve header by the hash from the source chain. + #[error("Failed to retrieve {0} header with hash {1}: {2:?}")] + RetrieveHeader(&'static str, Hash, client::Error), + /// Failed to submit signed extrinsic from to the target chain. + #[error( + "Failed to retrieve `is_initialized` flag of the with-{0} finality pallet at {1}: {2:?}" + )] + IsInitializedRetrieve(&'static str, &'static str, client::Error), +} diff --git a/relays/lib-substrate-relay/src/finality/engine.rs b/relays/lib-substrate-relay/src/finality/engine.rs new file mode 100644 index 00000000000..f2ddd32db86 --- /dev/null +++ b/relays/lib-substrate-relay/src/finality/engine.rs @@ -0,0 +1,308 @@ +// Copyright 2019-2021 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 . + +//! Support of different finality engines, available in Substrate. + +use crate::error::Error; +use async_trait::async_trait; +use bp_header_chain::{ + justification::{verify_and_optimize_justification, GrandpaJustification}, + ConsensusLogReader, FinalityProof, GrandpaConsensusLogReader, +}; +use bp_runtime::{BasicOperatingMode, HeaderIdProvider, OperatingMode}; +use codec::{Decode, Encode}; +use finality_grandpa::voter_set::VoterSet; +use num_traits::{One, Zero}; +use relay_substrate_client::{ + BlockNumberOf, Chain, ChainWithGrandpa, Client, Error as SubstrateError, HashOf, HeaderOf, + Subscription, SubstrateFinalityClient, SubstrateGrandpaFinalityClient, +}; +use sp_consensus_grandpa::{AuthorityList as GrandpaAuthoritiesSet, GRANDPA_ENGINE_ID}; +use sp_core::{storage::StorageKey, Bytes}; +use sp_runtime::{traits::Header, ConsensusEngineId}; +use std::marker::PhantomData; + +/// Finality engine, used by the Substrate chain. +#[async_trait] +pub trait Engine: Send { + /// Unique consensus engine identifier. + const ID: ConsensusEngineId; + /// A reader that can extract the consensus log from the header digest and interpret it. + type ConsensusLogReader: ConsensusLogReader; + /// Type of Finality RPC client used by this engine. + type FinalityClient: SubstrateFinalityClient; + /// Type of finality proofs, used by consensus engine. + type FinalityProof: FinalityProof> + Decode + Encode; + /// Type of bridge pallet initialization data. + type InitializationData: std::fmt::Debug + Send + Sync + 'static; + /// Type of bridge pallet operating mode. + type OperatingMode: OperatingMode + 'static; + + /// Returns storage at the bridged (target) chain that corresponds to some value that is + /// missing from the storage until bridge pallet is initialized. + /// + /// Note that we don't care about type of the value - just if it present or not. + fn is_initialized_key() -> StorageKey; + + /// Returns `Ok(true)` if finality pallet at the bridged chain has already been initialized. + async fn is_initialized( + target_client: &Client, + ) -> Result { + Ok(target_client + .raw_storage_value(Self::is_initialized_key(), None) + .await? + .is_some()) + } + + /// Returns storage key at the bridged (target) chain that corresponds to the variable + /// that holds the operating mode of the pallet. + fn pallet_operating_mode_key() -> StorageKey; + + /// Returns `Ok(true)` if finality pallet at the bridged chain is halted. + async fn is_halted( + target_client: &Client, + ) -> Result { + Ok(target_client + .storage_value::(Self::pallet_operating_mode_key(), None) + .await? + .map(|operating_mode| operating_mode.is_halted()) + .unwrap_or(false)) + } + + /// A method to subscribe to encoded finality proofs, given source client. + async fn finality_proofs(client: &Client) -> Result, SubstrateError> { + client.subscribe_finality_justifications::().await + } + + /// Optimize finality proof before sending it to the target node. + async fn optimize_proof( + target_client: &Client, + header: &C::Header, + proof: Self::FinalityProof, + ) -> Result; + + /// Prepare initialization data for the finality bridge pallet. + async fn prepare_initialization_data( + client: Client, + ) -> Result, BlockNumberOf>>; +} + +/// GRANDPA finality engine. +pub struct Grandpa(PhantomData); + +impl Grandpa { + /// Read header by hash from the source client. + async fn source_header( + source_client: &Client, + header_hash: C::Hash, + ) -> Result, BlockNumberOf>> { + source_client + .header_by_hash(header_hash) + .await + .map_err(|err| Error::RetrieveHeader(C::NAME, header_hash, err)) + } + + /// Read GRANDPA authorities set at given header. + async fn source_authorities_set( + source_client: &Client, + header_hash: C::Hash, + ) -> Result, BlockNumberOf>> { + let raw_authorities_set = source_client + .grandpa_authorities_set(header_hash) + .await + .map_err(|err| Error::RetrieveAuthorities(C::NAME, header_hash, err))?; + GrandpaAuthoritiesSet::decode(&mut &raw_authorities_set[..]) + .map_err(|err| Error::DecodeAuthorities(C::NAME, header_hash, err)) + } +} + +#[async_trait] +impl Engine for Grandpa { + const ID: ConsensusEngineId = GRANDPA_ENGINE_ID; + type ConsensusLogReader = GrandpaConsensusLogReader<::Number>; + type FinalityClient = SubstrateGrandpaFinalityClient; + type FinalityProof = GrandpaJustification>; + type InitializationData = bp_header_chain::InitializationData; + type OperatingMode = BasicOperatingMode; + + fn is_initialized_key() -> StorageKey { + bp_header_chain::storage_keys::best_finalized_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME) + } + + fn pallet_operating_mode_key() -> StorageKey { + bp_header_chain::storage_keys::pallet_operating_mode_key(C::WITH_CHAIN_GRANDPA_PALLET_NAME) + } + + async fn optimize_proof( + target_client: &Client, + header: &C::Header, + proof: Self::FinalityProof, + ) -> Result { + let current_authority_set_key = bp_header_chain::storage_keys::current_authority_set_key( + C::WITH_CHAIN_GRANDPA_PALLET_NAME, + ); + let (authority_set, authority_set_id): ( + sp_consensus_grandpa::AuthorityList, + sp_consensus_grandpa::SetId, + ) = target_client + .storage_value(current_authority_set_key, None) + .await? + .map(Ok) + .unwrap_or(Err(SubstrateError::Custom(format!( + "{} `CurrentAuthoritySet` is missing from the {} storage", + C::NAME, + TargetChain::NAME, + ))))?; + let authority_set = + finality_grandpa::voter_set::VoterSet::new(authority_set).expect("TODO"); + // we're risking with race here - we have decided to submit justification some time ago and + // actual authorities set (which we have read now) may have changed, so this + // `optimize_justification` may fail. But if target chain is configured properly, it'll fail + // anyway, after we submit transaction and failing earlier is better. So - it is fine + verify_and_optimize_justification( + (header.hash(), *header.number()), + authority_set_id, + &authority_set, + proof, + ) + .map_err(|e| { + SubstrateError::Custom(format!( + "Failed to optimize {} GRANDPA jutification for header {:?}: {:?}", + C::NAME, + header.id(), + e, + )) + }) + } + + /// Prepare initialization data for the GRANDPA verifier pallet. + async fn prepare_initialization_data( + source_client: Client, + ) -> Result, BlockNumberOf>> { + // In ideal world we just need to get best finalized header and then to read GRANDPA + // authorities set (`pallet_grandpa::CurrentSetId` + `GrandpaApi::grandpa_authorities()`) at + // this header. + // + // But now there are problems with this approach - `CurrentSetId` may return invalid value. + // So here we're waiting for the next justification, read the authorities set and then try + // to figure out the set id with bruteforce. + let justifications = Self::finality_proofs(&source_client) + .await + .map_err(|err| Error::Subscribe(C::NAME, err))?; + // Read next justification - the header that it finalizes will be used as initial header. + let justification = justifications + .next() + .await + .map_err(|e| Error::ReadJustification(C::NAME, e)) + .and_then(|justification| { + justification.ok_or(Error::ReadJustificationStreamEnded(C::NAME)) + })?; + + // Read initial header. + let justification: GrandpaJustification = + Decode::decode(&mut &justification.0[..]) + .map_err(|err| Error::DecodeJustification(C::NAME, err))?; + + let (initial_header_hash, initial_header_number) = + (justification.commit.target_hash, justification.commit.target_number); + + let initial_header = Self::source_header(&source_client, initial_header_hash).await?; + log::trace!(target: "bridge", "Selected {} initial header: {}/{}", + C::NAME, + initial_header_number, + initial_header_hash, + ); + + // Read GRANDPA authorities set at initial header. + let initial_authorities_set = + Self::source_authorities_set(&source_client, initial_header_hash).await?; + log::trace!(target: "bridge", "Selected {} initial authorities set: {:?}", + C::NAME, + initial_authorities_set, + ); + + // If initial header changes the GRANDPA authorities set, then we need previous authorities + // to verify justification. + let mut authorities_for_verification = initial_authorities_set.clone(); + let scheduled_change = + GrandpaConsensusLogReader::>::find_authorities_change( + initial_header.digest(), + ); + assert!( + scheduled_change.as_ref().map(|c| c.delay.is_zero()).unwrap_or(true), + "GRANDPA authorities change at {} scheduled to happen in {:?} blocks. We expect\ + regular change to have zero delay", + initial_header_hash, + scheduled_change.as_ref().map(|c| c.delay), + ); + let schedules_change = scheduled_change.is_some(); + if schedules_change { + authorities_for_verification = + Self::source_authorities_set(&source_client, *initial_header.parent_hash()).await?; + log::trace!( + target: "bridge", + "Selected {} header is scheduling GRANDPA authorities set changes. Using previous set: {:?}", + C::NAME, + authorities_for_verification, + ); + } + + // Now let's try to guess authorities set id by verifying justification. + let mut initial_authorities_set_id = 0; + let mut min_possible_block_number = C::BlockNumber::zero(); + let authorities_for_verification = VoterSet::new(authorities_for_verification.clone()) + .ok_or(Error::ReadInvalidAuthorities(C::NAME, authorities_for_verification))?; + loop { + log::trace!( + target: "bridge", "Trying {} GRANDPA authorities set id: {}", + C::NAME, + initial_authorities_set_id, + ); + + let is_valid_set_id = verify_and_optimize_justification( + (initial_header_hash, initial_header_number), + initial_authorities_set_id, + &authorities_for_verification, + justification.clone(), + ) + .is_ok(); + + if is_valid_set_id { + break + } + + initial_authorities_set_id += 1; + min_possible_block_number += One::one(); + if min_possible_block_number > initial_header_number { + // there can't be more authorities set changes than headers => if we have reached + // `initial_block_number` and still have not found correct value of + // `initial_authorities_set_id`, then something else is broken => fail + return Err(Error::GuessInitialAuthorities(C::NAME, initial_header_number)) + } + } + + Ok(bp_header_chain::InitializationData { + header: Box::new(initial_header), + authority_list: initial_authorities_set, + set_id: if schedules_change { + initial_authorities_set_id + 1 + } else { + initial_authorities_set_id + }, + operating_mode: BasicOperatingMode::Normal, + }) + } +} diff --git a/relays/lib-substrate-relay/src/finality/guards.rs b/relays/lib-substrate-relay/src/finality/guards.rs new file mode 100644 index 00000000000..188a03733a3 --- /dev/null +++ b/relays/lib-substrate-relay/src/finality/guards.rs @@ -0,0 +1,48 @@ +// Copyright 2019-2021 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 . + +//! Tools for starting guards of finality relays. + +use crate::TransactionParams; + +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, ChainWithBalances, ChainWithTransactions, +}; +use sp_core::Pair; + +/// Start finality relay guards. +pub async fn start( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams>, + enable_version_guard: bool, + maximal_balance_decrease_per_day: C::Balance, +) -> relay_substrate_client::Result<()> +where + AccountIdOf: From< as Pair>::Public>, +{ + if enable_version_guard { + relay_substrate_client::guard::abort_on_spec_version_change( + target_client.clone(), + target_client.simple_runtime_version().await?.spec_version, + ); + } + relay_substrate_client::guard::abort_when_account_balance_decreased( + target_client.clone(), + transaction_params.signer.public().into(), + maximal_balance_decrease_per_day, + ); + Ok(()) +} diff --git a/relays/lib-substrate-relay/src/finality/initialize.rs b/relays/lib-substrate-relay/src/finality/initialize.rs new file mode 100644 index 00000000000..87052cf7aa4 --- /dev/null +++ b/relays/lib-substrate-relay/src/finality/initialize.rs @@ -0,0 +1,163 @@ +// Copyright 2019-2021 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 . + +//! Initialize Substrate -> Substrate finality bridge. +//! +//! Initialization is a transaction that calls `initialize()` function of the +//! finality pallet (GRANDPA/BEEFY/...). This transaction brings initial header +//! and authorities set from source to target chain. The finality sync starts +//! with this header. + +use crate::{error::Error, finality::engine::Engine}; +use sp_core::Pair; + +use bp_runtime::HeaderIdOf; +use relay_substrate_client::{ + AccountKeyPairOf, Chain, ChainWithTransactions, Client, Error as SubstrateError, + UnsignedTransaction, +}; +use relay_utils::{TrackedTransactionStatus, TransactionTracker}; +use sp_runtime::traits::Header as HeaderT; + +/// Submit headers-bridge initialization transaction. +pub async fn initialize< + E: Engine, + SourceChain: Chain, + TargetChain: ChainWithTransactions, + F, +>( + source_client: Client, + target_client: Client, + target_signer: AccountKeyPairOf, + prepare_initialize_transaction: F, + dry_run: bool, +) where + F: FnOnce( + TargetChain::Index, + E::InitializationData, + ) -> Result, SubstrateError> + + Send + + 'static, + TargetChain::AccountId: From<::Public>, +{ + let result = do_initialize::( + source_client, + target_client, + target_signer, + prepare_initialize_transaction, + dry_run, + ) + .await; + + match result { + Ok(Some(tx_status)) => match tx_status { + TrackedTransactionStatus::Lost => { + log::error!( + target: "bridge", + "Failed to execute {}-headers bridge initialization transaction on {}: {:?}.", + SourceChain::NAME, + TargetChain::NAME, + tx_status + ) + }, + TrackedTransactionStatus::Finalized(_) => { + log::info!( + target: "bridge", + "Successfully executed {}-headers bridge initialization transaction on {}: {:?}.", + SourceChain::NAME, + TargetChain::NAME, + tx_status + ) + }, + }, + Ok(None) => (), + Err(err) => log::error!( + target: "bridge", + "Failed to submit {}-headers bridge initialization transaction to {}: {:?}", + SourceChain::NAME, + TargetChain::NAME, + err, + ), + } +} + +/// Craft and submit initialization transaction, returning any error that may occur. +async fn do_initialize< + E: Engine, + SourceChain: Chain, + TargetChain: ChainWithTransactions, + F, +>( + source_client: Client, + target_client: Client, + target_signer: AccountKeyPairOf, + prepare_initialize_transaction: F, + dry_run: bool, +) -> Result< + Option>>, + Error::Number>, +> +where + F: FnOnce( + TargetChain::Index, + E::InitializationData, + ) -> Result, SubstrateError> + + Send + + 'static, + TargetChain::AccountId: From<::Public>, +{ + let is_initialized = E::is_initialized(&target_client) + .await + .map_err(|e| Error::IsInitializedRetrieve(SourceChain::NAME, TargetChain::NAME, e))?; + if is_initialized { + log::info!( + target: "bridge", + "{}-headers bridge at {} is already initialized. Skipping", + SourceChain::NAME, + TargetChain::NAME, + ); + if !dry_run { + return Ok(None) + } + } + + let initialization_data = E::prepare_initialization_data(source_client).await?; + log::info!( + target: "bridge", + "Prepared initialization data for {}-headers bridge at {}: {:?}", + SourceChain::NAME, + TargetChain::NAME, + initialization_data, + ); + + let tx_status = target_client + .submit_and_watch_signed_extrinsic(&target_signer, move |_, transaction_nonce| { + let tx = prepare_initialize_transaction(transaction_nonce, initialization_data); + if dry_run { + Err(SubstrateError::Custom( + "Not submitting extrinsic in `dry-run` mode!".to_string(), + )) + } else { + tx + } + }) + .await + .map_err(|err| Error::SubmitTransaction(TargetChain::NAME, err))? + .wait() + .await; + + Ok(Some(tx_status)) +} diff --git a/relays/lib-substrate-relay/src/finality/mod.rs b/relays/lib-substrate-relay/src/finality/mod.rs new file mode 100644 index 00000000000..b0f0ee4e52c --- /dev/null +++ b/relays/lib-substrate-relay/src/finality/mod.rs @@ -0,0 +1,209 @@ +// Copyright 2019-2021 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 . + +//! Types and functions intended to ease adding of new Substrate -> Substrate +//! finality proofs synchronization pipelines. + +use crate::{ + finality::{ + engine::Engine, + source::{SubstrateFinalityProof, SubstrateFinalitySource}, + target::SubstrateFinalityTarget, + }, + TransactionParams, +}; + +use async_trait::async_trait; +use bp_header_chain::justification::GrandpaJustification; +use finality_relay::FinalitySyncPipeline; +use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; +use relay_substrate_client::{ + transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, + ChainWithTransactions, Client, HashOf, HeaderOf, SyncHeader, +}; +use relay_utils::metrics::MetricsParams; +use sp_core::Pair; +use std::{fmt::Debug, marker::PhantomData}; + +pub mod engine; +pub mod guards; +pub mod initialize; +pub mod source; +pub mod target; + +/// Default limit of recent finality proofs. +/// +/// Finality delay of 4096 blocks is unlikely to happen in practice in +/// Substrate+GRANDPA based chains (good to know). +pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096; + +/// Substrate -> Substrate finality proofs synchronization pipeline. +#[async_trait] +pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync { + /// Headers of this chain are submitted to the `TargetChain`. + type SourceChain: Chain; + /// Headers of the `SourceChain` are submitted to this chain. + type TargetChain: ChainWithTransactions; + + /// Finality engine. + type FinalityEngine: Engine; + /// How submit finality proof call is built? + type SubmitFinalityProofCallBuilder: SubmitFinalityProofCallBuilder; + + /// Add relay guards if required. + async fn start_relay_guards( + _target_client: &Client, + _transaction_params: &TransactionParams>, + _enable_version_guard: bool, + ) -> relay_substrate_client::Result<()> { + Ok(()) + } +} + +/// Adapter that allows all `SubstrateFinalitySyncPipeline` to act as `FinalitySyncPipeline`. +#[derive(Clone, Debug)] +pub struct FinalitySyncPipelineAdapter { + _phantom: PhantomData

, +} + +impl FinalitySyncPipeline for FinalitySyncPipelineAdapter

{ + const SOURCE_NAME: &'static str = P::SourceChain::NAME; + const TARGET_NAME: &'static str = P::TargetChain::NAME; + + type Hash = HashOf; + type Number = BlockNumberOf; + type ConsensusLogReader = >::ConsensusLogReader; + type Header = SyncHeader>; + type FinalityProof = SubstrateFinalityProof

; +} + +/// Different ways of building `submit_finality_proof` calls. +pub trait SubmitFinalityProofCallBuilder { + /// Given source chain header and its finality proofs, build call of `submit_finality_proof` + /// function of bridge GRANDPA module at the target chain. + fn build_submit_finality_proof_call( + header: SyncHeader>, + proof: SubstrateFinalityProof

, + ) -> CallOf; +} + +/// Building `submit_finality_proof` call when you have direct access to the target +/// chain runtime. +pub struct DirectSubmitGrandpaFinalityProofCallBuilder { + _phantom: PhantomData<(P, R, I)>, +} + +impl SubmitFinalityProofCallBuilder

+ for DirectSubmitGrandpaFinalityProofCallBuilder +where + P: SubstrateFinalitySyncPipeline, + R: BridgeGrandpaConfig, + I: 'static, + R::BridgedChain: bp_runtime::Chain

>, + CallOf: From>, + P::FinalityEngine: + Engine>>, +{ + fn build_submit_finality_proof_call( + header: SyncHeader>, + proof: GrandpaJustification>, + ) -> CallOf { + BridgeGrandpaCall::::submit_finality_proof { + finality_target: Box::new(header.into_inner()), + justification: proof, + } + .into() + } +} + +/// Macro that generates `SubmitFinalityProofCallBuilder` implementation for the case when +/// you only have an access to the mocked version of target chain runtime. In this case you +/// should provide "name" of the call variant for the bridge GRANDPA calls and the "name" of +/// the variant for the `submit_finality_proof` call within that first option. +#[rustfmt::skip] +#[macro_export] +macro_rules! generate_submit_finality_proof_call_builder { + ($pipeline:ident, $mocked_builder:ident, $bridge_grandpa:path, $submit_finality_proof:path) => { + pub struct $mocked_builder; + + impl $crate::finality::SubmitFinalityProofCallBuilder<$pipeline> + for $mocked_builder + { + fn build_submit_finality_proof_call( + header: relay_substrate_client::SyncHeader< + relay_substrate_client::HeaderOf< + <$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::SourceChain + > + >, + proof: bp_header_chain::justification::GrandpaJustification< + relay_substrate_client::HeaderOf< + <$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::SourceChain + > + >, + ) -> relay_substrate_client::CallOf< + <$pipeline as $crate::finality::SubstrateFinalitySyncPipeline>::TargetChain + > { + bp_runtime::paste::item! { + $bridge_grandpa($submit_finality_proof { + finality_target: Box::new(header.into_inner()), + justification: proof + }) + } + } + } + }; +} + +/// Run Substrate-to-Substrate finality sync loop. +pub async fn run( + source_client: Client, + target_client: Client, + only_mandatory_headers: bool, + transaction_params: TransactionParams>, + metrics_params: MetricsParams, +) -> anyhow::Result<()> +where + AccountIdOf: From< as Pair>::Public>, +{ + log::info!( + target: "bridge", + "Starting {} -> {} finality proof relay", + P::SourceChain::NAME, + P::TargetChain::NAME, + ); + + finality_relay::run( + SubstrateFinalitySource::

::new(source_client, None), + SubstrateFinalityTarget::

::new(target_client, transaction_params.clone()), + finality_relay::FinalitySyncParams { + tick: std::cmp::max( + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + ), + recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, + stall_timeout: transaction_stall_timeout( + transaction_params.mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + relay_utils::STALL_TIMEOUT, + ), + only_mandatory_headers, + }, + metrics_params, + futures::future::pending(), + ) + .await + .map_err(|e| anyhow::format_err!("{}", e)) +} diff --git a/relays/lib-substrate-relay/src/finality/source.rs b/relays/lib-substrate-relay/src/finality/source.rs new file mode 100644 index 00000000000..c8f11d99461 --- /dev/null +++ b/relays/lib-substrate-relay/src/finality/source.rs @@ -0,0 +1,298 @@ +// Copyright 2019-2021 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 . + +//! Default generic implementation of finality source for basic Substrate client. + +use crate::finality::{engine::Engine, FinalitySyncPipelineAdapter, SubstrateFinalitySyncPipeline}; + +use async_std::sync::{Arc, Mutex}; +use async_trait::async_trait; +use bp_header_chain::FinalityProof; +use codec::Decode; +use finality_relay::SourceClient; +use futures::{ + select, + stream::{try_unfold, unfold, Stream, StreamExt, TryStreamExt}, +}; +use num_traits::One; +use relay_substrate_client::{ + BlockNumberOf, BlockWithJustification, Chain, Client, Error, HeaderOf, +}; +use relay_utils::{relay_loop::Client as RelayClient, UniqueSaturatedInto}; +use std::pin::Pin; + +/// Shared updatable reference to the maximal header number that we want to sync from the source. +pub type RequiredHeaderNumberRef = Arc::BlockNumber>>; + +/// Substrate finality proofs stream. +pub type SubstrateFinalityProofsStream

= + Pin> + Send>>; + +/// Substrate finality proof. Specific to the used `FinalityEngine`. +pub type SubstrateFinalityProof

= + <

::FinalityEngine as Engine< +

::SourceChain, + >>::FinalityProof; + +/// Substrate node as finality source. +pub struct SubstrateFinalitySource { + client: Client, + maximal_header_number: Option>, +} + +impl SubstrateFinalitySource

{ + /// Create new headers source using given client. + pub fn new( + client: Client, + maximal_header_number: Option>, + ) -> Self { + SubstrateFinalitySource { client, maximal_header_number } + } + + /// Returns reference to the underlying RPC client. + pub fn client(&self) -> &Client { + &self.client + } + + /// Returns best finalized block number. + pub async fn on_chain_best_finalized_block_number( + &self, + ) -> Result, Error> { + // we **CAN** continue to relay finality proofs if source node is out of sync, because + // target node may be missing proofs that are already available at the source + self.client.best_finalized_header_number().await + } + + /// Return header and its justification of the given block or its descendant that + /// has a GRANDPA justification. + /// + /// This method is optimized for cases when `block_number` is close to the best finalized + /// chain block. + pub async fn prove_block_finality( + &self, + block_number: BlockNumberOf, + ) -> Result< + (relay_substrate_client::SyncHeader>, SubstrateFinalityProof

), + Error, + > { + // first, subscribe to proofs + let next_persistent_proof = + self.persistent_proofs_stream(block_number + One::one()).await?.fuse(); + let next_ephemeral_proof = self.ephemeral_proofs_stream(block_number).await?.fuse(); + + // in perfect world we'll need to return justfication for the requested `block_number` + let (header, maybe_proof) = self.header_and_finality_proof(block_number).await?; + if let Some(proof) = maybe_proof { + return Ok((header, proof)) + } + + // otherwise we don't care which header to return, so let's select first + futures::pin_mut!(next_persistent_proof, next_ephemeral_proof); + loop { + select! { + maybe_header_and_proof = next_persistent_proof.next() => match maybe_header_and_proof { + Some(header_and_proof) => return header_and_proof, + None => continue, + }, + maybe_header_and_proof = next_ephemeral_proof.next() => match maybe_header_and_proof { + Some(header_and_proof) => return header_and_proof, + None => continue, + }, + complete => return Err(Error::FinalityProofNotFound(block_number.unique_saturated_into())) + } + } + } + + /// Returns stream of headers and their persistent proofs, starting from given block. + async fn persistent_proofs_stream( + &self, + block_number: BlockNumberOf, + ) -> Result< + impl Stream< + Item = Result< + ( + relay_substrate_client::SyncHeader>, + SubstrateFinalityProof

, + ), + Error, + >, + >, + Error, + > { + let client = self.client.clone(); + let best_finalized_block_number = self.client.best_finalized_header_number().await?; + Ok(try_unfold((client, block_number), move |(client, current_block_number)| async move { + // if we've passed the `best_finalized_block_number`, we no longer need persistent + // justifications + if current_block_number > best_finalized_block_number { + return Ok(None) + } + + let (header, maybe_proof) = + header_and_finality_proof::

(&client, current_block_number).await?; + let next_block_number = current_block_number + One::one(); + let next_state = (client, next_block_number); + + Ok(Some((maybe_proof.map(|proof| (header, proof)), next_state))) + }) + .try_filter_map(|maybe_result| async { Ok(maybe_result) })) + } + + /// Returns stream of headers and their ephemeral proofs, starting from given block. + async fn ephemeral_proofs_stream( + &self, + block_number: BlockNumberOf, + ) -> Result< + impl Stream< + Item = Result< + ( + relay_substrate_client::SyncHeader>, + SubstrateFinalityProof

, + ), + Error, + >, + >, + Error, + > { + let client = self.client.clone(); + Ok(self.finality_proofs().await?.map(Ok).try_filter_map(move |proof| { + let client = client.clone(); + async move { + if proof.target_header_number() < block_number { + return Ok(None) + } + + let header = client.header_by_number(proof.target_header_number()).await?; + Ok(Some((header.into(), proof))) + } + })) + } +} + +impl Clone for SubstrateFinalitySource

{ + fn clone(&self) -> Self { + SubstrateFinalitySource { + client: self.client.clone(), + maximal_header_number: self.maximal_header_number.clone(), + } + } +} + +#[async_trait] +impl RelayClient for SubstrateFinalitySource

{ + type Error = Error; + + async fn reconnect(&mut self) -> Result<(), Error> { + self.client.reconnect().await + } +} + +#[async_trait] +impl SourceClient> + for SubstrateFinalitySource

+{ + type FinalityProofsStream = SubstrateFinalityProofsStream

; + + async fn best_finalized_block_number(&self) -> Result, Error> { + let mut finalized_header_number = self.on_chain_best_finalized_block_number().await?; + // never return block number larger than requested. This way we'll never sync headers + // past `maximal_header_number` + if let Some(ref maximal_header_number) = self.maximal_header_number { + let maximal_header_number = *maximal_header_number.lock().await; + if finalized_header_number > maximal_header_number { + finalized_header_number = maximal_header_number; + } + } + Ok(finalized_header_number) + } + + async fn header_and_finality_proof( + &self, + number: BlockNumberOf, + ) -> Result< + ( + relay_substrate_client::SyncHeader>, + Option>, + ), + Error, + > { + header_and_finality_proof::

(&self.client, number).await + } + + async fn finality_proofs(&self) -> Result { + Ok(unfold( + P::FinalityEngine::finality_proofs(&self.client).await?, + move |subscription| async move { + loop { + let log_error = |err| { + log::error!( + target: "bridge", + "Failed to read justification target from the {} justifications stream: {:?}", + P::SourceChain::NAME, + err, + ); + }; + + let next_justification = subscription + .next() + .await + .map_err(|err| log_error(err.to_string())) + .ok()??; + + let decoded_justification = + >::FinalityProof::decode( + &mut &next_justification[..], + ); + + let justification = match decoded_justification { + Ok(j) => j, + Err(err) => { + log_error(format!("decode failed with error {err:?}")); + continue + }, + }; + + return Some((justification, subscription)) + } + }, + ) + .boxed()) + } +} + +async fn header_and_finality_proof( + client: &Client, + number: BlockNumberOf, +) -> Result< + ( + relay_substrate_client::SyncHeader>, + Option>, + ), + Error, +> { + let header_hash = client.block_hash_by_number(number).await?; + let signed_block = client.get_block(Some(header_hash)).await?; + + let justification = signed_block + .justification(P::FinalityEngine::ID) + .map(|raw_justification| { + SubstrateFinalityProof::

::decode(&mut raw_justification.as_slice()) + }) + .transpose() + .map_err(Error::ResponseParseFailed)?; + + Ok((signed_block.header().into(), justification)) +} diff --git a/relays/lib-substrate-relay/src/finality/target.rs b/relays/lib-substrate-relay/src/finality/target.rs new file mode 100644 index 00000000000..81a22520fa9 --- /dev/null +++ b/relays/lib-substrate-relay/src/finality/target.rs @@ -0,0 +1,131 @@ +// Copyright 2019-2021 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 . + +//! Substrate client as Substrate finality proof target. + +use crate::{ + finality::{ + engine::Engine, source::SubstrateFinalityProof, FinalitySyncPipelineAdapter, + SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, + }, + TransactionParams, +}; + +use async_trait::async_trait; +use finality_relay::TargetClient; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, Client, Error, HeaderIdOf, HeaderOf, SyncHeader, TransactionEra, + TransactionTracker, UnsignedTransaction, +}; +use relay_utils::relay_loop::Client as RelayClient; +use sp_core::Pair; + +/// Substrate client as Substrate finality target. +pub struct SubstrateFinalityTarget { + client: Client, + transaction_params: TransactionParams>, +} + +impl SubstrateFinalityTarget

{ + /// Create new Substrate headers target. + pub fn new( + client: Client, + transaction_params: TransactionParams>, + ) -> Self { + SubstrateFinalityTarget { client, transaction_params } + } + + /// Ensure that the bridge pallet at target chain is active. + pub async fn ensure_pallet_active(&self) -> Result<(), Error> { + let is_halted = P::FinalityEngine::is_halted(&self.client).await?; + if is_halted { + return Err(Error::BridgePalletIsHalted) + } + + let is_initialized = P::FinalityEngine::is_initialized(&self.client).await?; + if !is_initialized { + return Err(Error::BridgePalletIsNotInitialized) + } + + Ok(()) + } +} + +impl Clone for SubstrateFinalityTarget

{ + fn clone(&self) -> Self { + SubstrateFinalityTarget { + client: self.client.clone(), + transaction_params: self.transaction_params.clone(), + } + } +} + +#[async_trait] +impl RelayClient for SubstrateFinalityTarget

{ + type Error = Error; + + async fn reconnect(&mut self) -> Result<(), Error> { + self.client.reconnect().await + } +} + +#[async_trait] +impl TargetClient> + for SubstrateFinalityTarget

+where + AccountIdOf: From< as Pair>::Public>, +{ + type TransactionTracker = TransactionTracker>; + + async fn best_finalized_source_block_id(&self) -> Result, Error> { + // we can't continue to relay finality if target node is out of sync, because + // it may have already received (some of) headers that we're going to relay + self.client.ensure_synced().await?; + // we can't relay finality if bridge pallet at target chain is halted + self.ensure_pallet_active().await?; + + Ok(crate::messages_source::read_client_state::( + &self.client, + None, + ) + .await? + .best_finalized_peer_at_best_self + .ok_or(Error::BridgePalletIsNotInitialized)?) + } + + async fn submit_finality_proof( + &self, + header: SyncHeader>, + proof: SubstrateFinalityProof

, + ) -> Result { + // runtime module at target chain may require optimized finality proof + let proof = P::FinalityEngine::optimize_proof(&self.client, &header, proof).await?; + + // now we may submit optimized finality proof + let transaction_params = self.transaction_params.clone(); + let call = + P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof); + self.client + .submit_and_watch_signed_extrinsic( + &self.transaction_params.signer, + move |best_block_id, transaction_nonce| { + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) + }, + ) + .await + } +} diff --git a/relays/lib-substrate-relay/src/lib.rs b/relays/lib-substrate-relay/src/lib.rs new file mode 100644 index 00000000000..37a4d602e59 --- /dev/null +++ b/relays/lib-substrate-relay/src/lib.rs @@ -0,0 +1,145 @@ +// Copyright 2019-2021 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 . + +//! The library of substrate relay. contains some public codes to provide to substrate relay. + +#![warn(missing_docs)] + +use relay_substrate_client::{Chain, ChainWithUtilityPallet, UtilityPallet}; + +use std::marker::PhantomData; + +pub mod error; +pub mod finality; +pub mod messages_lane; +pub mod messages_metrics; +pub mod messages_source; +pub mod messages_target; +pub mod on_demand; +pub mod parachains; + +/// Transaction creation parameters. +#[derive(Clone, Debug)] +pub struct TransactionParams { + /// Transactions author. + pub signer: TS, + /// Transactions mortality. + pub mortality: Option, +} + +/// Tagged relay account, which balance may be exposed as metrics by the relay. +#[derive(Clone, Debug)] +pub enum TaggedAccount { + /// Account, used to sign headers relay transactions from given bridged chain. + Headers { + /// Account id. + id: AccountId, + /// Name of the bridged chain, which headers are relayed. + bridged_chain: String, + }, + /// Account, used to sign parachains relay transactions from given bridged relay chain. + Parachains { + /// Account id. + id: AccountId, + /// Name of the bridged relay chain with parachain heads. + bridged_chain: String, + }, + /// Account, used to sign message relay transactions from given bridged chain. + Messages { + /// Account id. + id: AccountId, + /// Name of the bridged chain, which sends us messages or delivery confirmations. + bridged_chain: String, + }, +} + +impl TaggedAccount { + /// Returns reference to the account id. + pub fn id(&self) -> &AccountId { + match *self { + TaggedAccount::Headers { ref id, .. } => id, + TaggedAccount::Parachains { ref id, .. } => id, + TaggedAccount::Messages { ref id, .. } => id, + } + } + + /// Returns stringified account tag. + pub fn tag(&self) -> String { + match *self { + TaggedAccount::Headers { ref bridged_chain, .. } => format!("{bridged_chain}Headers"), + TaggedAccount::Parachains { ref bridged_chain, .. } => { + format!("{bridged_chain}Parachains") + }, + TaggedAccount::Messages { ref bridged_chain, .. } => { + format!("{bridged_chain}Messages") + }, + } + } +} + +/// Batch call builder. +pub trait BatchCallBuilder: Clone + Send { + /// Create batch call from given calls vector. + fn build_batch_call(&self, _calls: Vec) -> Call; +} + +/// Batch call builder constructor. +pub trait BatchCallBuilderConstructor: Clone { + /// Call builder, used by this constructor. + type CallBuilder: BatchCallBuilder; + /// Create a new instance of a batch call builder. + fn new_builder() -> Option; +} + +/// Batch call builder based on `pallet-utility`. +#[derive(Clone)] +pub struct UtilityPalletBatchCallBuilder(PhantomData); + +impl BatchCallBuilder for UtilityPalletBatchCallBuilder +where + C: ChainWithUtilityPallet, +{ + fn build_batch_call(&self, calls: Vec) -> C::Call { + C::UtilityPallet::build_batch_call(calls) + } +} + +impl BatchCallBuilderConstructor for UtilityPalletBatchCallBuilder +where + C: ChainWithUtilityPallet, +{ + type CallBuilder = Self; + + fn new_builder() -> Option { + Some(Self(Default::default())) + } +} + +// A `BatchCallBuilderConstructor` that always returns `None`. +impl BatchCallBuilderConstructor for () { + type CallBuilder = (); + fn new_builder() -> Option { + None + } +} + +// Dummy `BatchCallBuilder` implementation that must never be used outside +// of the `impl BatchCallBuilderConstructor for ()` code. +impl BatchCallBuilder for () { + fn build_batch_call(&self, _calls: Vec) -> Call { + unreachable!("never called, because ()::new_builder() returns None; qed") + } +} diff --git a/relays/lib-substrate-relay/src/messages_lane.rs b/relays/lib-substrate-relay/src/messages_lane.rs new file mode 100644 index 00000000000..b86a2629b07 --- /dev/null +++ b/relays/lib-substrate-relay/src/messages_lane.rs @@ -0,0 +1,572 @@ +// Copyright 2019-2021 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 . + +//! Tools for supporting message lanes between two Substrate-based chains. + +use crate::{ + messages_source::{SubstrateMessagesProof, SubstrateMessagesSource}, + messages_target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget}, + on_demand::OnDemandRelay, + BatchCallBuilder, BatchCallBuilderConstructor, TransactionParams, +}; + +use async_std::sync::Arc; +use bp_messages::{LaneId, MessageNonce}; +use bp_runtime::{ + AccountIdOf, Chain as _, EncodedOrDecodedCall, HeaderIdOf, TransactionEra, WeightExtraOps, +}; +use bridge_runtime_common::messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, +}; +use codec::Encode; +use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; +use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransaction}; +use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig}; +use relay_substrate_client::{ + transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, + ChainWithMessages, ChainWithTransactions, Client, Error as SubstrateError, HashOf, SignParam, + UnsignedTransaction, +}; +use relay_utils::{ + metrics::{GlobalMetrics, MetricsParams, StandaloneMetric}, + STALL_TIMEOUT, +}; +use sp_core::Pair; +use sp_runtime::traits::Zero; +use std::{convert::TryFrom, fmt::Debug, marker::PhantomData}; + +/// Substrate -> Substrate messages synchronization pipeline. +pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync { + /// Messages of this chain are relayed to the `TargetChain`. + type SourceChain: ChainWithMessages + ChainWithTransactions; + /// Messages from the `SourceChain` are dispatched on this chain. + type TargetChain: ChainWithMessages + ChainWithTransactions; + + /// How receive messages proof call is built? + type ReceiveMessagesProofCallBuilder: ReceiveMessagesProofCallBuilder; + /// How receive messages delivery proof call is built? + type ReceiveMessagesDeliveryProofCallBuilder: ReceiveMessagesDeliveryProofCallBuilder; + + /// How batch calls are built at the source chain? + type SourceBatchCallBuilder: BatchCallBuilderConstructor>; + /// How batch calls are built at the target chain? + type TargetBatchCallBuilder: BatchCallBuilderConstructor>; +} + +/// Adapter that allows all `SubstrateMessageLane` to act as `MessageLane`. +#[derive(Clone, Debug)] +pub struct MessageLaneAdapter { + _phantom: PhantomData

, +} + +impl MessageLane for MessageLaneAdapter

{ + const SOURCE_NAME: &'static str = P::SourceChain::NAME; + const TARGET_NAME: &'static str = P::TargetChain::NAME; + + type MessagesProof = SubstrateMessagesProof; + type MessagesReceivingProof = SubstrateMessagesDeliveryProof; + + type SourceChainBalance = BalanceOf; + type SourceHeaderNumber = BlockNumberOf; + type SourceHeaderHash = HashOf; + + type TargetHeaderNumber = BlockNumberOf; + type TargetHeaderHash = HashOf; +} + +/// Substrate <-> Substrate messages relay parameters. +pub struct MessagesRelayParams { + /// Messages source client. + pub source_client: Client, + /// Source transaction params. + pub source_transaction_params: TransactionParams>, + /// Messages target client. + pub target_client: Client, + /// Target transaction params. + pub target_transaction_params: TransactionParams>, + /// Optional on-demand source to target headers relay. + pub source_to_target_headers_relay: + Option>>, + /// Optional on-demand target to source headers relay. + pub target_to_source_headers_relay: + Option>>, + /// Identifier of lane that needs to be served. + pub lane_id: LaneId, + /// Metrics parameters. + pub metrics_params: MetricsParams, +} + +/// Batch transaction that brings headers + and messages delivery/receiving confirmations to the +/// source node. +#[derive(Clone)] +pub struct BatchProofTransaction>> { + builder: B::CallBuilder, + proved_header: HeaderIdOf, + prove_calls: Vec>, + + /// Using `fn() -> B` in order to avoid implementing `Send` for `B`. + _phantom: PhantomData B>, +} + +impl>> std::fmt::Debug + for BatchProofTransaction +{ + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct("BatchProofTransaction") + .field("proved_header", &self.proved_header) + .finish() + } +} + +impl>> + BatchProofTransaction +{ + /// Creates a new instance of `BatchProofTransaction`. + pub async fn new( + relay: Arc>, + block_num: BlockNumberOf, + ) -> Result, SubstrateError> { + if let Some(builder) = B::new_builder() { + let (proved_header, prove_calls) = relay.prove_header(block_num).await?; + return Ok(Some(Self { + builder, + proved_header, + prove_calls, + _phantom: Default::default(), + })) + } + + Ok(None) + } + + /// Return a batch call that includes the provided call. + pub fn append_call_and_build(mut self, call: CallOf) -> CallOf { + self.prove_calls.push(call); + self.builder.build_batch_call(self.prove_calls) + } +} + +impl>> + BatchTransaction> for BatchProofTransaction +{ + fn required_header_id(&self) -> HeaderIdOf { + self.proved_header + } +} + +/// Run Substrate-to-Substrate messages sync loop. +pub async fn run(params: MessagesRelayParams

) -> anyhow::Result<()> +where + AccountIdOf: From< as Pair>::Public>, + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom>, +{ + // 2/3 is reserved for proofs and tx overhead + let max_messages_size_in_single_batch = P::TargetChain::max_extrinsic_size() / 3; + // we don't know exact weights of the Polkadot runtime. So to guess weights we'll be using + // weights from Rialto and then simply dividing it by x2. + let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = + select_delivery_transaction_limits_rpc::

( + ¶ms, + P::TargetChain::max_extrinsic_weight(), + P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + ) + .await?; + let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = + (max_messages_in_single_batch / 2, max_messages_weight_in_single_batch / 2); + + let source_client = params.source_client; + let target_client = params.target_client; + let relayer_id_at_source: AccountIdOf = + params.source_transaction_params.signer.public().into(); + + log::info!( + target: "bridge", + "Starting {} -> {} messages relay.\n\t\ + {} relayer account id: {:?}\n\t\ + Max messages in single transaction: {}\n\t\ + Max messages size in single transaction: {}\n\t\ + Max messages weight in single transaction: {}\n\t\ + Tx mortality: {:?} (~{}m)/{:?} (~{}m)", + P::SourceChain::NAME, + P::TargetChain::NAME, + P::SourceChain::NAME, + relayer_id_at_source, + max_messages_in_single_batch, + max_messages_size_in_single_batch, + max_messages_weight_in_single_batch, + params.source_transaction_params.mortality, + transaction_stall_timeout( + params.source_transaction_params.mortality, + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ).as_secs_f64() / 60.0f64, + params.target_transaction_params.mortality, + transaction_stall_timeout( + params.target_transaction_params.mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ).as_secs_f64() / 60.0f64, + ); + + messages_relay::message_lane_loop::run( + messages_relay::message_lane_loop::Params { + lane: params.lane_id, + source_tick: P::SourceChain::AVERAGE_BLOCK_INTERVAL, + target_tick: P::TargetChain::AVERAGE_BLOCK_INTERVAL, + reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY, + delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams { + max_unrewarded_relayer_entries_at_target: + P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + max_unconfirmed_nonces_at_target: + P::SourceChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + max_messages_in_single_batch, + max_messages_weight_in_single_batch, + max_messages_size_in_single_batch, + }, + }, + SubstrateMessagesSource::

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

::new( + target_client, + source_client, + params.lane_id, + relayer_id_at_source, + params.target_transaction_params, + params.source_to_target_headers_relay, + ), + { + GlobalMetrics::new()?.register_and_spawn(¶ms.metrics_params.registry)?; + params.metrics_params + }, + futures::future::pending(), + ) + .await + .map_err(Into::into) +} + +/// Different ways of building `receive_messages_proof` calls. +pub trait ReceiveMessagesProofCallBuilder { + /// Given messages proof, build call of `receive_messages_proof` function of bridge + /// messages module at the target chain. + fn build_receive_messages_proof_call( + relayer_id_at_source: AccountIdOf, + proof: SubstrateMessagesProof, + messages_count: u32, + dispatch_weight: Weight, + trace_call: bool, + ) -> CallOf; +} + +/// Building `receive_messages_proof` call when you have direct access to the target +/// chain runtime. +pub struct DirectReceiveMessagesProofCallBuilder { + _phantom: PhantomData<(P, R, I)>, +} + +impl ReceiveMessagesProofCallBuilder

for DirectReceiveMessagesProofCallBuilder +where + P: SubstrateMessageLane, + R: BridgeMessagesConfig>, + I: 'static, + R::SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain< + MessagesProof = FromBridgedChainMessagesProof>, + >, + CallOf: From> + GetDispatchInfo, +{ + fn build_receive_messages_proof_call( + relayer_id_at_source: AccountIdOf, + proof: SubstrateMessagesProof, + messages_count: u32, + dispatch_weight: Weight, + trace_call: bool, + ) -> CallOf { + let call: CallOf = BridgeMessagesCall::::receive_messages_proof { + relayer_id_at_bridged_chain: relayer_id_at_source, + proof: proof.1, + messages_count, + dispatch_weight, + } + .into(); + if trace_call { + // this trace isn't super-accurate, because limits are for transactions and we + // have a call here, but it provides required information + log::trace!( + target: "bridge", + "Prepared {} -> {} messages delivery call. Weight: {}/{}, size: {}/{}", + P::SourceChain::NAME, + P::TargetChain::NAME, + call.get_dispatch_info().weight, + P::TargetChain::max_extrinsic_weight(), + call.encode().len(), + P::TargetChain::max_extrinsic_size(), + ); + } + call + } +} + +/// Macro that generates `ReceiveMessagesProofCallBuilder` implementation for the case when +/// you only have an access to the mocked version of target chain runtime. In this case you +/// should provide "name" of the call variant for the bridge messages calls and the "name" of +/// the variant for the `receive_messages_proof` call within that first option. +#[rustfmt::skip] +#[macro_export] +macro_rules! generate_receive_message_proof_call_builder { + ($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_proof:path) => { + pub struct $mocked_builder; + + impl $crate::messages_lane::ReceiveMessagesProofCallBuilder<$pipeline> + for $mocked_builder + { + fn build_receive_messages_proof_call( + relayer_id_at_source: relay_substrate_client::AccountIdOf< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + >, + proof: $crate::messages_source::SubstrateMessagesProof< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + >, + messages_count: u32, + dispatch_weight: bp_messages::Weight, + _trace_call: bool, + ) -> relay_substrate_client::CallOf< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::TargetChain + > { + bp_runtime::paste::item! { + $bridge_messages($receive_messages_proof { + relayer_id_at_bridged_chain: relayer_id_at_source, + proof: proof.1, + messages_count: messages_count, + dispatch_weight: dispatch_weight, + }) + } + } + } + }; +} + +/// Different ways of building `receive_messages_delivery_proof` calls. +pub trait ReceiveMessagesDeliveryProofCallBuilder { + /// Given messages delivery proof, build call of `receive_messages_delivery_proof` function of + /// bridge messages module at the source chain. + fn build_receive_messages_delivery_proof_call( + proof: SubstrateMessagesDeliveryProof, + trace_call: bool, + ) -> CallOf; +} + +/// Building `receive_messages_delivery_proof` call when you have direct access to the source +/// chain runtime. +pub struct DirectReceiveMessagesDeliveryProofCallBuilder { + _phantom: PhantomData<(P, R, I)>, +} + +impl ReceiveMessagesDeliveryProofCallBuilder

+ for DirectReceiveMessagesDeliveryProofCallBuilder +where + P: SubstrateMessageLane, + R: BridgeMessagesConfig, + I: 'static, + R::TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain< + R::OutboundPayload, + R::AccountId, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof>, + >, + CallOf: From> + GetDispatchInfo, +{ + fn build_receive_messages_delivery_proof_call( + proof: SubstrateMessagesDeliveryProof, + trace_call: bool, + ) -> CallOf { + let call: CallOf = + BridgeMessagesCall::::receive_messages_delivery_proof { + proof: proof.1, + relayers_state: proof.0, + } + .into(); + if trace_call { + // this trace isn't super-accurate, because limits are for transactions and we + // have a call here, but it provides required information + log::trace!( + target: "bridge", + "Prepared {} -> {} delivery confirmation transaction. Weight: {}/{}, size: {}/{}", + P::TargetChain::NAME, + P::SourceChain::NAME, + call.get_dispatch_info().weight, + P::SourceChain::max_extrinsic_weight(), + call.encode().len(), + P::SourceChain::max_extrinsic_size(), + ); + } + call + } +} + +/// Macro that generates `ReceiveMessagesDeliveryProofCallBuilder` implementation for the case when +/// you only have an access to the mocked version of source chain runtime. In this case you +/// should provide "name" of the call variant for the bridge messages calls and the "name" of +/// the variant for the `receive_messages_delivery_proof` call within that first option. +#[rustfmt::skip] +#[macro_export] +macro_rules! generate_receive_message_delivery_proof_call_builder { + ($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_delivery_proof:path) => { + pub struct $mocked_builder; + + impl $crate::messages_lane::ReceiveMessagesDeliveryProofCallBuilder<$pipeline> + for $mocked_builder + { + fn build_receive_messages_delivery_proof_call( + proof: $crate::messages_target::SubstrateMessagesDeliveryProof< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::TargetChain + >, + _trace_call: bool, + ) -> relay_substrate_client::CallOf< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + > { + bp_runtime::paste::item! { + $bridge_messages($receive_messages_delivery_proof { + proof: proof.1, + relayers_state: proof.0 + }) + } + } + } + }; +} + +/// Returns maximal number of messages and their maximal cumulative dispatch weight. +async fn select_delivery_transaction_limits_rpc( + params: &MessagesRelayParams

, + max_extrinsic_weight: Weight, + max_unconfirmed_messages_at_inbound_lane: MessageNonce, +) -> anyhow::Result<(MessageNonce, Weight)> +where + AccountIdOf: From< as Pair>::Public>, +{ + // We may try to guess accurate value, based on maximal number of messages and per-message + // weight overhead, but the relay loop isn't using this info in a super-accurate way anyway. + // So just a rough guess: let's say 1/3 of max tx weight is for tx itself and the rest is + // for messages dispatch. + + // Another thing to keep in mind is that our runtimes (when this code was written) accept + // messages with dispatch weight <= max_extrinsic_weight/2. So we can't reserve less than + // that for dispatch. + + let weight_for_delivery_tx = max_extrinsic_weight / 3; + let weight_for_messages_dispatch = max_extrinsic_weight - weight_for_delivery_tx; + + // weight of empty message delivery with outbound lane state + let delivery_tx_with_zero_messages = dummy_messages_delivery_transaction::

(params, 0)?; + let delivery_tx_with_zero_messages_weight = params + .target_client + .extimate_extrinsic_weight(delivery_tx_with_zero_messages) + .await + .map_err(|e| { + anyhow::format_err!("Failed to estimate delivery extrinsic weight: {:?}", e) + })?; + + // weight of single message delivery with outbound lane state + let delivery_tx_with_one_message = dummy_messages_delivery_transaction::

(params, 1)?; + let delivery_tx_with_one_message_weight = params + .target_client + .extimate_extrinsic_weight(delivery_tx_with_one_message) + .await + .map_err(|e| { + anyhow::format_err!("Failed to estimate delivery extrinsic weight: {:?}", e) + })?; + + // message overhead is roughly `delivery_tx_with_one_message_weight - + // delivery_tx_with_zero_messages_weight` + let delivery_tx_weight_rest = weight_for_delivery_tx - delivery_tx_with_zero_messages_weight; + let delivery_tx_message_overhead = + delivery_tx_with_one_message_weight.saturating_sub(delivery_tx_with_zero_messages_weight); + + let max_number_of_messages = std::cmp::min( + delivery_tx_weight_rest + .min_components_checked_div(delivery_tx_message_overhead) + .unwrap_or(u64::MAX), + max_unconfirmed_messages_at_inbound_lane, + ); + + assert!( + max_number_of_messages > 0, + "Relay should fit at least one message in every delivery transaction", + ); + assert!( + weight_for_messages_dispatch.ref_time() >= max_extrinsic_weight.ref_time() / 2, + "Relay shall be able to deliver messages with dispatch weight = max_extrinsic_weight / 2", + ); + + Ok((max_number_of_messages, weight_for_messages_dispatch)) +} + +/// Returns dummy message delivery transaction with zero messages and `1kb` proof. +fn dummy_messages_delivery_transaction( + params: &MessagesRelayParams

, + messages: u32, +) -> anyhow::Result<::SignedTransaction> +where + AccountIdOf: From< as Pair>::Public>, +{ + // we don't care about any call values here, because all that the estimation RPC does + // is calls `GetDispatchInfo::get_dispatch_info` for the wrapped call. So we only are + // interested in values that affect call weight - e.g. number of messages and the + // storage proof size + + let dummy_messages_delivery_call = + P::ReceiveMessagesProofCallBuilder::build_receive_messages_proof_call( + params.source_transaction_params.signer.public().into(), + ( + Weight::zero(), + FromBridgedChainMessagesProof { + bridged_header_hash: Default::default(), + // we may use per-chain `EXTRA_STORAGE_PROOF_SIZE`, but since we don't need + // exact values, this global estimation is fine + storage_proof: vec![vec![ + 42u8; + pallet_bridge_messages::EXTRA_STORAGE_PROOF_SIZE + as usize + ]], + lane: Default::default(), + nonces_start: 1, + nonces_end: messages as u64, + }, + ), + messages, + Weight::zero(), + false, + ); + P::TargetChain::sign_transaction( + SignParam { + spec_version: 0, + transaction_version: 0, + genesis_hash: Default::default(), + signer: params.target_transaction_params.signer.clone(), + }, + UnsignedTransaction { + call: EncodedOrDecodedCall::Decoded(dummy_messages_delivery_call), + nonce: Zero::zero(), + tip: Zero::zero(), + era: TransactionEra::Immortal, + }, + ) + .map_err(Into::into) +} diff --git a/relays/lib-substrate-relay/src/messages_metrics.rs b/relays/lib-substrate-relay/src/messages_metrics.rs new file mode 100644 index 00000000000..33d855a0263 --- /dev/null +++ b/relays/lib-substrate-relay/src/messages_metrics.rs @@ -0,0 +1,190 @@ +// Copyright 2019-2021 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 . + +//! Tools for supporting message lanes between two Substrate-based chains. + +use crate::TaggedAccount; + +use bp_messages::LaneId; +use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; +use bp_runtime::StorageDoubleMapKeyProvider; +use codec::Decode; +use frame_system::AccountInfo; +use pallet_balances::AccountData; +use relay_substrate_client::{ + metrics::{FloatStorageValue, FloatStorageValueMetric}, + AccountIdOf, BalanceOf, Chain, ChainWithBalances, ChainWithMessages, Client, + Error as SubstrateError, IndexOf, +}; +use relay_utils::metrics::{MetricsParams, StandaloneMetric}; +use sp_core::storage::StorageData; +use sp_runtime::{FixedPointNumber, FixedU128}; +use std::{convert::TryFrom, fmt::Debug, marker::PhantomData}; + +/// Add relay accounts balance metrics. +pub async fn add_relay_balances_metrics( + client: Client, + metrics: &mut MetricsParams, + relay_accounts: &Vec>>, + lanes: &[LaneId], +) -> anyhow::Result<()> +where + BalanceOf: Into + std::fmt::Debug, +{ + if relay_accounts.is_empty() { + return Ok(()) + } + + // if `tokenDecimals` is missing from system properties, we'll be using + let token_decimals = client + .token_decimals() + .await? + .map(|token_decimals| { + log::info!(target: "bridge", "Read `tokenDecimals` for {}: {}", C::NAME, token_decimals); + token_decimals + }) + .unwrap_or_else(|| { + // turns out it is normal not to have this property - e.g. when polkadot binary is + // started using `polkadot-local` chain. Let's use minimal nominal here + log::info!(target: "bridge", "Using default (zero) `tokenDecimals` value for {}", C::NAME); + 0 + }); + let token_decimals = u32::try_from(token_decimals).map_err(|e| { + anyhow::format_err!( + "Token decimals value ({}) of {} doesn't fit into u32: {:?}", + token_decimals, + C::NAME, + e, + ) + })?; + + for account in relay_accounts { + let relay_account_balance_metric = FloatStorageValueMetric::new( + AccountBalanceFromAccountInfo:: { token_decimals, _phantom: Default::default() }, + client.clone(), + C::account_info_storage_key(account.id()), + format!("at_{}_relay_{}_balance", C::NAME, account.tag()), + format!("Balance of the {} relay account at the {}", account.tag(), C::NAME), + )?; + relay_account_balance_metric.register_and_spawn(&metrics.registry)?; + + if let Some(relayers_pallet_name) = BC::WITH_CHAIN_RELAYERS_PALLET_NAME { + for lane in lanes { + FloatStorageValueMetric::new( + AccountBalance:: { token_decimals, _phantom: Default::default() }, + client.clone(), + bp_relayers::RelayerRewardsKeyProvider::, BalanceOf>::final_key( + relayers_pallet_name, + account.id(), + &RewardsAccountParams::new(*lane, BC::ID, RewardsAccountOwner::ThisChain), + ), + format!("at_{}_relay_{}_reward_for_msgs_from_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, hex::encode(lane.as_ref())), + format!("Reward of the {} relay account at {} for delivering messages from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane), + )?.register_and_spawn(&metrics.registry)?; + + FloatStorageValueMetric::new( + AccountBalance:: { token_decimals, _phantom: Default::default() }, + client.clone(), + bp_relayers::RelayerRewardsKeyProvider::, BalanceOf>::final_key( + relayers_pallet_name, + account.id(), + &RewardsAccountParams::new(*lane, BC::ID, RewardsAccountOwner::BridgedChain), + ), + format!("at_{}_relay_{}_reward_for_msgs_to_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, hex::encode(lane.as_ref())), + format!("Reward of the {} relay account at {} for delivering messages confirmations from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane), + )?.register_and_spawn(&metrics.registry)?; + } + } + } + + Ok(()) +} + +/// Adapter for `FloatStorageValueMetric` to decode account free balance. +#[derive(Clone, Debug)] +struct AccountBalanceFromAccountInfo { + token_decimals: u32, + _phantom: PhantomData, +} + +impl FloatStorageValue for AccountBalanceFromAccountInfo +where + C: Chain, + BalanceOf: Into, +{ + type Value = FixedU128; + + fn decode( + &self, + maybe_raw_value: Option, + ) -> Result, SubstrateError> { + maybe_raw_value + .map(|raw_value| { + AccountInfo::, AccountData>>::decode(&mut &raw_value.0[..]) + .map_err(SubstrateError::ResponseParseFailed) + .map(|account_data| { + convert_to_token_balance(account_data.data.free.into(), self.token_decimals) + }) + }) + .transpose() + } +} + +/// Adapter for `FloatStorageValueMetric` to decode account free balance. +#[derive(Clone, Debug)] +struct AccountBalance { + token_decimals: u32, + _phantom: PhantomData, +} + +impl FloatStorageValue for AccountBalance +where + C: Chain, + BalanceOf: Into, +{ + type Value = FixedU128; + + fn decode( + &self, + maybe_raw_value: Option, + ) -> Result, SubstrateError> { + maybe_raw_value + .map(|raw_value| { + BalanceOf::::decode(&mut &raw_value.0[..]) + .map_err(SubstrateError::ResponseParseFailed) + .map(|balance| convert_to_token_balance(balance.into(), self.token_decimals)) + }) + .transpose() + } +} + +/// Convert from raw `u128` balance (nominated in smallest chain token units) to the float regular +/// tokens value. +fn convert_to_token_balance(balance: u128, token_decimals: u32) -> FixedU128 { + FixedU128::from_inner(balance.saturating_mul(FixedU128::DIV / 10u128.pow(token_decimals))) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn token_decimals_used_properly() { + let plancks = 425_000_000_000; + let token_decimals = 10; + let dots = convert_to_token_balance(plancks, token_decimals); + assert_eq!(dots, FixedU128::saturating_from_rational(425, 10)); + } +} diff --git a/relays/lib-substrate-relay/src/messages_source.rs b/relays/lib-substrate-relay/src/messages_source.rs new file mode 100644 index 00000000000..de795beb787 --- /dev/null +++ b/relays/lib-substrate-relay/src/messages_source.rs @@ -0,0 +1,721 @@ +// Copyright 2019-2021 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 . + +//! Substrate client as Substrate messages source. The chain we connect to should have +//! runtime that implements `HeaderApi` to allow bridging with +//! `` chain. + +use crate::{ + messages_lane::{ + BatchProofTransaction, MessageLaneAdapter, ReceiveMessagesDeliveryProofCallBuilder, + SubstrateMessageLane, + }, + on_demand::OnDemandRelay, + TransactionParams, +}; + +use async_std::sync::Arc; +use async_trait::async_trait; +use bp_messages::{ + storage_keys::{operating_mode_key, outbound_lane_data_key}, + InboundMessageDetails, LaneId, MessageNonce, MessagePayload, MessagesOperatingMode, + OutboundLaneData, OutboundMessageDetails, +}; +use bp_runtime::{BasicOperatingMode, HeaderIdProvider}; +use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; +use codec::Encode; +use frame_support::weights::Weight; +use messages_relay::{ + message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, + message_lane_loop::{ + ClientState, MessageDetails, MessageDetailsMap, MessageProofParameters, SourceClient, + SourceClientState, + }, +}; +use num_traits::Zero; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, BalanceOf, Chain, ChainWithMessages, Client, + Error as SubstrateError, HashOf, HeaderIdOf, TransactionEra, TransactionTracker, + UnsignedTransaction, +}; +use relay_utils::relay_loop::Client as RelayClient; +use sp_core::Pair; +use std::ops::RangeInclusive; + +/// Intermediate message proof returned by the source Substrate node. Includes everything +/// required to submit to the target node: cumulative dispatch weight of bundled messages and +/// the proof itself. +pub type SubstrateMessagesProof = (Weight, FromBridgedChainMessagesProof>); +type MessagesToRefine<'a> = Vec<(MessagePayload, &'a mut OutboundMessageDetails)>; + +/// Substrate client as Substrate messages source. +pub struct SubstrateMessagesSource { + source_client: Client, + target_client: Client, + lane_id: LaneId, + transaction_params: TransactionParams>, + target_to_source_headers_relay: Option>>, +} + +impl SubstrateMessagesSource

{ + /// Create new Substrate headers source. + pub fn new( + source_client: Client, + target_client: Client, + lane_id: LaneId, + transaction_params: TransactionParams>, + target_to_source_headers_relay: Option< + Arc>, + >, + ) -> Self { + SubstrateMessagesSource { + source_client, + target_client, + lane_id, + transaction_params, + target_to_source_headers_relay, + } + } + + /// Read outbound lane state from the on-chain storage at given block. + async fn outbound_lane_data( + &self, + id: SourceHeaderIdOf>, + ) -> Result, SubstrateError> { + self.source_client + .storage_value( + outbound_lane_data_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + ), + Some(id.1), + ) + .await + } + + /// Ensure that the messages pallet at source chain is active. + async fn ensure_pallet_active(&self) -> Result<(), SubstrateError> { + ensure_messages_pallet_active::(&self.source_client).await + } +} + +impl Clone for SubstrateMessagesSource

{ + fn clone(&self) -> Self { + Self { + source_client: self.source_client.clone(), + target_client: self.target_client.clone(), + lane_id: self.lane_id, + transaction_params: self.transaction_params.clone(), + target_to_source_headers_relay: self.target_to_source_headers_relay.clone(), + } + } +} + +#[async_trait] +impl RelayClient for SubstrateMessagesSource

{ + type Error = SubstrateError; + + async fn reconnect(&mut self) -> Result<(), SubstrateError> { + // since the client calls RPC methods on both sides, we need to reconnect both + self.source_client.reconnect().await?; + self.target_client.reconnect().await?; + + // call reconnect on on-demand headers relay, because we may use different chains there + // and the error that has lead to reconnect may have came from those other chains + // (see `require_target_header_on_source`) + // + // this may lead to multiple reconnects to the same node during the same call and it + // needs to be addressed in the future + // TODO: https://github.com/paritytech/parity-bridges-common/issues/1928 + if let Some(ref mut target_to_source_headers_relay) = self.target_to_source_headers_relay { + target_to_source_headers_relay.reconnect().await?; + } + + Ok(()) + } +} + +#[async_trait] +impl SourceClient> for SubstrateMessagesSource

+where + AccountIdOf: From< as Pair>::Public>, +{ + type BatchTransaction = + BatchProofTransaction; + type TransactionTracker = TransactionTracker>; + + async fn state(&self) -> Result>, SubstrateError> { + // we can't continue to deliver confirmations if source node is out of sync, because + // it may have already received confirmations that we're going to deliver + // + // we can't continue to deliver messages if target node is out of sync, because + // it may have already received (some of) messages that we're going to deliver + self.source_client.ensure_synced().await?; + self.target_client.ensure_synced().await?; + // we can't relay confirmations if messages pallet at source chain is halted + self.ensure_pallet_active().await?; + + read_client_state(&self.source_client, Some(&self.target_client)).await + } + + async fn latest_generated_nonce( + &self, + id: SourceHeaderIdOf>, + ) -> Result<(SourceHeaderIdOf>, MessageNonce), SubstrateError> { + // lane data missing from the storage is fine until first message is sent + let latest_generated_nonce = self + .outbound_lane_data(id) + .await? + .map(|data| data.latest_generated_nonce) + .unwrap_or(0); + Ok((id, latest_generated_nonce)) + } + + async fn latest_confirmed_received_nonce( + &self, + id: SourceHeaderIdOf>, + ) -> Result<(SourceHeaderIdOf>, MessageNonce), SubstrateError> { + // lane data missing from the storage is fine until first message is sent + let latest_received_nonce = self + .outbound_lane_data(id) + .await? + .map(|data| data.latest_received_nonce) + .unwrap_or(0); + Ok((id, latest_received_nonce)) + } + + async fn generated_message_details( + &self, + id: SourceHeaderIdOf>, + nonces: RangeInclusive, + ) -> Result>, SubstrateError> { + let mut out_msgs_details = self + .source_client + .typed_state_call::<_, Vec<_>>( + P::TargetChain::TO_CHAIN_MESSAGE_DETAILS_METHOD.into(), + (self.lane_id, *nonces.start(), *nonces.end()), + Some(id.1), + ) + .await?; + validate_out_msgs_details::(&out_msgs_details, nonces)?; + + // prepare arguments of the inbound message details call (if we need it) + let mut msgs_to_refine = vec![]; + for out_msg_details in out_msgs_details.iter_mut() { + // in our current strategy all messages are supposed to be paid at the target chain + + // for pay-at-target messages we may want to ask target chain for + // refined dispatch weight + let msg_key = bp_messages::storage_keys::message_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + out_msg_details.nonce, + ); + let msg_payload: MessagePayload = + self.source_client.storage_value(msg_key, Some(id.1)).await?.ok_or_else(|| { + SubstrateError::Custom(format!( + "Message to {} {:?}/{} is missing from runtime the storage of {} at {:?}", + P::TargetChain::NAME, + self.lane_id, + out_msg_details.nonce, + P::SourceChain::NAME, + id, + )) + })?; + + msgs_to_refine.push((msg_payload, out_msg_details)); + } + + for mut msgs_to_refine_batch in + split_msgs_to_refine::(self.lane_id, msgs_to_refine)? + { + let in_msgs_details = self + .target_client + .typed_state_call::<_, Vec>( + P::SourceChain::FROM_CHAIN_MESSAGE_DETAILS_METHOD.into(), + (self.lane_id, &msgs_to_refine_batch), + None, + ) + .await?; + if in_msgs_details.len() != msgs_to_refine_batch.len() { + return Err(SubstrateError::Custom(format!( + "Call of {} at {} has returned {} entries instead of expected {}", + P::SourceChain::FROM_CHAIN_MESSAGE_DETAILS_METHOD, + P::TargetChain::NAME, + in_msgs_details.len(), + msgs_to_refine_batch.len(), + ))) + } + for ((_, out_msg_details), in_msg_details) in + msgs_to_refine_batch.iter_mut().zip(in_msgs_details) + { + log::trace!( + target: "bridge", + "Refined weight of {}->{} message {:?}/{}: at-source: {}, at-target: {}", + P::SourceChain::NAME, + P::TargetChain::NAME, + self.lane_id, + out_msg_details.nonce, + out_msg_details.dispatch_weight, + in_msg_details.dispatch_weight, + ); + out_msg_details.dispatch_weight = in_msg_details.dispatch_weight; + } + } + + let mut msgs_details_map = MessageDetailsMap::new(); + for out_msg_details in out_msgs_details { + msgs_details_map.insert( + out_msg_details.nonce, + MessageDetails { + dispatch_weight: out_msg_details.dispatch_weight, + size: out_msg_details.size as _, + reward: Zero::zero(), + }, + ); + } + + Ok(msgs_details_map) + } + + async fn prove_messages( + &self, + id: SourceHeaderIdOf>, + nonces: RangeInclusive, + proof_parameters: MessageProofParameters, + ) -> Result< + ( + SourceHeaderIdOf>, + RangeInclusive, + as MessageLane>::MessagesProof, + ), + SubstrateError, + > { + let mut storage_keys = + Vec::with_capacity(nonces.end().saturating_sub(*nonces.start()) as usize + 1); + let mut message_nonce = *nonces.start(); + while message_nonce <= *nonces.end() { + let message_key = bp_messages::storage_keys::message_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + message_nonce, + ); + storage_keys.push(message_key); + message_nonce += 1; + } + if proof_parameters.outbound_state_proof_required { + storage_keys.push(bp_messages::storage_keys::outbound_lane_data_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + )); + } + + let proof = self + .source_client + .prove_storage(storage_keys, id.1) + .await? + .into_iter_nodes() + .collect(); + let proof = FromBridgedChainMessagesProof { + bridged_header_hash: id.1, + storage_proof: proof, + lane: self.lane_id, + nonces_start: *nonces.start(), + nonces_end: *nonces.end(), + }; + Ok((id, nonces, (proof_parameters.dispatch_weight, proof))) + } + + async fn submit_messages_receiving_proof( + &self, + maybe_batch_tx: Option, + _generated_at_block: TargetHeaderIdOf>, + proof: as MessageLane>::MessagesReceivingProof, + ) -> Result { + let messages_proof_call = + P::ReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call( + proof, + maybe_batch_tx.is_none(), + ); + let final_call = match maybe_batch_tx { + Some(batch_tx) => batch_tx.append_call_and_build(messages_proof_call), + None => messages_proof_call, + }; + + let transaction_params = self.transaction_params.clone(); + self.source_client + .submit_and_watch_signed_extrinsic( + &self.transaction_params.signer, + move |best_block_id, transaction_nonce| { + Ok(UnsignedTransaction::new(final_call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) + }, + ) + .await + } + + async fn require_target_header_on_source( + &self, + id: TargetHeaderIdOf>, + ) -> Result, SubstrateError> { + if let Some(ref target_to_source_headers_relay) = self.target_to_source_headers_relay { + if let Some(batch_tx) = + BatchProofTransaction::new(target_to_source_headers_relay.clone(), id.0).await? + { + return Ok(Some(batch_tx)) + } + + target_to_source_headers_relay.require_more_headers(id.0).await; + } + + Ok(None) + } +} + +/// Ensure that the messages pallet at source chain is active. +pub(crate) async fn ensure_messages_pallet_active( + client: &Client, +) -> Result<(), SubstrateError> +where + AtChain: ChainWithMessages, + WithChain: ChainWithMessages, +{ + let operating_mode = client + .storage_value(operating_mode_key(WithChain::WITH_CHAIN_MESSAGES_PALLET_NAME), None) + .await?; + let is_halted = + operating_mode == Some(MessagesOperatingMode::Basic(BasicOperatingMode::Halted)); + if is_halted { + Err(SubstrateError::BridgePalletIsHalted) + } else { + Ok(()) + } +} + +/// Read best blocks from given client. +/// +/// This function assumes that the chain that is followed by the `self_client` has +/// bridge GRANDPA pallet deployed and it provides `best_finalized_header_id_method_name` +/// runtime API to read the best finalized Bridged chain header. +/// +/// If `peer_client` is `None`, the value of `actual_best_finalized_peer_at_best_self` will +/// always match the `best_finalized_peer_at_best_self`. +pub async fn read_client_state( + self_client: &Client, + peer_client: Option<&Client>, +) -> Result, HeaderIdOf>, SubstrateError> +where + SelfChain: Chain, + PeerChain: Chain, +{ + // let's read our state first: we need best finalized header hash on **this** chain + let self_best_finalized_id = self_client.best_finalized_header().await?.id(); + // now let's read our best header on **this** chain + let self_best_id = self_client.best_header().await?.id(); + + // now let's read id of best finalized peer header at our best finalized block + let peer_on_self_best_finalized_id = + best_finalized_peer_header_at_self::( + self_client, + self_best_id.hash(), + ) + .await?; + + // read actual header, matching the `peer_on_self_best_finalized_id` from the peer chain + let actual_peer_on_self_best_finalized_id = + match (peer_client, peer_on_self_best_finalized_id.as_ref()) { + (Some(peer_client), Some(peer_on_self_best_finalized_id)) => { + let actual_peer_on_self_best_finalized = + peer_client.header_by_number(peer_on_self_best_finalized_id.number()).await?; + Some(actual_peer_on_self_best_finalized.id()) + }, + _ => peer_on_self_best_finalized_id, + }; + + Ok(ClientState { + best_self: self_best_id, + best_finalized_self: self_best_finalized_id, + best_finalized_peer_at_best_self: peer_on_self_best_finalized_id, + actual_best_finalized_peer_at_best_self: actual_peer_on_self_best_finalized_id, + }) +} + +/// Reads best `PeerChain` header known to the `SelfChain` using provided runtime API method. +/// +/// Method is supposed to be the `FinalityApi::best_finalized()` method. +pub async fn best_finalized_peer_header_at_self( + self_client: &Client, + at_self_hash: HashOf, +) -> Result>, SubstrateError> +where + SelfChain: Chain, + PeerChain: Chain, +{ + // now let's read id of best finalized peer header at our best finalized block + self_client + .typed_state_call::<_, Option<_>>( + PeerChain::BEST_FINALIZED_HEADER_ID_METHOD.into(), + (), + Some(at_self_hash), + ) + .await +} + +fn validate_out_msgs_details( + out_msgs_details: &[OutboundMessageDetails], + nonces: RangeInclusive, +) -> Result<(), SubstrateError> { + let make_missing_nonce_error = |expected_nonce| { + Err(SubstrateError::Custom(format!( + "Missing nonce {expected_nonce} in message_details call result. Expected all nonces from {nonces:?}", + ))) + }; + + if out_msgs_details.len() > nonces.clone().count() { + return Err(SubstrateError::Custom( + "More messages than requested returned by the message_details call.".into(), + )) + } + + // Check if last nonce is missing. The loop below is not checking this. + if out_msgs_details.is_empty() && !nonces.is_empty() { + return make_missing_nonce_error(*nonces.end()) + } + + let mut nonces_iter = nonces.clone().rev().peekable(); + let mut out_msgs_details_iter = out_msgs_details.iter().rev(); + while let Some((out_msg_details, &nonce)) = out_msgs_details_iter.next().zip(nonces_iter.peek()) + { + nonces_iter.next(); + if out_msg_details.nonce != nonce { + // Some nonces are missing from the middle/tail of the range. This is critical error. + return make_missing_nonce_error(nonce) + } + } + + // Check if some nonces from the beginning of the range are missing. This may happen if + // some messages were already pruned from the source node. This is not a critical error + // and will be auto-resolved by messages lane (and target node). + if nonces_iter.peek().is_some() { + log::info!( + target: "bridge", + "Some messages are missing from the {} node: {:?}. Target node may be out of sync?", + C::NAME, + nonces_iter.rev().collect::>(), + ); + } + + Ok(()) +} + +fn split_msgs_to_refine( + lane_id: LaneId, + msgs_to_refine: MessagesToRefine, +) -> Result, SubstrateError> { + let max_batch_size = Target::max_extrinsic_size() as usize; + let mut batches = vec![]; + + let mut current_msgs_batch = msgs_to_refine; + while !current_msgs_batch.is_empty() { + let mut next_msgs_batch = vec![]; + while (lane_id, ¤t_msgs_batch).encoded_size() > max_batch_size { + if current_msgs_batch.len() <= 1 { + return Err(SubstrateError::Custom(format!( + "Call of {} at {} can't be executed even if only one message is supplied. \ + max_extrinsic_size(): {}", + Source::FROM_CHAIN_MESSAGE_DETAILS_METHOD, + Target::NAME, + Target::max_extrinsic_size(), + ))) + } + + if let Some(msg) = current_msgs_batch.pop() { + next_msgs_batch.insert(0, msg); + } + } + + batches.push(current_msgs_batch); + current_msgs_batch = next_msgs_batch; + } + + Ok(batches) +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_runtime::Chain as ChainBase; + use relay_rialto_client::Rialto; + use relay_rococo_client::Rococo; + use relay_wococo_client::Wococo; + + fn message_details_from_rpc( + nonces: RangeInclusive, + ) -> Vec { + nonces + .into_iter() + .map(|nonce| bp_messages::OutboundMessageDetails { + nonce, + dispatch_weight: Weight::zero(), + size: 0, + }) + .collect() + } + + #[test] + fn validate_out_msgs_details_succeeds_if_no_messages_are_missing() { + assert!( + validate_out_msgs_details::(&message_details_from_rpc(1..=3), 1..=3,).is_ok() + ); + } + + #[test] + fn validate_out_msgs_details_succeeds_if_head_messages_are_missing() { + assert!( + validate_out_msgs_details::(&message_details_from_rpc(2..=3), 1..=3,).is_ok() + ) + } + + #[test] + fn validate_out_msgs_details_fails_if_mid_messages_are_missing() { + let mut message_details_from_rpc = message_details_from_rpc(1..=3); + message_details_from_rpc.remove(1); + assert!(matches!( + validate_out_msgs_details::(&message_details_from_rpc, 1..=3,), + Err(SubstrateError::Custom(_)) + )); + } + + #[test] + fn validate_out_msgs_details_map_fails_if_tail_messages_are_missing() { + assert!(matches!( + validate_out_msgs_details::(&message_details_from_rpc(1..=2), 1..=3,), + Err(SubstrateError::Custom(_)) + )); + } + + #[test] + fn validate_out_msgs_details_fails_if_all_messages_are_missing() { + assert!(matches!( + validate_out_msgs_details::(&[], 1..=3), + Err(SubstrateError::Custom(_)) + )); + } + + #[test] + fn validate_out_msgs_details_fails_if_more_messages_than_nonces() { + assert!(matches!( + validate_out_msgs_details::(&message_details_from_rpc(1..=5), 2..=5,), + Err(SubstrateError::Custom(_)) + )); + } + + fn check_split_msgs_to_refine( + payload_sizes: Vec, + expected_batches: Result, ()>, + ) { + let mut out_msgs_details = vec![]; + for (idx, _) in payload_sizes.iter().enumerate() { + out_msgs_details.push(OutboundMessageDetails { + nonce: idx as MessageNonce, + dispatch_weight: Weight::zero(), + size: 0, + }); + } + + let mut msgs_to_refine = vec![]; + for (&payload_size, out_msg_details) in + payload_sizes.iter().zip(out_msgs_details.iter_mut()) + { + let payload = vec![1u8; payload_size]; + msgs_to_refine.push((payload, out_msg_details)); + } + + let maybe_batches = + split_msgs_to_refine::(LaneId([0, 0, 0, 0]), msgs_to_refine); + match expected_batches { + Ok(expected_batches) => { + let batches = maybe_batches.unwrap(); + let mut idx = 0; + assert_eq!(batches.len(), expected_batches.len()); + for (batch, &expected_batch_size) in batches.iter().zip(expected_batches.iter()) { + assert_eq!(batch.len(), expected_batch_size); + for msg_to_refine in batch { + assert_eq!(msg_to_refine.0.len(), payload_sizes[idx]); + idx += 1; + } + } + }, + Err(_) => { + matches!(maybe_batches, Err(SubstrateError::Custom(_))); + }, + } + } + + #[test] + fn test_split_msgs_to_refine() { + let max_extrinsic_size = Rococo::max_extrinsic_size() as usize; + + // Check that an error is returned when one of the messages is too big. + check_split_msgs_to_refine(vec![max_extrinsic_size], Err(())); + check_split_msgs_to_refine(vec![50, 100, max_extrinsic_size, 200], Err(())); + + // Otherwise check that the split is valid. + check_split_msgs_to_refine(vec![100, 200, 300, 400], Ok(vec![4])); + check_split_msgs_to_refine( + vec![ + 50, + 100, + max_extrinsic_size - 500, + 500, + 1000, + 1500, + max_extrinsic_size - 3500, + 5000, + 10000, + ], + Ok(vec![3, 4, 2]), + ); + check_split_msgs_to_refine( + vec![ + 50, + 100, + max_extrinsic_size - 150, + 500, + 1000, + 1500, + max_extrinsic_size - 3000, + 5000, + 10000, + ], + Ok(vec![2, 1, 3, 1, 2]), + ); + check_split_msgs_to_refine( + vec![ + 5000, + 10000, + max_extrinsic_size - 3500, + 500, + 1000, + 1500, + max_extrinsic_size - 500, + 50, + 100, + ], + Ok(vec![2, 4, 3]), + ); + } +} diff --git a/relays/lib-substrate-relay/src/messages_target.rs b/relays/lib-substrate-relay/src/messages_target.rs new file mode 100644 index 00000000000..68b68b19936 --- /dev/null +++ b/relays/lib-substrate-relay/src/messages_target.rs @@ -0,0 +1,311 @@ +// Copyright 2019-2021 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 . + +//! Substrate client as Substrate messages target. The chain we connect to should have +//! runtime that implements `HeaderApi` to allow bridging with +//! `` chain. + +use crate::{ + messages_lane::{ + BatchProofTransaction, MessageLaneAdapter, ReceiveMessagesProofCallBuilder, + SubstrateMessageLane, + }, + messages_source::{ensure_messages_pallet_active, read_client_state, SubstrateMessagesProof}, + on_demand::OnDemandRelay, + TransactionParams, +}; + +use async_std::sync::Arc; +use async_trait::async_trait; +use bp_messages::{ + storage_keys::inbound_lane_data_key, total_unrewarded_messages, InboundLaneData, LaneId, + MessageNonce, UnrewardedRelayersState, +}; +use bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof; +use messages_relay::{ + message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, + message_lane_loop::{NoncesSubmitArtifacts, TargetClient, TargetClientState}, +}; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, BalanceOf, CallOf, ChainWithMessages, Client, + Error as SubstrateError, HashOf, TransactionEra, TransactionTracker, UnsignedTransaction, +}; +use relay_utils::relay_loop::Client as RelayClient; +use sp_core::Pair; +use std::{collections::VecDeque, convert::TryFrom, ops::RangeInclusive}; + +/// Message receiving proof returned by the target Substrate node. +pub type SubstrateMessagesDeliveryProof = + (UnrewardedRelayersState, FromBridgedChainMessagesDeliveryProof>); + +/// Substrate client as Substrate messages target. +pub struct SubstrateMessagesTarget { + target_client: Client, + source_client: Client, + lane_id: LaneId, + relayer_id_at_source: AccountIdOf, + transaction_params: TransactionParams>, + source_to_target_headers_relay: Option>>, +} + +impl SubstrateMessagesTarget

{ + /// Create new Substrate headers target. + pub fn new( + target_client: Client, + source_client: Client, + lane_id: LaneId, + relayer_id_at_source: AccountIdOf, + transaction_params: TransactionParams>, + source_to_target_headers_relay: Option< + Arc>, + >, + ) -> Self { + SubstrateMessagesTarget { + target_client, + source_client, + lane_id, + relayer_id_at_source, + transaction_params, + source_to_target_headers_relay, + } + } + + /// Read inbound lane state from the on-chain storage at given block. + async fn inbound_lane_data( + &self, + id: TargetHeaderIdOf>, + ) -> Result>>, SubstrateError> { + self.target_client + .storage_value( + inbound_lane_data_key( + P::SourceChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + ), + Some(id.1), + ) + .await + } + + /// Ensure that the messages pallet at target chain is active. + async fn ensure_pallet_active(&self) -> Result<(), SubstrateError> { + ensure_messages_pallet_active::(&self.target_client).await + } +} + +impl Clone for SubstrateMessagesTarget

{ + fn clone(&self) -> Self { + Self { + target_client: self.target_client.clone(), + source_client: self.source_client.clone(), + lane_id: self.lane_id, + relayer_id_at_source: self.relayer_id_at_source.clone(), + transaction_params: self.transaction_params.clone(), + source_to_target_headers_relay: self.source_to_target_headers_relay.clone(), + } + } +} + +#[async_trait] +impl RelayClient for SubstrateMessagesTarget

{ + type Error = SubstrateError; + + async fn reconnect(&mut self) -> Result<(), SubstrateError> { + // since the client calls RPC methods on both sides, we need to reconnect both + self.target_client.reconnect().await?; + self.source_client.reconnect().await?; + + // call reconnect on on-demand headers relay, because we may use different chains there + // and the error that has lead to reconnect may have came from those other chains + // (see `require_source_header_on_target`) + // + // this may lead to multiple reconnects to the same node during the same call and it + // needs to be addressed in the future + // TODO: https://github.com/paritytech/parity-bridges-common/issues/1928 + if let Some(ref mut source_to_target_headers_relay) = self.source_to_target_headers_relay { + source_to_target_headers_relay.reconnect().await?; + } + + Ok(()) + } +} + +#[async_trait] +impl TargetClient> for SubstrateMessagesTarget

+where + AccountIdOf: From< as Pair>::Public>, + BalanceOf: TryFrom>, +{ + type BatchTransaction = + BatchProofTransaction; + type TransactionTracker = TransactionTracker>; + + async fn state(&self) -> Result>, SubstrateError> { + // we can't continue to deliver confirmations if source node is out of sync, because + // it may have already received confirmations that we're going to deliver + // + // we can't continue to deliver messages if target node is out of sync, because + // it may have already received (some of) messages that we're going to deliver + self.source_client.ensure_synced().await?; + self.target_client.ensure_synced().await?; + // we can't relay messages if messages pallet at target chain is halted + self.ensure_pallet_active().await?; + + read_client_state(&self.target_client, Some(&self.source_client)).await + } + + async fn latest_received_nonce( + &self, + id: TargetHeaderIdOf>, + ) -> Result<(TargetHeaderIdOf>, MessageNonce), SubstrateError> { + // lane data missing from the storage is fine until first message is received + let latest_received_nonce = self + .inbound_lane_data(id) + .await? + .map(|data| data.last_delivered_nonce()) + .unwrap_or(0); + Ok((id, latest_received_nonce)) + } + + async fn latest_confirmed_received_nonce( + &self, + id: TargetHeaderIdOf>, + ) -> Result<(TargetHeaderIdOf>, MessageNonce), SubstrateError> { + // lane data missing from the storage is fine until first message is received + let last_confirmed_nonce = self + .inbound_lane_data(id) + .await? + .map(|data| data.last_confirmed_nonce) + .unwrap_or(0); + Ok((id, last_confirmed_nonce)) + } + + async fn unrewarded_relayers_state( + &self, + id: TargetHeaderIdOf>, + ) -> Result<(TargetHeaderIdOf>, UnrewardedRelayersState), SubstrateError> + { + let inbound_lane_data = self.inbound_lane_data(id).await?; + let last_delivered_nonce = + inbound_lane_data.as_ref().map(|data| data.last_delivered_nonce()).unwrap_or(0); + let relayers = inbound_lane_data.map(|data| data.relayers).unwrap_or_else(VecDeque::new); + let unrewarded_relayers_state = bp_messages::UnrewardedRelayersState { + unrewarded_relayer_entries: relayers.len() as _, + messages_in_oldest_entry: relayers + .front() + .map(|entry| 1 + entry.messages.end - entry.messages.begin) + .unwrap_or(0), + total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX), + last_delivered_nonce, + }; + Ok((id, unrewarded_relayers_state)) + } + + async fn prove_messages_receiving( + &self, + id: TargetHeaderIdOf>, + ) -> Result< + ( + TargetHeaderIdOf>, + as MessageLane>::MessagesReceivingProof, + ), + SubstrateError, + > { + let (id, relayers_state) = self.unrewarded_relayers_state(id).await?; + let inbound_data_key = bp_messages::storage_keys::inbound_lane_data_key( + P::SourceChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + ); + let proof = self + .target_client + .prove_storage(vec![inbound_data_key], id.1) + .await? + .into_iter_nodes() + .collect(); + let proof = FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: id.1, + storage_proof: proof, + lane: self.lane_id, + }; + Ok((id, (relayers_state, proof))) + } + + async fn submit_messages_proof( + &self, + maybe_batch_tx: Option, + _generated_at_header: SourceHeaderIdOf>, + nonces: RangeInclusive, + proof: as MessageLane>::MessagesProof, + ) -> Result, SubstrateError> { + let messages_proof_call = make_messages_delivery_call::

( + self.relayer_id_at_source.clone(), + proof.1.nonces_start..=proof.1.nonces_end, + proof, + maybe_batch_tx.is_none(), + ); + let final_call = match maybe_batch_tx { + Some(batch_tx) => batch_tx.append_call_and_build(messages_proof_call), + None => messages_proof_call, + }; + + let transaction_params = self.transaction_params.clone(); + let tx_tracker = self + .target_client + .submit_and_watch_signed_extrinsic( + &self.transaction_params.signer, + move |best_block_id, transaction_nonce| { + Ok(UnsignedTransaction::new(final_call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) + }, + ) + .await?; + Ok(NoncesSubmitArtifacts { nonces, tx_tracker }) + } + + async fn require_source_header_on_target( + &self, + id: SourceHeaderIdOf>, + ) -> Result, SubstrateError> { + if let Some(ref source_to_target_headers_relay) = self.source_to_target_headers_relay { + if let Some(batch_tx) = + BatchProofTransaction::new(source_to_target_headers_relay.clone(), id.0).await? + { + return Ok(Some(batch_tx)) + } + + source_to_target_headers_relay.require_more_headers(id.0).await; + } + + Ok(None) + } +} + +/// Make messages delivery call from given proof. +fn make_messages_delivery_call( + relayer_id_at_source: AccountIdOf, + nonces: RangeInclusive, + proof: SubstrateMessagesProof, + trace_call: bool, +) -> CallOf { + let messages_count = nonces.end() - nonces.start() + 1; + let dispatch_weight = proof.0; + P::ReceiveMessagesProofCallBuilder::build_receive_messages_proof_call( + relayer_id_at_source, + proof, + messages_count as _, + dispatch_weight, + trace_call, + ) +} diff --git a/relays/lib-substrate-relay/src/on_demand/headers.rs b/relays/lib-substrate-relay/src/on_demand/headers.rs new file mode 100644 index 00000000000..aded79a857a --- /dev/null +++ b/relays/lib-substrate-relay/src/on_demand/headers.rs @@ -0,0 +1,511 @@ +// Copyright 2019-2021 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 . + +//! On-demand Substrate -> Substrate header finality relay. + +use crate::finality::SubmitFinalityProofCallBuilder; + +use async_std::sync::{Arc, Mutex}; +use async_trait::async_trait; +use bp_header_chain::ConsensusLogReader; +use bp_runtime::HeaderIdProvider; +use futures::{select, FutureExt}; +use num_traits::{One, Zero}; +use sp_runtime::traits::Header; + +use finality_relay::{FinalitySyncParams, TargetClient as FinalityTargetClient}; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, Error as SubstrateError, + HeaderIdOf, +}; +use relay_utils::{ + metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, MaybeConnectionError, + STALL_TIMEOUT, +}; + +use crate::{ + finality::{ + engine::Engine, + source::{RequiredHeaderNumberRef, SubstrateFinalitySource}, + target::SubstrateFinalityTarget, + SubstrateFinalitySyncPipeline, RECENT_FINALITY_PROOFS_LIMIT, + }, + on_demand::OnDemandRelay, + TransactionParams, +}; + +/// On-demand Substrate <-> Substrate header finality relay. +/// +/// This relay may be requested to sync more headers, whenever some other relay (e.g. messages +/// relay) needs it to continue its regular work. When enough headers are relayed, on-demand stops +/// syncing headers. +#[derive(Clone)] +pub struct OnDemandHeadersRelay { + /// Relay task name. + relay_task_name: String, + /// Shared reference to maximal required finalized header number. + required_header_number: RequiredHeaderNumberRef, + /// Client of the source chain. + source_client: Client, + /// Client of the target chain. + target_client: Client, +} + +impl OnDemandHeadersRelay

{ + /// Create new on-demand headers relay. + /// + /// If `metrics_params` is `Some(_)`, the metrics of the finality relay are registered. + /// Otherwise, all required metrics must be exposed outside of this method. + pub fn new( + source_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + only_mandatory_headers: bool, + metrics_params: Option, + ) -> Self + where + AccountIdOf: + From< as sp_core::Pair>::Public>, + { + let required_header_number = Arc::new(Mutex::new(Zero::zero())); + let this = OnDemandHeadersRelay { + relay_task_name: on_demand_headers_relay_name::(), + required_header_number: required_header_number.clone(), + source_client: source_client.clone(), + target_client: target_client.clone(), + }; + async_std::task::spawn(async move { + background_task::

( + source_client, + target_client, + target_transaction_params, + only_mandatory_headers, + required_header_number, + metrics_params, + ) + .await; + }); + + this + } +} + +#[async_trait] +impl OnDemandRelay + for OnDemandHeadersRelay

+{ + async fn reconnect(&self) -> Result<(), SubstrateError> { + // using clone is fine here (to avoid mut requirement), because clone on Client clones + // internal references + self.source_client.clone().reconnect().await?; + self.target_client.clone().reconnect().await + } + + async fn require_more_headers(&self, required_header: BlockNumberOf) { + let mut required_header_number = self.required_header_number.lock().await; + if required_header > *required_header_number { + log::trace!( + target: "bridge", + "[{}] More {} headers required. Going to sync up to the {}", + self.relay_task_name, + P::SourceChain::NAME, + required_header, + ); + + *required_header_number = required_header; + } + } + + async fn prove_header( + &self, + required_header: BlockNumberOf, + ) -> Result<(HeaderIdOf, Vec>), SubstrateError> { + // first find proper header (either `required_header`) or its descendant + let finality_source = SubstrateFinalitySource::

::new(self.source_client.clone(), None); + let (header, proof) = finality_source.prove_block_finality(required_header).await?; + let header_id = header.id(); + + // optimize justification before including it into the call + let proof = P::FinalityEngine::optimize_proof(&self.target_client, &header, proof).await?; + + log::debug!( + target: "bridge", + "[{}] Requested to prove {} head {:?}. Selected to prove {} head {:?}", + self.relay_task_name, + P::SourceChain::NAME, + required_header, + P::SourceChain::NAME, + header_id, + ); + + // and then craft the submit-proof call + let call = + P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof); + + Ok((header_id, vec![call])) + } +} + +/// Background task that is responsible for starting headers relay. +async fn background_task( + source_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + only_mandatory_headers: bool, + required_header_number: RequiredHeaderNumberRef, + metrics_params: Option, +) where + AccountIdOf: From< as sp_core::Pair>::Public>, +{ + let relay_task_name = on_demand_headers_relay_name::(); + let target_transactions_mortality = target_transaction_params.mortality; + let mut finality_source = SubstrateFinalitySource::

::new( + source_client.clone(), + Some(required_header_number.clone()), + ); + let mut finality_target = + SubstrateFinalityTarget::new(target_client.clone(), target_transaction_params); + let mut latest_non_mandatory_at_source = Zero::zero(); + + let mut restart_relay = true; + let finality_relay_task = futures::future::Fuse::terminated(); + futures::pin_mut!(finality_relay_task); + + loop { + select! { + _ = async_std::task::sleep(P::TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, + _ = finality_relay_task => { + // this should never happen in practice given the current code + restart_relay = true; + }, + } + + // read best finalized source header number from source + let best_finalized_source_header_at_source = + best_finalized_source_header_at_source(&finality_source, &relay_task_name).await; + if matches!(best_finalized_source_header_at_source, Err(ref e) if e.is_connection_error()) { + relay_utils::relay_loop::reconnect_failed_client( + FailedClient::Source, + relay_utils::relay_loop::RECONNECT_DELAY, + &mut finality_source, + &mut finality_target, + ) + .await; + continue + } + + // read best finalized source header number from target + let best_finalized_source_header_at_target = + best_finalized_source_header_at_target::

(&finality_target, &relay_task_name).await; + if matches!(best_finalized_source_header_at_target, Err(ref e) if e.is_connection_error()) { + relay_utils::relay_loop::reconnect_failed_client( + FailedClient::Target, + relay_utils::relay_loop::RECONNECT_DELAY, + &mut finality_source, + &mut finality_target, + ) + .await; + continue + } + + // submit mandatory header if some headers are missing + let best_finalized_source_header_at_source_fmt = + format!("{best_finalized_source_header_at_source:?}"); + let best_finalized_source_header_at_target_fmt = + format!("{best_finalized_source_header_at_target:?}"); + let required_header_number_value = *required_header_number.lock().await; + let mandatory_scan_range = mandatory_headers_scan_range::( + best_finalized_source_header_at_source.ok(), + best_finalized_source_header_at_target.ok(), + required_header_number_value, + ) + .await; + + log::trace!( + target: "bridge", + "[{}] Mandatory headers scan range: ({:?}, {:?}, {:?}) -> {:?}", + relay_task_name, + required_header_number_value, + best_finalized_source_header_at_source_fmt, + best_finalized_source_header_at_target_fmt, + mandatory_scan_range, + ); + + if let Some(mandatory_scan_range) = mandatory_scan_range { + let relay_mandatory_header_result = relay_mandatory_header_from_range( + &finality_source, + &required_header_number, + best_finalized_source_header_at_target_fmt, + ( + std::cmp::max(mandatory_scan_range.0, latest_non_mandatory_at_source), + mandatory_scan_range.1, + ), + &relay_task_name, + ) + .await; + match relay_mandatory_header_result { + Ok(true) => (), + Ok(false) => { + // there are no (or we don't need to relay them) mandatory headers in the range + // => to avoid scanning the same headers over and over again, remember that + latest_non_mandatory_at_source = mandatory_scan_range.1; + + log::trace!( + target: "bridge", + "[{}] No mandatory {} headers in the range {:?}", + relay_task_name, + P::SourceChain::NAME, + mandatory_scan_range, + ); + }, + Err(e) => { + log::warn!( + target: "bridge", + "[{}] Failed to scan mandatory {} headers range ({:?}): {:?}", + relay_task_name, + P::SourceChain::NAME, + mandatory_scan_range, + e, + ); + + if e.is_connection_error() { + relay_utils::relay_loop::reconnect_failed_client( + FailedClient::Source, + relay_utils::relay_loop::RECONNECT_DELAY, + &mut finality_source, + &mut finality_target, + ) + .await; + continue + } + }, + } + } + + // start/restart relay + if restart_relay { + let stall_timeout = relay_substrate_client::transaction_stall_timeout( + target_transactions_mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); + + log::info!( + target: "bridge", + "[{}] Starting on-demand headers relay task\n\t\ + Only mandatory headers: {}\n\t\ + Tx mortality: {:?} (~{}m)\n\t\ + Stall timeout: {:?}", + relay_task_name, + only_mandatory_headers, + target_transactions_mortality, + stall_timeout.as_secs_f64() / 60.0f64, + stall_timeout, + ); + + finality_relay_task.set( + finality_relay::run( + finality_source.clone(), + finality_target.clone(), + FinalitySyncParams { + tick: std::cmp::max( + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + ), + recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, + stall_timeout, + only_mandatory_headers, + }, + metrics_params.clone().unwrap_or_else(MetricsParams::disabled), + futures::future::pending(), + ) + .fuse(), + ); + + restart_relay = false; + } + } +} + +/// Returns `Some()` with inclusive range of headers which must be scanned for mandatory headers +/// and the first of such headers must be submitted to the target node. +async fn mandatory_headers_scan_range( + best_finalized_source_header_at_source: Option, + best_finalized_source_header_at_target: Option, + required_header_number: BlockNumberOf, +) -> Option<(C::BlockNumber, C::BlockNumber)> { + // if we have been unable to read header number from the target, then let's assume + // that it is the same as required header number. Otherwise we risk submitting + // unneeded transactions + let best_finalized_source_header_at_target = + best_finalized_source_header_at_target.unwrap_or(required_header_number); + + // if we have been unable to read header number from the source, then let's assume + // that it is the same as at the target + let best_finalized_source_header_at_source = + best_finalized_source_header_at_source.unwrap_or(best_finalized_source_header_at_target); + + // if relay is already asked to sync more headers than we have at source, don't do anything yet + if required_header_number >= best_finalized_source_header_at_source { + return None + } + + Some(( + best_finalized_source_header_at_target + One::one(), + best_finalized_source_header_at_source, + )) +} + +/// Try to find mandatory header in the inclusive headers range and, if one is found, ask to relay +/// it. +/// +/// Returns `true` if header was found and (asked to be) relayed and `false` otherwise. +async fn relay_mandatory_header_from_range( + finality_source: &SubstrateFinalitySource

, + required_header_number: &RequiredHeaderNumberRef, + best_finalized_source_header_at_target: String, + range: (BlockNumberOf, BlockNumberOf), + relay_task_name: &str, +) -> Result { + // search for mandatory header first + let mandatory_source_header_number = + find_mandatory_header_in_range(finality_source, range).await?; + + // if there are no mandatory headers - we have nothing to do + let mandatory_source_header_number = match mandatory_source_header_number { + Some(mandatory_source_header_number) => mandatory_source_header_number, + None => return Ok(false), + }; + + // `find_mandatory_header` call may take a while => check if `required_header_number` is still + // less than our `mandatory_source_header_number` before logging anything + let mut required_header_number = required_header_number.lock().await; + if *required_header_number >= mandatory_source_header_number { + return Ok(false) + } + + log::trace!( + target: "bridge", + "[{}] Too many {} headers missing at target ({} vs {}). Going to sync up to the mandatory {}", + relay_task_name, + P::SourceChain::NAME, + best_finalized_source_header_at_target, + range.1, + mandatory_source_header_number, + ); + + *required_header_number = mandatory_source_header_number; + Ok(true) +} + +/// Read best finalized source block number from source client. +/// +/// Returns `None` if we have failed to read the number. +async fn best_finalized_source_header_at_source( + finality_source: &SubstrateFinalitySource

, + relay_task_name: &str, +) -> Result, relay_substrate_client::Error> { + finality_source.on_chain_best_finalized_block_number().await.map_err(|error| { + log::error!( + target: "bridge", + "[{}] Failed to read best finalized source header from source: {:?}", + relay_task_name, + error, + ); + + error + }) +} + +/// Read best finalized source block number from target client. +/// +/// Returns `None` if we have failed to read the number. +async fn best_finalized_source_header_at_target( + finality_target: &SubstrateFinalityTarget

, + relay_task_name: &str, +) -> Result, as RelayClient>::Error> +where + AccountIdOf: From< as sp_core::Pair>::Public>, +{ + finality_target + .best_finalized_source_block_id() + .await + .map_err(|error| { + log::error!( + target: "bridge", + "[{}] Failed to read best finalized source header from target: {:?}", + relay_task_name, + error, + ); + + error + }) + .map(|id| id.0) +} + +/// Read first mandatory header in given inclusive range. +/// +/// Returns `Ok(None)` if there were no mandatory headers in the range. +async fn find_mandatory_header_in_range( + finality_source: &SubstrateFinalitySource

, + range: (BlockNumberOf, BlockNumberOf), +) -> Result>, relay_substrate_client::Error> { + let mut current = range.0; + while current <= range.1 { + let header = finality_source.client().header_by_number(current).await?; + if >::ConsensusLogReader::schedules_authorities_change( + header.digest(), + ) { + return Ok(Some(current)) + } + + current += One::one(); + } + + Ok(None) +} + +/// On-demand headers relay task name. +fn on_demand_headers_relay_name() -> String { + format!("{}-to-{}-on-demand-headers", SourceChain::NAME, TargetChain::NAME) +} + +#[cfg(test)] +mod tests { + use super::*; + + type TestChain = relay_rococo_client::Rococo; + + const AT_SOURCE: Option = Some(10); + const AT_TARGET: Option = Some(1); + + #[async_std::test] + async fn mandatory_headers_scan_range_selects_range_if_some_headers_are_missing() { + assert_eq!( + mandatory_headers_scan_range::(AT_SOURCE, AT_TARGET, 0,).await, + Some((AT_TARGET.unwrap() + 1, AT_SOURCE.unwrap())), + ); + } + + #[async_std::test] + async fn mandatory_headers_scan_range_selects_nothing_if_already_queued() { + assert_eq!( + mandatory_headers_scan_range::(AT_SOURCE, AT_TARGET, AT_SOURCE.unwrap(),) + .await, + None, + ); + } +} diff --git a/relays/lib-substrate-relay/src/on_demand/mod.rs b/relays/lib-substrate-relay/src/on_demand/mod.rs new file mode 100644 index 00000000000..00bb33d6740 --- /dev/null +++ b/relays/lib-substrate-relay/src/on_demand/mod.rs @@ -0,0 +1,48 @@ +// Copyright 2019-2021 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 . + +//! Types and functions intended to ease adding of new Substrate -> Substrate +//! on-demand pipelines. + +use async_trait::async_trait; +use relay_substrate_client::{BlockNumberOf, CallOf, Chain, Error as SubstrateError, HeaderIdOf}; + +pub mod headers; +pub mod parachains; + +/// On-demand headers relay that is relaying finalizing headers only when requested. +#[async_trait] +pub trait OnDemandRelay: Send + Sync { + /// Reconnect to source and target nodes. + async fn reconnect(&self) -> Result<(), SubstrateError>; + + /// Ask relay to relay source header with given number to the target chain. + /// + /// Depending on implementation, on-demand relay may also relay `required_header` ancestors + /// (e.g. if they're mandatory), or its descendants. The request is considered complete if + /// the best avbailable header at the target chain has number that is larger than or equal + /// to the `required_header`. + async fn require_more_headers(&self, required_header: BlockNumberOf); + + /// Ask relay to prove source `required_header` to the `TargetChain`. + /// + /// Returns number of header that is proved (it may be the `required_header` or one of its + /// descendants) and calls for delivering the proof. + async fn prove_header( + &self, + required_header: BlockNumberOf, + ) -> Result<(HeaderIdOf, Vec>), SubstrateError>; +} diff --git a/relays/lib-substrate-relay/src/on_demand/parachains.rs b/relays/lib-substrate-relay/src/on_demand/parachains.rs new file mode 100644 index 00000000000..4c205770d4a --- /dev/null +++ b/relays/lib-substrate-relay/src/on_demand/parachains.rs @@ -0,0 +1,1033 @@ +// Copyright 2019-2021 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 . + +//! On-demand Substrate -> Substrate parachain finality relay. + +use crate::{ + messages_source::best_finalized_peer_header_at_self, + on_demand::OnDemandRelay, + parachains::{ + source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter, + SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, + }, + TransactionParams, +}; + +use async_std::{ + channel::{unbounded, Receiver, Sender}, + sync::{Arc, Mutex}, +}; +use async_trait::async_trait; +use bp_polkadot_core::parachains::{ParaHash, ParaId}; +use bp_runtime::HeaderIdProvider; +use futures::{select, FutureExt}; +use num_traits::Zero; +use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use parachains_relay::parachains_loop::{AvailableHeader, SourceClient, TargetClient}; +use relay_substrate_client::{ + is_ancient_block, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, + Error as SubstrateError, HashOf, HeaderIdOf, ParachainBase, +}; +use relay_utils::{ + metrics::MetricsParams, relay_loop::Client as RelayClient, BlockNumberBase, FailedClient, + HeaderId, UniqueSaturatedInto, +}; +use std::fmt::Debug; + +/// On-demand Substrate <-> Substrate parachain finality relay. +/// +/// This relay may be requested to sync more parachain headers, whenever some other relay +/// (e.g. messages relay) needs it to continue its regular work. When enough parachain headers +/// are relayed, on-demand stops syncing headers. +#[derive(Clone)] +pub struct OnDemandParachainsRelay { + /// Relay task name. + relay_task_name: String, + /// Channel used to communicate with background task and ask for relay of parachain heads. + required_header_number_sender: Sender>, + /// Source relay chain client. + source_relay_client: Client, + /// Target chain client. + target_client: Client, + /// On-demand relay chain relay. + on_demand_source_relay_to_target_headers: + Arc>, +} + +impl OnDemandParachainsRelay

{ + /// Create new on-demand parachains relay. + /// + /// Note that the argument is the source relay chain client, not the parachain client. + /// That's because parachain finality is determined by the relay chain and we don't + /// need to connect to the parachain itself here. + pub fn new( + source_relay_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + on_demand_source_relay_to_target_headers: Arc< + dyn OnDemandRelay, + >, + ) -> Self + where + P::SourceParachain: Chain, + P::SourceRelayChain: + Chain, + AccountIdOf: + From< as sp_core::Pair>::Public>, + { + let (required_header_number_sender, required_header_number_receiver) = unbounded(); + let this = OnDemandParachainsRelay { + relay_task_name: on_demand_parachains_relay_name::( + ), + required_header_number_sender, + source_relay_client: source_relay_client.clone(), + target_client: target_client.clone(), + on_demand_source_relay_to_target_headers: on_demand_source_relay_to_target_headers + .clone(), + }; + async_std::task::spawn(async move { + background_task::

( + source_relay_client, + target_client, + target_transaction_params, + on_demand_source_relay_to_target_headers, + required_header_number_receiver, + ) + .await; + }); + + this + } +} + +#[async_trait] +impl OnDemandRelay + for OnDemandParachainsRelay

+where + P::SourceParachain: Chain, +{ + async fn reconnect(&self) -> Result<(), SubstrateError> { + // using clone is fine here (to avoid mut requirement), because clone on Client clones + // internal references + self.source_relay_client.clone().reconnect().await?; + self.target_client.clone().reconnect().await?; + // we'll probably need to reconnect relay chain relayer clients also + self.on_demand_source_relay_to_target_headers.reconnect().await + } + + async fn require_more_headers(&self, required_header: BlockNumberOf) { + if let Err(e) = self.required_header_number_sender.send(required_header).await { + log::trace!( + target: "bridge", + "[{}] Failed to request {} header {:?}: {:?}", + self.relay_task_name, + P::SourceParachain::NAME, + required_header, + e, + ); + } + } + + /// Ask relay to prove source `required_header` to the `TargetChain`. + async fn prove_header( + &self, + required_parachain_header: BlockNumberOf, + ) -> Result<(HeaderIdOf, Vec>), SubstrateError> { + // select headers to prove + let parachains_source = ParachainsSource::

::new( + self.source_relay_client.clone(), + Arc::new(Mutex::new(AvailableHeader::Missing)), + ); + let env = (self, ¶chains_source); + let (need_to_prove_relay_block, selected_relay_block, selected_parachain_block) = + select_headers_to_prove(env, required_parachain_header).await?; + + log::debug!( + target: "bridge", + "[{}] Requested to prove {} head {:?}. Selected to prove {} head {:?} and {} head {:?}", + self.relay_task_name, + P::SourceParachain::NAME, + required_parachain_header, + P::SourceParachain::NAME, + selected_parachain_block, + P::SourceRelayChain::NAME, + if need_to_prove_relay_block { + Some(selected_relay_block) + } else { + None + }, + ); + + // now let's prove relay chain block (if needed) + let mut calls = Vec::new(); + let mut proved_relay_block = selected_relay_block; + if need_to_prove_relay_block { + let (relay_block, relay_prove_call) = self + .on_demand_source_relay_to_target_headers + .prove_header(selected_relay_block.number()) + .await?; + proved_relay_block = relay_block; + calls.extend(relay_prove_call); + } + + // despite what we've selected before (in `select_headers_to_prove` call), if headers relay + // have chose the different header (e.g. because there's no GRANDPA jusstification for it), + // we need to prove parachain head available at this header + let para_id = ParaId(P::SourceParachain::PARACHAIN_ID); + let mut proved_parachain_block = selected_parachain_block; + if proved_relay_block != selected_relay_block { + proved_parachain_block = parachains_source + .on_chain_para_head_id(proved_relay_block) + .await? + // this could happen e.g. if parachain has been offboarded? + .ok_or_else(|| { + SubstrateError::MissingRequiredParachainHead( + para_id, + proved_relay_block.number().unique_saturated_into(), + ) + })?; + + log::debug!( + target: "bridge", + "[{}] Selected to prove {} head {:?} and {} head {:?}. Instead proved {} head {:?} and {} head {:?}", + self.relay_task_name, + P::SourceParachain::NAME, + selected_parachain_block, + P::SourceRelayChain::NAME, + selected_relay_block, + P::SourceParachain::NAME, + proved_parachain_block, + P::SourceRelayChain::NAME, + proved_relay_block, + ); + } + + // and finally - prove parachain head + let (para_proof, para_hash) = + parachains_source.prove_parachain_head(proved_relay_block).await?; + calls.push(P::SubmitParachainHeadsCallBuilder::build_submit_parachain_heads_call( + proved_relay_block, + vec![(para_id, para_hash)], + para_proof, + )); + + Ok((proved_parachain_block, calls)) + } +} + +/// Background task that is responsible for starting parachain headers relay. +async fn background_task( + source_relay_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + on_demand_source_relay_to_target_headers: Arc< + dyn OnDemandRelay, + >, + required_parachain_header_number_receiver: Receiver>, +) where + P::SourceParachain: Chain, + P::SourceRelayChain: + Chain, + AccountIdOf: From< as sp_core::Pair>::Public>, +{ + let relay_task_name = on_demand_parachains_relay_name::(); + let target_transactions_mortality = target_transaction_params.mortality; + + let mut relay_state = RelayState::Idle; + let mut required_parachain_header_number = Zero::zero(); + let required_para_header_ref = Arc::new(Mutex::new(AvailableHeader::Unavailable)); + + let mut restart_relay = true; + let parachains_relay_task = futures::future::Fuse::terminated(); + futures::pin_mut!(parachains_relay_task); + + let mut parachains_source = + ParachainsSource::

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

::new(target_client.clone(), target_transaction_params.clone()); + + loop { + select! { + new_required_parachain_header_number = required_parachain_header_number_receiver.recv().fuse() => { + let new_required_parachain_header_number = match new_required_parachain_header_number { + Ok(new_required_parachain_header_number) => new_required_parachain_header_number, + Err(e) => { + log::error!( + target: "bridge", + "[{}] Background task has exited with error: {:?}", + relay_task_name, + e, + ); + + return; + }, + }; + + // keep in mind that we are not updating `required_para_header_ref` here, because + // then we'll be submitting all previous headers as well (while required relay headers are + // delivered) and we want to avoid that (to reduce cost) + if new_required_parachain_header_number > required_parachain_header_number { + log::trace!( + target: "bridge", + "[{}] More {} headers required. Going to sync up to the {}", + relay_task_name, + P::SourceParachain::NAME, + new_required_parachain_header_number, + ); + + required_parachain_header_number = new_required_parachain_header_number; + } + }, + _ = async_std::task::sleep(P::TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, + _ = parachains_relay_task => { + // this should never happen in practice given the current code + restart_relay = true; + }, + } + + // the workflow of the on-demand parachains relay is: + // + // 1) message relay (or any other dependent relay) sees new message at parachain header + // `PH`; + // + // 2) it sees that the target chain does not know `PH`; + // + // 3) it asks on-demand parachains relay to relay `PH` to the target chain; + // + // Phase#1: relaying relay chain header + // + // 4) on-demand parachains relay waits for GRANDPA-finalized block of the source relay chain + // `RH` that is storing `PH` or its descendant. Let it be `PH'`; + // 5) it asks on-demand headers relay to relay `RH` to the target chain; + // 6) it waits until `RH` (or its descendant) is relayed to the target chain; + // + // Phase#2: relaying parachain header + // + // 7) on-demand parachains relay sets `ParachainsSource::maximal_header_number` to the + // `PH'.number()`. + // 8) parachains finality relay sees that the parachain head has been + // updated and relays `PH'` to the target chain. + + // select headers to relay + let relay_data = read_relay_data( + ¶chains_source, + ¶chains_target, + required_parachain_header_number, + ) + .await; + match relay_data { + Ok(relay_data) => { + let prev_relay_state = relay_state; + relay_state = select_headers_to_relay(&relay_data, relay_state); + log::trace!( + target: "bridge", + "[{}] Selected new relay state: {:?} using old state {:?} and data {:?}", + relay_task_name, + relay_state, + prev_relay_state, + relay_data, + ); + }, + Err(failed_client) => { + relay_utils::relay_loop::reconnect_failed_client( + failed_client, + relay_utils::relay_loop::RECONNECT_DELAY, + &mut parachains_source, + &mut parachains_target, + ) + .await; + continue + }, + } + + // we have selected our new 'state' => let's notify our source clients about our new + // requirements + match relay_state { + RelayState::Idle => (), + RelayState::RelayingRelayHeader(required_relay_header) => { + on_demand_source_relay_to_target_headers + .require_more_headers(required_relay_header) + .await; + }, + RelayState::RelayingParaHeader(required_para_header) => { + *required_para_header_ref.lock().await = + AvailableHeader::Available(required_para_header); + }, + } + + // start/restart relay + if restart_relay { + let stall_timeout = relay_substrate_client::transaction_stall_timeout( + target_transactions_mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + relay_utils::STALL_TIMEOUT, + ); + + log::info!( + target: "bridge", + "[{}] Starting on-demand-parachains relay task\n\t\ + Tx mortality: {:?} (~{}m)\n\t\ + Stall timeout: {:?}", + relay_task_name, + target_transactions_mortality, + stall_timeout.as_secs_f64() / 60.0f64, + stall_timeout, + ); + + parachains_relay_task.set( + parachains_relay::parachains_loop::run( + parachains_source.clone(), + parachains_target.clone(), + MetricsParams::disabled(), + futures::future::pending(), + ) + .fuse(), + ); + + restart_relay = false; + } + } +} + +/// On-demand parachains relay task name. +fn on_demand_parachains_relay_name() -> String { + format!("{}-to-{}-on-demand-parachain", SourceChain::NAME, TargetChain::NAME) +} + +/// On-demand relay state. +#[derive(Clone, Copy, Debug, PartialEq)] +enum RelayState { + /// On-demand relay is not doing anything. + Idle, + /// Relaying given relay header to relay given parachain header later. + RelayingRelayHeader(RelayNumber), + /// Relaying given parachain header. + RelayingParaHeader(HeaderId), +} + +/// Data gathered from source and target clients, used by on-demand relay. +#[derive(Debug)] +struct RelayData { + /// Parachain header number that is required at the target chain. + pub required_para_header: ParaNumber, + /// Parachain header number, known to the target chain. + pub para_header_at_target: Option, + /// Parachain header id, known to the source (relay) chain. + pub para_header_at_source: Option>, + /// Parachain header, that is available at the source relay chain at `relay_header_at_target` + /// block. + /// + /// May be `None` if there's no `relay_header_at_target` yet, or if the + /// `relay_header_at_target` is too old and we think its state has been pruned. + pub para_header_at_relay_header_at_target: Option>, + /// Relay header number at the source chain. + pub relay_header_at_source: RelayNumber, + /// Relay header number at the target chain. + pub relay_header_at_target: Option, +} + +/// Read required data from source and target clients. +async fn read_relay_data( + source: &ParachainsSource

, + target: &ParachainsTarget

, + required_header_number: BlockNumberOf, +) -> Result< + RelayData< + HashOf, + BlockNumberOf, + BlockNumberOf, + >, + FailedClient, +> +where + ParachainsTarget

: + TargetClient> + RelayClient, +{ + let map_target_err = |e| { + log::error!( + target: "bridge", + "[{}] Failed to read relay data from {} client: {:?}", + on_demand_parachains_relay_name::(), + P::TargetChain::NAME, + e, + ); + FailedClient::Target + }; + let map_source_err = |e| { + log::error!( + target: "bridge", + "[{}] Failed to read relay data from {} client: {:?}", + on_demand_parachains_relay_name::(), + P::SourceRelayChain::NAME, + e, + ); + FailedClient::Source + }; + + let best_target_block_hash = target.best_block().await.map_err(map_target_err)?.1; + let para_header_at_target = best_finalized_peer_header_at_self::< + P::TargetChain, + P::SourceParachain, + >(target.client(), best_target_block_hash) + .await; + // if there are no parachain heads at the target (`NoParachainHeadAtTarget`), we'll need to + // submit at least one. Otherwise the pallet will be treated as uninitialized and messages + // sync will stall. + let para_header_at_target = match para_header_at_target { + Ok(Some(para_header_at_target)) => Some(para_header_at_target.0), + Ok(None) => None, + Err(e) => return Err(map_target_err(e)), + }; + + let best_finalized_relay_header = + source.client().best_finalized_header().await.map_err(map_source_err)?; + let best_finalized_relay_block_id = best_finalized_relay_header.id(); + let para_header_at_source = source + .on_chain_para_head_id(best_finalized_relay_block_id) + .await + .map_err(map_source_err)?; + + let relay_header_at_source = best_finalized_relay_block_id.0; + let relay_header_at_target = best_finalized_peer_header_at_self::< + P::TargetChain, + P::SourceRelayChain, + >(target.client(), best_target_block_hash) + .await + .map_err(map_target_err)?; + + // if relay header at target is too old then its state may already be discarded at the source + // => just use `None` in this case + // + // the same is for case when there's no relay header at target at all + let available_relay_header_at_target = + relay_header_at_target.filter(|relay_header_at_target| { + !is_ancient_block(relay_header_at_target.number(), relay_header_at_source) + }); + let para_header_at_relay_header_at_target = + if let Some(available_relay_header_at_target) = available_relay_header_at_target { + source + .on_chain_para_head_id(available_relay_header_at_target) + .await + .map_err(map_source_err)? + } else { + None + }; + + Ok(RelayData { + required_para_header: required_header_number, + para_header_at_target, + para_header_at_source, + relay_header_at_source, + relay_header_at_target: relay_header_at_target + .map(|relay_header_at_target| relay_header_at_target.0), + para_header_at_relay_header_at_target, + }) +} + +/// Select relay and parachain headers that need to be relayed. +fn select_headers_to_relay( + data: &RelayData, + state: RelayState, +) -> RelayState +where + ParaHash: Clone, + ParaNumber: Copy + PartialOrd + Zero, + RelayNumber: Copy + Debug + Ord, +{ + // we can't do anything until **relay chain** bridge GRANDPA pallet is not initialized at the + // target chain + let relay_header_at_target = match data.relay_header_at_target { + Some(relay_header_at_target) => relay_header_at_target, + None => return RelayState::Idle, + }; + + // Process the `RelayingRelayHeader` state. + if let &RelayState::RelayingRelayHeader(relay_header_number) = &state { + if relay_header_at_target < relay_header_number { + // The required relay header hasn't yet been relayed. Ask / wait for it. + return state + } + + // We may switch to `RelayingParaHeader` if parachain head is available. + if let Some(para_header_at_relay_header_at_target) = + data.para_header_at_relay_header_at_target.as_ref() + { + return RelayState::RelayingParaHeader(para_header_at_relay_header_at_target.clone()) + } + + // else use the regular process - e.g. we may require to deliver new relay header first + } + + // Process the `RelayingParaHeader` state. + if let RelayState::RelayingParaHeader(para_header_id) = &state { + let para_header_at_target_or_zero = data.para_header_at_target.unwrap_or_else(Zero::zero); + if para_header_at_target_or_zero < para_header_id.0 { + // The required parachain header hasn't yet been relayed. Ask / wait for it. + return state + } + } + + // if we haven't read para head from the source, we can't yet do anything + let para_header_at_source = match data.para_header_at_source { + Some(ref para_header_at_source) => para_header_at_source.clone(), + None => return RelayState::Idle, + }; + + // if we have parachain head at the source, but no parachain heads at the target, we'll need + // to deliver at least one parachain head + let (required_para_header, para_header_at_target) = match data.para_header_at_target { + Some(para_header_at_target) => (data.required_para_header, para_header_at_target), + None => (para_header_at_source.0, Zero::zero()), + }; + + // if we have already satisfied our "customer", do nothing + if required_para_header <= para_header_at_target { + return RelayState::Idle + } + + // if required header is not available even at the source chain, let's wait + if required_para_header > para_header_at_source.0 { + return RelayState::Idle + } + + // we will always try to sync latest parachain/relay header, even if we've been asked for some + // its ancestor + + // we need relay chain header first + if relay_header_at_target < data.relay_header_at_source { + return RelayState::RelayingRelayHeader(data.relay_header_at_source) + } + + // if all relay headers synced, we may start directly with parachain header + RelayState::RelayingParaHeader(para_header_at_source) +} + +/// Environment for the `select_headers_to_prove` call. +#[async_trait] +trait SelectHeadersToProveEnvironment { + /// Returns associated parachain id. + fn parachain_id(&self) -> ParaId; + /// Returns best finalized relay block. + async fn best_finalized_relay_block_at_source( + &self, + ) -> Result, SubstrateError>; + /// Returns best finalized relay block that is known at `P::TargetChain`. + async fn best_finalized_relay_block_at_target( + &self, + ) -> Result, SubstrateError>; + /// Returns best finalized parachain block at given source relay chain block. + async fn best_finalized_para_block_at_source( + &self, + at_relay_block: HeaderId, + ) -> Result>, SubstrateError>; +} + +#[async_trait] +impl<'a, P: SubstrateParachainsPipeline> + SelectHeadersToProveEnvironment< + BlockNumberOf, + HashOf, + BlockNumberOf, + HashOf, + > for (&'a OnDemandParachainsRelay

, &'a ParachainsSource

) +{ + fn parachain_id(&self) -> ParaId { + ParaId(P::SourceParachain::PARACHAIN_ID) + } + + async fn best_finalized_relay_block_at_source( + &self, + ) -> Result, SubstrateError> { + Ok(self.0.source_relay_client.best_finalized_header().await?.id()) + } + + async fn best_finalized_relay_block_at_target( + &self, + ) -> Result, SubstrateError> { + Ok(crate::messages_source::read_client_state::( + &self.0.target_client, + None, + ) + .await? + .best_finalized_peer_at_best_self + .ok_or(SubstrateError::BridgePalletIsNotInitialized)?) + } + + async fn best_finalized_para_block_at_source( + &self, + at_relay_block: HeaderIdOf, + ) -> Result>, SubstrateError> { + self.1.on_chain_para_head_id(at_relay_block).await + } +} + +/// Given request to prove `required_parachain_header`, select actual headers that need to be +/// proved. +async fn select_headers_to_prove( + env: impl SelectHeadersToProveEnvironment, + required_parachain_header: PBN, +) -> Result<(bool, HeaderId, HeaderId), SubstrateError> +where + RBH: Copy, + RBN: BlockNumberBase, + PBH: Copy, + PBN: BlockNumberBase, +{ + // parachains proof also requires relay header proof. Let's first select relay block + // number that we'll be dealing with + let best_finalized_relay_block_at_source = env.best_finalized_relay_block_at_source().await?; + let best_finalized_relay_block_at_target = env.best_finalized_relay_block_at_target().await?; + + // if we can't prove `required_header` even using `best_finalized_relay_block_at_source`, we + // can't do anything here + // (this shall not actually happen, given current code, because we only require finalized + // headers) + let best_possible_parachain_block = env + .best_finalized_para_block_at_source(best_finalized_relay_block_at_source) + .await? + .filter(|best_possible_parachain_block| { + best_possible_parachain_block.number() >= required_parachain_header + }) + .ok_or(SubstrateError::MissingRequiredParachainHead( + env.parachain_id(), + required_parachain_header.unique_saturated_into(), + ))?; + + // we don't require source node to be archive, so we can't craft storage proofs using + // ancient headers. So if the `best_finalized_relay_block_at_target` is too ancient, we + // can't craft storage proofs using it + let may_use_state_at_best_finalized_relay_block_at_target = !is_ancient_block( + best_finalized_relay_block_at_target.number(), + best_finalized_relay_block_at_source.number(), + ); + + // now let's check if `required_header` may be proved using + // `best_finalized_relay_block_at_target` + let selection = if may_use_state_at_best_finalized_relay_block_at_target { + env.best_finalized_para_block_at_source(best_finalized_relay_block_at_target) + .await? + .filter(|best_finalized_para_block_at_target| { + best_finalized_para_block_at_target.number() >= required_parachain_header + }) + .map(|best_finalized_para_block_at_target| { + (false, best_finalized_relay_block_at_target, best_finalized_para_block_at_target) + }) + } else { + None + }; + + Ok(selection.unwrap_or(( + true, + best_finalized_relay_block_at_source, + best_possible_parachain_block, + ))) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn relay_waits_for_relay_header_to_be_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(50), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: Some(700), + para_header_at_relay_header_at_target: Some(HeaderId(100, 100)), + }, + RelayState::RelayingRelayHeader(750), + ), + RelayState::RelayingRelayHeader(750), + ); + } + + #[test] + fn relay_starts_relaying_requested_para_header_after_relay_header_is_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(50), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: Some(750), + para_header_at_relay_header_at_target: Some(HeaderId(100, 100)), + }, + RelayState::RelayingRelayHeader(750), + ), + RelayState::RelayingParaHeader(HeaderId(100, 100)), + ); + } + + #[test] + fn relay_selects_better_para_header_after_better_relay_header_is_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(50), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: Some(780), + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::RelayingRelayHeader(750), + ), + RelayState::RelayingParaHeader(HeaderId(105, 105)), + ); + } + #[test] + fn relay_waits_for_para_header_to_be_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(50), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: Some(780), + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::RelayingParaHeader(HeaderId(105, 105)), + ), + RelayState::RelayingParaHeader(HeaderId(105, 105)), + ); + } + + #[test] + fn relay_stays_idle_if_required_para_header_is_already_delivered() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 90, + para_header_at_target: Some(105), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: Some(780), + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::Idle, + ), + RelayState::Idle, + ); + } + + #[test] + fn relay_waits_for_required_para_header_to_appear_at_source_1() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: None, + relay_header_at_source: 800, + relay_header_at_target: Some(780), + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::Idle, + ), + RelayState::Idle, + ); + } + + #[test] + fn relay_waits_for_required_para_header_to_appear_at_source_2() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: Some(HeaderId(110, 110)), + relay_header_at_source: 800, + relay_header_at_target: Some(780), + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::Idle, + ), + RelayState::Idle, + ); + } + + #[test] + fn relay_starts_relaying_relay_header_when_new_para_header_is_requested() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: Some(HeaderId(125, 125)), + relay_header_at_source: 800, + relay_header_at_target: Some(780), + para_header_at_relay_header_at_target: Some(HeaderId(105, 105)), + }, + RelayState::Idle, + ), + RelayState::RelayingRelayHeader(800), + ); + } + + #[test] + fn relay_starts_relaying_para_header_when_new_para_header_is_requested() { + assert_eq!( + select_headers_to_relay( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: Some(HeaderId(125, 125)), + relay_header_at_source: 800, + relay_header_at_target: Some(800), + para_header_at_relay_header_at_target: Some(HeaderId(125, 125)), + }, + RelayState::Idle, + ), + RelayState::RelayingParaHeader(HeaderId(125, 125)), + ); + } + + #[test] + fn relay_goes_idle_when_parachain_is_deregistered() { + assert_eq!( + select_headers_to_relay::( + &RelayData { + required_para_header: 120, + para_header_at_target: Some(105), + para_header_at_source: None, + relay_header_at_source: 800, + relay_header_at_target: Some(800), + para_header_at_relay_header_at_target: None, + }, + RelayState::RelayingRelayHeader(800), + ), + RelayState::Idle, + ); + } + + #[test] + fn relay_starts_relaying_first_parachain_header() { + assert_eq!( + select_headers_to_relay::( + &RelayData { + required_para_header: 0, + para_header_at_target: None, + para_header_at_source: Some(HeaderId(125, 125)), + relay_header_at_source: 800, + relay_header_at_target: Some(800), + para_header_at_relay_header_at_target: Some(HeaderId(125, 125)), + }, + RelayState::Idle, + ), + RelayState::RelayingParaHeader(HeaderId(125, 125)), + ); + } + + #[test] + fn relay_starts_relaying_relay_header_to_relay_first_parachain_header() { + assert_eq!( + select_headers_to_relay::( + &RelayData { + required_para_header: 0, + para_header_at_target: None, + para_header_at_source: Some(HeaderId(125, 125)), + relay_header_at_source: 800, + relay_header_at_target: Some(700), + para_header_at_relay_header_at_target: Some(HeaderId(125, 125)), + }, + RelayState::Idle, + ), + RelayState::RelayingRelayHeader(800), + ); + } + + // tuple is: + // + // - best_finalized_relay_block_at_source + // - best_finalized_relay_block_at_target + // - best_finalized_para_block_at_source at best_finalized_relay_block_at_source + // - best_finalized_para_block_at_source at best_finalized_relay_block_at_target + #[async_trait] + impl SelectHeadersToProveEnvironment for (u32, u32, u32, u32) { + fn parachain_id(&self) -> ParaId { + ParaId(0) + } + + async fn best_finalized_relay_block_at_source( + &self, + ) -> Result, SubstrateError> { + Ok(HeaderId(self.0, self.0)) + } + + async fn best_finalized_relay_block_at_target( + &self, + ) -> Result, SubstrateError> { + Ok(HeaderId(self.1, self.1)) + } + + async fn best_finalized_para_block_at_source( + &self, + at_relay_block: HeaderId, + ) -> Result>, SubstrateError> { + if at_relay_block.0 == self.0 { + Ok(Some(HeaderId(self.2, self.2))) + } else if at_relay_block.0 == self.1 { + Ok(Some(HeaderId(self.3, self.3))) + } else { + Ok(None) + } + } + } + + #[async_std::test] + async fn select_headers_to_prove_returns_err_if_required_para_block_is_missing_at_source() { + assert!(matches!( + select_headers_to_prove((20_u32, 10_u32, 200_u32, 100_u32), 300_u32,).await, + Err(SubstrateError::MissingRequiredParachainHead(ParaId(0), 300_u64)), + )); + } + + #[async_std::test] + async fn select_headers_to_prove_fails_to_use_existing_ancient_relay_block() { + assert_eq!( + select_headers_to_prove((220_u32, 10_u32, 200_u32, 100_u32), 100_u32,) + .await + .map_err(drop), + Ok((true, HeaderId(220, 220), HeaderId(200, 200))), + ); + } + + #[async_std::test] + async fn select_headers_to_prove_is_able_to_use_existing_recent_relay_block() { + assert_eq!( + select_headers_to_prove((40_u32, 10_u32, 200_u32, 100_u32), 100_u32,) + .await + .map_err(drop), + Ok((false, HeaderId(10, 10), HeaderId(100, 100))), + ); + } + + #[async_std::test] + async fn select_headers_to_prove_uses_new_relay_block() { + assert_eq!( + select_headers_to_prove((20_u32, 10_u32, 200_u32, 100_u32), 200_u32,) + .await + .map_err(drop), + Ok((true, HeaderId(20, 20), HeaderId(200, 200))), + ); + } +} diff --git a/relays/lib-substrate-relay/src/parachains/mod.rs b/relays/lib-substrate-relay/src/parachains/mod.rs new file mode 100644 index 00000000000..722f9b61f9f --- /dev/null +++ b/relays/lib-substrate-relay/src/parachains/mod.rs @@ -0,0 +1,108 @@ +// Copyright 2019-2021 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 . + +//! Types and functions intended to ease adding of new Substrate -> Substrate +//! parachain finality proofs synchronization pipelines. + +use async_trait::async_trait; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use pallet_bridge_parachains::{ + Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash, + RelayBlockHasher, RelayBlockNumber, +}; +use parachains_relay::ParachainsPipeline; +use relay_substrate_client::{ + CallOf, Chain, ChainWithTransactions, HeaderIdOf, Parachain, RelayChain, +}; +use std::{fmt::Debug, marker::PhantomData}; + +pub mod source; +pub mod target; + +/// Substrate -> Substrate parachain finality proofs synchronization pipeline. +/// +/// This is currently restricted to the single parachain, because it is how it +/// will be used (at least) initially. +#[async_trait] +pub trait SubstrateParachainsPipeline: 'static + Clone + Debug + Send + Sync { + /// Headers of this parachain are submitted to the `Self::TargetChain`. + type SourceParachain: Parachain; + /// Relay chain that is storing headers of `Self::SourceParachain`. + type SourceRelayChain: RelayChain; + /// Target chain where `Self::SourceParachain` headers are submitted. + type TargetChain: ChainWithTransactions; + + /// How submit parachains heads call is built? + type SubmitParachainHeadsCallBuilder: SubmitParachainHeadsCallBuilder; +} + +/// Adapter that allows all `SubstrateParachainsPipeline` to act as `ParachainsPipeline`. +#[derive(Clone, Debug)] +pub struct ParachainsPipelineAdapter { + _phantom: PhantomData

, +} + +impl ParachainsPipeline for ParachainsPipelineAdapter

{ + type SourceParachain = P::SourceParachain; + type SourceRelayChain = P::SourceRelayChain; + type TargetChain = P::TargetChain; +} + +/// Different ways of building `submit_parachain_heads` calls. +pub trait SubmitParachainHeadsCallBuilder: + 'static + Send + Sync +{ + /// Given parachains and their heads proof, build call of `submit_parachain_heads` + /// function of bridge parachains module at the target chain. + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> CallOf; +} + +/// Building `submit_parachain_heads` call when you have direct access to the target +/// chain runtime. +pub struct DirectSubmitParachainHeadsCallBuilder { + _phantom: PhantomData<(P, R, I)>, +} + +impl SubmitParachainHeadsCallBuilder

for DirectSubmitParachainHeadsCallBuilder +where + P: SubstrateParachainsPipeline, + P::SourceRelayChain: Chain, + R: BridgeParachainsConfig + Send + Sync, + I: 'static + Send + Sync, + R::BridgedChain: bp_runtime::Chain< + BlockNumber = RelayBlockNumber, + Hash = RelayBlockHash, + Hasher = RelayBlockHasher, + >, + CallOf: From>, +{ + fn build_submit_parachain_heads_call( + at_relay_block: HeaderIdOf, + parachains: Vec<(ParaId, ParaHash)>, + parachain_heads_proof: ParaHeadsProof, + ) -> CallOf { + BridgeParachainsCall::::submit_parachain_heads { + at_relay_block: (at_relay_block.0, at_relay_block.1), + parachains, + parachain_heads_proof, + } + .into() + } +} diff --git a/relays/lib-substrate-relay/src/parachains/source.rs b/relays/lib-substrate-relay/src/parachains/source.rs new file mode 100644 index 00000000000..146c5840cd5 --- /dev/null +++ b/relays/lib-substrate-relay/src/parachains/source.rs @@ -0,0 +1,169 @@ +// Copyright 2019-2021 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 . + +//! Parachain heads source. + +use crate::parachains::{ParachainsPipelineAdapter, SubstrateParachainsPipeline}; + +use async_std::sync::{Arc, Mutex}; +use async_trait::async_trait; +use bp_parachains::parachain_head_storage_key_at_source; +use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; +use bp_runtime::HeaderIdProvider; +use codec::Decode; +use parachains_relay::parachains_loop::{AvailableHeader, SourceClient}; +use relay_substrate_client::{ + is_ancient_block, Chain, Client, Error as SubstrateError, HeaderIdOf, HeaderOf, ParachainBase, + RelayChain, +}; +use relay_utils::relay_loop::Client as RelayClient; + +/// Shared updatable reference to the maximal parachain header id that we want to sync from the +/// source. +pub type RequiredHeaderIdRef = Arc>>>; + +/// Substrate client as parachain heads source. +#[derive(Clone)] +pub struct ParachainsSource { + client: Client, + max_head_id: RequiredHeaderIdRef, +} + +impl ParachainsSource

{ + /// Creates new parachains source client. + pub fn new( + client: Client, + max_head_id: RequiredHeaderIdRef, + ) -> Self { + ParachainsSource { client, max_head_id } + } + + /// Returns reference to the underlying RPC client. + pub fn client(&self) -> &Client { + &self.client + } + + /// Return decoded head of given parachain. + pub async fn on_chain_para_head_id( + &self, + at_block: HeaderIdOf, + ) -> Result>, SubstrateError> { + let para_id = ParaId(P::SourceParachain::PARACHAIN_ID); + let storage_key = + parachain_head_storage_key_at_source(P::SourceRelayChain::PARAS_PALLET_NAME, para_id); + let para_head = self.client.raw_storage_value(storage_key, Some(at_block.1)).await?; + let para_head = para_head.map(|h| ParaHead::decode(&mut &h.0[..])).transpose()?; + let para_head = match para_head { + Some(para_head) => para_head, + None => return Ok(None), + }; + let para_head: HeaderOf = Decode::decode(&mut ¶_head.0[..])?; + Ok(Some(para_head.id())) + } +} + +#[async_trait] +impl RelayClient for ParachainsSource

{ + type Error = SubstrateError; + + async fn reconnect(&mut self) -> Result<(), SubstrateError> { + self.client.reconnect().await + } +} + +#[async_trait] +impl SourceClient> + for ParachainsSource

+where + P::SourceParachain: Chain, +{ + async fn ensure_synced(&self) -> Result { + match self.client.ensure_synced().await { + Ok(_) => Ok(true), + Err(SubstrateError::ClientNotSynced(_)) => Ok(false), + Err(e) => Err(e), + } + } + + async fn parachain_head( + &self, + at_block: HeaderIdOf, + ) -> Result>, Self::Error> { + // if requested relay header is ancient, then we don't even want to try to read the + // parachain head - we simply return `Unavailable` + let best_block_number = self.client.best_finalized_header_number().await?; + if is_ancient_block(at_block.number(), best_block_number) { + return Ok(AvailableHeader::Unavailable) + } + + // else - try to read head from the source client + let mut para_head_id = AvailableHeader::Missing; + if let Some(on_chain_para_head_id) = self.on_chain_para_head_id(at_block).await? { + // Never return head that is larger than requested. This way we'll never sync + // headers past `max_header_id`. + para_head_id = match *self.max_head_id.lock().await { + AvailableHeader::Unavailable => AvailableHeader::Unavailable, + AvailableHeader::Missing => { + // `max_header_id` is not set. There is no limit. + AvailableHeader::Available(on_chain_para_head_id) + }, + AvailableHeader::Available(max_head_id) => { + // We report at most `max_header_id`. + AvailableHeader::Available(std::cmp::min(on_chain_para_head_id, max_head_id)) + }, + } + } + + Ok(para_head_id) + } + + async fn prove_parachain_head( + &self, + at_block: HeaderIdOf, + ) -> Result<(ParaHeadsProof, ParaHash), Self::Error> { + let parachain = ParaId(P::SourceParachain::PARACHAIN_ID); + let storage_key = + parachain_head_storage_key_at_source(P::SourceRelayChain::PARAS_PALLET_NAME, parachain); + let parachain_heads_proof = self + .client + .prove_storage(vec![storage_key.clone()], at_block.1) + .await? + .into_iter_nodes() + .collect(); + + // why we're reading parachain head here once again (it has already been read at the + // `parachain_head`)? that's because `parachain_head` sometimes returns obsolete parachain + // head and loop sometimes asks to prove this obsolete head and gets other (actual) head + // instead + // + // => since we want to provide proper hashes in our `submit_parachain_heads` call, we're + // rereading actual value here + let parachain_head = self + .client + .raw_storage_value(storage_key, Some(at_block.1)) + .await? + .map(|h| ParaHead::decode(&mut &h.0[..])) + .transpose()? + .ok_or_else(|| { + SubstrateError::Custom(format!( + "Failed to read expected parachain {parachain:?} head at {at_block:?}" + )) + })?; + let parachain_head_hash = parachain_head.hash(); + + Ok((ParaHeadsProof(parachain_heads_proof), parachain_head_hash)) + } +} diff --git a/relays/lib-substrate-relay/src/parachains/target.rs b/relays/lib-substrate-relay/src/parachains/target.rs new file mode 100644 index 00000000000..6df7bc0a742 --- /dev/null +++ b/relays/lib-substrate-relay/src/parachains/target.rs @@ -0,0 +1,148 @@ +// Copyright 2019-2021 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 . + +//! Parachain heads target. + +use crate::{ + parachains::{ + ParachainsPipelineAdapter, SubmitParachainHeadsCallBuilder, SubstrateParachainsPipeline, + }, + TransactionParams, +}; + +use async_trait::async_trait; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; +use bp_runtime::HeaderIdProvider; +use codec::Decode; +use parachains_relay::parachains_loop::TargetClient; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, Chain, Client, Error as SubstrateError, HeaderIdOf, + ParachainBase, TransactionEra, TransactionTracker, UnsignedTransaction, +}; +use relay_utils::relay_loop::Client as RelayClient; +use sp_core::{Bytes, Pair}; + +/// Substrate client as parachain heads source. +pub struct ParachainsTarget { + client: Client, + transaction_params: TransactionParams>, +} + +impl ParachainsTarget

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

{ + fn clone(&self) -> Self { + ParachainsTarget { + client: self.client.clone(), + transaction_params: self.transaction_params.clone(), + } + } +} + +#[async_trait] +impl RelayClient for ParachainsTarget

{ + type Error = SubstrateError; + + async fn reconnect(&mut self) -> Result<(), SubstrateError> { + self.client.reconnect().await + } +} + +#[async_trait] +impl

TargetClient> for ParachainsTarget

+where + P: SubstrateParachainsPipeline, + AccountIdOf: From< as Pair>::Public>, +{ + type TransactionTracker = TransactionTracker>; + + async fn best_block(&self) -> Result, Self::Error> { + let best_header = self.client.best_header().await?; + let best_id = best_header.id(); + + Ok(best_id) + } + + async fn best_finalized_source_relay_chain_block( + &self, + at_block: &HeaderIdOf, + ) -> Result, Self::Error> { + self.client + .typed_state_call::<_, Option>>( + P::SourceRelayChain::BEST_FINALIZED_HEADER_ID_METHOD.into(), + (), + Some(at_block.1), + ) + .await? + .map(Ok) + .unwrap_or(Err(SubstrateError::BridgePalletIsNotInitialized)) + } + + async fn parachain_head( + &self, + at_block: HeaderIdOf, + ) -> Result>, Self::Error> { + let encoded_best_finalized_source_para_block = self + .client + .state_call( + P::SourceParachain::BEST_FINALIZED_HEADER_ID_METHOD.into(), + Bytes(Vec::new()), + Some(at_block.1), + ) + .await?; + + Ok(Option::>::decode( + &mut &encoded_best_finalized_source_para_block.0[..], + ) + .map_err(SubstrateError::ResponseParseFailed)?) + } + + async fn submit_parachain_head_proof( + &self, + at_relay_block: HeaderIdOf, + updated_head_hash: ParaHash, + proof: ParaHeadsProof, + ) -> Result { + let transaction_params = self.transaction_params.clone(); + let call = P::SubmitParachainHeadsCallBuilder::build_submit_parachain_heads_call( + at_relay_block, + vec![(ParaId(P::SourceParachain::PARACHAIN_ID), updated_head_hash)], + proof, + ); + self.client + .submit_and_watch_signed_extrinsic( + &transaction_params.signer, + move |best_block_id, transaction_nonce| { + Ok(UnsignedTransaction::new(call.into(), transaction_nonce) + .era(TransactionEra::new(best_block_id, transaction_params.mortality))) + }, + ) + .await + } +} diff --git a/relays/messages/Cargo.toml b/relays/messages/Cargo.toml new file mode 100644 index 00000000000..8c4b8257d5a --- /dev/null +++ b/relays/messages/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "messages-relay" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +async-std = { version = "1.6.5", features = ["attributes"] } +async-trait = "0.1" +futures = "0.3.28" +hex = "0.4" +log = "0.4.17" +num-traits = "0.2" +parking_lot = "0.12.1" + +# Bridge Dependencies + +bp-messages = { path = "../../primitives/messages" } +finality-relay = { path = "../finality" } +relay-utils = { path = "../utils" } + +sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/messages/src/lib.rs b/relays/messages/src/lib.rs new file mode 100644 index 00000000000..9c62cee5ee3 --- /dev/null +++ b/relays/messages/src/lib.rs @@ -0,0 +1,37 @@ +// Copyright 2019-2021 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 . + +//! Relaying [`pallet-bridge-messages`](../pallet_bridge_messages/index.html) application specific +//! data. Message lane allows sending arbitrary messages between bridged chains. This +//! module provides entrypoint that starts reading messages from given message lane +//! of source chain and submits proof-of-message-at-source-chain transactions to the +//! target chain. Additionally, proofs-of-messages-delivery are sent back from the +//! target chain to the source chain. + +// required for futures::select! +#![recursion_limit = "1024"] +#![warn(missing_docs)] + +mod metrics; + +pub mod message_lane; +pub mod message_lane_loop; + +mod message_race_delivery; +mod message_race_limits; +mod message_race_loop; +mod message_race_receiving; +mod message_race_strategy; diff --git a/relays/messages/src/message_lane.rs b/relays/messages/src/message_lane.rs new file mode 100644 index 00000000000..5c9728ad93a --- /dev/null +++ b/relays/messages/src/message_lane.rs @@ -0,0 +1,71 @@ +// Copyright 2019-2021 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 . + +//! One-way message lane types. Within single one-way lane we have three 'races' where we try to: +//! +//! 1) relay new messages from source to target node; +//! 2) relay proof-of-delivery from target to source node. + +use num_traits::{SaturatingAdd, Zero}; +use relay_utils::{BlockNumberBase, HeaderId}; +use sp_arithmetic::traits::AtLeast32BitUnsigned; +use std::{fmt::Debug, ops::Sub}; + +/// One-way message lane. +pub trait MessageLane: 'static + Clone + Send + Sync { + /// Name of the messages source. + const SOURCE_NAME: &'static str; + /// Name of the messages target. + const TARGET_NAME: &'static str; + + /// Messages proof. + type MessagesProof: Clone + Debug + Send + Sync; + /// Messages receiving proof. + type MessagesReceivingProof: Clone + Debug + Send + Sync; + + /// The type of the source chain token balance, that is used to: + /// + /// 1) pay transaction fees; + /// 2) pay message delivery and dispatch fee; + /// 3) pay relayer rewards. + type SourceChainBalance: AtLeast32BitUnsigned + + Clone + + Copy + + Debug + + PartialOrd + + Sub + + SaturatingAdd + + Zero + + Send + + Sync; + /// Number of the source header. + type SourceHeaderNumber: BlockNumberBase; + /// Hash of the source header. + type SourceHeaderHash: Clone + Debug + Default + PartialEq + Send + Sync; + + /// Number of the target header. + type TargetHeaderNumber: BlockNumberBase; + /// Hash of the target header. + type TargetHeaderHash: Clone + Debug + Default + PartialEq + Send + Sync; +} + +/// Source header id within given one-way message lane. +pub type SourceHeaderIdOf

= + HeaderId<

::SourceHeaderHash,

::SourceHeaderNumber>; + +/// Target header id within given one-way message lane. +pub type TargetHeaderIdOf

= + HeaderId<

::TargetHeaderHash,

::TargetHeaderNumber>; diff --git a/relays/messages/src/message_lane_loop.rs b/relays/messages/src/message_lane_loop.rs new file mode 100644 index 00000000000..ba86f05ffd3 --- /dev/null +++ b/relays/messages/src/message_lane_loop.rs @@ -0,0 +1,1261 @@ +// Copyright 2019-2021 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 . + +//! Message delivery loop. Designed to work with messages pallet. +//! +//! Single relay instance delivers messages of single lane in single direction. +//! To serve two-way lane, you would need two instances of relay. +//! To serve N two-way lanes, you would need N*2 instances of relay. +//! +//! Please keep in mind that the best header in this file is actually best +//! finalized header. I.e. when talking about headers in lane context, we +//! only care about finalized headers. + +use std::{collections::BTreeMap, fmt::Debug, future::Future, ops::RangeInclusive, time::Duration}; + +use async_trait::async_trait; +use futures::{channel::mpsc::unbounded, future::FutureExt, stream::StreamExt}; + +use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState, Weight}; +use relay_utils::{ + interval, metrics::MetricsParams, process_future_result, relay_loop::Client as RelayClient, + retry_backoff, FailedClient, TransactionTracker, +}; + +use crate::{ + message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, + message_race_delivery::run as run_message_delivery_race, + message_race_receiving::run as run_message_receiving_race, + metrics::MessageLaneLoopMetrics, +}; + +/// Message lane loop configuration params. +#[derive(Debug, Clone)] +pub struct Params { + /// Id of lane this loop is servicing. + pub lane: LaneId, + /// Interval at which we ask target node about its updates. + pub source_tick: Duration, + /// Interval at which we ask target node about its updates. + pub target_tick: Duration, + /// Delay between moments when connection error happens and our reconnect attempt. + pub reconnect_delay: Duration, + /// Message delivery race parameters. + pub delivery_params: MessageDeliveryParams, +} + +/// Message delivery race parameters. +#[derive(Debug, Clone)] +pub struct MessageDeliveryParams { + /// Maximal number of unconfirmed relayer entries at the inbound lane. If there's that number + /// of entries in the `InboundLaneData::relayers` set, all new messages will be rejected until + /// reward payment will be proved (by including outbound lane state to the message delivery + /// transaction). + pub max_unrewarded_relayer_entries_at_target: MessageNonce, + /// Message delivery race will stop delivering messages if there are + /// `max_unconfirmed_nonces_at_target` unconfirmed nonces on the target node. The race would + /// continue once they're confirmed by the receiving race. + pub max_unconfirmed_nonces_at_target: MessageNonce, + /// Maximal number of relayed messages in single delivery transaction. + pub max_messages_in_single_batch: MessageNonce, + /// Maximal cumulative dispatch weight of relayed messages in single delivery transaction. + pub max_messages_weight_in_single_batch: Weight, + /// Maximal cumulative size of relayed messages in single delivery transaction. + pub max_messages_size_in_single_batch: u32, +} + +/// Message details. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct MessageDetails { + /// Message dispatch weight. + pub dispatch_weight: Weight, + /// Message size (number of bytes in encoded payload). + pub size: u32, + /// The relayer reward paid in the source chain tokens. + pub reward: SourceChainBalance, +} + +/// Messages details map. +pub type MessageDetailsMap = + BTreeMap>; + +/// Message delivery race proof parameters. +#[derive(Debug, PartialEq, Eq)] +pub struct MessageProofParameters { + /// Include outbound lane state proof? + pub outbound_state_proof_required: bool, + /// Cumulative dispatch weight of messages that we're building proof for. + pub dispatch_weight: Weight, +} + +/// Artifacts of submitting nonces proof. +pub struct NoncesSubmitArtifacts { + /// Submitted nonces range. + pub nonces: RangeInclusive, + /// Submitted transaction tracker. + pub tx_tracker: T, +} + +/// Batch transaction that already submit some headers and needs to be extended with +/// messages/delivery proof before sending. +pub trait BatchTransaction: Debug + Send { + /// Header that was required in the original call and which is bundled within this + /// batch transaction. + fn required_header_id(&self) -> HeaderId; +} + +/// Source client trait. +#[async_trait] +pub trait SourceClient: RelayClient { + /// Type of batch transaction that submits finality and message receiving proof. + type BatchTransaction: BatchTransaction> + Clone; + /// Transaction tracker to track submitted transactions. + type TransactionTracker: TransactionTracker>; + + /// Returns state of the client. + async fn state(&self) -> Result, Self::Error>; + + /// Get nonce of instance of latest generated message. + async fn latest_generated_nonce( + &self, + id: SourceHeaderIdOf

, + ) -> Result<(SourceHeaderIdOf

, MessageNonce), Self::Error>; + + /// Get nonce of the latest message, which receiving has been confirmed by the target chain. + async fn latest_confirmed_received_nonce( + &self, + id: SourceHeaderIdOf

, + ) -> Result<(SourceHeaderIdOf

, MessageNonce), Self::Error>; + + /// Returns mapping of message nonces, generated on this client, to their weights. + /// + /// Some messages may be missing from returned map, if corresponding messages were pruned at + /// the source chain. + async fn generated_message_details( + &self, + id: SourceHeaderIdOf

, + nonces: RangeInclusive, + ) -> Result, Self::Error>; + + /// Prove messages in inclusive range [begin; end]. + async fn prove_messages( + &self, + id: SourceHeaderIdOf

, + nonces: RangeInclusive, + proof_parameters: MessageProofParameters, + ) -> Result<(SourceHeaderIdOf

, RangeInclusive, P::MessagesProof), Self::Error>; + + /// Submit messages receiving proof. + async fn submit_messages_receiving_proof( + &self, + maybe_batch_tx: Option, + generated_at_block: TargetHeaderIdOf

, + proof: P::MessagesReceivingProof, + ) -> Result; + + /// We need given finalized target header on source to continue synchronization. + /// + /// We assume that the absence of header `id` has already been checked by caller. + /// + /// The client may return `Some(_)`, which means that nothing has happened yet and + /// the caller must generate and append message receiving proof to the batch transaction + /// to actually send it (along with required header) to the node. + /// + /// If function has returned `None`, it means that the caller now must wait for the + /// appearance of the target header `id` at the source client. + async fn require_target_header_on_source( + &self, + id: TargetHeaderIdOf

, + ) -> Result, Self::Error>; +} + +/// Target client trait. +#[async_trait] +pub trait TargetClient: RelayClient { + /// Type of batch transaction that submits finality and messages proof. + type BatchTransaction: BatchTransaction> + Clone; + /// Transaction tracker to track submitted transactions. + type TransactionTracker: TransactionTracker>; + + /// Returns state of the client. + async fn state(&self) -> Result, Self::Error>; + + /// Get nonce of latest received message. + async fn latest_received_nonce( + &self, + id: TargetHeaderIdOf

, + ) -> Result<(TargetHeaderIdOf

, MessageNonce), Self::Error>; + + /// Get nonce of the latest confirmed message. + async fn latest_confirmed_received_nonce( + &self, + id: TargetHeaderIdOf

, + ) -> Result<(TargetHeaderIdOf

, MessageNonce), Self::Error>; + + /// Get state of unrewarded relayers set at the inbound lane. + async fn unrewarded_relayers_state( + &self, + id: TargetHeaderIdOf

, + ) -> Result<(TargetHeaderIdOf

, UnrewardedRelayersState), Self::Error>; + + /// Prove messages receiving at given block. + async fn prove_messages_receiving( + &self, + id: TargetHeaderIdOf

, + ) -> Result<(TargetHeaderIdOf

, P::MessagesReceivingProof), Self::Error>; + + /// Submit messages proof. + async fn submit_messages_proof( + &self, + maybe_batch_tx: Option, + generated_at_header: SourceHeaderIdOf

, + nonces: RangeInclusive, + proof: P::MessagesProof, + ) -> Result, Self::Error>; + + /// We need given finalized source header on target to continue synchronization. + /// + /// The client may return `Some(_)`, which means that nothing has happened yet and + /// the caller must generate and append messages proof to the batch transaction + /// to actually send it (along with required header) to the node. + /// + /// If function has returned `None`, it means that the caller now must wait for the + /// appearance of the source header `id` at the target client. + async fn require_source_header_on_target( + &self, + id: SourceHeaderIdOf

, + ) -> Result, Self::Error>; +} + +/// State of the client. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct ClientState { + /// The best header id of this chain. + pub best_self: SelfHeaderId, + /// Best finalized header id of this chain. + pub best_finalized_self: SelfHeaderId, + /// Best finalized header id of the peer chain read at the best block of this chain (at + /// `best_finalized_self`). + /// + /// It may be `None` e,g. if peer is a parachain and we haven't yet relayed any parachain + /// heads. + pub best_finalized_peer_at_best_self: Option, + /// Header id of the peer chain with the number, matching the + /// `best_finalized_peer_at_best_self`. + pub actual_best_finalized_peer_at_best_self: Option, +} + +/// State of source client in one-way message lane. +pub type SourceClientState

= ClientState, TargetHeaderIdOf

>; + +/// State of target client in one-way message lane. +pub type TargetClientState

= ClientState, SourceHeaderIdOf

>; + +/// Both clients state. +#[derive(Debug, Default)] +pub struct ClientsState { + /// Source client state. + pub source: Option>, + /// Target client state. + pub target: Option>, +} + +/// Return prefix that will be used by default to expose Prometheus metrics of the finality proofs +/// sync loop. +pub fn metrics_prefix(lane: &LaneId) -> String { + format!("{}_to_{}_MessageLane_{}", P::SOURCE_NAME, P::TARGET_NAME, hex::encode(lane)) +} + +/// Run message lane service loop. +pub async fn run( + params: Params, + source_client: impl SourceClient

, + target_client: impl TargetClient

, + metrics_params: MetricsParams, + exit_signal: impl Future + Send + 'static, +) -> Result<(), relay_utils::Error> { + let exit_signal = exit_signal.shared(); + relay_utils::relay_loop(source_client, target_client) + .reconnect_delay(params.reconnect_delay) + .with_metrics(metrics_params) + .loop_metric(MessageLaneLoopMetrics::new(Some(&metrics_prefix::

(¶ms.lane)))?)? + .expose() + .await? + .run(metrics_prefix::

(¶ms.lane), move |source_client, target_client, metrics| { + run_until_connection_lost( + params.clone(), + source_client, + target_client, + metrics, + exit_signal.clone(), + ) + }) + .await +} + +/// Run one-way message delivery loop until connection with target or source node is lost, or exit +/// signal is received. +async fn run_until_connection_lost, TC: TargetClient

>( + params: Params, + source_client: SC, + target_client: TC, + metrics_msg: Option, + exit_signal: impl Future, +) -> Result<(), FailedClient> { + let mut source_retry_backoff = retry_backoff(); + let mut source_client_is_online = false; + let mut source_state_required = true; + let source_state = source_client.state().fuse(); + let source_go_offline_future = futures::future::Fuse::terminated(); + let source_tick_stream = interval(params.source_tick).fuse(); + + let mut target_retry_backoff = retry_backoff(); + let mut target_client_is_online = false; + let mut target_state_required = true; + let target_state = target_client.state().fuse(); + let target_go_offline_future = futures::future::Fuse::terminated(); + let target_tick_stream = interval(params.target_tick).fuse(); + + let ( + (delivery_source_state_sender, delivery_source_state_receiver), + (delivery_target_state_sender, delivery_target_state_receiver), + ) = (unbounded(), unbounded()); + let delivery_race_loop = run_message_delivery_race( + source_client.clone(), + delivery_source_state_receiver, + target_client.clone(), + delivery_target_state_receiver, + metrics_msg.clone(), + params.delivery_params, + ) + .fuse(); + + let ( + (receiving_source_state_sender, receiving_source_state_receiver), + (receiving_target_state_sender, receiving_target_state_receiver), + ) = (unbounded(), unbounded()); + let receiving_race_loop = run_message_receiving_race( + source_client.clone(), + receiving_source_state_receiver, + target_client.clone(), + receiving_target_state_receiver, + metrics_msg.clone(), + ) + .fuse(); + + let exit_signal = exit_signal.fuse(); + + futures::pin_mut!( + source_state, + source_go_offline_future, + source_tick_stream, + target_state, + target_go_offline_future, + target_tick_stream, + delivery_race_loop, + receiving_race_loop, + exit_signal + ); + + loop { + futures::select! { + new_source_state = source_state => { + source_state_required = false; + + source_client_is_online = process_future_result( + new_source_state, + &mut source_retry_backoff, + |new_source_state| { + log::debug!( + target: "bridge", + "Received state from {} node: {:?}", + P::SOURCE_NAME, + new_source_state, + ); + let _ = delivery_source_state_sender.unbounded_send(new_source_state.clone()); + let _ = receiving_source_state_sender.unbounded_send(new_source_state.clone()); + + if let Some(metrics_msg) = metrics_msg.as_ref() { + metrics_msg.update_source_state::

(new_source_state); + } + }, + &mut source_go_offline_future, + async_std::task::sleep, + || format!("Error retrieving state from {} node", P::SOURCE_NAME), + ).fail_if_connection_error(FailedClient::Source)?; + }, + _ = source_go_offline_future => { + source_client_is_online = true; + }, + _ = source_tick_stream.next() => { + source_state_required = true; + }, + new_target_state = target_state => { + target_state_required = false; + + target_client_is_online = process_future_result( + new_target_state, + &mut target_retry_backoff, + |new_target_state| { + log::debug!( + target: "bridge", + "Received state from {} node: {:?}", + P::TARGET_NAME, + new_target_state, + ); + let _ = delivery_target_state_sender.unbounded_send(new_target_state.clone()); + let _ = receiving_target_state_sender.unbounded_send(new_target_state.clone()); + + if let Some(metrics_msg) = metrics_msg.as_ref() { + metrics_msg.update_target_state::

(new_target_state); + } + }, + &mut target_go_offline_future, + async_std::task::sleep, + || format!("Error retrieving state from {} node", P::TARGET_NAME), + ).fail_if_connection_error(FailedClient::Target)?; + }, + _ = target_go_offline_future => { + target_client_is_online = true; + }, + _ = target_tick_stream.next() => { + target_state_required = true; + }, + + delivery_error = delivery_race_loop => { + match delivery_error { + Ok(_) => unreachable!("only ends with error; qed"), + Err(err) => return Err(err), + } + }, + receiving_error = receiving_race_loop => { + match receiving_error { + Ok(_) => unreachable!("only ends with error; qed"), + Err(err) => return Err(err), + } + }, + + () = exit_signal => { + return Ok(()); + } + } + + if source_client_is_online && source_state_required { + log::debug!(target: "bridge", "Asking {} node about its state", P::SOURCE_NAME); + source_state.set(source_client.state().fuse()); + source_client_is_online = false; + } + + if target_client_is_online && target_state_required { + log::debug!(target: "bridge", "Asking {} node about its state", P::TARGET_NAME); + target_state.set(target_client.state().fuse()); + target_client_is_online = false; + } + } +} + +#[cfg(test)] +pub(crate) mod tests { + use std::sync::Arc; + + use futures::stream::StreamExt; + use parking_lot::Mutex; + + use relay_utils::{HeaderId, MaybeConnectionError, TrackedTransactionStatus}; + + use super::*; + + pub fn header_id(number: TestSourceHeaderNumber) -> TestSourceHeaderId { + HeaderId(number, number) + } + + pub type TestSourceChainBalance = u64; + pub type TestSourceHeaderId = HeaderId; + pub type TestTargetHeaderId = HeaderId; + + pub type TestMessagesProof = (RangeInclusive, Option); + pub type TestMessagesReceivingProof = MessageNonce; + + pub type TestSourceHeaderNumber = u64; + pub type TestSourceHeaderHash = u64; + + pub type TestTargetHeaderNumber = u64; + pub type TestTargetHeaderHash = u64; + + #[derive(Debug)] + pub struct TestError; + + impl MaybeConnectionError for TestError { + fn is_connection_error(&self) -> bool { + true + } + } + + #[derive(Clone)] + pub struct TestMessageLane; + + impl MessageLane for TestMessageLane { + const SOURCE_NAME: &'static str = "TestSource"; + const TARGET_NAME: &'static str = "TestTarget"; + + type MessagesProof = TestMessagesProof; + type MessagesReceivingProof = TestMessagesReceivingProof; + + type SourceChainBalance = TestSourceChainBalance; + type SourceHeaderNumber = TestSourceHeaderNumber; + type SourceHeaderHash = TestSourceHeaderHash; + + type TargetHeaderNumber = TestTargetHeaderNumber; + type TargetHeaderHash = TestTargetHeaderHash; + } + + #[derive(Clone, Debug)] + pub struct TestMessagesBatchTransaction { + required_header_id: TestSourceHeaderId, + } + + #[async_trait] + impl BatchTransaction for TestMessagesBatchTransaction { + fn required_header_id(&self) -> TestSourceHeaderId { + self.required_header_id + } + } + + #[derive(Clone, Debug)] + pub struct TestConfirmationBatchTransaction { + required_header_id: TestTargetHeaderId, + } + + #[async_trait] + impl BatchTransaction for TestConfirmationBatchTransaction { + fn required_header_id(&self) -> TestTargetHeaderId { + self.required_header_id + } + } + + #[derive(Clone, Debug)] + pub struct TestTransactionTracker(TrackedTransactionStatus); + + impl Default for TestTransactionTracker { + fn default() -> TestTransactionTracker { + TestTransactionTracker(TrackedTransactionStatus::Finalized(Default::default())) + } + } + + #[async_trait] + impl TransactionTracker for TestTransactionTracker { + type HeaderId = TestTargetHeaderId; + + async fn wait(self) -> TrackedTransactionStatus { + self.0 + } + } + + #[derive(Debug, Clone)] + pub struct TestClientData { + is_source_fails: bool, + is_source_reconnected: bool, + source_state: SourceClientState, + source_latest_generated_nonce: MessageNonce, + source_latest_confirmed_received_nonce: MessageNonce, + source_tracked_transaction_status: TrackedTransactionStatus, + submitted_messages_receiving_proofs: Vec, + is_target_fails: bool, + is_target_reconnected: bool, + target_state: SourceClientState, + target_latest_received_nonce: MessageNonce, + target_latest_confirmed_received_nonce: MessageNonce, + target_tracked_transaction_status: TrackedTransactionStatus, + submitted_messages_proofs: Vec, + target_to_source_batch_transaction: Option, + target_to_source_header_required: Option, + target_to_source_header_requirements: Vec, + source_to_target_batch_transaction: Option, + source_to_target_header_required: Option, + source_to_target_header_requirements: Vec, + } + + impl Default for TestClientData { + fn default() -> TestClientData { + TestClientData { + is_source_fails: false, + is_source_reconnected: false, + source_state: Default::default(), + source_latest_generated_nonce: 0, + source_latest_confirmed_received_nonce: 0, + source_tracked_transaction_status: TrackedTransactionStatus::Finalized(HeaderId( + 0, + Default::default(), + )), + submitted_messages_receiving_proofs: Vec::new(), + is_target_fails: false, + is_target_reconnected: false, + target_state: Default::default(), + target_latest_received_nonce: 0, + target_latest_confirmed_received_nonce: 0, + target_tracked_transaction_status: TrackedTransactionStatus::Finalized(HeaderId( + 0, + Default::default(), + )), + submitted_messages_proofs: Vec::new(), + target_to_source_batch_transaction: None, + target_to_source_header_required: None, + target_to_source_header_requirements: Vec::new(), + source_to_target_batch_transaction: None, + source_to_target_header_required: None, + source_to_target_header_requirements: Vec::new(), + } + } + } + + impl TestClientData { + fn receive_messages(&mut self, proof: TestMessagesProof) { + self.target_state.best_self = + HeaderId(self.target_state.best_self.0 + 1, self.target_state.best_self.1 + 1); + self.target_state.best_finalized_self = self.target_state.best_self; + self.target_latest_received_nonce = *proof.0.end(); + if let Some(target_latest_confirmed_received_nonce) = proof.1 { + self.target_latest_confirmed_received_nonce = + target_latest_confirmed_received_nonce; + } + self.submitted_messages_proofs.push(proof); + } + + fn receive_messages_delivery_proof(&mut self, proof: TestMessagesReceivingProof) { + self.source_state.best_self = + HeaderId(self.source_state.best_self.0 + 1, self.source_state.best_self.1 + 1); + self.source_state.best_finalized_self = self.source_state.best_self; + self.submitted_messages_receiving_proofs.push(proof); + self.source_latest_confirmed_received_nonce = proof; + } + } + + #[derive(Clone)] + pub struct TestSourceClient { + data: Arc>, + tick: Arc, + post_tick: Arc, + } + + impl Default for TestSourceClient { + fn default() -> Self { + TestSourceClient { + data: Arc::new(Mutex::new(TestClientData::default())), + tick: Arc::new(|_| {}), + post_tick: Arc::new(|_| {}), + } + } + } + + #[async_trait] + impl RelayClient for TestSourceClient { + type Error = TestError; + + async fn reconnect(&mut self) -> Result<(), TestError> { + { + let mut data = self.data.lock(); + (self.tick)(&mut data); + data.is_source_reconnected = true; + (self.post_tick)(&mut data); + } + Ok(()) + } + } + + #[async_trait] + impl SourceClient for TestSourceClient { + type BatchTransaction = TestConfirmationBatchTransaction; + type TransactionTracker = TestTransactionTracker; + + async fn state(&self) -> Result, TestError> { + let mut data = self.data.lock(); + (self.tick)(&mut data); + if data.is_source_fails { + return Err(TestError) + } + (self.post_tick)(&mut data); + Ok(data.source_state.clone()) + } + + async fn latest_generated_nonce( + &self, + id: SourceHeaderIdOf, + ) -> Result<(SourceHeaderIdOf, MessageNonce), TestError> { + let mut data = self.data.lock(); + (self.tick)(&mut data); + if data.is_source_fails { + return Err(TestError) + } + (self.post_tick)(&mut data); + Ok((id, data.source_latest_generated_nonce)) + } + + async fn latest_confirmed_received_nonce( + &self, + id: SourceHeaderIdOf, + ) -> Result<(SourceHeaderIdOf, MessageNonce), TestError> { + let mut data = self.data.lock(); + (self.tick)(&mut data); + (self.post_tick)(&mut data); + Ok((id, data.source_latest_confirmed_received_nonce)) + } + + async fn generated_message_details( + &self, + _id: SourceHeaderIdOf, + nonces: RangeInclusive, + ) -> Result, TestError> { + Ok(nonces + .map(|nonce| { + ( + nonce, + MessageDetails { + dispatch_weight: Weight::from_parts(1, 0), + size: 1, + reward: 1, + }, + ) + }) + .collect()) + } + + async fn prove_messages( + &self, + id: SourceHeaderIdOf, + nonces: RangeInclusive, + proof_parameters: MessageProofParameters, + ) -> Result< + (SourceHeaderIdOf, RangeInclusive, TestMessagesProof), + TestError, + > { + let mut data = self.data.lock(); + (self.tick)(&mut data); + (self.post_tick)(&mut data); + Ok(( + id, + nonces.clone(), + ( + nonces, + if proof_parameters.outbound_state_proof_required { + Some(data.source_latest_confirmed_received_nonce) + } else { + None + }, + ), + )) + } + + async fn submit_messages_receiving_proof( + &self, + _maybe_batch_tx: Option, + _generated_at_block: TargetHeaderIdOf, + proof: TestMessagesReceivingProof, + ) -> Result { + let mut data = self.data.lock(); + (self.tick)(&mut data); + data.receive_messages_delivery_proof(proof); + (self.post_tick)(&mut data); + Ok(TestTransactionTracker(data.source_tracked_transaction_status)) + } + + async fn require_target_header_on_source( + &self, + id: TargetHeaderIdOf, + ) -> Result, Self::Error> { + let mut data = self.data.lock(); + data.target_to_source_header_required = Some(id); + data.target_to_source_header_requirements.push(id); + (self.tick)(&mut data); + (self.post_tick)(&mut data); + + Ok(data.target_to_source_batch_transaction.take().map(|mut tx| { + tx.required_header_id = id; + tx + })) + } + } + + #[derive(Clone)] + pub struct TestTargetClient { + data: Arc>, + tick: Arc, + post_tick: Arc, + } + + impl Default for TestTargetClient { + fn default() -> Self { + TestTargetClient { + data: Arc::new(Mutex::new(TestClientData::default())), + tick: Arc::new(|_| {}), + post_tick: Arc::new(|_| {}), + } + } + } + + #[async_trait] + impl RelayClient for TestTargetClient { + type Error = TestError; + + async fn reconnect(&mut self) -> Result<(), TestError> { + { + let mut data = self.data.lock(); + (self.tick)(&mut data); + data.is_target_reconnected = true; + (self.post_tick)(&mut data); + } + Ok(()) + } + } + + #[async_trait] + impl TargetClient for TestTargetClient { + type BatchTransaction = TestMessagesBatchTransaction; + type TransactionTracker = TestTransactionTracker; + + async fn state(&self) -> Result, TestError> { + let mut data = self.data.lock(); + (self.tick)(&mut data); + if data.is_target_fails { + return Err(TestError) + } + (self.post_tick)(&mut data); + Ok(data.target_state.clone()) + } + + async fn latest_received_nonce( + &self, + id: TargetHeaderIdOf, + ) -> Result<(TargetHeaderIdOf, MessageNonce), TestError> { + let mut data = self.data.lock(); + (self.tick)(&mut data); + if data.is_target_fails { + return Err(TestError) + } + (self.post_tick)(&mut data); + Ok((id, data.target_latest_received_nonce)) + } + + async fn unrewarded_relayers_state( + &self, + id: TargetHeaderIdOf, + ) -> Result<(TargetHeaderIdOf, UnrewardedRelayersState), TestError> { + Ok(( + id, + UnrewardedRelayersState { + unrewarded_relayer_entries: 0, + messages_in_oldest_entry: 0, + total_messages: 0, + last_delivered_nonce: 0, + }, + )) + } + + async fn latest_confirmed_received_nonce( + &self, + id: TargetHeaderIdOf, + ) -> Result<(TargetHeaderIdOf, MessageNonce), TestError> { + let mut data = self.data.lock(); + (self.tick)(&mut data); + if data.is_target_fails { + return Err(TestError) + } + (self.post_tick)(&mut data); + Ok((id, data.target_latest_confirmed_received_nonce)) + } + + async fn prove_messages_receiving( + &self, + id: TargetHeaderIdOf, + ) -> Result<(TargetHeaderIdOf, TestMessagesReceivingProof), TestError> { + Ok((id, self.data.lock().target_latest_received_nonce)) + } + + async fn submit_messages_proof( + &self, + _maybe_batch_tx: Option, + _generated_at_header: SourceHeaderIdOf, + nonces: RangeInclusive, + proof: TestMessagesProof, + ) -> Result, TestError> { + let mut data = self.data.lock(); + (self.tick)(&mut data); + if data.is_target_fails { + return Err(TestError) + } + data.receive_messages(proof); + (self.post_tick)(&mut data); + Ok(NoncesSubmitArtifacts { + nonces, + tx_tracker: TestTransactionTracker(data.target_tracked_transaction_status), + }) + } + + async fn require_source_header_on_target( + &self, + id: SourceHeaderIdOf, + ) -> Result, Self::Error> { + let mut data = self.data.lock(); + data.source_to_target_header_required = Some(id); + data.source_to_target_header_requirements.push(id); + (self.tick)(&mut data); + (self.post_tick)(&mut data); + + Ok(data.source_to_target_batch_transaction.take().map(|mut tx| { + tx.required_header_id = id; + tx + })) + } + } + + fn run_loop_test( + data: Arc>, + source_tick: Arc, + source_post_tick: Arc, + target_tick: Arc, + target_post_tick: Arc, + exit_signal: impl Future + 'static + Send, + ) -> TestClientData { + async_std::task::block_on(async { + let source_client = TestSourceClient { + data: data.clone(), + tick: source_tick, + post_tick: source_post_tick, + }; + let target_client = TestTargetClient { + data: data.clone(), + tick: target_tick, + post_tick: target_post_tick, + }; + let _ = run( + Params { + lane: LaneId([0, 0, 0, 0]), + source_tick: Duration::from_millis(100), + target_tick: Duration::from_millis(100), + reconnect_delay: Duration::from_millis(0), + delivery_params: MessageDeliveryParams { + max_unrewarded_relayer_entries_at_target: 4, + max_unconfirmed_nonces_at_target: 4, + max_messages_in_single_batch: 4, + max_messages_weight_in_single_batch: Weight::from_parts(4, 0), + max_messages_size_in_single_batch: 4, + }, + }, + source_client, + target_client, + MetricsParams::disabled(), + exit_signal, + ) + .await; + let result = data.lock().clone(); + result + }) + } + + #[test] + fn message_lane_loop_is_able_to_recover_from_connection_errors() { + // with this configuration, source client will return Err, making source client + // reconnect. Then the target client will fail with Err + reconnect. Then we finally + // able to deliver messages. + let (exit_sender, exit_receiver) = unbounded(); + let result = run_loop_test( + Arc::new(Mutex::new(TestClientData { + is_source_fails: true, + source_state: ClientState { + best_self: HeaderId(0, 0), + best_finalized_self: HeaderId(0, 0), + best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + actual_best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + }, + source_latest_generated_nonce: 1, + target_state: ClientState { + best_self: HeaderId(0, 0), + best_finalized_self: HeaderId(0, 0), + best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + actual_best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + }, + target_latest_received_nonce: 0, + ..Default::default() + })), + Arc::new(|data: &mut TestClientData| { + if data.is_source_reconnected { + data.is_source_fails = false; + data.is_target_fails = true; + } + }), + Arc::new(|_| {}), + Arc::new(move |data: &mut TestClientData| { + if data.is_target_reconnected { + data.is_target_fails = false; + } + if data.target_state.best_finalized_peer_at_best_self.unwrap().0 < 10 { + data.target_state.best_finalized_peer_at_best_self = Some(HeaderId( + data.target_state.best_finalized_peer_at_best_self.unwrap().0 + 1, + data.target_state.best_finalized_peer_at_best_self.unwrap().0 + 1, + )); + } + if !data.submitted_messages_proofs.is_empty() { + exit_sender.unbounded_send(()).unwrap(); + } + }), + Arc::new(|_| {}), + exit_receiver.into_future().map(|(_, _)| ()), + ); + + assert_eq!(result.submitted_messages_proofs, vec![(1..=1, None)],); + } + + #[test] + fn message_lane_loop_is_able_to_recover_from_unsuccessful_transaction() { + // with this configuration, both source and target clients will mine their transactions, but + // their corresponding nonce won't be udpated => reconnect will happen + let (exit_sender, exit_receiver) = unbounded(); + let result = run_loop_test( + Arc::new(Mutex::new(TestClientData { + source_state: ClientState { + best_self: HeaderId(0, 0), + best_finalized_self: HeaderId(0, 0), + best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + actual_best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + }, + source_latest_generated_nonce: 1, + target_state: ClientState { + best_self: HeaderId(0, 0), + best_finalized_self: HeaderId(0, 0), + best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + actual_best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + }, + target_latest_received_nonce: 0, + ..Default::default() + })), + Arc::new(move |data: &mut TestClientData| { + // blocks are produced on every tick + data.source_state.best_self = + HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1); + data.source_state.best_finalized_self = data.source_state.best_self; + // syncing target headers -> source chain + if let Some(last_requirement) = data.target_to_source_header_requirements.last() { + if *last_requirement != + data.source_state.best_finalized_peer_at_best_self.unwrap() + { + data.source_state.best_finalized_peer_at_best_self = + Some(*last_requirement); + } + } + }), + Arc::new(move |data: &mut TestClientData| { + // if it is the first time we're submitting delivery proof, let's revert changes + // to source status => then the delivery confirmation transaction is "finalized", + // but the state is not altered + if data.submitted_messages_receiving_proofs.len() == 1 { + data.source_latest_confirmed_received_nonce = 0; + } + }), + Arc::new(move |data: &mut TestClientData| { + // blocks are produced on every tick + data.target_state.best_self = + HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.1 + 1); + data.target_state.best_finalized_self = data.target_state.best_self; + // syncing source headers -> target chain + if let Some(last_requirement) = data.source_to_target_header_requirements.last() { + if *last_requirement != + data.target_state.best_finalized_peer_at_best_self.unwrap() + { + data.target_state.best_finalized_peer_at_best_self = + Some(*last_requirement); + } + } + // if source has received all messages receiving confirmations => stop + if data.source_latest_confirmed_received_nonce == 1 { + exit_sender.unbounded_send(()).unwrap(); + } + }), + Arc::new(move |data: &mut TestClientData| { + // if it is the first time we're submitting messages proof, let's revert changes + // to target status => then the messages delivery transaction is "finalized", but + // the state is not altered + if data.submitted_messages_proofs.len() == 1 { + data.target_latest_received_nonce = 0; + data.target_latest_confirmed_received_nonce = 0; + } + }), + exit_receiver.into_future().map(|(_, _)| ()), + ); + + assert_eq!(result.submitted_messages_proofs.len(), 2); + assert_eq!(result.submitted_messages_receiving_proofs.len(), 2); + } + + #[test] + fn message_lane_loop_works() { + let (exit_sender, exit_receiver) = unbounded(); + let result = run_loop_test( + Arc::new(Mutex::new(TestClientData { + source_state: ClientState { + best_self: HeaderId(10, 10), + best_finalized_self: HeaderId(10, 10), + best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + actual_best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + }, + source_latest_generated_nonce: 10, + target_state: ClientState { + best_self: HeaderId(0, 0), + best_finalized_self: HeaderId(0, 0), + best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + actual_best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + }, + target_latest_received_nonce: 0, + ..Default::default() + })), + Arc::new(|data: &mut TestClientData| { + // blocks are produced on every tick + data.source_state.best_self = + HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1); + data.source_state.best_finalized_self = data.source_state.best_self; + // headers relay must only be started when we need new target headers at source node + if data.target_to_source_header_required.is_some() { + assert!( + data.source_state.best_finalized_peer_at_best_self.unwrap().0 < + data.target_state.best_self.0 + ); + data.target_to_source_header_required = None; + } + // syncing target headers -> source chain + if let Some(last_requirement) = data.target_to_source_header_requirements.last() { + if *last_requirement != + data.source_state.best_finalized_peer_at_best_self.unwrap() + { + data.source_state.best_finalized_peer_at_best_self = + Some(*last_requirement); + } + } + }), + Arc::new(|_| {}), + Arc::new(move |data: &mut TestClientData| { + // blocks are produced on every tick + data.target_state.best_self = + HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.1 + 1); + data.target_state.best_finalized_self = data.target_state.best_self; + // headers relay must only be started when we need new source headers at target node + if data.source_to_target_header_required.is_some() { + assert!( + data.target_state.best_finalized_peer_at_best_self.unwrap().0 < + data.source_state.best_self.0 + ); + data.source_to_target_header_required = None; + } + // syncing source headers -> target chain + if let Some(last_requirement) = data.source_to_target_header_requirements.last() { + if *last_requirement != + data.target_state.best_finalized_peer_at_best_self.unwrap() + { + data.target_state.best_finalized_peer_at_best_self = + Some(*last_requirement); + } + } + // if source has received all messages receiving confirmations => stop + if data.source_latest_confirmed_received_nonce == 10 { + exit_sender.unbounded_send(()).unwrap(); + } + }), + Arc::new(|_| {}), + exit_receiver.into_future().map(|(_, _)| ()), + ); + + // there are no strict restrictions on when reward confirmation should come + // (because `max_unconfirmed_nonces_at_target` is `100` in tests and this confirmation + // depends on the state of both clients) + // => we do not check it here + assert_eq!(result.submitted_messages_proofs[0].0, 1..=4); + assert_eq!(result.submitted_messages_proofs[1].0, 5..=8); + assert_eq!(result.submitted_messages_proofs[2].0, 9..=10); + assert!(!result.submitted_messages_receiving_proofs.is_empty()); + + // check that we have at least once required new source->target or target->source headers + assert!(!result.target_to_source_header_requirements.is_empty()); + assert!(!result.source_to_target_header_requirements.is_empty()); + } + + #[test] + fn message_lane_loop_works_with_batch_transactions() { + let (exit_sender, exit_receiver) = unbounded(); + let original_data = Arc::new(Mutex::new(TestClientData { + source_state: ClientState { + best_self: HeaderId(10, 10), + best_finalized_self: HeaderId(10, 10), + best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + actual_best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + }, + source_latest_generated_nonce: 10, + target_state: ClientState { + best_self: HeaderId(0, 0), + best_finalized_self: HeaderId(0, 0), + best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + actual_best_finalized_peer_at_best_self: Some(HeaderId(0, 0)), + }, + target_latest_received_nonce: 0, + ..Default::default() + })); + let result = run_loop_test( + original_data, + Arc::new(|_| {}), + Arc::new(move |data: &mut TestClientData| { + data.source_state.best_self = + HeaderId(data.source_state.best_self.0 + 1, data.source_state.best_self.1 + 1); + data.source_state.best_finalized_self = data.source_state.best_self; + if let Some(target_to_source_header_required) = + data.target_to_source_header_required.take() + { + data.target_to_source_batch_transaction = + Some(TestConfirmationBatchTransaction { + required_header_id: target_to_source_header_required, + }) + } + }), + Arc::new(|_| {}), + Arc::new(move |data: &mut TestClientData| { + data.target_state.best_self = + HeaderId(data.target_state.best_self.0 + 1, data.target_state.best_self.1 + 1); + data.target_state.best_finalized_self = data.target_state.best_self; + + if let Some(source_to_target_header_required) = + data.source_to_target_header_required.take() + { + data.source_to_target_batch_transaction = Some(TestMessagesBatchTransaction { + required_header_id: source_to_target_header_required, + }) + } + + if data.source_latest_confirmed_received_nonce == 10 { + exit_sender.unbounded_send(()).unwrap(); + } + }), + exit_receiver.into_future().map(|(_, _)| ()), + ); + + // there are no strict restrictions on when reward confirmation should come + // (because `max_unconfirmed_nonces_at_target` is `100` in tests and this confirmation + // depends on the state of both clients) + // => we do not check it here + assert_eq!(result.submitted_messages_proofs[0].0, 1..=4); + assert_eq!(result.submitted_messages_proofs[1].0, 5..=8); + assert_eq!(result.submitted_messages_proofs[2].0, 9..=10); + assert!(!result.submitted_messages_receiving_proofs.is_empty()); + + // check that we have at least once required new source->target or target->source headers + assert!(!result.target_to_source_header_requirements.is_empty()); + assert!(!result.source_to_target_header_requirements.is_empty()); + } +} diff --git a/relays/messages/src/message_race_delivery.rs b/relays/messages/src/message_race_delivery.rs new file mode 100644 index 00000000000..7a245858b32 --- /dev/null +++ b/relays/messages/src/message_race_delivery.rs @@ -0,0 +1,1162 @@ +// Copyright 2019-2021 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. + +//! Message delivery race delivers proof-of-messages from "lane.source" to "lane.target". + +use std::{collections::VecDeque, marker::PhantomData, ops::RangeInclusive}; + +use async_trait::async_trait; +use futures::stream::FusedStream; + +use bp_messages::{MessageNonce, UnrewardedRelayersState, Weight}; +use relay_utils::FailedClient; + +use crate::{ + message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, + message_lane_loop::{ + MessageDeliveryParams, MessageDetailsMap, MessageProofParameters, NoncesSubmitArtifacts, + SourceClient as MessageLaneSourceClient, SourceClientState, + TargetClient as MessageLaneTargetClient, TargetClientState, + }, + message_race_limits::{MessageRaceLimits, RelayMessagesBatchReference}, + message_race_loop::{ + MessageRace, NoncesRange, RaceState, RaceStrategy, SourceClient, SourceClientNonces, + TargetClient, TargetClientNonces, + }, + message_race_strategy::BasicStrategy, + metrics::MessageLaneLoopMetrics, +}; + +/// Run message delivery race. +pub async fn run( + source_client: impl MessageLaneSourceClient

, + source_state_updates: impl FusedStream>, + target_client: impl MessageLaneTargetClient

, + target_state_updates: impl FusedStream>, + metrics_msg: Option, + params: MessageDeliveryParams, +) -> Result<(), FailedClient> { + crate::message_race_loop::run( + MessageDeliveryRaceSource { + client: source_client.clone(), + metrics_msg: metrics_msg.clone(), + _phantom: Default::default(), + }, + source_state_updates, + MessageDeliveryRaceTarget { + client: target_client.clone(), + metrics_msg: metrics_msg.clone(), + _phantom: Default::default(), + }, + target_state_updates, + MessageDeliveryStrategy:: { + lane_source_client: source_client, + lane_target_client: target_client, + max_unrewarded_relayer_entries_at_target: params + .max_unrewarded_relayer_entries_at_target, + max_unconfirmed_nonces_at_target: params.max_unconfirmed_nonces_at_target, + max_messages_in_single_batch: params.max_messages_in_single_batch, + max_messages_weight_in_single_batch: params.max_messages_weight_in_single_batch, + max_messages_size_in_single_batch: params.max_messages_size_in_single_batch, + latest_confirmed_nonces_at_source: VecDeque::new(), + target_nonces: None, + strategy: BasicStrategy::new(), + metrics_msg, + }, + ) + .await +} + +/// Message delivery race. +struct MessageDeliveryRace

(std::marker::PhantomData

); + +impl MessageRace for MessageDeliveryRace

{ + type SourceHeaderId = SourceHeaderIdOf

; + type TargetHeaderId = TargetHeaderIdOf

; + + type MessageNonce = MessageNonce; + type Proof = P::MessagesProof; + + fn source_name() -> String { + format!("{}::MessagesDelivery", P::SOURCE_NAME) + } + + fn target_name() -> String { + format!("{}::MessagesDelivery", P::TARGET_NAME) + } +} + +/// Message delivery race source, which is a source of the lane. +struct MessageDeliveryRaceSource { + client: C, + metrics_msg: Option, + _phantom: PhantomData

, +} + +#[async_trait] +impl SourceClient> for MessageDeliveryRaceSource +where + P: MessageLane, + C: MessageLaneSourceClient

, +{ + type Error = C::Error; + type NoncesRange = MessageDetailsMap; + type ProofParameters = MessageProofParameters; + + async fn nonces( + &self, + at_block: SourceHeaderIdOf

, + prev_latest_nonce: MessageNonce, + ) -> Result<(SourceHeaderIdOf

, SourceClientNonces), Self::Error> { + let (at_block, latest_generated_nonce) = + self.client.latest_generated_nonce(at_block).await?; + let (at_block, latest_confirmed_nonce) = + self.client.latest_confirmed_received_nonce(at_block).await?; + + if let Some(metrics_msg) = self.metrics_msg.as_ref() { + metrics_msg.update_source_latest_generated_nonce(latest_generated_nonce); + metrics_msg.update_source_latest_confirmed_nonce(latest_confirmed_nonce); + } + + let new_nonces = if latest_generated_nonce > prev_latest_nonce { + self.client + .generated_message_details( + at_block.clone(), + prev_latest_nonce + 1..=latest_generated_nonce, + ) + .await? + } else { + MessageDetailsMap::new() + }; + + Ok(( + at_block, + SourceClientNonces { new_nonces, confirmed_nonce: Some(latest_confirmed_nonce) }, + )) + } + + async fn generate_proof( + &self, + at_block: SourceHeaderIdOf

, + nonces: RangeInclusive, + proof_parameters: Self::ProofParameters, + ) -> Result<(SourceHeaderIdOf

, RangeInclusive, P::MessagesProof), Self::Error> + { + self.client.prove_messages(at_block, nonces, proof_parameters).await + } +} + +/// Message delivery race target, which is a target of the lane. +struct MessageDeliveryRaceTarget { + client: C, + metrics_msg: Option, + _phantom: PhantomData

, +} + +#[async_trait] +impl TargetClient> for MessageDeliveryRaceTarget +where + P: MessageLane, + C: MessageLaneTargetClient

, +{ + type Error = C::Error; + type TargetNoncesData = DeliveryRaceTargetNoncesData; + type BatchTransaction = C::BatchTransaction; + type TransactionTracker = C::TransactionTracker; + + async fn require_source_header( + &self, + id: SourceHeaderIdOf

, + ) -> Result, Self::Error> { + self.client.require_source_header_on_target(id).await + } + + async fn nonces( + &self, + at_block: TargetHeaderIdOf

, + update_metrics: bool, + ) -> Result<(TargetHeaderIdOf

, TargetClientNonces), Self::Error> + { + let (at_block, latest_received_nonce) = self.client.latest_received_nonce(at_block).await?; + let (at_block, latest_confirmed_nonce) = + self.client.latest_confirmed_received_nonce(at_block).await?; + let (at_block, unrewarded_relayers) = + self.client.unrewarded_relayers_state(at_block).await?; + + if update_metrics { + if let Some(metrics_msg) = self.metrics_msg.as_ref() { + metrics_msg.update_target_latest_received_nonce(latest_received_nonce); + metrics_msg.update_target_latest_confirmed_nonce(latest_confirmed_nonce); + } + } + + Ok(( + at_block, + TargetClientNonces { + latest_nonce: latest_received_nonce, + nonces_data: DeliveryRaceTargetNoncesData { + confirmed_nonce: latest_confirmed_nonce, + unrewarded_relayers, + }, + }, + )) + } + + async fn submit_proof( + &self, + maybe_batch_tx: Option, + generated_at_block: SourceHeaderIdOf

, + nonces: RangeInclusive, + proof: P::MessagesProof, + ) -> Result, Self::Error> { + self.client + .submit_messages_proof(maybe_batch_tx, generated_at_block, nonces, proof) + .await + } +} + +/// Additional nonces data from the target client used by message delivery race. +#[derive(Debug, Clone)] +struct DeliveryRaceTargetNoncesData { + /// The latest nonce that we know: (1) has been delivered to us (2) has been confirmed + /// back to the source node (by confirmations race) and (3) relayer has received + /// reward for (and this has been confirmed by the message delivery race). + confirmed_nonce: MessageNonce, + /// State of the unrewarded relayers set at the target node. + unrewarded_relayers: UnrewardedRelayersState, +} + +/// Messages delivery strategy. +struct MessageDeliveryStrategy { + /// The client that is connected to the message lane source node. + lane_source_client: SC, + /// The client that is connected to the message lane target node. + lane_target_client: TC, + /// Maximal unrewarded relayer entries at target client. + max_unrewarded_relayer_entries_at_target: MessageNonce, + /// Maximal unconfirmed nonces at target client. + max_unconfirmed_nonces_at_target: MessageNonce, + /// Maximal number of messages in the single delivery transaction. + max_messages_in_single_batch: MessageNonce, + /// Maximal cumulative messages weight in the single delivery transaction. + max_messages_weight_in_single_batch: Weight, + /// Maximal messages size in the single delivery transaction. + max_messages_size_in_single_batch: u32, + /// Latest confirmed nonces at the source client + the header id where we have first met this + /// nonce. + latest_confirmed_nonces_at_source: VecDeque<(SourceHeaderIdOf

, MessageNonce)>, + /// Target nonces available at the **best** block of the target chain. + target_nonces: Option>, + /// Basic delivery strategy. + strategy: MessageDeliveryStrategyBase

, + /// Message lane metrics. + metrics_msg: Option, +} + +type MessageDeliveryStrategyBase

= BasicStrategy< +

::SourceHeaderNumber, +

::SourceHeaderHash, +

::TargetHeaderNumber, +

::TargetHeaderHash, + MessageDetailsMap<

::SourceChainBalance>, +

::MessagesProof, +>; + +impl std::fmt::Debug for MessageDeliveryStrategy { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + fmt.debug_struct("MessageDeliveryStrategy") + .field( + "max_unrewarded_relayer_entries_at_target", + &self.max_unrewarded_relayer_entries_at_target, + ) + .field("max_unconfirmed_nonces_at_target", &self.max_unconfirmed_nonces_at_target) + .field("max_messages_in_single_batch", &self.max_messages_in_single_batch) + .field("max_messages_weight_in_single_batch", &self.max_messages_weight_in_single_batch) + .field("max_messages_size_in_single_batch", &self.max_messages_size_in_single_batch) + .field("latest_confirmed_nonces_at_source", &self.latest_confirmed_nonces_at_source) + .field("target_nonces", &self.target_nonces) + .field("strategy", &self.strategy) + .finish() + } +} + +impl MessageDeliveryStrategy { + /// Returns total weight of all undelivered messages. + fn dispatch_weight_for_range(&self, range: &RangeInclusive) -> Weight { + self.strategy + .source_queue() + .iter() + .flat_map(|(_, subrange)| { + subrange + .iter() + .filter(|(nonce, _)| range.contains(nonce)) + .map(|(_, details)| details.dispatch_weight) + }) + .fold(Weight::zero(), |total, weight| total.saturating_add(weight)) + } +} + +#[async_trait] +impl RaceStrategy, TargetHeaderIdOf

, P::MessagesProof> + for MessageDeliveryStrategy +where + P: MessageLane, + SC: MessageLaneSourceClient

, + TC: MessageLaneTargetClient

, +{ + type SourceNoncesRange = MessageDetailsMap; + type ProofParameters = MessageProofParameters; + type TargetNoncesData = DeliveryRaceTargetNoncesData; + + fn is_empty(&self) -> bool { + self.strategy.is_empty() + } + + fn required_source_header_at_target, TargetHeaderIdOf

>>( + &self, + current_best: &SourceHeaderIdOf

, + race_state: RS, + ) -> Option> { + // we have already submitted something - let's wait until it is mined + if race_state.nonces_submitted().is_some() { + return None + } + + let has_nonces_to_deliver = !self.strategy.is_empty(); + let header_required_for_messages_delivery = + self.strategy.required_source_header_at_target(current_best, race_state); + let header_required_for_reward_confirmations_delivery = self + .latest_confirmed_nonces_at_source + .back() + .filter(|(id, nonce)| *nonce != 0 && id.0 > current_best.0) + .map(|(id, _)| id.clone()); + match ( + has_nonces_to_deliver, + header_required_for_messages_delivery, + header_required_for_reward_confirmations_delivery, + ) { + // if we need to delver messages and proof-of-delivery-confirmations, then we need to + // select the most recent header to avoid extra roundtrips + (true, Some(id1), Some(id2)) => Some(if id1.0 > id2.0 { id1 } else { id2 }), + // if we only need to deliver messages - fine, let's require some source header + // + // if we need new header for proof-of-delivery-confirmations - let's also ask for that. + // Even though it may require additional header, we'll be sure that we won't block the + // lane (sometimes we can't deliver messages without proof-of-delivery-confirmations) + (true, a, b) => a.or(b), + // we never submit delivery transaction without messages, so if `has_nonces_to_deliver` + // if `false`, we don't need any source headers at target + (false, _, _) => None, + } + } + + fn best_at_source(&self) -> Option { + self.strategy.best_at_source() + } + + fn best_at_target(&self) -> Option { + self.strategy.best_at_target() + } + + fn source_nonces_updated( + &mut self, + at_block: SourceHeaderIdOf

, + nonces: SourceClientNonces, + ) { + if let Some(confirmed_nonce) = nonces.confirmed_nonce { + let is_confirmed_nonce_updated = self + .latest_confirmed_nonces_at_source + .back() + .map(|(_, prev_nonce)| *prev_nonce != confirmed_nonce) + .unwrap_or(true); + if is_confirmed_nonce_updated { + self.latest_confirmed_nonces_at_source + .push_back((at_block.clone(), confirmed_nonce)); + } + } + self.strategy.source_nonces_updated(at_block, nonces) + } + + fn best_target_nonces_updated, TargetHeaderIdOf

>>( + &mut self, + nonces: TargetClientNonces, + race_state: &mut RS, + ) { + // best target nonces must always be ge than finalized target nonces + let latest_nonce = nonces.latest_nonce; + self.target_nonces = Some(nonces); + + self.strategy.best_target_nonces_updated( + TargetClientNonces { latest_nonce, nonces_data: () }, + race_state, + ) + } + + fn finalized_target_nonces_updated, TargetHeaderIdOf

>>( + &mut self, + nonces: TargetClientNonces, + race_state: &mut RS, + ) { + if let Some(ref best_finalized_source_header_id_at_best_target) = + race_state.best_finalized_source_header_id_at_best_target() + { + let oldest_header_number_to_keep = best_finalized_source_header_id_at_best_target.0; + while self + .latest_confirmed_nonces_at_source + .front() + .map(|(id, _)| id.0 < oldest_header_number_to_keep) + .unwrap_or(false) + { + self.latest_confirmed_nonces_at_source.pop_front(); + } + } + + if let Some(ref mut target_nonces) = self.target_nonces { + target_nonces.latest_nonce = + std::cmp::max(target_nonces.latest_nonce, nonces.latest_nonce); + } + + self.strategy.finalized_target_nonces_updated( + TargetClientNonces { latest_nonce: nonces.latest_nonce, nonces_data: () }, + race_state, + ) + } + + async fn select_nonces_to_deliver, TargetHeaderIdOf

>>( + &self, + race_state: RS, + ) -> Option<(RangeInclusive, Self::ProofParameters)> { + let best_target_nonce = self.strategy.best_at_target()?; + let best_finalized_source_header_id_at_best_target = + race_state.best_finalized_source_header_id_at_best_target()?; + let latest_confirmed_nonce_at_source = self + .latest_confirmed_nonces_at_source + .iter() + .take_while(|(id, _)| id.0 <= best_finalized_source_header_id_at_best_target.0) + .last() + .map(|(_, nonce)| *nonce) + .unwrap_or(best_target_nonce); + let target_nonces = self.target_nonces.as_ref()?; + + // There's additional condition in the message delivery race: target would reject messages + // if there are too much unconfirmed messages at the inbound lane. + + // The receiving race is responsible to deliver confirmations back to the source chain. So + // if there's a lot of unconfirmed messages, let's wait until it'll be able to do its job. + let latest_received_nonce_at_target = target_nonces.latest_nonce; + let confirmations_missing = + latest_received_nonce_at_target.checked_sub(latest_confirmed_nonce_at_source); + match confirmations_missing { + Some(confirmations_missing) + if confirmations_missing >= self.max_unconfirmed_nonces_at_target => + { + log::debug!( + target: "bridge", + "Cannot deliver any more messages from {} to {}. Too many unconfirmed nonces \ + at target: target.latest_received={:?}, source.latest_confirmed={:?}, max={:?}", + MessageDeliveryRace::

::source_name(), + MessageDeliveryRace::

::target_name(), + latest_received_nonce_at_target, + latest_confirmed_nonce_at_source, + self.max_unconfirmed_nonces_at_target, + ); + + return None + }, + _ => (), + } + + // Ok - we may have new nonces to deliver. But target may still reject new messages, because + // we haven't notified it that (some) messages have been confirmed. So we may want to + // include updated `source.latest_confirmed` in the proof. + // + // Important note: we're including outbound state lane proof whenever there are unconfirmed + // nonces on the target chain. Other strategy is to include it only if it's absolutely + // necessary. + let latest_confirmed_nonce_at_target = target_nonces.nonces_data.confirmed_nonce; + let outbound_state_proof_required = + latest_confirmed_nonce_at_target < latest_confirmed_nonce_at_source; + + // The target node would also reject messages if there are too many entries in the + // "unrewarded relayers" set. If we are unable to prove new rewards to the target node, then + // we should wait for confirmations race. + let unrewarded_relayer_entries_limit_reached = + target_nonces.nonces_data.unrewarded_relayers.unrewarded_relayer_entries >= + self.max_unrewarded_relayer_entries_at_target; + if unrewarded_relayer_entries_limit_reached { + // so there are already too many unrewarded relayer entries in the set + // + // => check if we can prove enough rewards. If not, we should wait for more rewards to + // be paid + let number_of_rewards_being_proved = + latest_confirmed_nonce_at_source.saturating_sub(latest_confirmed_nonce_at_target); + let enough_rewards_being_proved = number_of_rewards_being_proved >= + target_nonces.nonces_data.unrewarded_relayers.messages_in_oldest_entry; + if !enough_rewards_being_proved { + return None + } + } + + // If we're here, then the confirmations race did its job && sending side now knows that + // messages have been delivered. Now let's select nonces that we want to deliver. + // + // We may deliver at most: + // + // max_unconfirmed_nonces_at_target - (latest_received_nonce_at_target - + // latest_confirmed_nonce_at_target) + // + // messages in the batch. But since we're including outbound state proof in the batch, then + // it may be increased to: + // + // max_unconfirmed_nonces_at_target - (latest_received_nonce_at_target - + // latest_confirmed_nonce_at_source) + let future_confirmed_nonce_at_target = if outbound_state_proof_required { + latest_confirmed_nonce_at_source + } else { + latest_confirmed_nonce_at_target + }; + let max_nonces = latest_received_nonce_at_target + .checked_sub(future_confirmed_nonce_at_target) + .and_then(|diff| self.max_unconfirmed_nonces_at_target.checked_sub(diff)) + .unwrap_or_default(); + let max_nonces = std::cmp::min(max_nonces, self.max_messages_in_single_batch); + let max_messages_weight_in_single_batch = self.max_messages_weight_in_single_batch; + let max_messages_size_in_single_batch = self.max_messages_size_in_single_batch; + let lane_source_client = self.lane_source_client.clone(); + let lane_target_client = self.lane_target_client.clone(); + + let available_source_queue_indices = + self.strategy.available_source_queue_indices(race_state)?; + let source_queue = self.strategy.source_queue(); + + let reference = RelayMessagesBatchReference { + max_messages_in_this_batch: max_nonces, + max_messages_weight_in_single_batch, + max_messages_size_in_single_batch, + lane_source_client: lane_source_client.clone(), + lane_target_client: lane_target_client.clone(), + best_target_nonce, + nonces_queue: source_queue.clone(), + nonces_queue_range: available_source_queue_indices, + metrics: self.metrics_msg.clone(), + }; + + let selected_nonces = MessageRaceLimits::decide(reference).await?; + let dispatch_weight = self.dispatch_weight_for_range(&selected_nonces); + + Some(( + selected_nonces, + MessageProofParameters { outbound_state_proof_required, dispatch_weight }, + )) + } +} + +impl NoncesRange for MessageDetailsMap { + fn begin(&self) -> MessageNonce { + self.keys().next().cloned().unwrap_or_default() + } + + fn end(&self) -> MessageNonce { + self.keys().next_back().cloned().unwrap_or_default() + } + + fn greater_than(mut self, nonce: MessageNonce) -> Option { + let gte = self.split_off(&(nonce + 1)); + if gte.is_empty() { + None + } else { + Some(gte) + } + } +} + +#[cfg(test)] +mod tests { + use crate::{ + message_lane_loop::{ + tests::{ + header_id, TestMessageLane, TestMessagesBatchTransaction, TestMessagesProof, + TestSourceChainBalance, TestSourceClient, TestSourceHeaderId, TestTargetClient, + TestTargetHeaderId, + }, + MessageDetails, + }, + message_race_loop::RaceStateImpl, + }; + + use super::*; + + const DEFAULT_DISPATCH_WEIGHT: Weight = Weight::from_parts(1, 0); + const DEFAULT_SIZE: u32 = 1; + + type TestRaceState = RaceStateImpl< + TestSourceHeaderId, + TestTargetHeaderId, + TestMessagesProof, + TestMessagesBatchTransaction, + >; + type TestStrategy = + MessageDeliveryStrategy; + + fn source_nonces( + new_nonces: RangeInclusive, + confirmed_nonce: MessageNonce, + reward: TestSourceChainBalance, + ) -> SourceClientNonces> { + SourceClientNonces { + new_nonces: new_nonces + .into_iter() + .map(|nonce| { + ( + nonce, + MessageDetails { + dispatch_weight: DEFAULT_DISPATCH_WEIGHT, + size: DEFAULT_SIZE, + reward, + }, + ) + }) + .collect(), + confirmed_nonce: Some(confirmed_nonce), + } + } + + fn prepare_strategy() -> (TestRaceState, TestStrategy) { + let mut race_state = RaceStateImpl { + best_finalized_source_header_id_at_source: Some(header_id(1)), + best_finalized_source_header_id_at_best_target: Some(header_id(1)), + best_target_header_id: Some(header_id(1)), + best_finalized_target_header_id: Some(header_id(1)), + nonces_to_submit: None, + nonces_to_submit_batch: None, + nonces_submitted: None, + }; + + let mut race_strategy = TestStrategy { + max_unrewarded_relayer_entries_at_target: 4, + max_unconfirmed_nonces_at_target: 4, + max_messages_in_single_batch: 4, + max_messages_weight_in_single_batch: Weight::from_parts(4, 0), + max_messages_size_in_single_batch: 4, + latest_confirmed_nonces_at_source: vec![(header_id(1), 19)].into_iter().collect(), + lane_source_client: TestSourceClient::default(), + lane_target_client: TestTargetClient::default(), + metrics_msg: None, + target_nonces: Some(TargetClientNonces { + latest_nonce: 19, + nonces_data: DeliveryRaceTargetNoncesData { + confirmed_nonce: 19, + unrewarded_relayers: UnrewardedRelayersState { + unrewarded_relayer_entries: 0, + messages_in_oldest_entry: 0, + total_messages: 0, + last_delivered_nonce: 0, + }, + }, + }), + strategy: BasicStrategy::new(), + }; + + race_strategy + .strategy + .source_nonces_updated(header_id(1), source_nonces(20..=23, 19, 0)); + + let target_nonces = TargetClientNonces { latest_nonce: 19, nonces_data: () }; + race_strategy + .strategy + .best_target_nonces_updated(target_nonces.clone(), &mut race_state); + race_strategy + .strategy + .finalized_target_nonces_updated(target_nonces, &mut race_state); + + (race_state, race_strategy) + } + + fn proof_parameters(state_required: bool, weight: u32) -> MessageProofParameters { + MessageProofParameters { + outbound_state_proof_required: state_required, + dispatch_weight: Weight::from_parts(weight as u64, 0), + } + } + + #[test] + fn weights_map_works_as_nonces_range() { + fn build_map( + range: RangeInclusive, + ) -> MessageDetailsMap { + range + .map(|idx| { + ( + idx, + MessageDetails { + dispatch_weight: Weight::from_parts(idx, 0), + size: idx as _, + reward: idx as _, + }, + ) + }) + .collect() + } + + let map = build_map(20..=30); + + assert_eq!(map.begin(), 20); + assert_eq!(map.end(), 30); + assert_eq!(map.clone().greater_than(10), Some(build_map(20..=30))); + assert_eq!(map.clone().greater_than(19), Some(build_map(20..=30))); + assert_eq!(map.clone().greater_than(20), Some(build_map(21..=30))); + assert_eq!(map.clone().greater_than(25), Some(build_map(26..=30))); + assert_eq!(map.clone().greater_than(29), Some(build_map(30..=30))); + assert_eq!(map.greater_than(30), None); + } + + #[async_std::test] + async fn message_delivery_strategy_selects_messages_to_deliver() { + let (state, strategy) = prepare_strategy(); + + // both sides are ready to relay new messages + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=23), proof_parameters(false, 4))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_selects_nothing_if_too_many_confirmations_missing() { + let (state, mut strategy) = prepare_strategy(); + + // if there are already `max_unconfirmed_nonces_at_target` messages on target, + // we need to wait until confirmations will be delivered by receiving race + strategy.latest_confirmed_nonces_at_source = vec![( + header_id(1), + strategy.target_nonces.as_ref().unwrap().latest_nonce - + strategy.max_unconfirmed_nonces_at_target, + )] + .into_iter() + .collect(); + assert_eq!(strategy.select_nonces_to_deliver(state).await, None); + } + + #[async_std::test] + async fn message_delivery_strategy_includes_outbound_state_proof_when_new_nonces_are_available() + { + let (state, mut strategy) = prepare_strategy(); + + // if there are new confirmed nonces on source, we want to relay this information + // to target to prune rewards queue + let prev_confirmed_nonce_at_source = + strategy.latest_confirmed_nonces_at_source.back().unwrap().1; + strategy.target_nonces.as_mut().unwrap().nonces_data.confirmed_nonce = + prev_confirmed_nonce_at_source - 1; + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=23), proof_parameters(true, 4))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_selects_nothing_if_there_are_too_many_unrewarded_relayers() { + let (state, mut strategy) = prepare_strategy(); + + // if there are already `max_unrewarded_relayer_entries_at_target` entries at target, + // we need to wait until rewards will be paid + { + let mut unrewarded_relayers = + &mut strategy.target_nonces.as_mut().unwrap().nonces_data.unrewarded_relayers; + unrewarded_relayers.unrewarded_relayer_entries = + strategy.max_unrewarded_relayer_entries_at_target; + unrewarded_relayers.messages_in_oldest_entry = 4; + } + assert_eq!(strategy.select_nonces_to_deliver(state).await, None); + } + + #[async_std::test] + async fn message_delivery_strategy_selects_nothing_if_proved_rewards_is_not_enough_to_remove_oldest_unrewarded_entry( + ) { + let (state, mut strategy) = prepare_strategy(); + + // if there are already `max_unrewarded_relayer_entries_at_target` entries at target, + // we need to prove at least `messages_in_oldest_entry` rewards + let prev_confirmed_nonce_at_source = + strategy.latest_confirmed_nonces_at_source.back().unwrap().1; + { + let mut nonces_data = &mut strategy.target_nonces.as_mut().unwrap().nonces_data; + nonces_data.confirmed_nonce = prev_confirmed_nonce_at_source - 1; + let mut unrewarded_relayers = &mut nonces_data.unrewarded_relayers; + unrewarded_relayers.unrewarded_relayer_entries = + strategy.max_unrewarded_relayer_entries_at_target; + unrewarded_relayers.messages_in_oldest_entry = 4; + } + assert_eq!(strategy.select_nonces_to_deliver(state).await, None); + } + + #[async_std::test] + async fn message_delivery_strategy_includes_outbound_state_proof_if_proved_rewards_is_enough() { + let (state, mut strategy) = prepare_strategy(); + + // if there are already `max_unrewarded_relayer_entries_at_target` entries at target, + // we need to prove at least `messages_in_oldest_entry` rewards + let prev_confirmed_nonce_at_source = + strategy.latest_confirmed_nonces_at_source.back().unwrap().1; + { + let mut nonces_data = &mut strategy.target_nonces.as_mut().unwrap().nonces_data; + nonces_data.confirmed_nonce = prev_confirmed_nonce_at_source - 3; + let mut unrewarded_relayers = &mut nonces_data.unrewarded_relayers; + unrewarded_relayers.unrewarded_relayer_entries = + strategy.max_unrewarded_relayer_entries_at_target; + unrewarded_relayers.messages_in_oldest_entry = 3; + } + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=23), proof_parameters(true, 4))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_limits_batch_by_messages_weight() { + let (state, mut strategy) = prepare_strategy(); + + // not all queued messages may fit in the batch, because batch has max weight + strategy.max_messages_weight_in_single_batch = Weight::from_parts(3, 0); + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=22), proof_parameters(false, 3))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_accepts_single_message_even_if_its_weight_overflows_maximal_weight( + ) { + let (state, mut strategy) = prepare_strategy(); + + // first message doesn't fit in the batch, because it has weight (10) that overflows max + // weight (4) + strategy.strategy.source_queue_mut()[0].1.get_mut(&20).unwrap().dispatch_weight = + Weight::from_parts(10, 0); + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=20), proof_parameters(false, 10))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_limits_batch_by_messages_size() { + let (state, mut strategy) = prepare_strategy(); + + // not all queued messages may fit in the batch, because batch has max weight + strategy.max_messages_size_in_single_batch = 3; + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=22), proof_parameters(false, 3))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_accepts_single_message_even_if_its_weight_overflows_maximal_size( + ) { + let (state, mut strategy) = prepare_strategy(); + + // first message doesn't fit in the batch, because it has weight (10) that overflows max + // weight (4) + strategy.strategy.source_queue_mut()[0].1.get_mut(&20).unwrap().size = 10; + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=20), proof_parameters(false, 1))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_limits_batch_by_messages_count_when_there_is_upper_limit() { + let (state, mut strategy) = prepare_strategy(); + + // not all queued messages may fit in the batch, because batch has max number of messages + // limit + strategy.max_messages_in_single_batch = 3; + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=22), proof_parameters(false, 3))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_limits_batch_by_messages_count_when_there_are_unconfirmed_nonces( + ) { + let (state, mut strategy) = prepare_strategy(); + + // 1 delivery confirmation from target to source is still missing, so we may only + // relay 3 new messages + let prev_confirmed_nonce_at_source = + strategy.latest_confirmed_nonces_at_source.back().unwrap().1; + strategy.latest_confirmed_nonces_at_source = + vec![(header_id(1), prev_confirmed_nonce_at_source - 1)].into_iter().collect(); + strategy.target_nonces.as_mut().unwrap().nonces_data.confirmed_nonce = + prev_confirmed_nonce_at_source - 1; + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=22), proof_parameters(false, 3))) + ); + } + + #[async_std::test] + async fn message_delivery_strategy_waits_for_confirmed_nonce_header_to_appear_on_target() { + // 1 delivery confirmation from target to source is still missing, so we may deliver + // reward confirmation with our message delivery transaction. But the problem is that + // the reward has been paid at header 2 && this header is still unknown to target node. + // + // => so we can't deliver more than 3 messages + let (mut state, mut strategy) = prepare_strategy(); + let prev_confirmed_nonce_at_source = + strategy.latest_confirmed_nonces_at_source.back().unwrap().1; + strategy.latest_confirmed_nonces_at_source = vec![ + (header_id(1), prev_confirmed_nonce_at_source - 1), + (header_id(2), prev_confirmed_nonce_at_source), + ] + .into_iter() + .collect(); + strategy.target_nonces.as_mut().unwrap().nonces_data.confirmed_nonce = + prev_confirmed_nonce_at_source - 1; + state.best_finalized_source_header_id_at_best_target = Some(header_id(1)); + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=22), proof_parameters(false, 3))) + ); + + // the same situation, but the header 2 is known to the target node, so we may deliver + // reward confirmation + let (mut state, mut strategy) = prepare_strategy(); + let prev_confirmed_nonce_at_source = + strategy.latest_confirmed_nonces_at_source.back().unwrap().1; + strategy.latest_confirmed_nonces_at_source = vec![ + (header_id(1), prev_confirmed_nonce_at_source - 1), + (header_id(2), prev_confirmed_nonce_at_source), + ] + .into_iter() + .collect(); + strategy.target_nonces.as_mut().unwrap().nonces_data.confirmed_nonce = + prev_confirmed_nonce_at_source - 1; + state.best_finalized_source_header_id_at_source = Some(header_id(2)); + state.best_finalized_source_header_id_at_best_target = Some(header_id(2)); + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=23), proof_parameters(true, 4))) + ); + } + + #[async_std::test] + async fn source_header_is_required_when_confirmations_are_required() { + // let's prepare situation when: + // - all messages [20; 23] have been generated at source block#1; + let (mut state, mut strategy) = prepare_strategy(); + // + // - messages [20; 23] have been delivered + assert_eq!( + strategy.select_nonces_to_deliver(state.clone()).await, + Some(((20..=23), proof_parameters(false, 4))) + ); + strategy.finalized_target_nonces_updated( + TargetClientNonces { + latest_nonce: 23, + nonces_data: DeliveryRaceTargetNoncesData { + confirmed_nonce: 19, + unrewarded_relayers: UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 4, + total_messages: 4, + last_delivered_nonce: 23, + }, + }, + }, + &mut state, + ); + // nothing needs to be delivered now and we don't need any new headers + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, None); + assert_eq!(strategy.required_source_header_at_target(&header_id(1), state.clone()), None); + + // now let's generate two more nonces [24; 25] at the soruce; + strategy.source_nonces_updated(header_id(2), source_nonces(24..=25, 19, 0)); + // + // - so now we'll need to relay source block#2 to be able to accept messages [24; 25]. + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, None); + assert_eq!( + strategy.required_source_header_at_target(&header_id(1), state.clone()), + Some(header_id(2)) + ); + + // let's relay source block#2 + state.best_finalized_source_header_id_at_source = Some(header_id(2)); + state.best_finalized_source_header_id_at_best_target = Some(header_id(2)); + state.best_target_header_id = Some(header_id(2)); + state.best_finalized_target_header_id = Some(header_id(2)); + + // and ask strategy again => still nothing to deliver, because parallel confirmations + // race need to be pushed further + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, None); + assert_eq!(strategy.required_source_header_at_target(&header_id(2), state.clone()), None); + + // let's confirm messages [20; 23] + strategy.source_nonces_updated(header_id(2), source_nonces(24..=25, 23, 0)); + + // and ask strategy again => now we have everything required to deliver remaining + // [24; 25] nonces and proof of [20; 23] confirmation + assert_eq!( + strategy.select_nonces_to_deliver(state.clone()).await, + Some(((24..=25), proof_parameters(true, 2))), + ); + assert_eq!(strategy.required_source_header_at_target(&header_id(2), state), None); + } + + #[async_std::test] + async fn relayer_uses_flattened_view_of_the_source_queue_to_select_nonces() { + // Real scenario that has happened on test deployments: + // 1) relayer witnessed M1 at block 1 => it has separate entry in the `source_queue` + // 2) relayer witnessed M2 at block 2 => it has separate entry in the `source_queue` + // 3) if block 2 is known to the target node, then both M1 and M2 are selected for single + // delivery, even though weight(M1+M2) > larger than largest allowed weight + // + // This was happening because selector (`select_nonces_for_delivery_transaction`) has been + // called for every `source_queue` entry separately without preserving any context. + let (mut state, mut strategy) = prepare_strategy(); + let nonces = source_nonces(24..=25, 19, 0); + strategy.strategy.source_nonces_updated(header_id(2), nonces); + strategy.max_unrewarded_relayer_entries_at_target = 100; + strategy.max_unconfirmed_nonces_at_target = 100; + strategy.max_messages_in_single_batch = 5; + strategy.max_messages_weight_in_single_batch = Weight::from_parts(100, 0); + strategy.max_messages_size_in_single_batch = 100; + state.best_finalized_source_header_id_at_best_target = Some(header_id(2)); + + assert_eq!( + strategy.select_nonces_to_deliver(state).await, + Some(((20..=24), proof_parameters(false, 5))) + ); + } + + #[test] + #[allow(clippy::reversed_empty_ranges)] + fn no_source_headers_required_at_target_if_lanes_are_empty() { + let (state, _) = prepare_strategy(); + let mut strategy = TestStrategy { + max_unrewarded_relayer_entries_at_target: 4, + max_unconfirmed_nonces_at_target: 4, + max_messages_in_single_batch: 4, + max_messages_weight_in_single_batch: Weight::from_parts(4, 0), + max_messages_size_in_single_batch: 4, + latest_confirmed_nonces_at_source: VecDeque::new(), + lane_source_client: TestSourceClient::default(), + lane_target_client: TestTargetClient::default(), + metrics_msg: None, + target_nonces: None, + strategy: BasicStrategy::new(), + }; + + let source_header_id = header_id(10); + strategy.source_nonces_updated( + source_header_id, + // MessageDeliveryRaceSource::nonces returns Some(0), because that's how it is + // represented in memory (there's no Options in OutboundLaneState) + source_nonces(1u64..=0u64, 0, 0), + ); + + // even though `latest_confirmed_nonces_at_source` is not empty, new headers are not + // requested + assert_eq!( + strategy.latest_confirmed_nonces_at_source, + VecDeque::from([(source_header_id, 0)]) + ); + assert_eq!(strategy.required_source_header_at_target(&source_header_id, state), None); + } + + #[async_std::test] + async fn previous_nonces_are_selected_if_reorg_happens_at_target_chain() { + // this is the copy of the similar test in the `mesage_race_strategy.rs`, but it also tests + // that the `MessageDeliveryStrategy` acts properly in the similar scenario + + // tune parameters to allow 5 nonces per delivery transaction + let (mut state, mut strategy) = prepare_strategy(); + strategy.max_unrewarded_relayer_entries_at_target = 5; + strategy.max_unconfirmed_nonces_at_target = 5; + strategy.max_messages_in_single_batch = 5; + strategy.max_messages_weight_in_single_batch = Weight::from_parts(5, 0); + strategy.max_messages_size_in_single_batch = 5; + + // in this state we have 4 available nonces for delivery + assert_eq!( + strategy.select_nonces_to_deliver(state.clone()).await, + Some(( + 20..=23, + MessageProofParameters { + outbound_state_proof_required: false, + dispatch_weight: Weight::from_parts(4, 0), + } + )), + ); + + // let's say we have submitted 20..=23 + state.nonces_submitted = Some(20..=23); + + // then new nonce 24 appear at the source block 2 + let new_nonce_24 = vec![( + 24, + MessageDetails { dispatch_weight: Weight::from_parts(1, 0), size: 0, reward: 0 }, + )] + .into_iter() + .collect(); + let source_header_2 = header_id(2); + state.best_finalized_source_header_id_at_source = Some(source_header_2); + strategy.source_nonces_updated( + source_header_2, + SourceClientNonces { new_nonces: new_nonce_24, confirmed_nonce: None }, + ); + // and nonce 23 appear at the best block of the target node (best finalized still has 0 + // nonces) + let target_nonces_data = DeliveryRaceTargetNoncesData { + confirmed_nonce: 19, + unrewarded_relayers: UnrewardedRelayersState::default(), + }; + let target_header_2 = header_id(2); + state.best_target_header_id = Some(target_header_2); + strategy.best_target_nonces_updated( + TargetClientNonces { latest_nonce: 23, nonces_data: target_nonces_data.clone() }, + &mut state, + ); + + // then best target header is retracted + strategy.best_target_nonces_updated( + TargetClientNonces { latest_nonce: 19, nonces_data: target_nonces_data.clone() }, + &mut state, + ); + + // ... and some fork with 19 delivered nonces is finalized + let target_header_2_fork = header_id(2_1); + state.best_finalized_source_header_id_at_source = Some(source_header_2); + state.best_finalized_source_header_id_at_best_target = Some(source_header_2); + state.best_target_header_id = Some(target_header_2_fork); + state.best_finalized_target_header_id = Some(target_header_2_fork); + strategy.finalized_target_nonces_updated( + TargetClientNonces { latest_nonce: 19, nonces_data: target_nonces_data.clone() }, + &mut state, + ); + + // now we have to select nonces 20..=23 for delivery again + assert_eq!( + strategy.select_nonces_to_deliver(state.clone()).await, + Some(( + 20..=24, + MessageProofParameters { + outbound_state_proof_required: false, + dispatch_weight: Weight::from_parts(5, 0), + } + )), + ); + } +} diff --git a/relays/messages/src/message_race_limits.rs b/relays/messages/src/message_race_limits.rs new file mode 100644 index 00000000000..873bb6aad04 --- /dev/null +++ b/relays/messages/src/message_race_limits.rs @@ -0,0 +1,206 @@ +// Copyright 2019-2021 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 . + +//! enforcement strategy + +use num_traits::Zero; +use std::ops::RangeInclusive; + +use bp_messages::{MessageNonce, Weight}; + +use crate::{ + message_lane::MessageLane, + message_lane_loop::{ + MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient, + TargetClient as MessageLaneTargetClient, + }, + message_race_loop::NoncesRange, + message_race_strategy::SourceRangesQueue, + metrics::MessageLaneLoopMetrics, +}; + +/// Reference data for participating in relay +pub struct RelayReference< + P: MessageLane, + SourceClient: MessageLaneSourceClient

, + TargetClient: MessageLaneTargetClient

, +> { + /// The client that is connected to the message lane source node. + pub lane_source_client: SourceClient, + /// The client that is connected to the message lane target node. + pub lane_target_client: TargetClient, + /// Metrics reference. + pub metrics: Option, + /// Messages size summary + pub selected_size: u32, + + /// Hard check begin nonce + pub hard_selected_begin_nonce: MessageNonce, + + /// Index by all ready nonces + pub index: usize, + /// Current nonce + pub nonce: MessageNonce, + /// Current nonce details + pub details: MessageDetails, +} + +/// Relay reference data +pub struct RelayMessagesBatchReference< + P: MessageLane, + SourceClient: MessageLaneSourceClient

, + TargetClient: MessageLaneTargetClient

, +> { + /// Maximal number of relayed messages in single delivery transaction. + pub max_messages_in_this_batch: MessageNonce, + /// Maximal cumulative dispatch weight of relayed messages in single delivery transaction. + pub max_messages_weight_in_single_batch: Weight, + /// Maximal cumulative size of relayed messages in single delivery transaction. + pub max_messages_size_in_single_batch: u32, + /// The client that is connected to the message lane source node. + pub lane_source_client: SourceClient, + /// The client that is connected to the message lane target node. + pub lane_target_client: TargetClient, + /// Metrics reference. + pub metrics: Option, + /// Best available nonce at the **best** target block. We do not want to deliver nonces + /// less than this nonce, even though the block may be retracted. + pub best_target_nonce: MessageNonce, + /// Source queue. + pub nonces_queue: SourceRangesQueue< + P::SourceHeaderHash, + P::SourceHeaderNumber, + MessageDetailsMap, + >, + /// Range of indices within the `nonces_queue` that are available for selection. + pub nonces_queue_range: RangeInclusive, +} + +/// Limits of the message race transactions. +#[derive(Clone)] +pub struct MessageRaceLimits; + +impl MessageRaceLimits { + pub async fn decide< + P: MessageLane, + SourceClient: MessageLaneSourceClient

, + TargetClient: MessageLaneTargetClient

, + >( + reference: RelayMessagesBatchReference, + ) -> Option> { + let mut hard_selected_count = 0; + + let mut selected_weight = Weight::zero(); + let mut selected_count: MessageNonce = 0; + + let hard_selected_begin_nonce = std::cmp::max( + reference.best_target_nonce + 1, + reference.nonces_queue[*reference.nonces_queue_range.start()].1.begin(), + ); + + // relay reference + let mut relay_reference = RelayReference { + lane_source_client: reference.lane_source_client.clone(), + lane_target_client: reference.lane_target_client.clone(), + metrics: reference.metrics.clone(), + + selected_size: 0, + + hard_selected_begin_nonce, + + index: 0, + nonce: 0, + details: MessageDetails { + dispatch_weight: Weight::zero(), + size: 0, + reward: P::SourceChainBalance::zero(), + }, + }; + + let all_ready_nonces = reference + .nonces_queue + .range(reference.nonces_queue_range.clone()) + .flat_map(|(_, ready_nonces)| ready_nonces.iter()) + .filter(|(nonce, _)| **nonce >= hard_selected_begin_nonce) + .enumerate(); + for (index, (nonce, details)) in all_ready_nonces { + relay_reference.index = index; + relay_reference.nonce = *nonce; + relay_reference.details = *details; + + // Since we (hopefully) have some reserves in `max_messages_weight_in_single_batch` + // and `max_messages_size_in_single_batch`, we may still try to submit transaction + // with single message if message overflows these limits. The worst case would be if + // transaction will be rejected by the target runtime, but at least we have tried. + + // limit messages in the batch by weight + let new_selected_weight = match selected_weight.checked_add(&details.dispatch_weight) { + Some(new_selected_weight) + if new_selected_weight + .all_lte(reference.max_messages_weight_in_single_batch) => + new_selected_weight, + new_selected_weight if selected_count == 0 => { + log::warn!( + target: "bridge", + "Going to submit message delivery transaction with declared dispatch \ + weight {:?} that overflows maximal configured weight {}", + new_selected_weight, + reference.max_messages_weight_in_single_batch, + ); + new_selected_weight.unwrap_or(Weight::MAX) + }, + _ => break, + }; + + // limit messages in the batch by size + let new_selected_size = match relay_reference.selected_size.checked_add(details.size) { + Some(new_selected_size) + if new_selected_size <= reference.max_messages_size_in_single_batch => + new_selected_size, + new_selected_size if selected_count == 0 => { + log::warn!( + target: "bridge", + "Going to submit message delivery transaction with message \ + size {:?} that overflows maximal configured size {}", + new_selected_size, + reference.max_messages_size_in_single_batch, + ); + new_selected_size.unwrap_or(u32::MAX) + }, + _ => break, + }; + + // limit number of messages in the batch + let new_selected_count = selected_count + 1; + if new_selected_count > reference.max_messages_in_this_batch { + break + } + relay_reference.selected_size = new_selected_size; + + hard_selected_count = index + 1; + selected_weight = new_selected_weight; + selected_count = new_selected_count; + } + + if hard_selected_count != 0 { + let selected_max_nonce = + hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1; + Some(hard_selected_begin_nonce..=selected_max_nonce) + } else { + None + } + } +} diff --git a/relays/messages/src/message_race_loop.rs b/relays/messages/src/message_race_loop.rs new file mode 100644 index 00000000000..7e3f84dd5d1 --- /dev/null +++ b/relays/messages/src/message_race_loop.rs @@ -0,0 +1,816 @@ +// Copyright 2019-2021 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. + +//! Loop that is serving single race within message lane. This could be +//! message delivery race, receiving confirmations race or processing +//! confirmations race. +//! +//! The idea of the race is simple - we have `nonce`-s on source and target +//! nodes. We're trying to prove that the source node has this nonce (and +//! associated data - like messages, lane state, etc) to the target node by +//! generating and submitting proof. + +use crate::message_lane_loop::{BatchTransaction, ClientState, NoncesSubmitArtifacts}; + +use async_trait::async_trait; +use bp_messages::MessageNonce; +use futures::{ + future::{FutureExt, TryFutureExt}, + stream::{FusedStream, StreamExt}, +}; +use relay_utils::{ + process_future_result, retry_backoff, FailedClient, MaybeConnectionError, + TrackedTransactionStatus, TransactionTracker, +}; +use std::{ + fmt::Debug, + ops::RangeInclusive, + time::{Duration, Instant}, +}; + +/// One of races within lane. +pub trait MessageRace { + /// Header id of the race source. + type SourceHeaderId: Debug + Clone + PartialEq + Send; + /// Header id of the race source. + type TargetHeaderId: Debug + Clone + PartialEq + Send; + + /// Message nonce used in the race. + type MessageNonce: Debug + Clone; + /// Proof that is generated and delivered in this race. + type Proof: Debug + Clone + Send; + + /// Name of the race source. + fn source_name() -> String; + /// Name of the race target. + fn target_name() -> String; +} + +/// State of race source client. +type SourceClientState

= + ClientState<

::SourceHeaderId,

::TargetHeaderId>; + +/// State of race target client. +type TargetClientState

= + ClientState<

::TargetHeaderId,

::SourceHeaderId>; + +/// Inclusive nonces range. +pub trait NoncesRange: Debug + Sized { + /// Get begin of the range. + fn begin(&self) -> MessageNonce; + /// Get end of the range. + fn end(&self) -> MessageNonce; + /// Returns new range with current range nonces that are greater than the passed `nonce`. + /// If there are no such nonces, `None` is returned. + fn greater_than(self, nonce: MessageNonce) -> Option; +} + +/// Nonces on the race source client. +#[derive(Debug, Clone)] +pub struct SourceClientNonces { + /// New nonces range known to the client. `New` here means all nonces generated after + /// `prev_latest_nonce` passed to the `SourceClient::nonces` method. + pub new_nonces: NoncesRange, + /// The latest nonce that is confirmed to the bridged client. This nonce only makes + /// sense in some races. In other races it is `None`. + pub confirmed_nonce: Option, +} + +/// Nonces on the race target client. +#[derive(Debug, Clone)] +pub struct TargetClientNonces { + /// The latest nonce that is known to the target client. + pub latest_nonce: MessageNonce, + /// Additional data from target node that may be used by the race. + pub nonces_data: TargetNoncesData, +} + +/// One of message lane clients, which is source client for the race. +#[async_trait] +pub trait SourceClient { + /// Type of error these clients returns. + type Error: std::fmt::Debug + MaybeConnectionError; + /// Type of nonces range returned by the source client. + type NoncesRange: NoncesRange; + /// Additional proof parameters required to generate proof. + type ProofParameters; + + /// Return nonces that are known to the source client. + async fn nonces( + &self, + at_block: P::SourceHeaderId, + prev_latest_nonce: MessageNonce, + ) -> Result<(P::SourceHeaderId, SourceClientNonces), Self::Error>; + /// Generate proof for delivering to the target client. + async fn generate_proof( + &self, + at_block: P::SourceHeaderId, + nonces: RangeInclusive, + proof_parameters: Self::ProofParameters, + ) -> Result<(P::SourceHeaderId, RangeInclusive, P::Proof), Self::Error>; +} + +/// One of message lane clients, which is target client for the race. +#[async_trait] +pub trait TargetClient { + /// Type of error these clients returns. + type Error: std::fmt::Debug + MaybeConnectionError; + /// Type of the additional data from the target client, used by the race. + type TargetNoncesData: std::fmt::Debug; + /// Type of batch transaction that submits finality and proof to the target node. + type BatchTransaction: BatchTransaction + Clone; + /// Transaction tracker to track submitted transactions. + type TransactionTracker: TransactionTracker; + + /// Ask headers relay to relay finalized headers up to (and including) given header + /// from race source to race target. + /// + /// The client may return `Some(_)`, which means that nothing has happened yet and + /// the caller must generate and append proof to the batch transaction + /// to actually send it (along with required header) to the node. + /// + /// If function has returned `None`, it means that the caller now must wait for the + /// appearance of the required header `id` at the target client. + async fn require_source_header( + &self, + id: P::SourceHeaderId, + ) -> Result, Self::Error>; + + /// Return nonces that are known to the target client. + async fn nonces( + &self, + at_block: P::TargetHeaderId, + update_metrics: bool, + ) -> Result<(P::TargetHeaderId, TargetClientNonces), Self::Error>; + /// Submit proof to the target client. + async fn submit_proof( + &self, + maybe_batch_tx: Option, + generated_at_block: P::SourceHeaderId, + nonces: RangeInclusive, + proof: P::Proof, + ) -> Result, Self::Error>; +} + +/// Race strategy. +#[async_trait] +pub trait RaceStrategy: Debug { + /// Type of nonces range expected from the source client. + type SourceNoncesRange: NoncesRange; + /// Additional proof parameters required to generate proof. + type ProofParameters; + /// Additional data expected from the target client. + type TargetNoncesData; + + /// Should return true if nothing has to be synced. + fn is_empty(&self) -> bool; + /// Return id of source header that is required to be on target to continue synchronization. + fn required_source_header_at_target>( + &self, + current_best: &SourceHeaderId, + race_state: RS, + ) -> Option; + /// Return the best nonce at source node. + /// + /// `Some` is returned only if we are sure that the value is greater or equal + /// than the result of `best_at_target`. + fn best_at_source(&self) -> Option; + /// Return the best nonce at target node. + /// + /// May return `None` if value is yet unknown. + fn best_at_target(&self) -> Option; + + /// Called when nonces are updated at source node of the race. + fn source_nonces_updated( + &mut self, + at_block: SourceHeaderId, + nonces: SourceClientNonces, + ); + /// Called when best nonces are updated at target node of the race. + fn best_target_nonces_updated>( + &mut self, + nonces: TargetClientNonces, + race_state: &mut RS, + ); + /// Called when finalized nonces are updated at target node of the race. + fn finalized_target_nonces_updated>( + &mut self, + nonces: TargetClientNonces, + race_state: &mut RS, + ); + /// Should return `Some(nonces)` if we need to deliver proof of `nonces` (and associated + /// data) from source to target node. + /// Additionally, parameters required to generate proof are returned. + async fn select_nonces_to_deliver>( + &self, + race_state: RS, + ) -> Option<(RangeInclusive, Self::ProofParameters)>; +} + +/// State of the race. +pub trait RaceState: Send { + /// Best finalized source header id at the source client. + fn best_finalized_source_header_id_at_source(&self) -> Option; + /// Best finalized source header id at the best block on the target + /// client (at the `best_finalized_source_header_id_at_best_target`). + fn best_finalized_source_header_id_at_best_target(&self) -> Option; + /// The best header id at the target client. + fn best_target_header_id(&self) -> Option; + /// Best finalized header id at the target client. + fn best_finalized_target_header_id(&self) -> Option; + + /// Returns `true` if we have selected nonces to submit to the target node. + fn nonces_to_submit(&self) -> Option>; + /// Reset our nonces selection. + fn reset_nonces_to_submit(&mut self); + + /// Returns `true` if we have submitted some nonces to the target node and are + /// waiting for them to appear there. + fn nonces_submitted(&self) -> Option>; + /// Reset our nonces submission. + fn reset_nonces_submitted(&mut self); +} + +/// State of the race and prepared batch transaction (if available). +#[derive(Debug, Clone)] +pub(crate) struct RaceStateImpl { + /// Best finalized source header id at the source client. + pub best_finalized_source_header_id_at_source: Option, + /// Best finalized source header id at the best block on the target + /// client (at the `best_finalized_source_header_id_at_best_target`). + pub best_finalized_source_header_id_at_best_target: Option, + /// The best header id at the target client. + pub best_target_header_id: Option, + /// Best finalized header id at the target client. + pub best_finalized_target_header_id: Option, + /// Range of nonces that we have selected to submit. + pub nonces_to_submit: Option<(SourceHeaderId, RangeInclusive, Proof)>, + /// Batch transaction ready to include and deliver selected `nonces_to_submit` from the + /// `state`. + pub nonces_to_submit_batch: Option, + /// Range of nonces that is currently submitted. + pub nonces_submitted: Option>, +} + +impl Default + for RaceStateImpl +{ + fn default() -> Self { + RaceStateImpl { + best_finalized_source_header_id_at_source: None, + best_finalized_source_header_id_at_best_target: None, + best_target_header_id: None, + best_finalized_target_header_id: None, + nonces_to_submit: None, + nonces_to_submit_batch: None, + nonces_submitted: None, + } + } +} + +impl RaceState + for RaceStateImpl +where + SourceHeaderId: Clone + Send, + TargetHeaderId: Clone + Send, + Proof: Clone + Send, + BatchTx: Clone + Send, +{ + fn best_finalized_source_header_id_at_source(&self) -> Option { + self.best_finalized_source_header_id_at_source.clone() + } + + fn best_finalized_source_header_id_at_best_target(&self) -> Option { + self.best_finalized_source_header_id_at_best_target.clone() + } + + fn best_target_header_id(&self) -> Option { + self.best_target_header_id.clone() + } + + fn best_finalized_target_header_id(&self) -> Option { + self.best_finalized_target_header_id.clone() + } + + fn nonces_to_submit(&self) -> Option> { + self.nonces_to_submit.as_ref().map(|(_, nonces, _)| nonces.clone()) + } + + fn reset_nonces_to_submit(&mut self) { + self.nonces_to_submit = None; + self.nonces_to_submit_batch = None; + } + + fn nonces_submitted(&self) -> Option> { + self.nonces_submitted.clone() + } + + fn reset_nonces_submitted(&mut self) { + self.nonces_submitted = None; + } +} + +/// Run race loop until connection with target or source node is lost. +pub async fn run, TC: TargetClient

>( + race_source: SC, + race_source_updated: impl FusedStream>, + race_target: TC, + race_target_updated: impl FusedStream>, + mut strategy: impl RaceStrategy< + P::SourceHeaderId, + P::TargetHeaderId, + P::Proof, + SourceNoncesRange = SC::NoncesRange, + ProofParameters = SC::ProofParameters, + TargetNoncesData = TC::TargetNoncesData, + >, +) -> Result<(), FailedClient> { + let mut progress_context = Instant::now(); + let mut race_state = RaceStateImpl::default(); + + let mut source_retry_backoff = retry_backoff(); + let mut source_client_is_online = true; + let mut source_nonces_required = false; + let mut source_required_header = None; + let source_nonces = futures::future::Fuse::terminated(); + let source_generate_proof = futures::future::Fuse::terminated(); + let source_go_offline_future = futures::future::Fuse::terminated(); + + let mut target_retry_backoff = retry_backoff(); + let mut target_client_is_online = true; + let mut target_best_nonces_required = false; + let mut target_finalized_nonces_required = false; + let mut target_batch_transaction = None; + let target_require_source_header = futures::future::Fuse::terminated(); + let target_best_nonces = futures::future::Fuse::terminated(); + let target_finalized_nonces = futures::future::Fuse::terminated(); + let target_submit_proof = futures::future::Fuse::terminated(); + let target_tx_tracker = futures::future::Fuse::terminated(); + let target_go_offline_future = futures::future::Fuse::terminated(); + + futures::pin_mut!( + race_source_updated, + source_nonces, + source_generate_proof, + source_go_offline_future, + race_target_updated, + target_require_source_header, + target_best_nonces, + target_finalized_nonces, + target_submit_proof, + target_tx_tracker, + target_go_offline_future, + ); + + loop { + futures::select! { + // when headers ids are updated + source_state = race_source_updated.next() => { + if let Some(source_state) = source_state { + let is_source_state_updated = race_state.best_finalized_source_header_id_at_source.as_ref() + != Some(&source_state.best_finalized_self); + if is_source_state_updated { + source_nonces_required = true; + race_state.best_finalized_source_header_id_at_source + = Some(source_state.best_finalized_self); + } + } + }, + target_state = race_target_updated.next() => { + if let Some(target_state) = target_state { + let is_target_best_state_updated = race_state.best_target_header_id.as_ref() + != Some(&target_state.best_self); + + if is_target_best_state_updated { + target_best_nonces_required = true; + race_state.best_target_header_id = Some(target_state.best_self); + race_state.best_finalized_source_header_id_at_best_target + = target_state.best_finalized_peer_at_best_self; + } + + let is_target_finalized_state_updated = race_state.best_finalized_target_header_id.as_ref() + != Some(&target_state.best_finalized_self); + if is_target_finalized_state_updated { + target_finalized_nonces_required = true; + race_state.best_finalized_target_header_id = Some(target_state.best_finalized_self); + } + } + }, + + // when nonces are updated + nonces = source_nonces => { + source_nonces_required = false; + + source_client_is_online = process_future_result( + nonces, + &mut source_retry_backoff, + |(at_block, nonces)| { + log::debug!( + target: "bridge", + "Received nonces from {}: {:?}", + P::source_name(), + nonces, + ); + + strategy.source_nonces_updated(at_block, nonces); + }, + &mut source_go_offline_future, + async_std::task::sleep, + || format!("Error retrieving nonces from {}", P::source_name()), + ).fail_if_connection_error(FailedClient::Source)?; + + // ask for more headers if we have nonces to deliver and required headers are missing + source_required_header = race_state + .best_finalized_source_header_id_at_best_target + .as_ref() + .and_then(|best| strategy.required_source_header_at_target(best, race_state.clone())); + }, + nonces = target_best_nonces => { + target_best_nonces_required = false; + + target_client_is_online = process_future_result( + nonces, + &mut target_retry_backoff, + |(_, nonces)| { + log::debug!( + target: "bridge", + "Received best nonces from {}: {:?}", + P::target_name(), + nonces, + ); + + strategy.best_target_nonces_updated(nonces, &mut race_state); + }, + &mut target_go_offline_future, + async_std::task::sleep, + || format!("Error retrieving best nonces from {}", P::target_name()), + ).fail_if_connection_error(FailedClient::Target)?; + }, + nonces = target_finalized_nonces => { + target_finalized_nonces_required = false; + + target_client_is_online = process_future_result( + nonces, + &mut target_retry_backoff, + |(_, nonces)| { + log::debug!( + target: "bridge", + "Received finalized nonces from {}: {:?}", + P::target_name(), + nonces, + ); + + strategy.finalized_target_nonces_updated(nonces, &mut race_state); + }, + &mut target_go_offline_future, + async_std::task::sleep, + || format!("Error retrieving finalized nonces from {}", P::target_name()), + ).fail_if_connection_error(FailedClient::Target)?; + }, + + // proof generation and submission + maybe_batch_transaction = target_require_source_header => { + source_required_header = None; + + target_client_is_online = process_future_result( + maybe_batch_transaction, + &mut target_retry_backoff, + |maybe_batch_transaction: Option| { + log::debug!( + target: "bridge", + "Target {} client has been asked for more {} headers. Batch tx: {}", + P::target_name(), + P::source_name(), + maybe_batch_transaction + .as_ref() + .map(|bt| format!("yes ({:?})", bt.required_header_id())) + .unwrap_or_else(|| "no".into()), + ); + + target_batch_transaction = maybe_batch_transaction; + }, + &mut target_go_offline_future, + async_std::task::sleep, + || format!("Error asking for source headers at {}", P::target_name()), + ).fail_if_connection_error(FailedClient::Target)?; + }, + proof = source_generate_proof => { + source_client_is_online = process_future_result( + proof, + &mut source_retry_backoff, + |(at_block, nonces_range, proof, batch_transaction)| { + log::debug!( + target: "bridge", + "Received proof for nonces in range {:?} from {}", + nonces_range, + P::source_name(), + ); + + race_state.nonces_to_submit = Some((at_block, nonces_range, proof)); + race_state.nonces_to_submit_batch = batch_transaction; + }, + &mut source_go_offline_future, + async_std::task::sleep, + || format!("Error generating proof at {}", P::source_name()), + ).fail_if_error(FailedClient::Source).map(|_| true)?; + }, + proof_submit_result = target_submit_proof => { + target_client_is_online = process_future_result( + proof_submit_result, + &mut target_retry_backoff, + |artifacts: NoncesSubmitArtifacts| { + log::debug!( + target: "bridge", + "Successfully submitted proof of nonces {:?} to {}", + artifacts.nonces, + P::target_name(), + ); + + race_state.reset_nonces_to_submit(); + race_state.nonces_submitted = Some(artifacts.nonces); + target_tx_tracker.set(artifacts.tx_tracker.wait().fuse()); + }, + &mut target_go_offline_future, + async_std::task::sleep, + || format!("Error submitting proof {}", P::target_name()), + ).fail_if_error(FailedClient::Target).map(|_| true)?; + }, + target_transaction_status = target_tx_tracker => { + match (target_transaction_status, race_state.nonces_submitted.as_ref()) { + (TrackedTransactionStatus::Finalized(at_block), Some(nonces_submitted)) => { + // our transaction has been mined, but was it successful or not? let's check the best + // nonce at the target node. + let _ = race_target.nonces(at_block, false) + .await + .map_err(|e| format!("failed to read nonces from target node: {e:?}")) + .and_then(|(_, nonces_at_target)| { + if nonces_at_target.latest_nonce < *nonces_submitted.end() { + Err(format!( + "best nonce at target after tx is {:?} and we've submitted {:?}", + nonces_at_target.latest_nonce, + nonces_submitted.end(), + )) + } else { + Ok(()) + } + }) + .map_err(|e| { + log::error!( + target: "bridge", + "{} -> {} race transaction failed: {}", + P::source_name(), + P::target_name(), + e, + ); + + race_state.reset_nonces_submitted(); + }); + }, + (TrackedTransactionStatus::Lost, _) => { + log::warn!( + target: "bridge", + "{} -> {} race transaction has been lost. State: {:?}. Strategy: {:?}", + P::source_name(), + P::target_name(), + race_state, + strategy, + ); + + race_state.reset_nonces_submitted(); + }, + _ => (), + } + }, + + // when we're ready to retry request + _ = source_go_offline_future => { + source_client_is_online = true; + }, + _ = target_go_offline_future => { + target_client_is_online = true; + }, + } + + progress_context = print_race_progress::(progress_context, &strategy); + + if source_client_is_online { + source_client_is_online = false; + + // if we've started to submit batch transaction, let's prioritize it + // + // we're using `take` here, because we don't need batch transaction (i.e. some + // underlying finality proof) anymore for our future calls - we were unable to + // use it for our current state, so why would we need to keep an obsolete proof + // for the future? + let target_batch_transaction = target_batch_transaction.take(); + let expected_race_state = + if let Some(ref target_batch_transaction) = target_batch_transaction { + // when selecting nonces for the batch transaction, we assume that the required + // source header is already at the target chain + let required_source_header_at_target = + target_batch_transaction.required_header_id(); + let mut expected_race_state = race_state.clone(); + expected_race_state.best_finalized_source_header_id_at_best_target = + Some(required_source_header_at_target); + expected_race_state + } else { + race_state.clone() + }; + + let nonces_to_deliver = select_nonces_to_deliver(expected_race_state, &strategy).await; + let best_at_source = strategy.best_at_source(); + + if let Some((at_block, nonces_range, proof_parameters)) = nonces_to_deliver { + log::debug!( + target: "bridge", + "Asking {} to prove nonces in range {:?} at block {:?}", + P::source_name(), + nonces_range, + at_block, + ); + + source_generate_proof.set( + race_source + .generate_proof(at_block, nonces_range, proof_parameters) + .and_then(|(at_source_block, nonces, proof)| async { + Ok((at_source_block, nonces, proof, target_batch_transaction)) + }) + .fuse(), + ); + } else if source_nonces_required && best_at_source.is_some() { + log::debug!(target: "bridge", "Asking {} about message nonces", P::source_name()); + let at_block = race_state + .best_finalized_source_header_id_at_source + .as_ref() + .expect( + "source_nonces_required is only true when\ + best_finalized_source_header_id_at_source is Some; qed", + ) + .clone(); + source_nonces.set( + race_source + .nonces(at_block, best_at_source.expect("guaranteed by if condition; qed")) + .fuse(), + ); + } else { + source_client_is_online = true; + } + } + + if target_client_is_online { + target_client_is_online = false; + + if let Some((at_block, nonces_range, proof)) = race_state.nonces_to_submit.as_ref() { + log::debug!( + target: "bridge", + "Going to submit proof of messages in range {:?} to {} node{}", + nonces_range, + P::target_name(), + race_state.nonces_to_submit_batch.as_ref().map(|tx| format!( + ". This transaction is batched with sending the proof for header {:?}.", + tx.required_header_id()) + ).unwrap_or_default(), + ); + + target_submit_proof.set( + race_target + .submit_proof( + race_state.nonces_to_submit_batch.clone(), + at_block.clone(), + nonces_range.clone(), + proof.clone(), + ) + .fuse(), + ); + } else if let Some(source_required_header) = source_required_header.clone() { + log::debug!(target: "bridge", "Going to require {} header {:?} at {}", P::source_name(), source_required_header, P::target_name()); + target_require_source_header + .set(race_target.require_source_header(source_required_header).fuse()); + } else if target_best_nonces_required { + log::debug!(target: "bridge", "Asking {} about best message nonces", P::target_name()); + let at_block = race_state + .best_target_header_id + .as_ref() + .expect("target_best_nonces_required is only true when best_target_header_id is Some; qed") + .clone(); + target_best_nonces.set(race_target.nonces(at_block, false).fuse()); + } else if target_finalized_nonces_required { + log::debug!(target: "bridge", "Asking {} about finalized message nonces", P::target_name()); + let at_block = race_state + .best_finalized_target_header_id + .as_ref() + .expect( + "target_finalized_nonces_required is only true when\ + best_finalized_target_header_id is Some; qed", + ) + .clone(); + target_finalized_nonces.set(race_target.nonces(at_block, true).fuse()); + } else { + target_client_is_online = true; + } + } + } +} + +/// Print race progress. +fn print_race_progress(prev_time: Instant, strategy: &S) -> Instant +where + P: MessageRace, + S: RaceStrategy, +{ + let now_time = Instant::now(); + + let need_update = now_time.saturating_duration_since(prev_time) > Duration::from_secs(10); + if !need_update { + return prev_time + } + + let now_best_nonce_at_source = strategy.best_at_source(); + let now_best_nonce_at_target = strategy.best_at_target(); + log::info!( + target: "bridge", + "Synced {:?} of {:?} nonces in {} -> {} race", + now_best_nonce_at_target, + now_best_nonce_at_source, + P::source_name(), + P::target_name(), + ); + now_time +} + +async fn select_nonces_to_deliver( + race_state: impl RaceState, + strategy: &Strategy, +) -> Option<(SourceHeaderId, RangeInclusive, Strategy::ProofParameters)> +where + SourceHeaderId: Clone, + Strategy: RaceStrategy, +{ + let best_finalized_source_header_id_at_best_target = + race_state.best_finalized_source_header_id_at_best_target()?; + strategy + .select_nonces_to_deliver(race_state) + .await + .map(|(nonces_range, proof_parameters)| { + (best_finalized_source_header_id_at_best_target, nonces_range, proof_parameters) + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::message_race_strategy::BasicStrategy; + use relay_utils::HeaderId; + + #[async_std::test] + async fn proof_is_generated_at_best_block_known_to_target_node() { + const GENERATED_AT: u64 = 6; + const BEST_AT_SOURCE: u64 = 10; + const BEST_AT_TARGET: u64 = 8; + + // target node only knows about source' BEST_AT_TARGET block + // source node has BEST_AT_SOURCE > BEST_AT_TARGET block + let mut race_state = RaceStateImpl::<_, _, (), ()> { + best_finalized_source_header_id_at_source: Some(HeaderId( + BEST_AT_SOURCE, + BEST_AT_SOURCE, + )), + best_finalized_source_header_id_at_best_target: Some(HeaderId( + BEST_AT_TARGET, + BEST_AT_TARGET, + )), + best_target_header_id: Some(HeaderId(0, 0)), + best_finalized_target_header_id: Some(HeaderId(0, 0)), + nonces_to_submit: None, + nonces_to_submit_batch: None, + nonces_submitted: None, + }; + + // we have some nonces to deliver and they're generated at GENERATED_AT < BEST_AT_SOURCE + let mut strategy = BasicStrategy::<_, _, _, _, _, ()>::new(); + strategy.source_nonces_updated( + HeaderId(GENERATED_AT, GENERATED_AT), + SourceClientNonces { new_nonces: 0..=10, confirmed_nonce: None }, + ); + strategy.best_target_nonces_updated( + TargetClientNonces { latest_nonce: 5u64, nonces_data: () }, + &mut race_state, + ); + + // the proof will be generated on source, but using BEST_AT_TARGET block + assert_eq!( + select_nonces_to_deliver(race_state, &strategy).await, + Some((HeaderId(BEST_AT_TARGET, BEST_AT_TARGET), 6..=10, (),)) + ); + } +} diff --git a/relays/messages/src/message_race_receiving.rs b/relays/messages/src/message_race_receiving.rs new file mode 100644 index 00000000000..e6497a1b79e --- /dev/null +++ b/relays/messages/src/message_race_receiving.rs @@ -0,0 +1,235 @@ +// Copyright 2019-2021 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. + +//! Message receiving race delivers proof-of-messages-delivery from "lane.target" to "lane.source". + +use crate::{ + message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, + message_lane_loop::{ + NoncesSubmitArtifacts, SourceClient as MessageLaneSourceClient, SourceClientState, + TargetClient as MessageLaneTargetClient, TargetClientState, + }, + message_race_loop::{ + MessageRace, NoncesRange, SourceClient, SourceClientNonces, TargetClient, + TargetClientNonces, + }, + message_race_strategy::BasicStrategy, + metrics::MessageLaneLoopMetrics, +}; + +use async_trait::async_trait; +use bp_messages::MessageNonce; +use futures::stream::FusedStream; +use relay_utils::FailedClient; +use std::{marker::PhantomData, ops::RangeInclusive}; + +/// Message receiving confirmations delivery strategy. +type ReceivingConfirmationsBasicStrategy

= BasicStrategy< +

::TargetHeaderNumber, +

::TargetHeaderHash, +

::SourceHeaderNumber, +

::SourceHeaderHash, + RangeInclusive, +

::MessagesReceivingProof, +>; + +/// Run receiving confirmations race. +pub async fn run( + source_client: impl MessageLaneSourceClient

, + source_state_updates: impl FusedStream>, + target_client: impl MessageLaneTargetClient

, + target_state_updates: impl FusedStream>, + metrics_msg: Option, +) -> Result<(), FailedClient> { + crate::message_race_loop::run( + ReceivingConfirmationsRaceSource { + client: target_client, + metrics_msg: metrics_msg.clone(), + _phantom: Default::default(), + }, + target_state_updates, + ReceivingConfirmationsRaceTarget { + client: source_client, + metrics_msg, + _phantom: Default::default(), + }, + source_state_updates, + ReceivingConfirmationsBasicStrategy::

::new(), + ) + .await +} + +/// Messages receiving confirmations race. +struct ReceivingConfirmationsRace

(std::marker::PhantomData

); + +impl MessageRace for ReceivingConfirmationsRace

{ + type SourceHeaderId = TargetHeaderIdOf

; + type TargetHeaderId = SourceHeaderIdOf

; + + type MessageNonce = MessageNonce; + type Proof = P::MessagesReceivingProof; + + fn source_name() -> String { + format!("{}::ReceivingConfirmationsDelivery", P::TARGET_NAME) + } + + fn target_name() -> String { + format!("{}::ReceivingConfirmationsDelivery", P::SOURCE_NAME) + } +} + +/// Message receiving confirmations race source, which is a target of the lane. +struct ReceivingConfirmationsRaceSource { + client: C, + metrics_msg: Option, + _phantom: PhantomData

, +} + +#[async_trait] +impl SourceClient> for ReceivingConfirmationsRaceSource +where + P: MessageLane, + C: MessageLaneTargetClient

, +{ + type Error = C::Error; + type NoncesRange = RangeInclusive; + type ProofParameters = (); + + async fn nonces( + &self, + at_block: TargetHeaderIdOf

, + prev_latest_nonce: MessageNonce, + ) -> Result<(TargetHeaderIdOf

, SourceClientNonces), Self::Error> { + let (at_block, latest_received_nonce) = self.client.latest_received_nonce(at_block).await?; + if let Some(metrics_msg) = self.metrics_msg.as_ref() { + metrics_msg.update_target_latest_received_nonce(latest_received_nonce); + } + Ok(( + at_block, + SourceClientNonces { + new_nonces: prev_latest_nonce + 1..=latest_received_nonce, + confirmed_nonce: None, + }, + )) + } + + #[allow(clippy::unit_arg)] + async fn generate_proof( + &self, + at_block: TargetHeaderIdOf

, + nonces: RangeInclusive, + _proof_parameters: Self::ProofParameters, + ) -> Result< + (TargetHeaderIdOf

, RangeInclusive, P::MessagesReceivingProof), + Self::Error, + > { + self.client + .prove_messages_receiving(at_block) + .await + .map(|(at_block, proof)| (at_block, nonces, proof)) + } +} + +/// Message receiving confirmations race target, which is a source of the lane. +struct ReceivingConfirmationsRaceTarget { + client: C, + metrics_msg: Option, + _phantom: PhantomData

, +} + +#[async_trait] +impl TargetClient> for ReceivingConfirmationsRaceTarget +where + P: MessageLane, + C: MessageLaneSourceClient

, +{ + type Error = C::Error; + type TargetNoncesData = (); + type BatchTransaction = C::BatchTransaction; + type TransactionTracker = C::TransactionTracker; + + async fn require_source_header( + &self, + id: TargetHeaderIdOf

, + ) -> Result, Self::Error> { + self.client.require_target_header_on_source(id).await + } + + async fn nonces( + &self, + at_block: SourceHeaderIdOf

, + update_metrics: bool, + ) -> Result<(SourceHeaderIdOf

, TargetClientNonces<()>), Self::Error> { + let (at_block, latest_confirmed_nonce) = + self.client.latest_confirmed_received_nonce(at_block).await?; + if update_metrics { + if let Some(metrics_msg) = self.metrics_msg.as_ref() { + metrics_msg.update_source_latest_confirmed_nonce(latest_confirmed_nonce); + } + } + Ok((at_block, TargetClientNonces { latest_nonce: latest_confirmed_nonce, nonces_data: () })) + } + + async fn submit_proof( + &self, + maybe_batch_tx: Option, + generated_at_block: TargetHeaderIdOf

, + nonces: RangeInclusive, + proof: P::MessagesReceivingProof, + ) -> Result, Self::Error> { + let tx_tracker = self + .client + .submit_messages_receiving_proof(maybe_batch_tx, generated_at_block, proof) + .await?; + Ok(NoncesSubmitArtifacts { nonces, tx_tracker }) + } +} + +impl NoncesRange for RangeInclusive { + fn begin(&self) -> MessageNonce { + *RangeInclusive::::start(self) + } + + fn end(&self) -> MessageNonce { + *RangeInclusive::::end(self) + } + + fn greater_than(self, nonce: MessageNonce) -> Option { + let next_nonce = nonce + 1; + let end = *self.end(); + if next_nonce > end { + None + } else { + Some(std::cmp::max(self.begin(), next_nonce)..=end) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn range_inclusive_works_as_nonces_range() { + let range = 20..=30; + + assert_eq!(NoncesRange::begin(&range), 20); + assert_eq!(NoncesRange::end(&range), 30); + assert_eq!(range.clone().greater_than(10), Some(20..=30)); + assert_eq!(range.clone().greater_than(19), Some(20..=30)); + assert_eq!(range.clone().greater_than(20), Some(21..=30)); + assert_eq!(range.clone().greater_than(25), Some(26..=30)); + assert_eq!(range.clone().greater_than(29), Some(30..=30)); + assert_eq!(range.greater_than(30), None); + } +} diff --git a/relays/messages/src/message_race_strategy.rs b/relays/messages/src/message_race_strategy.rs new file mode 100644 index 00000000000..e6016448c95 --- /dev/null +++ b/relays/messages/src/message_race_strategy.rs @@ -0,0 +1,596 @@ +// Copyright 2019-2021 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. + +//! Basic delivery strategy. The strategy selects nonces if: +//! +//! 1) there are more nonces on the source side than on the target side; +//! 2) new nonces may be proved to target node (i.e. they have appeared at the +//! block, which is known to the target node). + +use crate::message_race_loop::{ + NoncesRange, RaceState, RaceStrategy, SourceClientNonces, TargetClientNonces, +}; + +use async_trait::async_trait; +use bp_messages::MessageNonce; +use relay_utils::HeaderId; +use std::{collections::VecDeque, fmt::Debug, marker::PhantomData, ops::RangeInclusive}; + +/// Queue of nonces known to the source node. +pub type SourceRangesQueue = + VecDeque<(HeaderId, SourceNoncesRange)>; + +/// Nonces delivery strategy. +#[derive(Debug)] +pub struct BasicStrategy< + SourceHeaderNumber, + SourceHeaderHash, + TargetHeaderNumber, + TargetHeaderHash, + SourceNoncesRange, + Proof, +> { + /// All queued nonces. + /// + /// The queue may contain already delivered nonces. We only remove entries from this + /// queue after corresponding nonces are finalized by the target chain. + source_queue: SourceRangesQueue, + /// The best nonce known to target node at its best block. `None` if it has not been received + /// yet. + best_target_nonce: Option, + /// Unused generic types dump. + _phantom: PhantomData<(TargetHeaderNumber, TargetHeaderHash, Proof)>, +} + +impl< + SourceHeaderNumber, + SourceHeaderHash, + TargetHeaderNumber, + TargetHeaderHash, + SourceNoncesRange, + Proof, + > + BasicStrategy< + SourceHeaderNumber, + SourceHeaderHash, + TargetHeaderNumber, + TargetHeaderHash, + SourceNoncesRange, + Proof, + > where + SourceHeaderHash: Clone, + SourceHeaderNumber: Clone + Ord, + SourceNoncesRange: NoncesRange, +{ + /// Create new delivery strategy. + pub fn new() -> Self { + BasicStrategy { + source_queue: VecDeque::new(), + best_target_nonce: None, + _phantom: Default::default(), + } + } + + /// Reference to source queue. + pub(crate) fn source_queue( + &self, + ) -> &VecDeque<(HeaderId, SourceNoncesRange)> { + &self.source_queue + } + + /// Mutable reference to source queue to use in tests. + #[cfg(test)] + pub(crate) fn source_queue_mut( + &mut self, + ) -> &mut VecDeque<(HeaderId, SourceNoncesRange)> { + &mut self.source_queue + } + + /// Returns indices of source queue entries, which may be delivered to the target node. + /// + /// The function may skip some nonces from the queue front if nonces from this entry are + /// already available at the **best** target block. After this block is finalized, the entry + /// will be removed from the queue. + /// + /// All entries before and including the range end index, are guaranteed to be witnessed + /// at source blocks that are known to be finalized at the target node. + /// + /// Returns `None` if no entries may be delivered. + pub fn available_source_queue_indices< + RS: RaceState< + HeaderId, + HeaderId, + >, + >( + &self, + race_state: RS, + ) -> Option> { + // if we do not know best nonce at target node, we can't select anything + let best_target_nonce = self.best_target_nonce?; + + // if we have already selected nonces that we want to submit, do nothing + if race_state.nonces_to_submit().is_some() { + return None + } + + // if we already submitted some nonces, do nothing + if race_state.nonces_submitted().is_some() { + return None + } + + // find first entry that may be delivered to the target node + let begin_index = self + .source_queue + .iter() + .enumerate() + .skip_while(|(_, (_, nonces))| nonces.end() <= best_target_nonce) + .map(|(index, _)| index) + .next()?; + + // 1) we want to deliver all nonces, starting from `target_nonce + 1` + // 2) we can't deliver new nonce until header, that has emitted this nonce, is finalized + // by target client + // 3) selector is used for more complicated logic + // + // => let's first select range of entries inside deque that are already finalized at + // the target client and pass this range to the selector + let best_header_at_target = race_state.best_finalized_source_header_id_at_best_target()?; + let end_index = self + .source_queue + .iter() + .enumerate() + .skip(begin_index) + .take_while(|(_, (queued_at, _))| queued_at.0 <= best_header_at_target.0) + .map(|(index, _)| index) + .last()?; + + Some(begin_index..=end_index) + } + + /// Remove all nonces that are less than or equal to given nonce from the source queue. + fn remove_le_nonces_from_source_queue(&mut self, nonce: MessageNonce) { + while let Some((queued_at, queued_range)) = self.source_queue.pop_front() { + if let Some(range_to_requeue) = queued_range.greater_than(nonce) { + self.source_queue.push_front((queued_at, range_to_requeue)); + break + } + } + } +} + +#[async_trait] +impl< + SourceHeaderNumber, + SourceHeaderHash, + TargetHeaderNumber, + TargetHeaderHash, + SourceNoncesRange, + Proof, + > + RaceStrategy< + HeaderId, + HeaderId, + Proof, + > + for BasicStrategy< + SourceHeaderNumber, + SourceHeaderHash, + TargetHeaderNumber, + TargetHeaderHash, + SourceNoncesRange, + Proof, + > where + SourceHeaderHash: Clone + Debug + Send + Sync, + SourceHeaderNumber: Clone + Ord + Debug + Send + Sync, + SourceNoncesRange: NoncesRange + Debug + Send + Sync, + TargetHeaderHash: Debug + Send + Sync, + TargetHeaderNumber: Debug + Send + Sync, + Proof: Debug + Send + Sync, +{ + type SourceNoncesRange = SourceNoncesRange; + type ProofParameters = (); + type TargetNoncesData = (); + + fn is_empty(&self) -> bool { + self.source_queue.is_empty() + } + + fn required_source_header_at_target< + RS: RaceState< + HeaderId, + HeaderId, + >, + >( + &self, + current_best: &HeaderId, + _race_state: RS, + ) -> Option> { + self.source_queue + .back() + .and_then(|(h, _)| if h.0 > current_best.0 { Some(h.clone()) } else { None }) + } + + fn best_at_source(&self) -> Option { + let best_in_queue = self.source_queue.back().map(|(_, range)| range.end()); + match (best_in_queue, self.best_target_nonce) { + (Some(best_in_queue), Some(best_target_nonce)) if best_in_queue > best_target_nonce => + Some(best_in_queue), + (_, Some(best_target_nonce)) => Some(best_target_nonce), + (_, None) => None, + } + } + + fn best_at_target(&self) -> Option { + self.best_target_nonce + } + + fn source_nonces_updated( + &mut self, + at_block: HeaderId, + nonces: SourceClientNonces, + ) { + let best_in_queue = self + .source_queue + .back() + .map(|(_, range)| range.end()) + .or(self.best_target_nonce) + .unwrap_or_default(); + self.source_queue.extend( + nonces + .new_nonces + .greater_than(best_in_queue) + .into_iter() + .map(move |range| (at_block.clone(), range)), + ) + } + + fn best_target_nonces_updated< + RS: RaceState< + HeaderId, + HeaderId, + >, + >( + &mut self, + nonces: TargetClientNonces<()>, + race_state: &mut RS, + ) { + let nonce = nonces.latest_nonce; + + let need_to_select_new_nonces = race_state + .nonces_to_submit() + .map(|nonces| *nonces.end() <= nonce) + .unwrap_or(false); + if need_to_select_new_nonces { + race_state.reset_nonces_to_submit(); + } + + let need_new_nonces_to_submit = race_state + .nonces_submitted() + .map(|nonces| *nonces.end() <= nonce) + .unwrap_or(false); + if need_new_nonces_to_submit { + race_state.reset_nonces_submitted(); + } + + self.best_target_nonce = Some(nonce); + } + + fn finalized_target_nonces_updated< + RS: RaceState< + HeaderId, + HeaderId, + >, + >( + &mut self, + nonces: TargetClientNonces<()>, + _race_state: &mut RS, + ) { + self.remove_le_nonces_from_source_queue(nonces.latest_nonce); + self.best_target_nonce = Some(std::cmp::max( + self.best_target_nonce.unwrap_or(nonces.latest_nonce), + nonces.latest_nonce, + )); + } + + async fn select_nonces_to_deliver< + RS: RaceState< + HeaderId, + HeaderId, + >, + >( + &self, + race_state: RS, + ) -> Option<(RangeInclusive, Self::ProofParameters)> { + let available_indices = self.available_source_queue_indices(race_state)?; + let range_begin = std::cmp::max( + self.best_target_nonce? + 1, + self.source_queue[*available_indices.start()].1.begin(), + ); + let range_end = self.source_queue[*available_indices.end()].1.end(); + Some((range_begin..=range_end, ())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, + message_lane_loop::tests::{ + header_id, TestMessageLane, TestMessagesProof, TestSourceHeaderHash, + TestSourceHeaderNumber, + }, + message_race_loop::RaceStateImpl, + }; + + type SourceNoncesRange = RangeInclusive; + + type TestRaceStateImpl = RaceStateImpl< + SourceHeaderIdOf, + TargetHeaderIdOf, + TestMessagesProof, + (), + >; + + type BasicStrategy

= super::BasicStrategy< +

::SourceHeaderNumber, +

::SourceHeaderHash, +

::TargetHeaderNumber, +

::TargetHeaderHash, + SourceNoncesRange, +

::MessagesProof, + >; + + fn source_nonces(new_nonces: SourceNoncesRange) -> SourceClientNonces { + SourceClientNonces { new_nonces, confirmed_nonce: None } + } + + fn target_nonces(latest_nonce: MessageNonce) -> TargetClientNonces<()> { + TargetClientNonces { latest_nonce, nonces_data: () } + } + + #[test] + fn strategy_is_empty_works() { + let mut strategy = BasicStrategy::::new(); + assert!(strategy.is_empty()); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=1)); + assert!(!strategy.is_empty()); + } + + #[test] + fn best_at_source_is_never_lower_than_target_nonce() { + let mut strategy = BasicStrategy::::new(); + assert_eq!(strategy.best_at_source(), None); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=5)); + assert_eq!(strategy.best_at_source(), None); + strategy.best_target_nonces_updated(target_nonces(10), &mut TestRaceStateImpl::default()); + assert_eq!(strategy.source_queue, vec![(header_id(1), 1..=5)]); + assert_eq!(strategy.best_at_source(), Some(10)); + } + + #[test] + fn source_nonce_is_never_lower_than_known_target_nonce() { + let mut strategy = BasicStrategy::::new(); + strategy.best_target_nonces_updated(target_nonces(10), &mut TestRaceStateImpl::default()); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=5)); + assert_eq!(strategy.source_queue, vec![]); + } + + #[test] + fn source_nonce_is_never_lower_than_latest_known_source_nonce() { + let mut strategy = BasicStrategy::::new(); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=5)); + strategy.source_nonces_updated(header_id(2), source_nonces(1..=3)); + strategy.source_nonces_updated(header_id(2), source_nonces(1..=5)); + assert_eq!(strategy.source_queue, vec![(header_id(1), 1..=5)]); + } + + #[test] + fn updated_target_nonce_removes_queued_entries() { + let mut strategy = BasicStrategy::::new(); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=5)); + strategy.source_nonces_updated(header_id(2), source_nonces(6..=10)); + strategy.source_nonces_updated(header_id(3), source_nonces(11..=15)); + strategy.source_nonces_updated(header_id(4), source_nonces(16..=20)); + strategy + .finalized_target_nonces_updated(target_nonces(15), &mut TestRaceStateImpl::default()); + assert_eq!(strategy.source_queue, vec![(header_id(4), 16..=20)]); + strategy + .finalized_target_nonces_updated(target_nonces(17), &mut TestRaceStateImpl::default()); + assert_eq!(strategy.source_queue, vec![(header_id(4), 18..=20)]); + } + + #[test] + fn selected_nonces_are_dropped_on_target_nonce_update() { + let mut state = TestRaceStateImpl::default(); + let mut strategy = BasicStrategy::::new(); + state.nonces_to_submit = Some((header_id(1), 5..=10, (5..=10, None))); + strategy.best_target_nonces_updated(target_nonces(7), &mut state); + assert!(state.nonces_to_submit.is_some()); + strategy.best_target_nonces_updated(target_nonces(10), &mut state); + assert!(state.nonces_to_submit.is_none()); + } + + #[test] + fn submitted_nonces_are_dropped_on_target_nonce_update() { + let mut state = TestRaceStateImpl::default(); + let mut strategy = BasicStrategy::::new(); + state.nonces_submitted = Some(5..=10); + strategy.best_target_nonces_updated(target_nonces(7), &mut state); + assert!(state.nonces_submitted.is_some()); + strategy.best_target_nonces_updated(target_nonces(10), &mut state); + assert!(state.nonces_submitted.is_none()); + } + + #[async_std::test] + async fn nothing_is_selected_if_something_is_already_selected() { + let mut state = TestRaceStateImpl::default(); + let mut strategy = BasicStrategy::::new(); + state.nonces_to_submit = Some((header_id(1), 1..=10, (1..=10, None))); + strategy.best_target_nonces_updated(target_nonces(0), &mut state); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=10)); + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, None); + } + + #[async_std::test] + async fn nothing_is_selected_if_something_is_already_submitted() { + let mut state = TestRaceStateImpl::default(); + let mut strategy = BasicStrategy::::new(); + state.nonces_submitted = Some(1..=10); + strategy.best_target_nonces_updated(target_nonces(0), &mut state); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=10)); + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, None); + } + + #[async_std::test] + async fn select_nonces_to_deliver_works() { + let mut state = TestRaceStateImpl::default(); + let mut strategy = BasicStrategy::::new(); + strategy.best_target_nonces_updated(target_nonces(0), &mut state); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=1)); + strategy.source_nonces_updated(header_id(2), source_nonces(2..=2)); + strategy.source_nonces_updated(header_id(3), source_nonces(3..=6)); + strategy.source_nonces_updated(header_id(5), source_nonces(7..=8)); + + state.best_finalized_source_header_id_at_best_target = Some(header_id(4)); + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, Some((1..=6, ()))); + strategy.best_target_nonces_updated(target_nonces(6), &mut state); + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, None); + + state.best_finalized_source_header_id_at_best_target = Some(header_id(5)); + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, Some((7..=8, ()))); + strategy.best_target_nonces_updated(target_nonces(8), &mut state); + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, None); + } + + #[test] + fn available_source_queue_indices_works() { + let mut state = TestRaceStateImpl::default(); + let mut strategy = BasicStrategy::::new(); + strategy.best_target_nonces_updated(target_nonces(0), &mut state); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=3)); + strategy.source_nonces_updated(header_id(2), source_nonces(4..=6)); + strategy.source_nonces_updated(header_id(3), source_nonces(7..=9)); + + state.best_finalized_source_header_id_at_best_target = Some(header_id(0)); + assert_eq!(strategy.available_source_queue_indices(state.clone()), None); + + state.best_finalized_source_header_id_at_best_target = Some(header_id(1)); + assert_eq!(strategy.available_source_queue_indices(state.clone()), Some(0..=0)); + + state.best_finalized_source_header_id_at_best_target = Some(header_id(2)); + assert_eq!(strategy.available_source_queue_indices(state.clone()), Some(0..=1)); + + state.best_finalized_source_header_id_at_best_target = Some(header_id(3)); + assert_eq!(strategy.available_source_queue_indices(state.clone()), Some(0..=2)); + + state.best_finalized_source_header_id_at_best_target = Some(header_id(4)); + assert_eq!(strategy.available_source_queue_indices(state), Some(0..=2)); + } + + #[test] + fn remove_le_nonces_from_source_queue_works() { + let mut state = TestRaceStateImpl::default(); + let mut strategy = BasicStrategy::::new(); + strategy.best_target_nonces_updated(target_nonces(0), &mut state); + strategy.source_nonces_updated(header_id(1), source_nonces(1..=3)); + strategy.source_nonces_updated(header_id(2), source_nonces(4..=6)); + strategy.source_nonces_updated(header_id(3), source_nonces(7..=9)); + + fn source_queue_nonces( + source_queue: &SourceRangesQueue< + TestSourceHeaderHash, + TestSourceHeaderNumber, + SourceNoncesRange, + >, + ) -> Vec { + source_queue.iter().flat_map(|(_, range)| range.clone()).collect() + } + + strategy.remove_le_nonces_from_source_queue(1); + assert_eq!(source_queue_nonces(&strategy.source_queue), vec![2, 3, 4, 5, 6, 7, 8, 9],); + + strategy.remove_le_nonces_from_source_queue(5); + assert_eq!(source_queue_nonces(&strategy.source_queue), vec![6, 7, 8, 9],); + + strategy.remove_le_nonces_from_source_queue(9); + assert_eq!(source_queue_nonces(&strategy.source_queue), Vec::::new(),); + + strategy.remove_le_nonces_from_source_queue(100); + assert_eq!(source_queue_nonces(&strategy.source_queue), Vec::::new(),); + } + + #[async_std::test] + async fn previous_nonces_are_selected_if_reorg_happens_at_target_chain() { + let source_header_1 = header_id(1); + let target_header_1 = header_id(1); + + // we start in perfec sync state - all headers are synced and finalized on both ends + let mut state = TestRaceStateImpl { + best_finalized_source_header_id_at_source: Some(source_header_1), + best_finalized_source_header_id_at_best_target: Some(source_header_1), + best_target_header_id: Some(target_header_1), + best_finalized_target_header_id: Some(target_header_1), + nonces_to_submit: None, + nonces_to_submit_batch: None, + nonces_submitted: None, + }; + + // in this state we have 1 available nonce for delivery + let mut strategy = BasicStrategy:: { + source_queue: vec![(header_id(1), 1..=1)].into_iter().collect(), + best_target_nonce: Some(0), + _phantom: PhantomData, + }; + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, Some((1..=1, ())),); + + // let's say we have submitted 1..=1 + state.nonces_submitted = Some(1..=1); + + // then new nonce 2 appear at the source block 2 + let source_header_2 = header_id(2); + state.best_finalized_source_header_id_at_source = Some(source_header_2); + strategy.source_nonces_updated( + source_header_2, + SourceClientNonces { new_nonces: 2..=2, confirmed_nonce: None }, + ); + // and nonce 1 appear at the best block of the target node (best finalized still has 0 + // nonces) + let target_header_2 = header_id(2); + state.best_target_header_id = Some(target_header_2); + strategy.best_target_nonces_updated( + TargetClientNonces { latest_nonce: 1, nonces_data: () }, + &mut state, + ); + + // then best target header is retracted + strategy.best_target_nonces_updated( + TargetClientNonces { latest_nonce: 0, nonces_data: () }, + &mut state, + ); + + // ... and some fork with zero delivered nonces is finalized + let target_header_2_fork = header_id(2_1); + state.best_finalized_source_header_id_at_source = Some(source_header_2); + state.best_finalized_source_header_id_at_best_target = Some(source_header_2); + state.best_target_header_id = Some(target_header_2_fork); + state.best_finalized_target_header_id = Some(target_header_2_fork); + strategy.finalized_target_nonces_updated( + TargetClientNonces { latest_nonce: 0, nonces_data: () }, + &mut state, + ); + + // now we have to select nonce 1 for delivery again + assert_eq!(strategy.select_nonces_to_deliver(state.clone()).await, Some((1..=2, ())),); + } +} diff --git a/relays/messages/src/metrics.rs b/relays/messages/src/metrics.rs new file mode 100644 index 00000000000..69d80d178de --- /dev/null +++ b/relays/messages/src/metrics.rs @@ -0,0 +1,148 @@ +// Copyright 2019-2021 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 . + +//! Metrics for message lane relay loop. + +use crate::{ + message_lane::MessageLane, + message_lane_loop::{SourceClientState, TargetClientState}, +}; + +use bp_messages::MessageNonce; +use finality_relay::SyncLoopMetrics; +use relay_utils::metrics::{ + metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64, +}; + +/// Message lane relay metrics. +/// +/// Cloning only clones references. +#[derive(Clone)] +pub struct MessageLaneLoopMetrics { + /// Best finalized block numbers - "source", "source_at_target", "target_at_source". + source_to_target_finality_metrics: SyncLoopMetrics, + /// Best finalized block numbers - "source", "target", "source_at_target", "target_at_source". + target_to_source_finality_metrics: SyncLoopMetrics, + /// Lane state nonces: "source_latest_generated", "source_latest_confirmed", + /// "target_latest_received", "target_latest_confirmed". + lane_state_nonces: GaugeVec, +} + +impl MessageLaneLoopMetrics { + /// Create and register messages loop metrics. + pub fn new(prefix: Option<&str>) -> Result { + Ok(MessageLaneLoopMetrics { + source_to_target_finality_metrics: SyncLoopMetrics::new( + prefix, + "source", + "source_at_target", + )?, + target_to_source_finality_metrics: SyncLoopMetrics::new( + prefix, + "target", + "target_at_source", + )?, + lane_state_nonces: GaugeVec::new( + Opts::new(metric_name(prefix, "lane_state_nonces"), "Nonces of the lane state"), + &["type"], + )?, + }) + } + + /// Update source client state metrics. + pub fn update_source_state(&self, source_client_state: SourceClientState

) { + self.source_to_target_finality_metrics + .update_best_block_at_source(source_client_state.best_self.0); + if let Some(best_finalized_peer_at_best_self) = + source_client_state.best_finalized_peer_at_best_self + { + self.target_to_source_finality_metrics + .update_best_block_at_target(best_finalized_peer_at_best_self.0); + if let Some(actual_best_finalized_peer_at_best_self) = + source_client_state.actual_best_finalized_peer_at_best_self + { + self.target_to_source_finality_metrics.update_using_same_fork( + best_finalized_peer_at_best_self.1 == actual_best_finalized_peer_at_best_self.1, + ); + } + } + } + + /// Update target client state metrics. + pub fn update_target_state(&self, target_client_state: TargetClientState

) { + self.target_to_source_finality_metrics + .update_best_block_at_source(target_client_state.best_self.0); + if let Some(best_finalized_peer_at_best_self) = + target_client_state.best_finalized_peer_at_best_self + { + self.source_to_target_finality_metrics + .update_best_block_at_target(best_finalized_peer_at_best_self.0); + if let Some(actual_best_finalized_peer_at_best_self) = + target_client_state.actual_best_finalized_peer_at_best_self + { + self.source_to_target_finality_metrics.update_using_same_fork( + best_finalized_peer_at_best_self.1 == actual_best_finalized_peer_at_best_self.1, + ); + } + } + } + + /// Update latest generated nonce at source. + pub fn update_source_latest_generated_nonce( + &self, + source_latest_generated_nonce: MessageNonce, + ) { + self.lane_state_nonces + .with_label_values(&["source_latest_generated"]) + .set(source_latest_generated_nonce); + } + + /// Update the latest confirmed nonce at source. + pub fn update_source_latest_confirmed_nonce( + &self, + source_latest_confirmed_nonce: MessageNonce, + ) { + self.lane_state_nonces + .with_label_values(&["source_latest_confirmed"]) + .set(source_latest_confirmed_nonce); + } + + /// Update the latest received nonce at target. + pub fn update_target_latest_received_nonce(&self, target_latest_generated_nonce: MessageNonce) { + self.lane_state_nonces + .with_label_values(&["target_latest_received"]) + .set(target_latest_generated_nonce); + } + + /// Update the latest confirmed nonce at target. + pub fn update_target_latest_confirmed_nonce( + &self, + target_latest_confirmed_nonce: MessageNonce, + ) { + self.lane_state_nonces + .with_label_values(&["target_latest_confirmed"]) + .set(target_latest_confirmed_nonce); + } +} + +impl Metric for MessageLaneLoopMetrics { + fn register(&self, registry: &Registry) -> Result<(), PrometheusError> { + self.source_to_target_finality_metrics.register(registry)?; + self.target_to_source_finality_metrics.register(registry)?; + register(self.lane_state_nonces.clone(), registry)?; + Ok(()) + } +} diff --git a/relays/parachains/Cargo.toml b/relays/parachains/Cargo.toml new file mode 100644 index 00000000000..0cecf063922 --- /dev/null +++ b/relays/parachains/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "parachains-relay" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +async-std = "1.6.5" +async-trait = "0.1.68" +futures = "0.3.28" +log = "0.4.17" +relay-utils = { path = "../utils" } + +# Bridge dependencies + +bp-polkadot-core = { path = "../../primitives/polkadot-core" } +relay-substrate-client = { path = "../client-substrate" } + +[dev-dependencies] +codec = { package = "parity-scale-codec", version = "3.1.5" } +relay-substrate-client = { path = "../client-substrate", features = ["test-helpers"] } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/parachains/README.md b/relays/parachains/README.md new file mode 100644 index 00000000000..fc5ad03fb34 --- /dev/null +++ b/relays/parachains/README.md @@ -0,0 +1,49 @@ +# Parachains Finality Relay + +The parachains finality relay works with two chains - source relay chain and target chain (which may be standalone +chain, relay chain or a parachain). The source chain must have the +[`paras` pallet](https://github.com/paritytech/polkadot/tree/master/runtime/parachains/src/paras) deployed at its +runtime. The target chain must have the [bridge parachains pallet](../../modules/parachains/) deployed at its runtime. + +The relay is configured to submit heads of one or several parachains. It pokes source chain periodically and compares +parachain heads that are known to the source relay chain to heads at the target chain. If there are new heads, +the relay submits them to the target chain. + +More: [Parachains Finality Relay Sequence Diagram](../../docs/parachains-finality-relay.html). + +## How to Use the Parachains Finality Relay + +There are only two traits that need to be implemented. The [`SourceChain`](./src/parachains_loop.rs) implementation +is supposed to connect to the source chain node. It must be able to read parachain heads from the `Heads` map of +the [`paras` pallet](https://github.com/paritytech/polkadot/tree/master/runtime/parachains/src/paras). +It also must create storage proofs of `Heads` map entries, when required. + +The [`TargetChain`](./src/parachains_loop.rs) implementation connects to the target chain node. It must be able +to return the best known head of given parachain. When required, it must be able to craft and submit parachains +finality delivery transaction to the target node. + +The main entrypoint for the crate is the [`run` function](./src/parachains_loop.rs), which takes source and target +clients and [`ParachainSyncParams`](./src/parachains_loop.rs) parameters. The most imporant parameter is the +`parachains` - it is the set of parachains, which relay tracks and updates. The other important parameter that +may affect the relay operational costs is the `strategy`. If it is set to `Any`, then the finality delivery +transaction is submitted if at least one of tracked parachain heads is updated. The other option is `All`. Then +the relay waits until all tracked parachain heads are updated and submits them all in a single finality delivery +transaction. + +## Parachain Finality Relay Metrics + +Every parachain in Polkadot is identified by the 32-bit number. All metrics, exposed by the parachains finality +relay have the `parachain` label, which is set to the parachain id. And the metrics are prefixed with the prefix, +that depends on the name of the source relay and target chains. The list below shows metrics names for +Rialto (source relay chain) to Millau (target chain) parachains finality relay. For other chains, simply +change chain names. So the metrics are: + +- `Rialto_to_Millau_Parachains_best_parachain_block_number_at_source` - returns best known parachain block + number, registered in the `paras` pallet at the source relay chain (Rialto in our example); + +- `Rialto_to_Millau_Parachains_best_parachain_block_number_at_target` - returns best known parachain block + number, registered in the bridge parachains pallet at the target chain (Millau in our example). + +If relay operates properly, you should see that the `Rialto_to_Millau_Parachains_best_parachain_block_number_at_target` +tries to reach the `Rialto_to_Millau_Parachains_best_parachain_block_number_at_source`. And the latter one +always increases. diff --git a/relays/parachains/src/lib.rs b/relays/parachains/src/lib.rs new file mode 100644 index 00000000000..81ea983a6f7 --- /dev/null +++ b/relays/parachains/src/lib.rs @@ -0,0 +1,32 @@ +// Copyright 2019-2021 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 . + +use std::fmt::Debug; + +use relay_substrate_client::{Chain, Parachain}; + +pub mod parachains_loop; +pub mod parachains_loop_metrics; + +/// Finality proofs synchronization pipeline. +pub trait ParachainsPipeline: 'static + Clone + Debug + Send + Sync { + /// Relay chain which is storing parachain heads in its `paras` module. + type SourceRelayChain: Chain; + /// Parachain which headers we are syncing here. + type SourceParachain: Parachain; + /// Target chain (either relay or para) which wants to know about new parachain heads. + type TargetChain: Chain; +} diff --git a/relays/parachains/src/parachains_loop.rs b/relays/parachains/src/parachains_loop.rs new file mode 100644 index 00000000000..9b9038fd976 --- /dev/null +++ b/relays/parachains/src/parachains_loop.rs @@ -0,0 +1,953 @@ +// Copyright 2019-2021 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 . + +use crate::{parachains_loop_metrics::ParachainsLoopMetrics, ParachainsPipeline}; + +use async_trait::async_trait; +use bp_polkadot_core::{ + parachains::{ParaHash, ParaHeadsProof, ParaId}, + BlockNumber as RelayBlockNumber, +}; +use futures::{ + future::{FutureExt, Shared}, + poll, select_biased, +}; +use relay_substrate_client::{Chain, HeaderIdOf, ParachainBase}; +use relay_utils::{ + metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, + TrackedTransactionStatus, TransactionTracker, +}; +use std::{future::Future, pin::Pin, task::Poll}; + +/// Parachain header availability at a certain chain. +#[derive(Clone, Copy, Debug)] +pub enum AvailableHeader { + /// The client can not report actual parachain head at this moment. + /// + /// It is a "mild" error, which may appear when e.g. on-demand parachains relay is used. + /// This variant must be treated as "we don't want to update parachain head value at the + /// target chain at this moment". + Unavailable, + /// There's no parachain header at the relay chain. + /// + /// Normally it means that the parachain is not registered there. + Missing, + /// Parachain head with given hash is available at the source chain. + Available(T), +} + +impl AvailableHeader { + /// Return available header. + pub fn as_available(&self) -> Option<&T> { + match *self { + AvailableHeader::Available(ref header) => Some(header), + _ => None, + } + } +} + +impl From> for AvailableHeader { + fn from(maybe_header: Option) -> AvailableHeader { + match maybe_header { + Some(header) => AvailableHeader::Available(header), + None => AvailableHeader::Missing, + } + } +} + +/// Source client used in parachain heads synchronization loop. +#[async_trait] +pub trait SourceClient: RelayClient { + /// Returns `Ok(true)` if client is in synced state. + async fn ensure_synced(&self) -> Result; + + /// Get parachain head id at given block. + async fn parachain_head( + &self, + at_block: HeaderIdOf, + ) -> Result>, Self::Error>; + + /// Get parachain head proof at given block. + async fn prove_parachain_head( + &self, + at_block: HeaderIdOf, + ) -> Result<(ParaHeadsProof, ParaHash), Self::Error>; +} + +/// Target client used in parachain heads synchronization loop. +#[async_trait] +pub trait TargetClient: RelayClient { + /// Transaction tracker to track submitted transactions. + type TransactionTracker: TransactionTracker>; + + /// Get best block id. + async fn best_block(&self) -> Result, Self::Error>; + + /// Get best finalized source relay chain block id. + async fn best_finalized_source_relay_chain_block( + &self, + at_block: &HeaderIdOf, + ) -> Result, Self::Error>; + + /// Get parachain head id at given block. + async fn parachain_head( + &self, + at_block: HeaderIdOf, + ) -> Result>, Self::Error>; + + /// Submit parachain heads proof. + async fn submit_parachain_head_proof( + &self, + at_source_block: HeaderIdOf, + para_head_hash: ParaHash, + proof: ParaHeadsProof, + ) -> Result; +} + +/// Return prefix that will be used by default to expose Prometheus metrics of the parachains +/// sync loop. +pub fn metrics_prefix() -> String { + format!( + "{}_to_{}_Parachains_{}", + P::SourceRelayChain::NAME, + P::TargetChain::NAME, + P::SourceParachain::PARACHAIN_ID + ) +} + +/// Run parachain heads synchronization. +pub async fn run( + source_client: impl SourceClient

, + target_client: impl TargetClient

, + metrics_params: MetricsParams, + exit_signal: impl Future + 'static + Send, +) -> Result<(), relay_utils::Error> +where + P::SourceRelayChain: Chain, +{ + let exit_signal = exit_signal.shared(); + relay_utils::relay_loop(source_client, target_client) + .with_metrics(metrics_params) + .loop_metric(ParachainsLoopMetrics::new(Some(&metrics_prefix::

()))?)? + .expose() + .await? + .run(metrics_prefix::

(), move |source_client, target_client, metrics| { + run_until_connection_lost(source_client, target_client, metrics, exit_signal.clone()) + }) + .await +} + +/// Run parachain heads synchronization. +async fn run_until_connection_lost( + source_client: impl SourceClient

, + target_client: impl TargetClient

, + metrics: Option, + exit_signal: impl Future + Send, +) -> Result<(), FailedClient> +where + P::SourceRelayChain: Chain, +{ + let exit_signal = exit_signal.fuse(); + let min_block_interval = std::cmp::min( + P::SourceRelayChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + ); + + let mut submitted_heads_tracker: Option> = None; + + futures::pin_mut!(exit_signal); + + // Note that the internal loop breaks with `FailedClient` error even if error is non-connection. + // It is Ok for now, but it may need to be fixed in the future to use exponential backoff for + // regular errors. + + loop { + // Either wait for new block, or exit signal. + // Please note that we are prioritizing the exit signal since if both events happen at once + // it doesn't make sense to perform one more loop iteration. + select_biased! { + _ = exit_signal => return Ok(()), + _ = async_std::task::sleep(min_block_interval).fuse() => {}, + } + + // if source client is not yet synced, we'll need to sleep. Otherwise we risk submitting too + // much redundant transactions + match source_client.ensure_synced().await { + Ok(true) => (), + Ok(false) => { + log::warn!( + target: "bridge", + "{} client is syncing. Won't do anything until it is synced", + P::SourceRelayChain::NAME, + ); + continue + }, + Err(e) => { + log::warn!( + target: "bridge", + "{} client has failed to return its sync status: {:?}", + P::SourceRelayChain::NAME, + e, + ); + return Err(FailedClient::Source) + }, + } + + // if we have active transaction, we'll need to wait until it is mined or dropped + let best_target_block = target_client.best_block().await.map_err(|e| { + log::warn!(target: "bridge", "Failed to read best {} block: {:?}", P::SourceRelayChain::NAME, e); + FailedClient::Target + })?; + let head_at_target = + read_head_at_target(&target_client, metrics.as_ref(), &best_target_block).await?; + + // check if our transaction has been mined + if let Some(tracker) = submitted_heads_tracker.take() { + match tracker.update(&best_target_block, &head_at_target).await { + SubmittedHeadStatus::Waiting(tracker) => { + // no news about our transaction and we shall keep waiting + submitted_heads_tracker = Some(tracker); + continue + }, + SubmittedHeadStatus::Final(TrackedTransactionStatus::Finalized(_)) => { + // all heads have been updated, we don't need this tracker anymore + }, + SubmittedHeadStatus::Final(TrackedTransactionStatus::Lost) => { + log::warn!( + target: "bridge", + "Parachains synchronization from {} to {} has stalled. Going to restart", + P::SourceRelayChain::NAME, + P::TargetChain::NAME, + ); + + return Err(FailedClient::Both) + }, + } + } + + // we have no active transaction and may need to update heads, but do we have something for + // update? + let best_finalized_relay_block = target_client + .best_finalized_source_relay_chain_block(&best_target_block) + .await + .map_err(|e| { + log::warn!( + target: "bridge", + "Failed to read best finalized {} block from {}: {:?}", + P::SourceRelayChain::NAME, + P::TargetChain::NAME, + e, + ); + FailedClient::Target + })?; + let head_at_source = + read_head_at_source(&source_client, metrics.as_ref(), &best_finalized_relay_block) + .await?; + let is_update_required = is_update_required::

(head_at_source, head_at_target); + + if is_update_required { + let (head_proof, head_hash) = source_client + .prove_parachain_head(best_finalized_relay_block) + .await + .map_err(|e| { + log::warn!( + target: "bridge", + "Failed to prove {} parachain ParaId({}) heads: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + e, + ); + FailedClient::Source + })?; + log::info!( + target: "bridge", + "Submitting {} parachain ParaId({}) head update transaction to {}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + ); + + let transaction_tracker = target_client + .submit_parachain_head_proof(best_finalized_relay_block, head_hash, head_proof) + .await + .map_err(|e| { + log::warn!( + target: "bridge", + "Failed to submit {} parachain ParaId({}) heads proof to {}: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + e, + ); + FailedClient::Target + })?; + submitted_heads_tracker = + Some(SubmittedHeadsTracker::

::new(head_at_source, transaction_tracker)); + } + } +} + +/// Returns `true` if we need to submit parachain-head-update transaction. +fn is_update_required( + head_at_source: AvailableHeader>, + head_at_target: Option>, +) -> bool +where + P::SourceRelayChain: Chain, +{ + log::trace!( + target: "bridge", + "Checking if {} parachain ParaId({}) needs update at {}:\n\t\ + At {}: {:?}\n\t\ + At {}: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + P::SourceRelayChain::NAME, + head_at_source, + P::TargetChain::NAME, + head_at_target, + ); + + let needs_update = match (head_at_source, head_at_target) { + (AvailableHeader::Unavailable, _) => { + // source client has politely asked us not to update current parachain head + // at the target chain + false + }, + (AvailableHeader::Available(head_at_source), Some(head_at_target)) + if head_at_source.number() > head_at_target.number() => + { + // source client knows head that is better than the head known to the target + // client + true + }, + (AvailableHeader::Available(_), Some(_)) => { + // this is normal case when relay has recently updated heads, when parachain is + // not progressing, or when our source client is still syncing + false + }, + (AvailableHeader::Available(_), None) => { + // parachain is not yet known to the target client. This is true when parachain + // or bridge has been just onboarded/started + true + }, + (AvailableHeader::Missing, Some(_)) => { + // parachain/parathread has been offboarded removed from the system. It needs to + // be propageted to the target client + true + }, + (AvailableHeader::Missing, None) => { + // all's good - parachain is unknown to both clients + false + }, + }; + + if needs_update { + log::trace!( + target: "bridge", + "{} parachain ParaId({}) needs update at {}: {:?} vs {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + head_at_source, + head_at_target, + ); + } + + needs_update +} + +/// Reads parachain head from the source client. +async fn read_head_at_source( + source_client: &impl SourceClient

, + metrics: Option<&ParachainsLoopMetrics>, + at_relay_block: &HeaderIdOf, +) -> Result>, FailedClient> { + let para_head = source_client.parachain_head(*at_relay_block).await; + match para_head { + Ok(AvailableHeader::Available(para_head)) => { + if let Some(metrics) = metrics { + metrics.update_best_parachain_block_at_source( + ParaId(P::SourceParachain::PARACHAIN_ID), + para_head.number(), + ); + } + Ok(AvailableHeader::Available(para_head)) + }, + Ok(r) => Ok(r), + Err(e) => { + log::warn!( + target: "bridge", + "Failed to read head of {} parachain ParaId({:?}): {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + e, + ); + Err(FailedClient::Source) + }, + } +} + +/// Reads parachain head from the target client. +async fn read_head_at_target( + target_client: &impl TargetClient

, + metrics: Option<&ParachainsLoopMetrics>, + at_block: &HeaderIdOf, +) -> Result>, FailedClient> { + let para_head_id = target_client.parachain_head(*at_block).await; + match para_head_id { + Ok(Some(para_head_id)) => { + if let Some(metrics) = metrics { + metrics.update_best_parachain_block_at_target( + ParaId(P::SourceParachain::PARACHAIN_ID), + para_head_id.number(), + ); + } + Ok(Some(para_head_id)) + }, + Ok(None) => Ok(None), + Err(e) => { + log::warn!( + target: "bridge", + "Failed to read head of {} parachain ParaId({}) at {}: {:?}", + P::SourceRelayChain::NAME, + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + e, + ); + Err(FailedClient::Target) + }, + } +} + +/// Submitted heads status. +enum SubmittedHeadStatus { + /// Heads are not yet updated. + Waiting(SubmittedHeadsTracker

), + /// Heads transaction has either been finalized or lost (i.e. received its "final" status). + Final(TrackedTransactionStatus>), +} + +/// Type of the transaction tracker that the `SubmittedHeadsTracker` is using. +/// +/// It needs to be shared because of `poll` macro and our consuming `update` method. +type SharedTransactionTracker

= Shared< + Pin< + Box< + dyn Future< + Output = TrackedTransactionStatus< + HeaderIdOf<

::TargetChain>, + >, + > + Send, + >, + >, +>; + +/// Submitted parachain heads transaction. +struct SubmittedHeadsTracker { + /// Parachain header id that we have submitted. + submitted_head: AvailableHeader>, + /// Future that waits for submitted transaction finality or loss. + /// + /// It needs to be shared because of `poll` macro and our consuming `update` method. + transaction_tracker: SharedTransactionTracker

, +} + +impl SubmittedHeadsTracker

{ + /// Creates new parachain heads transaction tracker. + pub fn new( + submitted_head: AvailableHeader>, + transaction_tracker: impl TransactionTracker> + 'static, + ) -> Self { + SubmittedHeadsTracker { + submitted_head, + transaction_tracker: transaction_tracker.wait().fuse().boxed().shared(), + } + } + + /// Returns `None` if all submitted parachain heads have been updated. + pub async fn update( + self, + at_target_block: &HeaderIdOf, + head_at_target: &Option>, + ) -> SubmittedHeadStatus

{ + // check if our head has been updated + let is_head_updated = match (self.submitted_head, head_at_target) { + (AvailableHeader::Available(submitted_head), Some(head_at_target)) + if head_at_target.number() >= submitted_head.number() => + true, + (AvailableHeader::Missing, None) => true, + _ => false, + }; + if is_head_updated { + log::trace!( + target: "bridge", + "Head of parachain ParaId({}) has been updated at {}: {:?}", + P::SourceParachain::PARACHAIN_ID, + P::TargetChain::NAME, + head_at_target, + ); + + return SubmittedHeadStatus::Final(TrackedTransactionStatus::Finalized(*at_target_block)) + } + + // if underlying transaction tracker has reported that the transaction is lost, we may + // then restart our sync + let transaction_tracker = self.transaction_tracker.clone(); + match poll!(transaction_tracker) { + Poll::Ready(TrackedTransactionStatus::Lost) => + return SubmittedHeadStatus::Final(TrackedTransactionStatus::Lost), + Poll::Ready(TrackedTransactionStatus::Finalized(_)) => { + // so we are here and our transaction is mined+finalized, but some of heads were not + // updated => we're considering our loop as stalled + return SubmittedHeadStatus::Final(TrackedTransactionStatus::Lost) + }, + _ => (), + } + + SubmittedHeadStatus::Waiting(self) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use async_std::sync::{Arc, Mutex}; + use codec::Encode; + use futures::{SinkExt, StreamExt}; + use relay_substrate_client::test_chain::{TestChain, TestParachain}; + use relay_utils::{HeaderId, MaybeConnectionError}; + use sp_core::H256; + + const PARA_10_HASH: ParaHash = H256([10u8; 32]); + const PARA_20_HASH: ParaHash = H256([20u8; 32]); + + #[derive(Clone, Debug)] + enum TestError { + Error, + } + + impl MaybeConnectionError for TestError { + fn is_connection_error(&self) -> bool { + false + } + } + + #[derive(Clone, Debug, PartialEq, Eq)] + struct TestParachainsPipeline; + + impl ParachainsPipeline for TestParachainsPipeline { + type SourceRelayChain = TestChain; + type SourceParachain = TestParachain; + type TargetChain = TestChain; + } + + #[derive(Clone, Debug)] + struct TestClient { + data: Arc>, + } + + #[derive(Clone, Debug)] + struct TestTransactionTracker(Option>>); + + #[async_trait] + impl TransactionTracker for TestTransactionTracker { + type HeaderId = HeaderIdOf; + + async fn wait(self) -> TrackedTransactionStatus> { + match self.0 { + Some(status) => status, + None => futures::future::pending().await, + } + } + } + + #[derive(Clone, Debug)] + struct TestClientData { + source_sync_status: Result, + source_head: Result>, TestError>, + source_proof: Result<(), TestError>, + + target_best_block: Result, TestError>, + target_best_finalized_source_block: Result, TestError>, + target_head: Result>, TestError>, + target_submit_result: Result<(), TestError>, + + exit_signal_sender: Option>>, + } + + impl TestClientData { + pub fn minimal() -> Self { + TestClientData { + source_sync_status: Ok(true), + source_head: Ok(AvailableHeader::Available(HeaderId(0, PARA_20_HASH))), + source_proof: Ok(()), + + target_best_block: Ok(HeaderId(0, Default::default())), + target_best_finalized_source_block: Ok(HeaderId(0, Default::default())), + target_head: Ok(None), + target_submit_result: Ok(()), + + exit_signal_sender: None, + } + } + + pub fn with_exit_signal_sender( + sender: futures::channel::mpsc::UnboundedSender<()>, + ) -> Self { + let mut client = Self::minimal(); + client.exit_signal_sender = Some(Box::new(sender)); + client + } + } + + impl From for TestClient { + fn from(data: TestClientData) -> TestClient { + TestClient { data: Arc::new(Mutex::new(data)) } + } + } + + #[async_trait] + impl RelayClient for TestClient { + type Error = TestError; + + async fn reconnect(&mut self) -> Result<(), TestError> { + unimplemented!() + } + } + + #[async_trait] + impl SourceClient for TestClient { + async fn ensure_synced(&self) -> Result { + self.data.lock().await.source_sync_status.clone() + } + + async fn parachain_head( + &self, + _at_block: HeaderIdOf, + ) -> Result>, TestError> { + self.data.lock().await.source_head.clone() + } + + async fn prove_parachain_head( + &self, + _at_block: HeaderIdOf, + ) -> Result<(ParaHeadsProof, ParaHash), TestError> { + let head = *self.data.lock().await.source_head.clone()?.as_available().unwrap(); + let proof = (ParaHeadsProof(vec![head.hash().encode()]), head.hash()); + self.data.lock().await.source_proof.clone().map(|_| proof) + } + } + + #[async_trait] + impl TargetClient for TestClient { + type TransactionTracker = TestTransactionTracker; + + async fn best_block(&self) -> Result, TestError> { + self.data.lock().await.target_best_block.clone() + } + + async fn best_finalized_source_relay_chain_block( + &self, + _at_block: &HeaderIdOf, + ) -> Result, TestError> { + self.data.lock().await.target_best_finalized_source_block.clone() + } + + async fn parachain_head( + &self, + _at_block: HeaderIdOf, + ) -> Result>, TestError> { + self.data.lock().await.target_head.clone() + } + + async fn submit_parachain_head_proof( + &self, + _at_source_block: HeaderIdOf, + _updated_parachain_head: ParaHash, + _proof: ParaHeadsProof, + ) -> Result { + let mut data = self.data.lock().await; + data.target_submit_result.clone()?; + + if let Some(mut exit_signal_sender) = data.exit_signal_sender.take() { + exit_signal_sender.send(()).await.unwrap(); + } + Ok(TestTransactionTracker(Some( + TrackedTransactionStatus::Finalized(Default::default()), + ))) + } + } + + #[test] + fn when_source_client_fails_to_return_sync_state() { + let mut test_source_client = TestClientData::minimal(); + test_source_client.source_sync_status = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(test_source_client), + TestClient::from(TestClientData::minimal()), + None, + futures::future::pending(), + )), + Err(FailedClient::Source), + ); + } + + #[test] + fn when_target_client_fails_to_return_best_block() { + let mut test_target_client = TestClientData::minimal(); + test_target_client.target_best_block = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(test_target_client), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn when_target_client_fails_to_read_heads() { + let mut test_target_client = TestClientData::minimal(); + test_target_client.target_head = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(test_target_client), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn when_target_client_fails_to_read_best_finalized_source_block() { + let mut test_target_client = TestClientData::minimal(); + test_target_client.target_best_finalized_source_block = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(test_target_client), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn when_source_client_fails_to_read_heads() { + let mut test_source_client = TestClientData::minimal(); + test_source_client.source_head = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(test_source_client), + TestClient::from(TestClientData::minimal()), + None, + futures::future::pending(), + )), + Err(FailedClient::Source), + ); + } + + #[test] + fn when_source_client_fails_to_prove_heads() { + let mut test_source_client = TestClientData::minimal(); + test_source_client.source_proof = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(test_source_client), + TestClient::from(TestClientData::minimal()), + None, + futures::future::pending(), + )), + Err(FailedClient::Source), + ); + } + + #[test] + fn when_target_client_rejects_update_transaction() { + let mut test_target_client = TestClientData::minimal(); + test_target_client.target_submit_result = Err(TestError::Error); + + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(test_target_client), + None, + futures::future::pending(), + )), + Err(FailedClient::Target), + ); + } + + #[test] + fn minimal_working_case() { + let (exit_signal_sender, exit_signal) = futures::channel::mpsc::unbounded(); + assert_eq!( + async_std::task::block_on(run_until_connection_lost( + TestClient::from(TestClientData::minimal()), + TestClient::from(TestClientData::with_exit_signal_sender(exit_signal_sender)), + None, + exit_signal.into_future().map(|(_, _)| ()), + )), + Ok(()), + ); + } + + fn test_tx_tracker() -> SubmittedHeadsTracker { + SubmittedHeadsTracker::new( + AvailableHeader::Available(HeaderId(20, PARA_20_HASH)), + TestTransactionTracker(None), + ) + } + + impl From> for Option<()> { + fn from(status: SubmittedHeadStatus) -> Option<()> { + match status { + SubmittedHeadStatus::Waiting(_) => Some(()), + _ => None, + } + } + } + + #[async_std::test] + async fn tx_tracker_update_when_head_at_target_has_none_value() { + assert_eq!( + Some(()), + test_tx_tracker() + .update(&HeaderId(0, Default::default()), &Some(HeaderId(10, PARA_10_HASH))) + .await + .into(), + ); + } + + #[async_std::test] + async fn tx_tracker_update_when_head_at_target_has_old_value() { + assert_eq!( + Some(()), + test_tx_tracker() + .update(&HeaderId(0, Default::default()), &Some(HeaderId(10, PARA_10_HASH))) + .await + .into(), + ); + } + + #[async_std::test] + async fn tx_tracker_update_when_head_at_target_has_same_value() { + assert!(matches!( + test_tx_tracker() + .update(&HeaderId(0, Default::default()), &Some(HeaderId(20, PARA_20_HASH))) + .await, + SubmittedHeadStatus::Final(TrackedTransactionStatus::Finalized(_)), + )); + } + + #[async_std::test] + async fn tx_tracker_update_when_head_at_target_has_better_value() { + assert!(matches!( + test_tx_tracker() + .update(&HeaderId(0, Default::default()), &Some(HeaderId(30, PARA_20_HASH))) + .await, + SubmittedHeadStatus::Final(TrackedTransactionStatus::Finalized(_)), + )); + } + + #[async_std::test] + async fn tx_tracker_update_when_tx_is_lost() { + let mut tx_tracker = test_tx_tracker(); + tx_tracker.transaction_tracker = + futures::future::ready(TrackedTransactionStatus::Lost).boxed().shared(); + assert!(matches!( + tx_tracker + .update(&HeaderId(0, Default::default()), &Some(HeaderId(10, PARA_10_HASH))) + .await, + SubmittedHeadStatus::Final(TrackedTransactionStatus::Lost), + )); + } + + #[async_std::test] + async fn tx_tracker_update_when_tx_is_finalized_but_heads_are_not_updated() { + let mut tx_tracker = test_tx_tracker(); + tx_tracker.transaction_tracker = + futures::future::ready(TrackedTransactionStatus::Finalized(Default::default())) + .boxed() + .shared(); + assert!(matches!( + tx_tracker + .update(&HeaderId(0, Default::default()), &Some(HeaderId(10, PARA_10_HASH))) + .await, + SubmittedHeadStatus::Final(TrackedTransactionStatus::Lost), + )); + } + + #[test] + fn parachain_is_not_updated_if_it_is_unavailable() { + assert!(!is_update_required::(AvailableHeader::Unavailable, None)); + assert!(!is_update_required::( + AvailableHeader::Unavailable, + Some(HeaderId(10, PARA_10_HASH)) + )); + } + + #[test] + fn parachain_is_not_updated_if_it_is_unknown_to_both_clients() { + assert!(!is_update_required::(AvailableHeader::Missing, None),); + } + + #[test] + fn parachain_is_not_updated_if_target_has_better_head() { + assert!(!is_update_required::( + AvailableHeader::Available(HeaderId(10, Default::default())), + Some(HeaderId(20, Default::default())), + ),); + } + + #[test] + fn parachain_is_updated_after_offboarding() { + assert!(is_update_required::( + AvailableHeader::Missing, + Some(HeaderId(20, Default::default())), + ),); + } + + #[test] + fn parachain_is_updated_after_onboarding() { + assert!(is_update_required::( + AvailableHeader::Available(HeaderId(30, Default::default())), + None, + ),); + } + + #[test] + fn parachain_is_updated_if_newer_head_is_known() { + assert!(is_update_required::( + AvailableHeader::Available(HeaderId(40, Default::default())), + Some(HeaderId(30, Default::default())), + ),); + } +} diff --git a/relays/parachains/src/parachains_loop_metrics.rs b/relays/parachains/src/parachains_loop_metrics.rs new file mode 100644 index 00000000000..8138a43b3b3 --- /dev/null +++ b/relays/parachains/src/parachains_loop_metrics.rs @@ -0,0 +1,86 @@ +// Copyright 2019-2021 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 . + +use bp_polkadot_core::parachains::ParaId; +use relay_utils::{ + metrics::{metric_name, register, Gauge, Metric, PrometheusError, Registry, U64}, + UniqueSaturatedInto, +}; + +/// Parachains sync metrics. +#[derive(Clone)] +pub struct ParachainsLoopMetrics { + /// Best parachains header numbers at the source. + best_source_block_numbers: Gauge, + /// Best parachains header numbers at the target. + best_target_block_numbers: Gauge, +} + +impl ParachainsLoopMetrics { + /// Create and register parachains loop metrics. + pub fn new(prefix: Option<&str>) -> Result { + Ok(ParachainsLoopMetrics { + best_source_block_numbers: Gauge::new( + metric_name(prefix, "best_parachain_block_number_at_source"), + "Best parachain block numbers at the source relay chain".to_string(), + )?, + best_target_block_numbers: Gauge::new( + metric_name(prefix, "best_parachain_block_number_at_target"), + "Best parachain block numbers at the target chain".to_string(), + )?, + }) + } + + /// Update best block number at source. + pub fn update_best_parachain_block_at_source>( + &self, + parachain: ParaId, + block_number: Number, + ) { + let block_number = block_number.unique_saturated_into(); + log::trace!( + target: "bridge-metrics", + "Updated value of metric 'best_parachain_block_number_at_source[{:?}]': {:?}", + parachain, + block_number, + ); + self.best_source_block_numbers.set(block_number); + } + + /// Update best block number at target. + pub fn update_best_parachain_block_at_target>( + &self, + parachain: ParaId, + block_number: Number, + ) { + let block_number = block_number.unique_saturated_into(); + log::trace!( + target: "bridge-metrics", + "Updated value of metric 'best_parachain_block_number_at_target[{:?}]': {:?}", + parachain, + block_number, + ); + self.best_target_block_numbers.set(block_number); + } +} + +impl Metric for ParachainsLoopMetrics { + fn register(&self, registry: &Registry) -> Result<(), PrometheusError> { + register(self.best_source_block_numbers.clone(), registry)?; + register(self.best_target_block_numbers.clone(), registry)?; + Ok(()) + } +} diff --git a/relays/utils/Cargo.toml b/relays/utils/Cargo.toml new file mode 100644 index 00000000000..aa14e2ae2e3 --- /dev/null +++ b/relays/utils/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "relay-utils" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +ansi_term = "0.12" +anyhow = "1.0" +async-std = "1.6.5" +async-trait = "0.1" +backoff = "0.4" +isahc = "1.2" +env_logger = "0.10.0" +futures = "0.3.28" +jsonpath_lib = "0.3" +log = "0.4.17" +num-traits = "0.2" +serde_json = "1.0" +sysinfo = "0.28" +time = { version = "0.3", features = ["formatting", "local-offset", "std"] } +tokio = { version = "1.27", features = ["rt"] } +thiserror = "1.0.40" + +# Bridge dependencies + +bp-runtime = { path = "../../primitives/runtime" } + +# Substrate dependencies + +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/utils/src/error.rs b/relays/utils/src/error.rs new file mode 100644 index 00000000000..26f1d0cacef --- /dev/null +++ b/relays/utils/src/error.rs @@ -0,0 +1,46 @@ +// Copyright 2019-2021 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 . + +use std::net::AddrParseError; +use thiserror::Error; + +/// Result type used by relay utilities. +pub type Result = std::result::Result; + +/// Relay utilities errors. +#[derive(Error, Debug)] +pub enum Error { + /// Failed to request a float value from HTTP service. + #[error("Failed to fetch token price from remote server: {0}")] + FetchTokenPrice(#[source] anyhow::Error), + /// Failed to parse the response from HTTP service. + #[error("Failed to parse HTTP service response: {0:?}. Response: {1:?}")] + ParseHttp(serde_json::Error, String), + /// Failed to select response value from the Json response. + #[error("Failed to select value from response: {0:?}. Response: {1:?}")] + SelectResponseValue(jsonpath_lib::JsonPathError, String), + /// Failed to parse float value from the selected value. + #[error( + "Failed to parse float value {0:?} from response. It is assumed to be positive and normal" + )] + ParseFloat(f64), + /// Couldn't found value in the JSON response. + #[error("Missing required value from response: {0:?}")] + MissingResponseValue(String), + /// Invalid host address was used for exposing Prometheus metrics. + #[error("Invalid host {0} is used to expose Prometheus metrics: {1}")] + ExposingMetricsInvalidHost(String, AddrParseError), + /// Prometheus error. + #[error("{0}")] + Prometheus(#[from] substrate_prometheus_endpoint::prometheus::Error), +} diff --git a/relays/utils/src/initialize.rs b/relays/utils/src/initialize.rs new file mode 100644 index 00000000000..8224c1803ad --- /dev/null +++ b/relays/utils/src/initialize.rs @@ -0,0 +1,136 @@ +// Copyright 2019-2021 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 . + +//! Relayer initialization functions. + +use std::{cell::RefCell, fmt::Display, io::Write}; + +async_std::task_local! { + pub(crate) static LOOP_NAME: RefCell = RefCell::new(String::default()); +} + +/// Initialize relay environment. +pub fn initialize_relay() { + initialize_logger(true); +} + +/// Initialize Relay logger instance. +pub fn initialize_logger(with_timestamp: bool) { + let format = time::format_description::parse( + "[year]-[month]-[day] \ + [hour repr:24]:[minute]:[second] [offset_hour sign:mandatory]", + ) + .expect("static format string is valid"); + + let mut builder = env_logger::Builder::new(); + builder.filter_level(log::LevelFilter::Warn); + builder.filter_module("bridge", log::LevelFilter::Info); + builder.parse_default_env(); + if with_timestamp { + builder.format(move |buf, record| { + let timestamp = time::OffsetDateTime::now_local() + .unwrap_or_else(|_| time::OffsetDateTime::now_utc()); + let timestamp = timestamp.format(&format).unwrap_or_else(|_| timestamp.to_string()); + + let log_level = color_level(record.level()); + let log_target = color_target(record.target()); + let timestamp = if cfg!(windows) { + Either::Left(timestamp) + } else { + Either::Right(ansi_term::Colour::Fixed(8).bold().paint(timestamp)) + }; + + writeln!( + buf, + "{}{} {} {} {}", + loop_name_prefix(), + timestamp, + log_level, + log_target, + record.args(), + ) + }); + } else { + builder.format(move |buf, record| { + let log_level = color_level(record.level()); + let log_target = color_target(record.target()); + + writeln!(buf, "{}{log_level} {log_target} {}", loop_name_prefix(), record.args(),) + }); + } + + builder.init(); +} + +/// Initialize relay loop. Must only be called once per every loop task. +pub(crate) fn initialize_loop(loop_name: String) { + LOOP_NAME.with(|g_loop_name| *g_loop_name.borrow_mut() = loop_name); +} + +/// Returns loop name prefix to use in logs. The prefix is initialized with the `initialize_loop` +/// call. +fn loop_name_prefix() -> String { + // try_with to avoid panic outside of async-std task context + LOOP_NAME + .try_with(|loop_name| { + // using borrow is ok here, because loop is only initialized once (=> borrow_mut will + // only be called once) + let loop_name = loop_name.borrow(); + if loop_name.is_empty() { + String::new() + } else { + format!("[{loop_name}] ") + } + }) + .unwrap_or_else(|_| String::new()) +} + +enum Either { + Left(A), + Right(B), +} +impl Display for Either { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Left(a) => write!(fmt, "{a}"), + Self::Right(b) => write!(fmt, "{b}"), + } + } +} + +fn color_target(target: &str) -> impl Display + '_ { + if cfg!(windows) { + Either::Left(target) + } else { + Either::Right(ansi_term::Colour::Fixed(8).paint(target)) + } +} + +fn color_level(level: log::Level) -> impl Display { + if cfg!(windows) { + Either::Left(level) + } else { + let s = level.to_string(); + use ansi_term::Colour as Color; + Either::Right(match level { + log::Level::Error => Color::Fixed(9).bold().paint(s), + log::Level::Warn => Color::Fixed(11).bold().paint(s), + log::Level::Info => Color::Fixed(10).paint(s), + log::Level::Debug => Color::Fixed(14).paint(s), + log::Level::Trace => Color::Fixed(12).paint(s), + }) + } +} diff --git a/relays/utils/src/lib.rs b/relays/utils/src/lib.rs new file mode 100644 index 00000000000..428ee33494c --- /dev/null +++ b/relays/utils/src/lib.rs @@ -0,0 +1,313 @@ +// Copyright 2019-2021 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 . + +//! Utilities used by different relays. + +pub use bp_runtime::HeaderId; +pub use error::Error; +pub use relay_loop::{relay_loop, relay_metrics}; +pub use sp_runtime::traits::{UniqueSaturatedFrom, UniqueSaturatedInto}; + +use async_trait::async_trait; +use backoff::{backoff::Backoff, ExponentialBackoff}; +use futures::future::FutureExt; +use std::time::Duration; +use thiserror::Error; + +/// Default relay loop stall timeout. If transactions generated by relay are immortal, then +/// this timeout is used. +/// +/// There are no any strict requirements on block time in Substrate. But we assume here that all +/// Substrate-based chains will be designed to produce relatively fast (compared to the slowest +/// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine +/// transaction, or remove it from the pool. +pub const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60); + +/// Max delay after connection-unrelated error happened before we'll try the +/// same request again. +pub const MAX_BACKOFF_INTERVAL: Duration = Duration::from_secs(60); +/// Delay after connection-related error happened before we'll try +/// reconnection again. +pub const CONNECTION_ERROR_DELAY: Duration = Duration::from_secs(10); + +pub mod error; +pub mod initialize; +pub mod metrics; +pub mod relay_loop; + +/// Block number traits shared by all chains that relay is able to serve. +pub trait BlockNumberBase: + 'static + + From + + UniqueSaturatedInto + + Ord + + Clone + + Copy + + Default + + Send + + Sync + + std::fmt::Debug + + std::fmt::Display + + std::hash::Hash + + std::ops::Add + + std::ops::Sub + + num_traits::CheckedSub + + num_traits::Saturating + + num_traits::Zero + + num_traits::One +{ +} + +impl BlockNumberBase for T where + T: 'static + + From + + UniqueSaturatedInto + + Ord + + Clone + + Copy + + Default + + Send + + Sync + + std::fmt::Debug + + std::fmt::Display + + std::hash::Hash + + std::ops::Add + + std::ops::Sub + + num_traits::CheckedSub + + num_traits::Saturating + + num_traits::Zero + + num_traits::One +{ +} + +/// Macro that returns (client, Err(error)) tuple from function if result is Err(error). +#[macro_export] +macro_rules! bail_on_error { + ($result: expr) => { + match $result { + (client, Ok(result)) => (client, result), + (client, Err(error)) => return (client, Err(error)), + } + }; +} + +/// Macro that returns (client, Err(error)) tuple from function if result is Err(error). +#[macro_export] +macro_rules! bail_on_arg_error { + ($result: expr, $client: ident) => { + match $result { + Ok(result) => result, + Err(error) => return ($client, Err(error)), + } + }; +} + +/// Error type that can signal connection errors. +pub trait MaybeConnectionError { + /// Returns true if error (maybe) represents connection error. + fn is_connection_error(&self) -> bool; +} + +/// Final status of the tracked transaction. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum TrackedTransactionStatus { + /// Transaction has been lost. + Lost, + /// Transaction has been mined and finalized at given block. + Finalized(BlockId), +} + +/// Transaction tracker. +#[async_trait] +pub trait TransactionTracker: Send { + /// Header id, used by the chain. + type HeaderId: Clone + Send; + + /// Wait until transaction is either finalized or invalidated/lost. + async fn wait(self) -> TrackedTransactionStatus; +} + +/// Stringified error that may be either connection-related or not. +#[derive(Error, Debug)] +pub enum StringifiedMaybeConnectionError { + /// The error is connection-related error. + #[error("{0}")] + Connection(String), + /// The error is connection-unrelated error. + #[error("{0}")] + NonConnection(String), +} + +impl StringifiedMaybeConnectionError { + /// Create new stringified connection error. + pub fn new(is_connection_error: bool, error: String) -> Self { + if is_connection_error { + StringifiedMaybeConnectionError::Connection(error) + } else { + StringifiedMaybeConnectionError::NonConnection(error) + } + } +} + +impl MaybeConnectionError for StringifiedMaybeConnectionError { + fn is_connection_error(&self) -> bool { + match *self { + StringifiedMaybeConnectionError::Connection(_) => true, + StringifiedMaybeConnectionError::NonConnection(_) => false, + } + } +} + +/// Exponential backoff for connection-unrelated errors retries. +pub fn retry_backoff() -> ExponentialBackoff { + ExponentialBackoff { + // we do not want relayer to stop + max_elapsed_time: None, + max_interval: MAX_BACKOFF_INTERVAL, + ..Default::default() + } +} + +/// Compact format of IDs vector. +pub fn format_ids(mut ids: impl ExactSizeIterator) -> String { + const NTH_PROOF: &str = "we have checked len; qed"; + match ids.len() { + 0 => "".into(), + 1 => format!("{:?}", ids.next().expect(NTH_PROOF)), + 2 => { + let id0 = ids.next().expect(NTH_PROOF); + let id1 = ids.next().expect(NTH_PROOF); + format!("[{id0:?}, {id1:?}]") + }, + len => { + let id0 = ids.next().expect(NTH_PROOF); + let id_last = ids.last().expect(NTH_PROOF); + format!("{len}:[{id0:?} ... {id_last:?}]") + }, + } +} + +/// Stream that emits item every `timeout_ms` milliseconds. +pub fn interval(timeout: Duration) -> impl futures::Stream { + futures::stream::unfold((), move |_| async move { + async_std::task::sleep(timeout).await; + Some(((), ())) + }) +} + +/// Which client has caused error. +#[derive(Debug, Eq, Clone, Copy, PartialEq)] +pub enum FailedClient { + /// It is the source client who has caused error. + Source, + /// It is the target client who has caused error. + Target, + /// Both clients are failing, or we just encountered some other error that + /// should be treated like that. + Both, +} + +/// Future process result. +#[derive(Debug, Clone, Copy)] +pub enum ProcessFutureResult { + /// Future has been processed successfully. + Success, + /// Future has failed with non-connection error. + Failed, + /// Future has failed with connection error. + ConnectionFailed, +} + +impl ProcessFutureResult { + /// Returns true if result is Success. + pub fn is_ok(self) -> bool { + match self { + ProcessFutureResult::Success => true, + ProcessFutureResult::Failed | ProcessFutureResult::ConnectionFailed => false, + } + } + + /// Returns `Ok(())` if future has succeeded. + /// Returns `Err(failed_client)` otherwise. + pub fn fail_if_error(self, failed_client: FailedClient) -> Result<(), FailedClient> { + if self.is_ok() { + Ok(()) + } else { + Err(failed_client) + } + } + + /// Returns Ok(true) if future has succeeded. + /// Returns Ok(false) if future has failed with non-connection error. + /// Returns Err if future is `ConnectionFailed`. + pub fn fail_if_connection_error( + self, + failed_client: FailedClient, + ) -> Result { + match self { + ProcessFutureResult::Success => Ok(true), + ProcessFutureResult::Failed => Ok(false), + ProcessFutureResult::ConnectionFailed => Err(failed_client), + } + } +} + +/// Process result of the future from a client. +pub fn process_future_result( + result: Result, + retry_backoff: &mut ExponentialBackoff, + on_success: impl FnOnce(TResult), + go_offline_future: &mut std::pin::Pin<&mut futures::future::Fuse>, + go_offline: impl FnOnce(Duration) -> TGoOfflineFuture, + error_pattern: impl FnOnce() -> String, +) -> ProcessFutureResult +where + TError: std::fmt::Debug + MaybeConnectionError, + TGoOfflineFuture: FutureExt, +{ + match result { + Ok(result) => { + on_success(result); + retry_backoff.reset(); + ProcessFutureResult::Success + }, + Err(error) if error.is_connection_error() => { + log::error!( + target: "bridge", + "{}: {:?}. Going to restart", + error_pattern(), + error, + ); + + retry_backoff.reset(); + go_offline_future.set(go_offline(CONNECTION_ERROR_DELAY).fuse()); + ProcessFutureResult::ConnectionFailed + }, + Err(error) => { + let retry_delay = retry_backoff.next_backoff().unwrap_or(CONNECTION_ERROR_DELAY); + log::error!( + target: "bridge", + "{}: {:?}. Retrying in {}", + error_pattern(), + error, + retry_delay.as_secs_f64(), + ); + + go_offline_future.set(go_offline(retry_delay).fuse()); + ProcessFutureResult::Failed + }, + } +} diff --git a/relays/utils/src/metrics.rs b/relays/utils/src/metrics.rs new file mode 100644 index 00000000000..2e6c8236da4 --- /dev/null +++ b/relays/utils/src/metrics.rs @@ -0,0 +1,192 @@ +// Copyright 2019-2021 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 . + +pub use float_json_value::FloatJsonValueMetric; +pub use global::GlobalMetrics; +pub use substrate_prometheus_endpoint::{ + prometheus::core::{Atomic, Collector}, + register, Counter, CounterVec, Gauge, GaugeVec, Opts, PrometheusError, Registry, F64, I64, U64, +}; + +use async_std::sync::{Arc, RwLock}; +use async_trait::async_trait; +use std::{fmt::Debug, time::Duration}; + +mod float_json_value; +mod global; + +/// Shared reference to `f64` value that is updated by the metric. +pub type F64SharedRef = Arc>>; +/// Int gauge metric type. +pub type IntGauge = Gauge; + +/// Unparsed address that needs to be used to expose Prometheus metrics. +#[derive(Debug, Clone)] +pub struct MetricsAddress { + /// Serve HTTP requests at given host. + pub host: String, + /// Serve HTTP requests at given port. + pub port: u16, +} + +/// Prometheus endpoint MetricsParams. +#[derive(Debug, Clone)] +pub struct MetricsParams { + /// Interface and TCP port to be used when exposing Prometheus metrics. + pub address: Option, + /// Metrics registry. May be `Some(_)` if several components share the same endpoint. + pub registry: Registry, +} + +/// Metric API. +pub trait Metric: Clone + Send + Sync + 'static { + fn register(&self, registry: &Registry) -> Result<(), PrometheusError>; +} + +/// Standalone metric API. +/// +/// Metrics of this kind know how to update themselves, so we may just spawn and forget the +/// asynchronous self-update task. +#[async_trait] +pub trait StandaloneMetric: Metric { + /// Update metric values. + async fn update(&self); + + /// Metrics update interval. + fn update_interval(&self) -> Duration; + + /// Register and spawn metric. Metric is only spawned if it is registered for the first time. + fn register_and_spawn(self, registry: &Registry) -> Result<(), PrometheusError> { + match self.register(registry) { + Ok(()) => { + self.spawn(); + Ok(()) + }, + Err(PrometheusError::AlreadyReg) => Ok(()), + Err(e) => Err(e), + } + } + + /// Spawn the self update task that will keep update metric value at given intervals. + fn spawn(self) { + async_std::task::spawn(async move { + let update_interval = self.update_interval(); + loop { + self.update().await; + async_std::task::sleep(update_interval).await; + } + }); + } +} + +impl Default for MetricsAddress { + fn default() -> Self { + MetricsAddress { host: "127.0.0.1".into(), port: 9616 } + } +} + +impl MetricsParams { + /// Creates metrics params from metrics address. + pub fn new( + address: Option, + relay_version: String, + relay_commit: String, + ) -> Result { + const BUILD_INFO_METRIC: &str = "substrate_relay_build_info"; + + let registry = Registry::new(); + register( + Gauge::::with_opts( + Opts::new( + BUILD_INFO_METRIC, + "A metric with a constant '1' value labeled by version", + ) + .const_label("version", &relay_version) + .const_label("commit", &relay_commit), + )?, + ®istry, + )? + .set(1); + + log::info!( + target: "bridge", + "Exposed {} metric: version={} commit={}", + BUILD_INFO_METRIC, + relay_version, + relay_commit, + ); + + Ok(MetricsParams { address, registry }) + } + + /// Creates metrics params so that metrics are not exposed. + pub fn disabled() -> Self { + MetricsParams { address: None, registry: Registry::new() } + } + + /// Do not expose metrics. + #[must_use] + pub fn disable(mut self) -> Self { + self.address = None; + self + } +} + +/// Returns metric name optionally prefixed with given prefix. +pub fn metric_name(prefix: Option<&str>, name: &str) -> String { + if let Some(prefix) = prefix { + format!("{prefix}_{name}") + } else { + name.into() + } +} + +/// Set value of gauge metric. +/// +/// If value is `Ok(None)` or `Err(_)`, metric would have default value. +pub fn set_gauge_value, E: Debug>( + gauge: &Gauge, + value: Result, E>, +) { + gauge.set(match value { + Ok(Some(value)) => { + log::trace!( + target: "bridge-metrics", + "Updated value of metric '{:?}': {:?}", + gauge.desc().first().map(|d| &d.fq_name), + value, + ); + value + }, + Ok(None) => { + log::warn!( + target: "bridge-metrics", + "Failed to update metric '{:?}': value is empty", + gauge.desc().first().map(|d| &d.fq_name), + ); + Default::default() + }, + Err(error) => { + log::warn!( + target: "bridge-metrics", + "Failed to update metric '{:?}': {:?}", + gauge.desc().first().map(|d| &d.fq_name), + error, + ); + Default::default() + }, + }) +} diff --git a/relays/utils/src/metrics/float_json_value.rs b/relays/utils/src/metrics/float_json_value.rs new file mode 100644 index 00000000000..17b09e05097 --- /dev/null +++ b/relays/utils/src/metrics/float_json_value.rs @@ -0,0 +1,147 @@ +// Copyright 2019-2020 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 . + +use crate::{ + error::{self, Error}, + metrics::{ + metric_name, register, F64SharedRef, Gauge, Metric, PrometheusError, Registry, + StandaloneMetric, F64, + }, +}; + +use async_std::sync::{Arc, RwLock}; +use async_trait::async_trait; +use std::time::Duration; + +/// Value update interval. +const UPDATE_INTERVAL: Duration = Duration::from_secs(300); + +/// Metric that represents float value received from HTTP service as float gauge. +/// +/// The float value returned by the service is assumed to be normal (`f64::is_normal` +/// should return `true`) and strictly positive. +#[derive(Debug, Clone)] +pub struct FloatJsonValueMetric { + url: String, + json_path: String, + metric: Gauge, + shared_value_ref: F64SharedRef, +} + +impl FloatJsonValueMetric { + /// Create new metric instance with given name and help. + pub fn new( + url: String, + json_path: String, + name: String, + help: String, + ) -> Result { + let shared_value_ref = Arc::new(RwLock::new(None)); + Ok(FloatJsonValueMetric { + url, + json_path, + metric: Gauge::new(metric_name(None, &name), help)?, + shared_value_ref, + }) + } + + /// Get shared reference to metric value. + pub fn shared_value_ref(&self) -> F64SharedRef { + self.shared_value_ref.clone() + } + + /// Request value from HTTP service. + async fn request_value(&self) -> anyhow::Result { + use isahc::{AsyncReadResponseExt, HttpClient, Request}; + + let request = Request::get(&self.url).header("Accept", "application/json").body(())?; + let raw_response = HttpClient::new()?.send_async(request).await?.text().await?; + Ok(raw_response) + } + + /// Read value from HTTP service. + async fn read_value(&self) -> error::Result { + let raw_response = self.request_value().await.map_err(Error::FetchTokenPrice)?; + parse_service_response(&self.json_path, &raw_response) + } +} + +impl Metric for FloatJsonValueMetric { + fn register(&self, registry: &Registry) -> Result<(), PrometheusError> { + register(self.metric.clone(), registry).map(drop) + } +} + +#[async_trait] +impl StandaloneMetric for FloatJsonValueMetric { + fn update_interval(&self) -> Duration { + UPDATE_INTERVAL + } + + async fn update(&self) { + let value = self.read_value().await; + let maybe_ok = value.as_ref().ok().copied(); + crate::metrics::set_gauge_value(&self.metric, value.map(Some)); + *self.shared_value_ref.write().await = maybe_ok; + } +} + +/// Parse HTTP service response. +fn parse_service_response(json_path: &str, response: &str) -> error::Result { + let json = + serde_json::from_str(response).map_err(|err| Error::ParseHttp(err, response.to_owned()))?; + + let mut selector = jsonpath_lib::selector(&json); + let maybe_selected_value = + selector(json_path).map_err(|err| Error::SelectResponseValue(err, response.to_owned()))?; + let selected_value = maybe_selected_value + .first() + .and_then(|v| v.as_f64()) + .ok_or_else(|| Error::MissingResponseValue(response.to_owned()))?; + if !selected_value.is_normal() || selected_value < 0.0 { + return Err(Error::ParseFloat(selected_value)) + } + + Ok(selected_value) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_service_response_works() { + assert_eq!( + parse_service_response("$.kusama.usd", r#"{"kusama":{"usd":433.05}}"#).map_err(drop), + Ok(433.05), + ); + } + + #[test] + fn parse_service_response_rejects_negative_numbers() { + assert!(parse_service_response("$.kusama.usd", r#"{"kusama":{"usd":-433.05}}"#).is_err()); + } + + #[test] + fn parse_service_response_rejects_zero_numbers() { + assert!(parse_service_response("$.kusama.usd", r#"{"kusama":{"usd":0.0}}"#).is_err()); + } + + #[test] + fn parse_service_response_rejects_nan() { + assert!(parse_service_response("$.kusama.usd", r#"{"kusama":{"usd":NaN}}"#).is_err()); + } +} diff --git a/relays/utils/src/metrics/global.rs b/relays/utils/src/metrics/global.rs new file mode 100644 index 00000000000..f7d3e25c964 --- /dev/null +++ b/relays/utils/src/metrics/global.rs @@ -0,0 +1,118 @@ +// Copyright 2019-2021 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 . + +//! Global system-wide Prometheus metrics exposed by relays. + +use crate::metrics::{ + metric_name, register, Gauge, GaugeVec, Metric, Opts, PrometheusError, Registry, + StandaloneMetric, F64, U64, +}; + +use async_std::sync::{Arc, Mutex}; +use async_trait::async_trait; +use std::time::Duration; +use sysinfo::{ProcessExt, RefreshKind, System, SystemExt}; + +/// Global metrics update interval. +const UPDATE_INTERVAL: Duration = Duration::from_secs(10); + +/// Global Prometheus metrics. +#[derive(Debug, Clone)] +pub struct GlobalMetrics { + system: Arc>, + system_average_load: GaugeVec, + process_cpu_usage_percentage: Gauge, + process_memory_usage_bytes: Gauge, +} + +impl GlobalMetrics { + /// Create and register global metrics. + pub fn new() -> Result { + Ok(GlobalMetrics { + system: Arc::new(Mutex::new(System::new_with_specifics(RefreshKind::everything()))), + system_average_load: GaugeVec::new( + Opts::new(metric_name(None, "system_average_load"), "System load average"), + &["over"], + )?, + process_cpu_usage_percentage: Gauge::new( + metric_name(None, "process_cpu_usage_percentage"), + "Process CPU usage", + )?, + process_memory_usage_bytes: Gauge::new( + metric_name(None, "process_memory_usage_bytes"), + "Process memory (resident set size) usage", + )?, + }) + } +} + +impl Metric for GlobalMetrics { + fn register(&self, registry: &Registry) -> Result<(), PrometheusError> { + register(self.system_average_load.clone(), registry)?; + register(self.process_cpu_usage_percentage.clone(), registry)?; + register(self.process_memory_usage_bytes.clone(), registry)?; + Ok(()) + } +} + +#[async_trait] +impl StandaloneMetric for GlobalMetrics { + async fn update(&self) { + // update system-wide metrics + let mut system = self.system.lock().await; + let load = system.load_average(); + self.system_average_load.with_label_values(&["1min"]).set(load.one); + self.system_average_load.with_label_values(&["5min"]).set(load.five); + self.system_average_load.with_label_values(&["15min"]).set(load.fifteen); + + // update process-related metrics + let pid = sysinfo::get_current_pid().expect( + "only fails where pid is unavailable (os=unknown || arch=wasm32);\ + relay is not supposed to run in such MetricsParamss;\ + qed", + ); + let is_process_refreshed = system.refresh_process(pid); + match (is_process_refreshed, system.process(pid)) { + (true, Some(process_info)) => { + let cpu_usage = process_info.cpu_usage() as f64; + let memory_usage = process_info.memory() * 1024; + log::trace!( + target: "bridge-metrics", + "Refreshed process metrics: CPU={}, memory={}", + cpu_usage, + memory_usage, + ); + + self.process_cpu_usage_percentage.set(if cpu_usage.is_finite() { + cpu_usage + } else { + 0f64 + }); + self.process_memory_usage_bytes.set(memory_usage); + }, + _ => { + log::warn!( + target: "bridge-metrics", + "Failed to refresh process information. Metrics may show obsolete values", + ); + }, + } + } + + fn update_interval(&self) -> Duration { + UPDATE_INTERVAL + } +} diff --git a/relays/utils/src/relay_loop.rs b/relays/utils/src/relay_loop.rs new file mode 100644 index 00000000000..11e14744a07 --- /dev/null +++ b/relays/utils/src/relay_loop.rs @@ -0,0 +1,269 @@ +// Copyright 2019-2021 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 . + +use crate::{ + error::Error, + metrics::{Metric, MetricsAddress, MetricsParams}, + FailedClient, MaybeConnectionError, +}; + +use async_trait::async_trait; +use std::{fmt::Debug, future::Future, net::SocketAddr, time::Duration}; +use substrate_prometheus_endpoint::{init_prometheus, Registry}; + +/// Default pause between reconnect attempts. +pub const RECONNECT_DELAY: Duration = Duration::from_secs(10); + +/// Basic blockchain client from relay perspective. +#[async_trait] +pub trait Client: 'static + Clone + Send + Sync { + /// Type of error these clients returns. + type Error: 'static + Debug + MaybeConnectionError + Send + Sync; + + /// Try to reconnect to source node. + async fn reconnect(&mut self) -> Result<(), Self::Error>; +} + +#[async_trait] +impl Client for () { + type Error = crate::StringifiedMaybeConnectionError; + + async fn reconnect(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +/// Returns generic loop that may be customized and started. +pub fn relay_loop(source_client: SC, target_client: TC) -> Loop { + Loop { reconnect_delay: RECONNECT_DELAY, source_client, target_client, loop_metric: None } +} + +/// Returns generic relay loop metrics that may be customized and used in one or several relay +/// loops. +pub fn relay_metrics(params: MetricsParams) -> LoopMetrics<(), (), ()> { + LoopMetrics { + relay_loop: Loop { + reconnect_delay: RECONNECT_DELAY, + source_client: (), + target_client: (), + loop_metric: None, + }, + address: params.address, + registry: params.registry, + loop_metric: None, + } +} + +/// Generic relay loop. +pub struct Loop { + reconnect_delay: Duration, + source_client: SC, + target_client: TC, + loop_metric: Option, +} + +/// Relay loop metrics builder. +pub struct LoopMetrics { + relay_loop: Loop, + address: Option, + registry: Registry, + loop_metric: Option, +} + +impl Loop { + /// Customize delay between reconnect attempts. + #[must_use] + pub fn reconnect_delay(mut self, reconnect_delay: Duration) -> Self { + self.reconnect_delay = reconnect_delay; + self + } + + /// Start building loop metrics using given prefix. + pub fn with_metrics(self, params: MetricsParams) -> LoopMetrics { + LoopMetrics { + relay_loop: Loop { + reconnect_delay: self.reconnect_delay, + source_client: self.source_client, + target_client: self.target_client, + loop_metric: None, + }, + address: params.address, + registry: params.registry, + loop_metric: None, + } + } + + /// Run relay loop. + /// + /// This function represents an outer loop, which in turn calls provided `run_loop` function to + /// do actual job. When `run_loop` returns, this outer loop reconnects to failed client (source, + /// target or both) and calls `run_loop` again. + pub async fn run(mut self, loop_name: String, run_loop: R) -> Result<(), Error> + where + R: 'static + Send + Fn(SC, TC, Option) -> F, + F: 'static + Send + Future>, + SC: 'static + Client, + TC: 'static + Client, + LM: 'static + Send + Clone, + { + let run_loop_task = async move { + crate::initialize::initialize_loop(loop_name); + + loop { + let loop_metric = self.loop_metric.clone(); + let future_result = + run_loop(self.source_client.clone(), self.target_client.clone(), loop_metric); + let result = future_result.await; + + match result { + Ok(()) => break, + Err(failed_client) => + reconnect_failed_client( + failed_client, + self.reconnect_delay, + &mut self.source_client, + &mut self.target_client, + ) + .await, + } + + log::debug!(target: "bridge", "Restarting relay loop"); + } + + Ok(()) + }; + + async_std::task::spawn(run_loop_task).await + } +} + +impl LoopMetrics { + /// Add relay loop metrics. + /// + /// Loop metrics will be passed to the loop callback. + pub fn loop_metric( + self, + metric: NewLM, + ) -> Result, Error> { + metric.register(&self.registry)?; + + Ok(LoopMetrics { + relay_loop: self.relay_loop, + address: self.address, + registry: self.registry, + loop_metric: Some(metric), + }) + } + + /// Convert into `MetricsParams` structure so that metrics registry may be extended later. + pub fn into_params(self) -> MetricsParams { + MetricsParams { address: self.address, registry: self.registry } + } + + /// Expose metrics using address passed at creation. + /// + /// If passed `address` is `None`, metrics are not exposed. + pub async fn expose(self) -> Result, Error> { + if let Some(address) = self.address { + let socket_addr = SocketAddr::new( + address + .host + .parse() + .map_err(|err| Error::ExposingMetricsInvalidHost(address.host.clone(), err))?, + address.port, + ); + + let registry = self.registry; + async_std::task::spawn(async move { + let runtime = + match tokio::runtime::Builder::new_current_thread().enable_all().build() { + Ok(runtime) => runtime, + Err(err) => { + log::trace!( + target: "bridge-metrics", + "Failed to create tokio runtime. Prometheus meterics are not available: {:?}", + err, + ); + return + }, + }; + + runtime.block_on(async move { + log::trace!( + target: "bridge-metrics", + "Starting prometheus endpoint at: {:?}", + socket_addr, + ); + let result = init_prometheus(socket_addr, registry).await; + log::trace!( + target: "bridge-metrics", + "Prometheus endpoint has exited with result: {:?}", + result, + ); + }); + }); + } + + Ok(Loop { + reconnect_delay: self.relay_loop.reconnect_delay, + source_client: self.relay_loop.source_client, + target_client: self.relay_loop.target_client, + loop_metric: self.loop_metric, + }) + } +} + +/// Deal with the client who has returned connection error. +pub async fn reconnect_failed_client( + failed_client: FailedClient, + reconnect_delay: Duration, + source_client: &mut impl Client, + target_client: &mut impl Client, +) { + loop { + async_std::task::sleep(reconnect_delay).await; + if failed_client == FailedClient::Both || failed_client == FailedClient::Source { + match source_client.reconnect().await { + Ok(()) => (), + Err(error) => { + log::warn!( + target: "bridge", + "Failed to reconnect to source client. Going to retry in {}s: {:?}", + reconnect_delay.as_secs(), + error, + ); + continue + }, + } + } + if failed_client == FailedClient::Both || failed_client == FailedClient::Target { + match target_client.reconnect().await { + Ok(()) => (), + Err(error) => { + log::warn!( + target: "bridge", + "Failed to reconnect to target client. Going to retry in {}s: {:?}", + reconnect_delay.as_secs(), + error, + ); + continue + }, + } + } + + break + } +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000000..082150daf04 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,24 @@ +# 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/scripts/add_license.sh b/scripts/add_license.sh new file mode 100755 index 00000000000..49864b47c05 --- /dev/null +++ b/scripts/add_license.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +PAT_GPL="^// Copyright.*If not, see \.$" +PAT_OTHER="^// Copyright" + +SCRIPTS_DIR=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) + +for f in $(find . -type f | egrep '\.(c|cpp|rs)$'); do + HEADER=$(head -16 $f) + if [[ $HEADER =~ $PAT_GPL ]]; then + BODY=$(tail -n +17 $f) + cat $SCRIPTS_DIR/license_header > temp + echo "$BODY" >> temp + mv temp $f + elif [[ $HEADER =~ $PAT_OTHER ]]; then + echo "Other license was found do nothing" + else + echo "$f was missing header" + cat $SCRIPTS_DIR/license_header $f > temp + mv temp $f + fi +done diff --git a/scripts/build-containers.sh b/scripts/build-containers.sh new file mode 100755 index 00000000000..d0af254d93f --- /dev/null +++ b/scripts/build-containers.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -eux + +time docker build . -t local/substrate-relay --build-arg=PROJECT=substrate-relay +time docker build . -t local/rialto-bridge-node --build-arg=PROJECT=rialto-bridge-node +time docker build . -t local/millau-bridge-node --build-arg=PROJECT=millau-bridge-node +time docker build . -t local/rialto-parachain-collator --build-arg=PROJECT=rialto-parachain-collator diff --git a/scripts/ci-cache.sh b/scripts/ci-cache.sh new file mode 100755 index 00000000000..040d44fa74a --- /dev/null +++ b/scripts/ci-cache.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -xeu + +echo $CARGO_TARGET_DIR; +mkdir -p $CARGO_TARGET_DIR; +echo "Current Rust nightly version:"; +rustc +nightly --version; +echo "Cached Rust nightly version:"; +if [ ! -f $CARGO_TARGET_DIR/check_nightly_rust ]; then + echo "" > $CARGO_TARGET_DIR/check_nightly_rust; +fi +cat $CARGO_TARGET_DIR/check_nightly_rust; +if [[ $(cat $CARGO_TARGET_DIR/check_nightly_rust) == $(rustc +nightly --version) ]]; then + echo "The Rust nightly version has not changed"; +else + echo "The Rust nightly version has changed. Clearing the cache"; + rm -rf $CARGO_TARGET_DIR/*; +fi diff --git a/scripts/dump-logs.sh b/scripts/dump-logs.sh new file mode 100755 index 00000000000..709a5065887 --- /dev/null +++ b/scripts/dump-logs.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +# A script to dump logs from selected important docker containers +# to make it easier to analyze locally. + +set -xeu + +DATE=$(date +"%Y-%m-%d-%T") +LOGS_DIR="${DATE//:/-}-logs" +mkdir $LOGS_DIR +cd $LOGS_DIR + +# From $ docker ps --format '{{.Names}}' + +SERVICES=(\ + deployments_relay-messages-millau-to-rialto-generator_1 \ + deployments_relay-messages-rialto-to-millau-generator_1 \ + deployments_relay-millau-rialto_1 \ + deployments_relay-headers-westend-to-millau-1_1 \ + deployments_relay-headers-westend-to-millau-2_1 \ + deployments_relay-parachains-westend-to-millau-1_1 \ + deployments_relay-parachains-westend-to-millau-1_2 \ + deployments_relay-messages-millau-to-rialto-parachain-generator_1 \ + deployments_relay-messages-rialto-parachain-to-millau-generator_1 \ + deployments_relay-millau-rialto-parachain-1_1 \ + deployments_relay-millau-rialto-parachain-2_1 \ + deployments_rialto-node-alice_1 \ + deployments_rialto-node-bob_1 \ + deployments_millau-node-alice_1 \ + deployments_millau-node-bob_1 \ + deployments_rialto-parachain-collator-alice_1 \ + deployments_rialto-parachain-collator-bob_1 \ + deployments_relay-messages-millau-to-rialto-resubmitter_1 \ + deployments_relay-messages-millau-to-rialto-parachain-resubmitter_1 \ +) + +for SVC in ${SERVICES[*]} +do + SHORT_NAME="${SVC//deployments_/}" + docker logs $SVC &> $SHORT_NAME.log | true +done + +cd - +tar cvjf $LOGS_DIR.tar.bz2 $LOGS_DIR diff --git a/scripts/license_header b/scripts/license_header new file mode 100644 index 00000000000..f9b301209bb --- /dev/null +++ b/scripts/license_header @@ -0,0 +1,16 @@ +// Copyright 2019-2021 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 . + diff --git a/scripts/send-message-from-millau-rialto.sh b/scripts/send-message-from-millau-rialto.sh new file mode 100755 index 00000000000..1a736b4f8bd --- /dev/null +++ b/scripts/send-message-from-millau-rialto.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Used for manually sending a message to a running network. +# +# You could for example spin up a full network using the Docker Compose files +# we have (to make sure the message relays are running), but remove the message +# generator service. From there you may submit messages manually using this script. + +# TODO: Fix demeo scripts https://github.com/paritytech/parity-bridges-common/issues/1406 + +MILLAU_PORT="${MILLAU_PORT:-9945}" + +RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ +./target/debug/substrate-relay send-message millau-to-rialto \ + --source-host localhost \ + --source-port $MILLAU_PORT \ + --source-signer //Alice \ + raw 030426020109020419a8 diff --git a/scripts/send-message-from-rialto-millau.sh b/scripts/send-message-from-rialto-millau.sh new file mode 100755 index 00000000000..8133978f6ce --- /dev/null +++ b/scripts/send-message-from-rialto-millau.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Used for manually sending a message to a running network. +# +# You could for example spin up a full network using the Docker Compose files +# we have (to make sure the message relays are running), but remove the message +# generator service. From there you may submit messages manually using this script. + +# TODO: Fix demeo scripts https://github.com/paritytech/parity-bridges-common/issues/1406 + +RIALTO_PORT="${RIALTO_PORT:-9944}" + +RUST_LOG=runtime=trace,substrate-relay=trace,bridge=trace \ +./target/debug/substrate-relay send-message rialto-to-millau \ + --source-host localhost \ + --source-port $RIALTO_PORT \ + --source-signer //Bob \ + raw 030426030109030419a8 diff --git a/scripts/update-weights-setup.sh b/scripts/update-weights-setup.sh new file mode 100644 index 00000000000..72534423d63 --- /dev/null +++ b/scripts/update-weights-setup.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -exu + +# Set up the standardized machine and run `update-weights.sh` script. +# The system is assumed to be pristine Ubuntu 20.04 and we install +# all required dependencies. + +# To avoid interruptions you might want to run this script in `screen` cause it will take a while +# to finish. + +# We start off with upgrading the system +apt update && apt dist-upgrade + +# and installing `git` and other required deps. +apt install -y git clang curl libssl-dev llvm libudev-dev screen + +# Now we clone the repository +git clone https://github.com/paritytech/parity-bridges-common.git +cd parity-bridges-common + +# Install rustup & toolchain +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y + +# Source config +source ~/.cargo/env + +# Add nightly and WASM +rustup install nightly +rustup target add wasm32-unknown-unknown --toolchain nightly + +# Update the weights +./scripts/update-weights.sh diff --git a/scripts/update-weights.sh b/scripts/update-weights.sh new file mode 100755 index 00000000000..84ddf0cdaae --- /dev/null +++ b/scripts/update-weights.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# +# Runtime benchmarks for the `pallet-bridge-messages` and `pallet-bridge-grandpa` pallets. +# +# Run this script from root of the repo. + +set -eux + +time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet \ + --chain=dev \ + --steps=50 \ + --repeat=20 \ + --pallet=RialtoMessages \ + --extrinsic=* \ + --execution=wasm \ + --wasm-execution=Compiled \ + --heap-pages=4096 \ + --output=./modules/messages/src/weights.rs \ + --template=./.maintain/millau-weight-template.hbs + +time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet \ + --chain=dev \ + --steps=50 \ + --repeat=20 \ + --pallet=pallet_bridge_grandpa \ + --extrinsic=* \ + --execution=wasm \ + --wasm-execution=Compiled \ + --heap-pages=4096 \ + --output=./modules/grandpa/src/weights.rs \ + --template=./.maintain/millau-weight-template.hbs + +time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet \ + --chain=dev \ + --steps=50 \ + --repeat=20 \ + --pallet=pallet_bridge_parachains \ + --extrinsic=* \ + --execution=wasm \ + --wasm-execution=Compiled \ + --heap-pages=4096 \ + --output=./modules/parachains/src/weights.rs \ + --template=./.maintain/millau-weight-template.hbs + +time cargo run --release -p millau-bridge-node --features=runtime-benchmarks -- benchmark pallet \ + --chain=dev \ + --steps=50 \ + --repeat=20 \ + --pallet=pallet_bridge_relayers \ + --extrinsic=* \ + --execution=wasm \ + --wasm-execution=Compiled \ + --heap-pages=4096 \ + --output=./modules/relayers/src/weights.rs \ + --template=./.maintain/millau-weight-template.hbs diff --git a/scripts/update_substrate.sh b/scripts/update_substrate.sh new file mode 100755 index 00000000000..f7715bda5d1 --- /dev/null +++ b/scripts/update_substrate.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# One-liner to update between Substrate releases +# Usage: ./update_substrate.sh 2.0.0-rc6 2.0.0 +set -xeu + +OLD_VERSION=$1 +NEW_VERSION=$2 + +find . -type f -name 'Cargo.toml' -exec sed -i '' -e "s/$OLD_VERSION/$NEW_VERSION/g" {} \; diff --git a/scripts/verify-pallets-build.sh b/scripts/verify-pallets-build.sh new file mode 100755 index 00000000000..ad69c5df008 --- /dev/null +++ b/scripts/verify-pallets-build.sh @@ -0,0 +1,133 @@ +#!/bin/bash + +# A script to remove everything from bridges repository/subtree, except: +# +# - modules/grandpa; +# - modules/messages; +# - modules/parachains; +# - modules/relayers; +# - everything required from primitives folder. + +set -eux + +# show CLI help +function show_help() { + set +x + echo " " + echo Error: $1 + echo "Usage:" + echo " ./scripts/verify-pallets-build.sh Exit with code 0 if pallets code is well decoupled from the other code in the repo" + echo "Options:" + echo " --no-revert Leaves only runtime code on exit" + echo " --ignore-git-state Ignores git actual state" + exit 1 +} + +# parse CLI args +NO_REVERT= +IGNORE_GIT_STATE= +for i in "$@" +do + case $i in + --no-revert) + NO_REVERT=true + shift + ;; + --ignore-git-state) + IGNORE_GIT_STATE=true + shift + ;; + *) + show_help "Unknown option: $i" + ;; + esac +done + +# the script is able to work only on clean git copy, unless we want to ignore this check +[[ ! -z "${IGNORE_GIT_STATE}" ]] || [[ -z "$(git status --porcelain)" ]] || { echo >&2 "The git copy must be clean"; exit 1; } + +# let's avoid any restrictions on where this script can be called for - bridges repo may be +# plugged into any other repo folder. So the script (and other stuff that needs to be removed) +# may be located either in call dir, or one of it subdirs. +BRIDGES_FOLDER="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/.." + +# let's leave repository/subtree in its original (clean) state if something fails below +function revert_to_clean_state { + [[ ! -z "${NO_REVERT}" ]] || { echo "Reverting to clean state..."; git checkout .; } +} +trap revert_to_clean_state EXIT + +# remove everything we think is not required for our needs +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/primitives/chain-westend +rm -rf $BRIDGES_FOLDER/relays +rm -rf $BRIDGES_FOLDER/scripts/add_license.sh +rm -rf $BRIDGES_FOLDER/scripts/build-containers.sh +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/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 +rm -rf $BRIDGES_FOLDER/tools +rm -f $BRIDGES_FOLDER/.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/Dockerfile + +# 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] + resolver = "2" + + members = [ + "bin/runtime-common", + "modules/*", + "primitives/*", + ] + CARGO_TOML +fi + +# let's test if everything we need compiles + +cargo check -p pallet-bridge-grandpa +cargo check -p pallet-bridge-grandpa --features runtime-benchmarks +cargo check -p pallet-bridge-grandpa --features try-runtime +cargo check -p pallet-bridge-messages +cargo check -p pallet-bridge-messages --features runtime-benchmarks +cargo check -p pallet-bridge-messages --features try-runtime +cargo check -p pallet-bridge-parachains +cargo check -p pallet-bridge-parachains --features runtime-benchmarks +cargo check -p pallet-bridge-parachains --features try-runtime +cargo check -p pallet-bridge-relayers +cargo check -p pallet-bridge-relayers --features runtime-benchmarks +cargo check -p pallet-bridge-relayers --features try-runtime +cargo check -p bridge-runtime-common +cargo check -p bridge-runtime-common --features runtime-benchmarks + +# we're removing lock file after all chechs are done. Otherwise we may use different +# Substrate/Polkadot/Cumulus commits and our checks will fail +rm -f $BRIDGES_FOLDER/Cargo.lock + +echo "OK" diff --git a/tools/runtime-codegen/Cargo.lock b/tools/runtime-codegen/Cargo.lock new file mode 100644 index 00000000000..46093b70727 --- /dev/null +++ b/tools/runtime-codegen/Cargo.lock @@ -0,0 +1,4508 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli 0.26.2", +] + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli 0.27.2", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.8", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom 0.2.8", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + +[[package]] +name = "array-bytes" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52f63c5c1316a16a4b35eaac8b76a98248961a533f061684cb2a7cb0eafb6c6" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-lock" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-trait" +version = "0.1.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ea188f25f0255d8f92797797c97ebf5631fa88178beb1a46fdf5622c9a00e4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.8", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line 0.19.0", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object 0.30.3", + "rustc-demangle", +] + +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +dependencies = [ + "serde", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "bounded-collections" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a071c348a5ef6da1d3a87166b408170b46002382b1dda83992b5c2208cefb370" +dependencies = [ + "log", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +dependencies = [ + "iana-time-zone", + "num-integer", + "num-traits", + "winapi", +] + +[[package]] +name = "clap" +version = "4.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c911b090850d79fc64fe9ea01e28e465f65e821e08813ced95bced72f7a8a9b" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "is-terminal", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a932373bab67b984c790ddf2c9ca295d8e3af3b7ef92de5a5bacdccdee4b09b" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.8", +] + +[[package]] +name = "clap_lex" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "color-eyre" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "cpp_demangle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaa953eaad386a53111e47172c2fedba671e5684c8dd601a5f474f4f118710f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7379abaacee0f14abf3204a7606118f0465785252169d186337bcb75030815a" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9489fa336927df749631f1008007ced2871068544f40a202ce6d93fbf2366a7b" +dependencies = [ + "arrayvec 0.7.2", + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-entity", + "cranelift-isle", + "gimli 0.26.2", + "hashbrown 0.12.3", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05bbb67da91ec721ed57cef2f7c5ef7728e1cd9bde9ffd3ef8601022e73e3239" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418ecb2f36032f6665dc1a5e2060a143dbab41d83b784882e97710e890a7a16d" + +[[package]] +name = "cranelift-entity" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705" +dependencies = [ + "serde", +] + +[[package]] +name = "cranelift-frontend" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b66bf9e916f57fbbd0f7703ec6286f4624866bf45000111627c70d272c8dda1" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649782a39ce99798dd6b4029e2bb318a2fbeaade1b4fa25330763c10c65bc358" + +[[package]] +name = "cranelift-native" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "937e021e089c51f9749d09e7ad1c4f255c2f8686cb8c3df63a34b3ec9921bc41" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.93.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d850cf6775477747c9dfda9ae23355dd70512ffebc70cf82b85a5b111ae668b5" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset 0.8.0", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.6", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array 0.14.6", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b85542f99a2dfa2a1b8e192662741c9859a846b296bef1c92ef9b58b5a216" +dependencies = [ + "byteorder", + "digest 0.8.1", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cxx" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c00419335c41018365ddf7e4d5f1c12ee3659ddcf3e01974650ba1de73d038" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8307ad413a98fff033c8545ecf133e3257747b3bae935e7602aab8aa92d4ca" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.8", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc52e2eb08915cb12596d29d55f0b5384f00d697a646dbd269b6ecb0fbd9d31" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "631569015d0d8d54e6c241733f944042623ab6df7bc3be7466874b05fcdb1c5f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.8", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.6", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "dyn-clonable" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +dependencies = [ + "dyn-clonable-impl", + "dyn-clone", +] + +[[package]] +name = "dyn-clonable-impl" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[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", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "environmental" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "file-per-thread-logger" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f2e425d9790201ba4af4630191feac6dcc98765b118d4d18e91d23c2353866" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "frame-metadata" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df6bb8542ef006ef0de09a5c4420787d79823c0ed7924225822362fd2bf2ff2d" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", + "serde", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" + +[[package]] +name = "futures-executor" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" + +[[package]] +name = "futures-macro" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "futures-sink" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" + +[[package]] +name = "futures-task" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +dependencies = [ + "gloo-timers", + "send_wrapper", +] + +[[package]] +name = "futures-util" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + +[[package]] +name = "gloo-net" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-utils" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "h2" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash-db" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" + +[[package]] +name = "hash256-std-hasher" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac 0.11.1", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.6", + "hmac 0.8.1", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +dependencies = [ + "http", + "hyper", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "webpki-roots", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "integer-sqrt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770" +dependencies = [ + "num-traits", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonrpsee" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d291e3a5818a2384645fd9756362e6d89cf0541b0b916fa7702ea4a9833608e" +dependencies = [ + "jsonrpsee-client-transport 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpsee-core 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpsee-http-client 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpsee-types 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "jsonrpsee" +version = "0.16.2" +source = "git+https://github.com/paritytech/jsonrpsee#7144be544f6fbbb607a5df858b736a2b917edc10" +dependencies = [ + "jsonrpsee-client-transport 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-core 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-http-client 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-types 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-wasm-client", + "jsonrpsee-ws-client", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965de52763f2004bc91ac5bcec504192440f0b568a5d621c59d9dbd6f886c3fb" +dependencies = [ + "futures-util", + "http", + "jsonrpsee-core 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpsee-types 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project", + "rustls-native-certs", + "soketto", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "webpki-roots", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.16.2" +source = "git+https://github.com/paritytech/jsonrpsee#7144be544f6fbbb607a5df858b736a2b917edc10" +dependencies = [ + "futures-channel", + "futures-util", + "gloo-net", + "http", + "jsonrpsee-core 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "pin-project", + "rustls-native-certs", + "soketto", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "webpki-roots", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e70b4439a751a5de7dd5ed55eacff78ebf4ffe0fc009cb1ebb11417f5b536b" +dependencies = [ + "anyhow", + "async-lock", + "async-trait", + "beef", + "futures-channel", + "futures-timer", + "futures-util", + "hyper", + "jsonrpsee-types 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.16.2" +source = "git+https://github.com/paritytech/jsonrpsee#7144be544f6fbbb607a5df858b736a2b917edc10" +dependencies = [ + "anyhow", + "async-lock", + "async-trait", + "beef", + "futures-timer", + "futures-util", + "hyper", + "jsonrpsee-types 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc345b0a43c6bc49b947ebeb936e886a419ee3d894421790c969cc56040542ad" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpsee-types 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.16.2" +source = "git+https://github.com/paritytech/jsonrpsee#7144be544f6fbbb607a5df858b736a2b917edc10" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-types 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd522fe1ce3702fd94812965d7bb7a3364b1c9aba743944c5a00529aae80f8c" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.16.2" +source = "git+https://github.com/paritytech/jsonrpsee#7144be544f6fbbb607a5df858b736a2b917edc10" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "jsonrpsee-wasm-client" +version = "0.16.2" +source = "git+https://github.com/paritytech/jsonrpsee#7144be544f6fbbb607a5df858b736a2b917edc10" +dependencies = [ + "jsonrpsee-client-transport 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-core 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-types 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.16.2" +source = "git+https://github.com/paritytech/jsonrpsee#7144be544f6fbbb607a5df858b736a2b917edc10" +dependencies = [ + "http", + "jsonrpsee-client-transport 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-core 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "jsonrpsee-types 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lru" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" +dependencies = [ + "hashbrown 0.12.3", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memfd" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b20a59d985586e4a5aef64564ac77299f8586d8be6cf9106a5a40207e8908efb" +dependencies = [ + "rustix", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memory-db" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0c7cba9ce19ac7ffd2053ac9f49843bbd3f4318feedfd74e85c19d5fb0ba66" +dependencies = [ + "hash-db", + "hashbrown 0.12.3", +] + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "merlin" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e261cf0f8b3c42ded9f7d2bb59dea03aa52bc8a1cbc7482f9fc3fd1229d3b42" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.5.1", + "zeroize", +] + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.45.0", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec 0.7.2", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "crc32fast", + "hashbrown 0.12.3", + "indexmap", + "memchr", +] + +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "os_str_bytes" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "parity-scale-codec" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637935964ff85a605d114591d4d2c13c5d1ba2806dae97cea6bf180238a749ac" +dependencies = [ + "arrayvec 0.7.2", + "bitvec", + "byte-slice-cast", + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parity-wasm" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "pbkdf2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" +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.6", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.8", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.8", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43faa91b1c8b36841ee70e97188a869d37ae21759da6846d4be66de5bf7b12c" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.8", +] + +[[package]] +name = "regalloc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "region" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e189c2369884dce920945e2ddf79b3dff49e071a167dd1817fa9c4c00d512e" +dependencies = [ + "bitflags", + "libc", + "mach", + "winapi", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "runtime-codegen" +version = "0.1.0" +dependencies = [ + "clap", + "color-eyre", + "parity-scale-codec", + "proc-macro2", + "subxt-codegen", + "syn 1.0.109", + "wasm-loader", + "wasm-testbed", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustix" +version = "0.36.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.0", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "sc-allocator" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "log", + "sp-core", + "sp-wasm-interface", + "thiserror", +] + +[[package]] +name = "sc-executor" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "lru", + "parity-scale-codec", + "parking_lot", + "sc-executor-common", + "sc-executor-wasmi", + "sc-executor-wasmtime", + "sp-api", + "sp-core", + "sp-externalities", + "sp-io", + "sp-panic-handler", + "sp-runtime-interface", + "sp-trie", + "sp-version", + "sp-wasm-interface", + "tracing", + "wasmi", +] + +[[package]] +name = "sc-executor-common" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "sc-allocator", + "sp-maybe-compressed-blob", + "sp-wasm-interface", + "thiserror", + "wasm-instrument", + "wasmi", +] + +[[package]] +name = "sc-executor-wasmi" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "log", + "sc-allocator", + "sc-executor-common", + "sp-runtime-interface", + "sp-wasm-interface", + "wasmi", +] + +[[package]] +name = "sc-executor-wasmtime" +version = "0.10.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "log", + "once_cell", + "rustix", + "sc-allocator", + "sc-executor-common", + "sp-runtime-interface", + "sp-wasm-interface", + "wasmtime", +] + +[[package]] +name = "scale-info" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61471dff9096de1d8b2319efed7162081e96793f5ebb147e50db10d50d648a4d" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219580e803a66b3f05761fd06f1f879a872444e49ce23f73694d26e5a954c7e6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "schnellru" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +dependencies = [ + "ahash 0.8.3", + "cfg-if", + "hashbrown 0.13.2", +] + +[[package]] +name = "schnorrkel" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021b403afe70d81eea68f6ea12f6b3c9588e5d536a94c3bf80f15e7faa267862" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "curve25519-dalek 2.1.3", + "getrandom 0.1.16", + "merlin", + "rand 0.7.3", + "rand_core 0.5.1", + "sha2 0.8.2", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scratch" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secp256k1" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "serde" +version = "1.0.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.8", +] + +[[package]] +name = "serde_json" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +dependencies = [ + "digest 0.10.6", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b634d87b960ab1a38c4fe143b508576f075e7c978bfad18217645ebfdfa2ec" + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +dependencies = [ + "base64 0.13.1", + "bytes", + "futures", + "httparse", + "log", + "rand 0.8.5", + "sha-1", +] + +[[package]] +name = "sp-api" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "sp-api-proc-macro", + "sp-core", + "sp-runtime", + "sp-state-machine", + "sp-std 5.0.0", + "sp-trie", + "sp-version", + "thiserror", +] + +[[package]] +name = "sp-api-proc-macro" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "blake2", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp-application-crypto" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-arithmetic" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std 5.0.0", + "static_assertions", +] + +[[package]] +name = "sp-core" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "array-bytes", + "base58", + "bitflags", + "blake2", + "bounded-collections", + "dyn-clonable", + "ed25519-zebra", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde", + "lazy_static", + "libsecp256k1", + "log", + "merlin", + "parity-scale-codec", + "parking_lot", + "primitive-types", + "rand 0.8.5", + "regex", + "scale-info", + "schnorrkel", + "secp256k1", + "secrecy", + "serde", + "sp-core-hashing 5.0.0", + "sp-debug-derive", + "sp-externalities", + "sp-runtime-interface", + "sp-std 5.0.0", + "sp-storage", + "ss58-registry", + "substrate-bip39", + "thiserror", + "tiny-bip39", + "zeroize", +] + +[[package]] +name = "sp-core-hashing" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "blake2", + "byteorder", + "digest 0.10.6", + "sha2 0.10.6", + "sha3", + "sp-std 5.0.0", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc2d1947252b7a4e403b0a260f596920443742791765ec111daa2bbf98eff25" +dependencies = [ + "blake2", + "byteorder", + "digest 0.10.6", + "sha2 0.10.6", + "sha3", + "sp-std 6.0.0", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing-proc-macro" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "proc-macro2", + "quote", + "sp-core-hashing 5.0.0", + "syn 1.0.109", +] + +[[package]] +name = "sp-debug-derive" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp-externalities" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-std 5.0.0", + "sp-storage", +] + +[[package]] +name = "sp-io" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "bytes", + "ed25519", + "ed25519-dalek", + "futures", + "libsecp256k1", + "log", + "parity-scale-codec", + "secp256k1", + "sp-core", + "sp-externalities", + "sp-keystore", + "sp-runtime-interface", + "sp-state-machine", + "sp-std 5.0.0", + "sp-tracing", + "sp-trie", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-keystore" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "async-trait", + "futures", + "merlin", + "parity-scale-codec", + "parking_lot", + "schnorrkel", + "sp-core", + "sp-externalities", + "thiserror", +] + +[[package]] +name = "sp-maybe-compressed-blob" +version = "4.1.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "thiserror", + "zstd", +] + +[[package]] +name = "sp-panic-handler" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "backtrace", + "lazy_static", + "regex", +] + +[[package]] +name = "sp-runtime" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "paste", + "rand 0.8.5", + "scale-info", + "serde", + "sp-application-crypto", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-std 5.0.0", + "sp-weights", +] + +[[package]] +name = "sp-runtime-interface" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "primitive-types", + "sp-externalities", + "sp-runtime-interface-proc-macro", + "sp-std 5.0.0", + "sp-storage", + "sp-tracing", + "sp-wasm-interface", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "Inflector", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp-state-machine" +version = "0.13.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "parking_lot", + "rand 0.8.5", + "smallvec", + "sp-core", + "sp-externalities", + "sp-panic-handler", + "sp-std 5.0.0", + "sp-trie", + "thiserror", + "tracing", +] + +[[package]] +name = "sp-std" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" + +[[package]] +name = "sp-std" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af0ee286f98455272f64ac5bb1384ff21ac029fbb669afbaf48477faff12760e" + +[[package]] +name = "sp-storage" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive", + "sp-std 5.0.0", +] + +[[package]] +name = "sp-tracing" +version = "6.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "parity-scale-codec", + "sp-std 5.0.0", + "tracing", + "tracing-core", + "tracing-subscriber 0.2.25", +] + +[[package]] +name = "sp-trie" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "ahash 0.8.3", + "hash-db", + "hashbrown 0.12.3", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot", + "scale-info", + "schnellru", + "sp-core", + "sp-std 5.0.0", + "thiserror", + "tracing", + "trie-db", + "trie-root", +] + +[[package]] +name = "sp-version" +version = "5.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "impl-serde", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-core-hashing-proc-macro", + "sp-runtime", + "sp-std 5.0.0", + "sp-version-proc-macro", + "thiserror", +] + +[[package]] +name = "sp-version-proc-macro" +version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "parity-scale-codec", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp-wasm-interface" +version = "7.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std 5.0.0", + "wasmi", + "wasmtime", +] + +[[package]] +name = "sp-weights" +version = "4.0.0" +source = "git+https://github.com/paritytech/substrate?tag=monthly-2023-03#ad5399644aebc54e32a107ac37ae08e6cd1f0cfb" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic", + "sp-core", + "sp-debug-derive", + "sp-std 5.0.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "ss58-registry" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecf0bd63593ef78eca595a7fc25e9a443ca46fe69fd472f8f09f5245cdcd769d" +dependencies = [ + "Inflector", + "num-format", + "proc-macro2", + "quote", + "serde", + "serde_json", + "unicode-xid", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "substrate-bip39" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49eee6965196b32f882dd2ee85a92b1dbead41b04e53907f269de3b0dc04733c" +dependencies = [ + "hmac 0.11.0", + "pbkdf2 0.8.0", + "schnorrkel", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "substrate-runtime-proposal-hash" +version = "0.19.0" +source = "git+https://github.com/chevdor/subwasm?branch=master#fd047d76d52beab8c062eb94141f8d14ddc0f59d" +dependencies = [ + "blake2", + "hex", + "parity-scale-codec", + "sp-core", + "sp-io", + "sp-runtime", + "sp-wasm-interface", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "subxt-codegen" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e86cb719003f1cedf2710a6e55ca4c37aba4c989bbd3b81dd1c52af9e4827e" +dependencies = [ + "darling", + "frame-metadata", + "heck", + "hex", + "jsonrpsee 0.16.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec", + "proc-macro-error", + "proc-macro2", + "quote", + "scale-info", + "subxt-metadata", + "syn 1.0.109", + "tokio", +] + +[[package]] +name = "subxt-metadata" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2593ab5f53435e6352675af4f9851342607f37785d84c7a3fb3139550d3c35f0" +dependencies = [ + "frame-metadata", + "parity-scale-codec", + "scale-info", + "sp-core-hashing 6.0.0", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae9980cab1db3fceee2f6c6f643d5d8de2997c58ee8d25fb0cc8a9e9e7348e5" + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.8", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[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.6", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.45.0", +] + +[[package]] +name = "tokio-macros" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber 0.3.16", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "trie-db" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3390c0409daaa6027d6681393316f4ccd3ff82e1590a1e4725014e3ae2bf1920" +dependencies = [ + "hash-db", + "hashbrown 0.13.2", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-root" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a36c5ca3911ed3c9a5416ee6c679042064b93fc637ded67e25f92e68d783891" +dependencies = [ + "hash-db", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "digest 0.10.6", + "rand 0.8.5", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "wasm-instrument" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa1dafb3e60065305741e83db35c6c2584bb3725b692b5b66148a38d72ace6cd" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "wasm-loader" +version = "0.19.0" +source = "git+https://github.com/chevdor/subwasm?branch=master#fd047d76d52beab8c062eb94141f8d14ddc0f59d" +dependencies = [ + "hex", + "jsonrpsee 0.16.2 (git+https://github.com/paritytech/jsonrpsee)", + "log", + "serde", + "sp-maybe-compressed-blob", + "tokio", +] + +[[package]] +name = "wasm-testbed" +version = "0.19.0" +source = "git+https://github.com/chevdor/subwasm?branch=master#fd047d76d52beab8c062eb94141f8d14ddc0f59d" +dependencies = [ + "frame-metadata", + "hex", + "log", + "parity-scale-codec", + "sc-executor", + "sc-executor-common", + "sp-core", + "sp-io", + "sp-runtime", + "sp-state-machine", + "sp-version", + "sp-wasm-interface", + "substrate-runtime-proposal-hash", + "wasm-loader", +] + +[[package]] +name = "wasmi" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c326c93fbf86419608361a2c925a31754cf109da1b8b55737070b4d6669422" +dependencies = [ + "parity-wasm", + "wasmi-validation", + "wasmi_core", +] + +[[package]] +name = "wasmi-validation" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ff416ad1ff0c42e5a926ed5d5fab74c0f098749aa0ad8b2a34b982ce0e867b" +dependencies = [ + "parity-wasm", +] + +[[package]] +name = "wasmi_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" +dependencies = [ + "downcast-rs", + "libm", + "memory_units", + "num-rational", + "num-traits", + "region", +] + +[[package]] +name = "wasmparser" +version = "0.100.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b20236ab624147dfbb62cf12a19aaf66af0e41b8398838b66e997d07d269d4" +dependencies = [ + "indexmap", + "url", +] + +[[package]] +name = "wasmtime" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e89f9819523447330ffd70367ef4a18d8c832e24e8150fe054d1d912841632" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "indexmap", + "libc", + "log", + "object 0.29.0", + "once_cell", + "paste", + "psm", + "rayon", + "serde", + "target-lexicon", + "wasmparser", + "wasmtime-cache", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd3a5e46c198032da934469f3a6e48649d1f9142438e4fd4617b68a35644b8a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "wasmtime-cache" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b389ae9b678b9c3851091a4804f4182d688d27aff7abc9aa37fa7be37d8ecffa" +dependencies = [ + "anyhow", + "base64 0.13.1", + "bincode", + "directories-next", + "file-per-thread-logger", + "log", + "rustix", + "serde", + "sha2 0.10.6", + "toml", + "windows-sys 0.42.0", + "zstd", +] + +[[package]] +name = "wasmtime-cranelift" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b2c92a08c0db6efffd88fdc97d7aa9c7c63b03edb0971dbca745469f820e8c" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli 0.26.2", + "log", + "object 0.29.0", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a6db9fc52985ba06ca601f2ff0ff1f526c5d724c7ac267b47326304b0c97883" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli 0.26.2", + "indexmap", + "log", + "object 0.29.0", + "serde", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b77e3a52cd84d0f7f18554afa8060cfe564ccac61e3b0802d3fd4084772fa5f6" +dependencies = [ + "addr2line 0.17.0", + "anyhow", + "bincode", + "cfg-if", + "cpp_demangle", + "gimli 0.26.2", + "log", + "object 0.29.0", + "rustc-demangle", + "serde", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-debug", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-jit-debug" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0245e8a9347017c7185a72e215218a802ff561545c242953c11ba00fccc930f" +dependencies = [ + "object 0.29.0", + "once_cell", + "rustix", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d412e9340ab1c83867051d8d1d7c90aa8c9afc91da086088068e2734e25064" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d594e791b5fdd4dbaf8cf7ae62f2e4ff85018ce90f483ca6f42947688e48827d" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "indexmap", + "libc", + "log", + "mach", + "memfd", + "memoffset 0.6.5", + "paste", + "rand 0.8.5", + "rustix", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-jit-debug", + "windows-sys 0.42.0", +] + +[[package]] +name = "wasmtime-types" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6688d6f96d4dbc1f89fab626c56c1778936d122b5f4ae7a57c2eb42b8d982e2" +dependencies = [ + "cranelift-entity", + "serde", + "thiserror", + "wasmparser", +] + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "winnow" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deac0939bd6e4f24ab5919fbf751c97a8cfc8543bb083a305ed5c0c10bb241d1" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.7+zstd.1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" +dependencies = [ + "cc", + "libc", + "pkg-config", +] diff --git a/tools/runtime-codegen/Cargo.toml b/tools/runtime-codegen/Cargo.toml new file mode 100644 index 00000000000..5eea4cdbc88 --- /dev/null +++ b/tools/runtime-codegen/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "runtime-codegen" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2021" +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 + +[workspace] + +[dependencies] +clap = { version = "4.0.8", features = ["derive", "cargo"] } +codec = { package = "parity-scale-codec", version = "3.1.5", default-features = false, features = ["derive"] } +color-eyre = "0.6.1" +proc-macro2 = "1.0.51" +subxt-codegen = "0.27.1" +syn = "1.0" +wasm-loader = { git = "https://github.com/chevdor/subwasm", branch = "master" } +wasm-testbed = { git = "https://github.com/chevdor/subwasm", branch = "master" } \ No newline at end of file diff --git a/tools/runtime-codegen/README.md b/tools/runtime-codegen/README.md new file mode 100644 index 00000000000..155e90b369c --- /dev/null +++ b/tools/runtime-codegen/README.md @@ -0,0 +1,11 @@ +This is a tool for generating the bridge runtime code from metadata. + +Example commands: + +``` +cargo run --bin runtime-codegen -- --from-node-url "http://localhost:20433" > /tmp/rialto_codegen.rs +``` + +``` +cargo run --bin runtime-codegen -- --from-wasm ~/workplace/bridge-hub-rococo_runtime-v9360.compact.compressed.wasm > /tmp/rococo_bridge_hub_codegen.rs +``` \ No newline at end of file diff --git a/tools/runtime-codegen/src/main.rs b/tools/runtime-codegen/src/main.rs new file mode 100644 index 00000000000..e1aa142e558 --- /dev/null +++ b/tools/runtime-codegen/src/main.rs @@ -0,0 +1,173 @@ +// Copyright 2019-2023 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 . + +use clap::Parser as ClapParser; +use codec::Encode; +use color_eyre::eyre; +use std::{env, path::PathBuf}; +use subxt_codegen::{ + generate_runtime_api_from_bytes, generate_runtime_api_from_url, utils::Uri, CratePath, + DerivesRegistry, TypeSubstitutes, +}; +use wasm_testbed::WasmTestBed; + +/// Command for generating indirect runtimes code. +#[derive(Debug, ClapParser)] +struct Command { + #[clap(name = "from-node-url", long, value_parser)] + node_url: Option, + #[clap(name = "from-wasm-file", long, value_parser)] + wasm_file: Option, +} + +enum RuntimeMetadataSource { + NodeUrl(Uri), + WasmFile(wasm_loader::Source), +} + +impl RuntimeMetadataSource { + fn from_command(cmd: Command) -> color_eyre::Result { + match (cmd.node_url, cmd.wasm_file) { + (Some(_), Some(_)) => Err(eyre::eyre!( + "Please specify one of `--from-node-url` or `--from-wasm-file` but not both" + )), + (None, None) => + Err(eyre::eyre!("Please specify one of `--from-node-url` or `--from-wasm-file`")), + (Some(node_url), None) => Ok(Self::NodeUrl(node_url)), + (None, Some(source)) => + Ok(Self::WasmFile(wasm_loader::Source::File(PathBuf::from(source)))), + } + } +} + +struct TypeSubstitute { + subxt_type: syn::Path, + substitute: syn::Path, +} + +impl TypeSubstitute { + fn simple(subxt_type: &str) -> Self { + Self { + subxt_type: syn::parse_str::(subxt_type).unwrap(), + substitute: syn::parse_str::(&format!("::{subxt_type}")).unwrap(), + } + } + + fn custom(subxt_type: &str, substitute: &str) -> Self { + Self { + subxt_type: syn::parse_str::(subxt_type).unwrap(), + substitute: syn::parse_str::(substitute).unwrap(), + } + } +} + +fn print_runtime(runtime_api: proc_macro2::TokenStream) { + println!( + "// Copyright 2019-2023 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 . + + //! Autogenerated runtime API + //! THIS FILE WAS AUTOGENERATED USING parity-bridges-common::runtime-codegen + //! EXECUTED COMMAND: {} + + {} + ", + env::args().collect::>().join(" "), + runtime_api + ); +} + +fn main() -> color_eyre::Result<()> { + let args: Command = Command::parse(); + let metadata_source = RuntimeMetadataSource::from_command(args)?; + + // Module under which the API is generated. + let item_mod = syn::parse_quote!( + pub mod api {} + ); + // Default module derivatives. + let mut derives = DerivesRegistry::new(&CratePath::default()); + derives.extend_for_all(vec![syn::parse_quote!(Clone)]); + // Type substitutes + let mut type_substitutes = TypeSubstitutes::new(&CratePath::default()); + type_substitutes.extend( + vec![ + TypeSubstitute::simple("sp_core::crypto::AccountId32"), + TypeSubstitute::custom("bp_millau::millau_hash::MillauHash", "::bp_millau::MillauHash"), + TypeSubstitute::simple("bp_millau::BlakeTwoAndKeccak256"), + TypeSubstitute::custom( + "sp_runtime::generic::digest::Digest", + "::sp_runtime::generic::Digest", + ), + TypeSubstitute::custom("sp_runtime::generic::era::Era", "::sp_runtime::generic::Era"), + TypeSubstitute::custom( + "sp_runtime::generic::header::Header", + "::sp_runtime::generic::Header", + ), + TypeSubstitute::simple("bp_header_chain::justification::GrandpaJustification"), + TypeSubstitute::simple("bp_header_chain::InitializationData"), + TypeSubstitute::simple( + "bridge_runtime_common::messages::target::FromBridgedChainMessagesProof", + ), + TypeSubstitute::custom("sp_weights::weight_v2::Weight", "::sp_weights::Weight"), + TypeSubstitute::simple( + "bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof", + ), + TypeSubstitute::simple("bp_messages::UnrewardedRelayersState"), + ] + .drain(..) + .map(|substitute| (substitute.subxt_type, substitute.substitute.try_into().unwrap())), + ); + + // Generate the Runtime API. + let runtime_api = match metadata_source { + RuntimeMetadataSource::NodeUrl(node_url) => generate_runtime_api_from_url( + item_mod, + &node_url, + derives, + type_substitutes, + CratePath::default(), + ), + RuntimeMetadataSource::WasmFile(source) => { + let testbed = WasmTestBed::new(&source) + .map_err(|e| eyre::eyre!("Error creating WasmTestBed: {:?}", e))?; + generate_runtime_api_from_bytes( + item_mod, + &testbed.runtime_metadata_prefixed().encode(), + derives, + type_substitutes, + CratePath::default(), + ) + }, + }; + + print_runtime(runtime_api); + + Ok(()) +} From 1e489dddce1f36824bfe00157f9972f7e7ad22ee Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 17 Apr 2023 14:18:00 +0200 Subject: [PATCH 55/57] Updated REAMDE.md and BRIDGES.md (inspired by original https://github.com/paritytech/polkadot/blob/d22eb62fe40e55e15eb91d375f48cc540d83a47e/BRIDGES.md) --- BRIDGES.md | 88 +++++++++++++++++++++++ parachains/runtimes/bridge-hubs/README.md | 38 ---------- 2 files changed, 88 insertions(+), 38 deletions(-) create mode 100644 BRIDGES.md diff --git a/BRIDGES.md b/BRIDGES.md new file mode 100644 index 00000000000..a9fff624cdc --- /dev/null +++ b/BRIDGES.md @@ -0,0 +1,88 @@ +# 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. + +(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? + +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 +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 +(in practice) +``` +cd + +# this will update new git branches from bridges repo +# there could be unresolved conflicts, but dont worry, +# lots of them are caused because of removed unneeded files with patch step, +./scripts/bridges_update_subtree.sh fetch + +# so, after fetch and before solving conflicts just run patch, +# this will remove unneeded files and checks if subtree modules compiles +./scripts/bridges_update_subtree.sh patch + +# if there are conflicts, this could help, +# this removes locally deleted files at least (move changes to git stash for commit) +./scripts/bridges_update_subtree.sh merge + +# (optional) when conflicts resolved, you can check build again - should pass +# also important: this updates global Cargo.lock +./scripts/bridges_update_subtree.sh patch + +# add changes to the commit, first command `fetch` starts merge, +# 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? +(in theory) + +Note that it's totally fine to ping the **Bridges Team** to do that for you. The point +of adding the code as `git subtree` is to **reduce maintenance cost** for Cumulus/Polkadot +developers. + +If you still would like to either update the code to match latest code from the repo +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: +``` +$ 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 +``` + +2. To update Bridges: +``` +$ git fetch bridges master +$ git subtree pull --prefix=bridges bridges master --squash +```` + +We use `--squash` to avoid adding individual commits and rather squashing them +all into one. + +3. Clean unneeded files here: +``` +./bridges/scripts/verify-pallets-build.sh --ignore-git-state --no-revert +``` + +4. Contributing back to Bridges (creating upstream PR) +``` +$ git subtree push --prefix=bridges my-bridges master +``` +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/parachains/runtimes/bridge-hubs/README.md b/parachains/runtimes/bridge-hubs/README.md index 7a6cb35aaf7..79e82f3497a 100644 --- a/parachains/runtimes/bridge-hubs/README.md +++ b/parachains/runtimes/bridge-hubs/README.md @@ -35,41 +35,3 @@ or # BridgeHubPolkadot zombienet-linux --provider native spawn ./zombienet/examples/bridge_hub_polkadot_local_network.toml ``` - ----- -## Git subtree `./bridges` - -Add Bridges repo as a local remote and synchronize it with latest `master` from bridges repo: - -### How to update `bridges` subtree -``` -cd -# this will update new git branches from bridges repo -# there could be unresolved conflicts, but dont worry, -# lots of them are caused because of removed unneeded files with patch step :) -# so before solving conflicts just run patch -./scripts/bridges_update_subtree.sh fetch -# this will remove unneeded files and checks if subtree modules compiles -./scripts/bridges_update_subtree.sh patch -# if there are conflicts, this could help, removes locally deleted files at least -# (but you can also do this manually) -./scripts/bridges_update_subtree.sh merge -# when conflicts resolved, you can check build again - should pass -# also important: this updates global Cargo.lock -./scripts/bridges_update_subtree.sh patch -```` -We use `--squash` to avoid adding individual commits and rather squashing them -all into one. -Now we use `master` branch, but in future, it could change to some release branch/tag. - -### How was first time initialized (does not need anymore) -``` -cd -git remote add -f bridges git@github.com:paritytech/parity-bridges-common.git -# (ran just only first time, when subtree was initialized) -git subtree add --prefix=bridges bridges master --squash -# remove unnecessery files -./scripts/bridges_update_subtree.sh patch -./scripts/bridges_update_subtree.sh merge -git commit --amend -``` From 0670d9fa5ae67f6f01028440318a723d1b330720 Mon Sep 17 00:00:00 2001 From: Branislav Kontur Date: Mon, 17 Apr 2023 14:19:03 +0200 Subject: [PATCH 56/57] Squashed 'bridges/' changes from d30927c08..d3970944b d3970944b Small simplifications (#2050) git-subtree-dir: bridges git-subtree-split: d3970944b0cfc4ea5226225e1ca07dab234c3556 --- modules/messages/src/inbound_lane.rs | 16 +++++++--------- primitives/messages/src/lib.rs | 12 +++++------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/modules/messages/src/inbound_lane.rs b/modules/messages/src/inbound_lane.rs index 3f64ab765b5..59ff5667195 100644 --- a/modules/messages/src/inbound_lane.rs +++ b/modules/messages/src/inbound_lane.rs @@ -198,19 +198,17 @@ impl InboundLane { ); // now let's update inbound lane storage - let push_new = match data.relayers.back_mut() { + match data.relayers.back_mut() { Some(entry) if entry.relayer == *relayer_at_bridged_chain => { entry.messages.note_dispatched_message(); - false }, - _ => true, + _ => { + data.relayers.push_back(UnrewardedRelayer { + relayer: relayer_at_bridged_chain.clone(), + messages: DeliveredMessages::new(nonce), + }); + }, }; - if push_new { - data.relayers.push_back(UnrewardedRelayer { - relayer: (*relayer_at_bridged_chain).clone(), - messages: DeliveredMessages::new(nonce), - }); - } self.storage.set_data(data); ReceivalResult::Dispatched(dispatch_result) diff --git a/primitives/messages/src/lib.rs b/primitives/messages/src/lib.rs index 3910837a442..2828d5af006 100644 --- a/primitives/messages/src/lib.rs +++ b/primitives/messages/src/lib.rs @@ -164,11 +164,9 @@ impl InboundLaneData { where RelayerId: MaxEncodedLen, { - let message_nonce_size = MessageNonce::max_encoded_len(); - let relayer_id_encoded_size = RelayerId::max_encoded_len(); - let relayers_entry_size = relayer_id_encoded_size.checked_add(2 * message_nonce_size)?; - let relayers_size = relayers_entries.checked_mul(relayers_entry_size)?; - relayers_size.checked_add(message_nonce_size) + relayers_entries + .checked_mul(UnrewardedRelayer::::max_encoded_len())? + .checked_add(MessageNonce::max_encoded_len()) } /// Returns the approximate size of the struct as u32, given a number of entries in the @@ -223,7 +221,7 @@ pub struct InboundMessageDetails { /// /// This struct represents a continuous range of messages that have been delivered by the same /// relayer and whose confirmations are still pending. -#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)] +#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct UnrewardedRelayer { /// Identifier of the relayer. pub relayer: RelayerId, @@ -270,7 +268,7 @@ pub enum ReceivalResult { } /// Delivered messages with their dispatch result. -#[derive(Clone, Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +#[derive(Clone, Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub struct DeliveredMessages { /// Nonce of the first message that has been delivered (inclusive). pub begin: MessageNonce, From 95c088b0aeed74a5061eca05e1ee8bff80566049 Mon Sep 17 00:00:00 2001 From: Alistair Singh Date: Mon, 17 Apr 2023 15:05:54 +0000 Subject: [PATCH 57/57] updated lock file --- Cargo.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 31e0bba3937..654e7621522 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12508,12 +12508,10 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "snowbridge-core", "sp-core", "sp-runtime", "sp-std", "xcm", - "xcm-executor", ] [[package]]